fix: 适配claude code调度openai账号的websearch功能
This commit is contained in:
@@ -54,6 +54,25 @@ func ResponsesToAnthropic(resp *ResponsesResponse, model string) *AnthropicRespo
|
||||
Name: item.Name,
|
||||
Input: json.RawMessage(item.Arguments),
|
||||
})
|
||||
case "web_search_call":
|
||||
toolUseID := "srvtoolu_" + item.ID
|
||||
query := ""
|
||||
if item.Action != nil {
|
||||
query = item.Action.Query
|
||||
}
|
||||
inputJSON, _ := json.Marshal(map[string]string{"query": query})
|
||||
blocks = append(blocks, AnthropicContentBlock{
|
||||
Type: "server_tool_use",
|
||||
ID: toolUseID,
|
||||
Name: "web_search",
|
||||
Input: inputJSON,
|
||||
})
|
||||
emptyResults, _ := json.Marshal([]struct{}{})
|
||||
blocks = append(blocks, AnthropicContentBlock{
|
||||
Type: "web_search_tool_result",
|
||||
ToolUseID: toolUseID,
|
||||
Content: emptyResults,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,12 +388,73 @@ func resToAnthHandleOutputItemDone(evt *ResponsesStreamEvent, state *ResponsesEv
|
||||
if evt.Item == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Handle web_search_call → synthesize server_tool_use + web_search_tool_result blocks.
|
||||
if evt.Item.Type == "web_search_call" && evt.Item.Status == "completed" {
|
||||
return resToAnthHandleWebSearchDone(evt, state)
|
||||
}
|
||||
|
||||
if state.ContentBlockOpen {
|
||||
return closeCurrentBlock(state)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// resToAnthHandleWebSearchDone converts an OpenAI web_search_call output item
|
||||
// into Anthropic server_tool_use + web_search_tool_result content block pairs.
|
||||
// This allows Claude Code to count the searches performed.
|
||||
func resToAnthHandleWebSearchDone(evt *ResponsesStreamEvent, state *ResponsesEventToAnthropicState) []AnthropicStreamEvent {
|
||||
var events []AnthropicStreamEvent
|
||||
events = append(events, closeCurrentBlock(state)...)
|
||||
|
||||
toolUseID := "srvtoolu_" + evt.Item.ID
|
||||
query := ""
|
||||
if evt.Item.Action != nil {
|
||||
query = evt.Item.Action.Query
|
||||
}
|
||||
inputJSON, _ := json.Marshal(map[string]string{"query": query})
|
||||
|
||||
// Emit server_tool_use block (start + stop).
|
||||
idx1 := state.ContentBlockIndex
|
||||
events = append(events, AnthropicStreamEvent{
|
||||
Type: "content_block_start",
|
||||
Index: &idx1,
|
||||
ContentBlock: &AnthropicContentBlock{
|
||||
Type: "server_tool_use",
|
||||
ID: toolUseID,
|
||||
Name: "web_search",
|
||||
Input: inputJSON,
|
||||
},
|
||||
})
|
||||
events = append(events, AnthropicStreamEvent{
|
||||
Type: "content_block_stop",
|
||||
Index: &idx1,
|
||||
})
|
||||
state.ContentBlockIndex++
|
||||
|
||||
// Emit web_search_tool_result block (start + stop).
|
||||
// Content is empty because OpenAI does not expose individual search results;
|
||||
// the model consumes them internally and produces text output.
|
||||
emptyResults, _ := json.Marshal([]struct{}{})
|
||||
idx2 := state.ContentBlockIndex
|
||||
events = append(events, AnthropicStreamEvent{
|
||||
Type: "content_block_start",
|
||||
Index: &idx2,
|
||||
ContentBlock: &AnthropicContentBlock{
|
||||
Type: "web_search_tool_result",
|
||||
ToolUseID: toolUseID,
|
||||
Content: emptyResults,
|
||||
},
|
||||
})
|
||||
events = append(events, AnthropicStreamEvent{
|
||||
Type: "content_block_stop",
|
||||
Index: &idx2,
|
||||
})
|
||||
state.ContentBlockIndex++
|
||||
|
||||
return events
|
||||
}
|
||||
|
||||
func resToAnthHandleCompleted(evt *ResponsesStreamEvent, state *ResponsesEventToAnthropicState) []AnthropicStreamEvent {
|
||||
if state.MessageStopSent {
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user