Add projects
This commit is contained in:
parent
2d3a9ad623
commit
8b607dd700
1802 changed files with 503346 additions and 2 deletions
110
backend/internal/runtime/executor/helps/claude_code_session.go
Normal file
110
backend/internal/runtime/executor/helps/claude_code_session.go
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
package helps
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
const (
|
||||
ClaudeCodeSessionHeader = "X-Claude-Code-Session-Id"
|
||||
ClaudeCodeAgentHeader = "X-Claude-Code-Agent-Id"
|
||||
ClaudeCodeMainAgentID = "main"
|
||||
)
|
||||
|
||||
var claudeCodeSessionSuffixPattern = regexp.MustCompile(`_session_([a-f0-9-]+)$`)
|
||||
|
||||
// ExtractClaudeCodeSessionID resolves a Claude Code session ID, preferring X-Claude-Code-Session-Id over payload metadata.
|
||||
func ExtractClaudeCodeSessionID(ctx context.Context, payload []byte, headers http.Header) string {
|
||||
if sessionID := claudeCodeHeader(ctx, headers, ClaudeCodeSessionHeader); sessionID != "" {
|
||||
return sessionID
|
||||
}
|
||||
return extractClaudeCodeSessionIDFromPayload(payload)
|
||||
}
|
||||
|
||||
// ExtractClaudeCodeAgentID resolves the Claude Code agent ID and uses a stable sentinel for the root agent.
|
||||
func ExtractClaudeCodeAgentID(ctx context.Context, headers http.Header) string {
|
||||
if agentID := claudeCodeHeader(ctx, headers, ClaudeCodeAgentHeader); agentID != "" {
|
||||
return agentID
|
||||
}
|
||||
return ClaudeCodeMainAgentID
|
||||
}
|
||||
|
||||
// ClaudeCodeExecutionScope returns the stable root-session and agent identity used by Codex execution state.
|
||||
func ClaudeCodeExecutionScope(ctx context.Context, payload []byte, headers http.Header) (string, bool) {
|
||||
sessionID := ExtractClaudeCodeSessionID(ctx, payload, headers)
|
||||
if sessionID == "" {
|
||||
return "", false
|
||||
}
|
||||
return "claude:" + sessionID + ":agent:" + ExtractClaudeCodeAgentID(ctx, headers), true
|
||||
}
|
||||
|
||||
func claudeCodeHeader(ctx context.Context, headers http.Header, name string) string {
|
||||
if value := headerValueCaseInsensitive(headers, name); value != "" {
|
||||
return value
|
||||
}
|
||||
if ctx != nil {
|
||||
if ginCtx, ok := ctx.Value("gin").(*gin.Context); ok && ginCtx != nil && ginCtx.Request != nil {
|
||||
return headerValueCaseInsensitive(ginCtx.Request.Header, name)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// HeaderValueCaseInsensitive returns the first non-empty header value matching name case-insensitively.
|
||||
func HeaderValueCaseInsensitive(headers http.Header, name string) string {
|
||||
return headerValueCaseInsensitive(headers, name)
|
||||
}
|
||||
|
||||
func headerValueCaseInsensitive(headers http.Header, name string) string {
|
||||
if headers == nil {
|
||||
return ""
|
||||
}
|
||||
if value := strings.TrimSpace(headers.Get(name)); value != "" {
|
||||
return value
|
||||
}
|
||||
for key, values := range headers {
|
||||
if !strings.EqualFold(key, name) {
|
||||
continue
|
||||
}
|
||||
for _, value := range values {
|
||||
if value = strings.TrimSpace(value); value != "" {
|
||||
return value
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func extractClaudeCodeSessionIDFromPayload(payload []byte) string {
|
||||
if len(payload) == 0 {
|
||||
return ""
|
||||
}
|
||||
userID := gjson.GetBytes(payload, "metadata.user_id").String()
|
||||
if userID == "" {
|
||||
return ""
|
||||
}
|
||||
if matches := claudeCodeSessionSuffixPattern.FindStringSubmatch(userID); len(matches) >= 2 {
|
||||
return matches[1]
|
||||
}
|
||||
if len(userID) > 0 && userID[0] == '{' {
|
||||
return strings.TrimSpace(gjson.Get(userID, "session_id").String())
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// ClaudeCodePromptCache derives a deterministic upstream prompt_cache_key for one Claude Code agent.
|
||||
func ClaudeCodePromptCache(ctx context.Context, modelName string, payload []byte, headers http.Header) (CodexCache, bool, error) {
|
||||
modelName = strings.TrimSpace(modelName)
|
||||
executionScope, ok := ClaudeCodeExecutionScope(ctx, payload, headers)
|
||||
if modelName == "" || !ok {
|
||||
return CodexCache{}, false, nil
|
||||
}
|
||||
identity := strings.Join([]string{"cli-proxy-api:codex:claude-code", modelName, executionScope}, "\x00")
|
||||
return CodexCache{ID: uuid.NewSHA1(uuid.NameSpaceOID, []byte(identity)).String()}, true, nil
|
||||
}
|
||||
Loading…
Reference in a new issue