diff --git a/plugins/wasm-go/extensions/ai-proxy/provider/claude.go b/plugins/wasm-go/extensions/ai-proxy/provider/claude.go index 812ed43af..5c9e40fdc 100644 --- a/plugins/wasm-go/extensions/ai-proxy/provider/claude.go +++ b/plugins/wasm-go/extensions/ai-proxy/provider/claude.go @@ -21,8 +21,11 @@ const ( claudeDefaultMaxTokens = 4096 // Claude Code mode constants - claudeCodeUserAgent = "claude-cli/2.1.2 (external, cli)" - claudeCodeBetaFeatures = "oauth-2025-04-20,interleaved-thinking-2025-05-14,claude-code-20250219" + claudeCodeUserAgent = "claude-cli/2.1.2 (external, cli)" + claudeCodeBetaFeatures = "oauth-2025-04-20,interleaved-thinking-2025-05-14,claude-code-20250219" + claudeCodeSystemPrompt = "You are Claude Code, Anthropic's official CLI for Claude." + claudeCodeBashToolName = "Bash" + claudeCodeBashToolDesc = "Run bash commands" ) type claudeProviderInitializer struct{} @@ -440,8 +443,11 @@ func (c *claudeProvider) buildClaudeTextGenRequest(origRequest *chatCompletionRe claudeRequest.MaxTokens = claudeDefaultMaxTokens } + // Track if system message exists in original request + hasSystemMessage := false for _, message := range origRequest.Messages { if message.Role == roleSystem { + hasSystemMessage = true // In Claude Code mode, use array format with cache_control if c.config.claudeCodeMode { claudeRequest.System = &claudeSystemPrompt{ @@ -521,6 +527,22 @@ func (c *claudeProvider) buildClaudeTextGenRequest(origRequest *chatCompletionRe claudeRequest.Messages = append(claudeRequest.Messages, claudeMessage) } + // In Claude Code mode, add default system prompt if not present + if c.config.claudeCodeMode && !hasSystemMessage { + claudeRequest.System = &claudeSystemPrompt{ + ArrayValue: []claudeChatMessageContent{ + { + Type: contentTypeText, + Text: claudeCodeSystemPrompt, + CacheControl: map[string]interface{}{ + "type": "ephemeral", + }, + }, + }, + IsArray: true, + } + } + for _, tool := range origRequest.Tools { claudeTool := claudeTool{ Name: tool.Function.Name, @@ -530,6 +552,32 @@ func (c *claudeProvider) buildClaudeTextGenRequest(origRequest *chatCompletionRe claudeRequest.Tools = append(claudeRequest.Tools, claudeTool) } + // In Claude Code mode, add Bash tool if not present + if c.config.claudeCodeMode { + hasBashTool := false + for _, tool := range claudeRequest.Tools { + if tool.Name == claudeCodeBashToolName { + hasBashTool = true + break + } + } + if !hasBashTool { + claudeRequest.Tools = append(claudeRequest.Tools, claudeTool{ + Name: claudeCodeBashToolName, + Description: claudeCodeBashToolDesc, + InputSchema: map[string]interface{}{ + "type": "object", + "properties": map[string]interface{}{ + "command": map[string]interface{}{ + "type": "string", + }, + }, + "required": []string{"command"}, + }, + }) + } + } + if tc := origRequest.getToolChoiceObject(); tc != nil { claudeRequest.ToolChoice = &claudeToolChoice{ Name: tc.Function.Name,