mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
This reverts commit e556a816e4.
This commit is contained in:
@@ -55,12 +55,6 @@ func buildCLIToolsPrompt(tools []ToolDefinition) string {
|
||||
func NormalizeToolCall(tc ToolCall) ToolCall {
|
||||
normalized := tc
|
||||
|
||||
if normalized.ThoughtSignature == "" &&
|
||||
normalized.ExtraContent != nil &&
|
||||
normalized.ExtraContent.Google != nil {
|
||||
normalized.ThoughtSignature = normalized.ExtraContent.Google.ThoughtSignature
|
||||
}
|
||||
|
||||
// Ensure Name is populated from Function if not set
|
||||
if normalized.Name == "" && normalized.Function != nil {
|
||||
normalized.Name = normalized.Function.Name
|
||||
@@ -83,9 +77,8 @@ func NormalizeToolCall(tc ToolCall) ToolCall {
|
||||
argsJSON, _ := json.Marshal(normalized.Arguments)
|
||||
if normalized.Function == nil {
|
||||
normalized.Function = &FunctionCall{
|
||||
Name: normalized.Name,
|
||||
Arguments: string(argsJSON),
|
||||
ThoughtSignature: normalized.ThoughtSignature,
|
||||
Name: normalized.Name,
|
||||
Arguments: string(argsJSON),
|
||||
}
|
||||
} else {
|
||||
if normalized.Function.Name == "" {
|
||||
@@ -97,12 +90,6 @@ func NormalizeToolCall(tc ToolCall) ToolCall {
|
||||
if normalized.Function.Arguments == "" {
|
||||
normalized.Function.Arguments = string(argsJSON)
|
||||
}
|
||||
if normalized.Function.ThoughtSignature == "" {
|
||||
normalized.Function.ThoughtSignature = normalized.ThoughtSignature
|
||||
}
|
||||
if normalized.ThoughtSignature == "" {
|
||||
normalized.ThoughtSignature = normalized.Function.ThoughtSignature
|
||||
}
|
||||
}
|
||||
|
||||
return normalized
|
||||
|
||||
@@ -70,23 +70,11 @@ func NewHTTPClient(proxy string) *http.Client {
|
||||
// It mirrors protocoltypes.Message but omits SystemParts, which is an
|
||||
// internal field that would be unknown to third-party endpoints.
|
||||
type openaiMessage struct {
|
||||
Role string `json:"role"`
|
||||
Content string `json:"content"`
|
||||
ReasoningContent string `json:"reasoning_content,omitempty"`
|
||||
ToolCalls []openaiToolCall `json:"tool_calls,omitempty"`
|
||||
ToolCallID string `json:"tool_call_id,omitempty"`
|
||||
}
|
||||
|
||||
type openaiToolCall struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Function *openaiFunctionCall `json:"function,omitempty"`
|
||||
}
|
||||
|
||||
type openaiFunctionCall struct {
|
||||
Name string `json:"name"`
|
||||
Arguments string `json:"arguments"`
|
||||
ThoughtSignature string `json:"thought_signature,omitempty"`
|
||||
Role string `json:"role"`
|
||||
Content string `json:"content"`
|
||||
ReasoningContent string `json:"reasoning_content,omitempty"`
|
||||
ToolCalls []ToolCall `json:"tool_calls,omitempty"`
|
||||
ToolCallID string `json:"tool_call_id,omitempty"`
|
||||
}
|
||||
|
||||
// SerializeMessages converts internal Message structs to the OpenAI wire format.
|
||||
@@ -96,13 +84,12 @@ type openaiFunctionCall struct {
|
||||
func SerializeMessages(messages []Message) []any {
|
||||
out := make([]any, 0, len(messages))
|
||||
for _, m := range messages {
|
||||
toolCalls := serializeToolCalls(m.ToolCalls)
|
||||
if len(m.Media) == 0 {
|
||||
out = append(out, openaiMessage{
|
||||
Role: m.Role,
|
||||
Content: m.Content,
|
||||
ReasoningContent: m.ReasoningContent,
|
||||
ToolCalls: toolCalls,
|
||||
ToolCalls: m.ToolCalls,
|
||||
ToolCallID: m.ToolCallID,
|
||||
})
|
||||
continue
|
||||
@@ -145,8 +132,8 @@ func SerializeMessages(messages []Message) []any {
|
||||
if m.ToolCallID != "" {
|
||||
msg["tool_call_id"] = m.ToolCallID
|
||||
}
|
||||
if len(toolCalls) > 0 {
|
||||
msg["tool_calls"] = toolCalls
|
||||
if len(m.ToolCalls) > 0 {
|
||||
msg["tool_calls"] = m.ToolCalls
|
||||
}
|
||||
if m.ReasoningContent != "" {
|
||||
msg["reasoning_content"] = m.ReasoningContent
|
||||
@@ -156,55 +143,6 @@ func SerializeMessages(messages []Message) []any {
|
||||
return out
|
||||
}
|
||||
|
||||
func serializeToolCalls(toolCalls []ToolCall) []openaiToolCall {
|
||||
if len(toolCalls) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
out := make([]openaiToolCall, 0, len(toolCalls))
|
||||
for _, tc := range toolCalls {
|
||||
wireCall := openaiToolCall{
|
||||
ID: tc.ID,
|
||||
Type: tc.Type,
|
||||
}
|
||||
|
||||
if tc.Function != nil {
|
||||
thoughtSignature := tc.Function.ThoughtSignature
|
||||
if thoughtSignature == "" {
|
||||
thoughtSignature = tc.ThoughtSignature
|
||||
}
|
||||
if thoughtSignature == "" && tc.ExtraContent != nil && tc.ExtraContent.Google != nil {
|
||||
thoughtSignature = tc.ExtraContent.Google.ThoughtSignature
|
||||
}
|
||||
wireCall.Function = &openaiFunctionCall{
|
||||
Name: tc.Function.Name,
|
||||
Arguments: tc.Function.Arguments,
|
||||
ThoughtSignature: thoughtSignature,
|
||||
}
|
||||
} else if tc.Name != "" || len(tc.Arguments) > 0 || tc.ThoughtSignature != "" {
|
||||
thoughtSignature := tc.ThoughtSignature
|
||||
if thoughtSignature == "" && tc.ExtraContent != nil && tc.ExtraContent.Google != nil {
|
||||
thoughtSignature = tc.ExtraContent.Google.ThoughtSignature
|
||||
}
|
||||
argsJSON := "{}"
|
||||
if len(tc.Arguments) > 0 {
|
||||
if encoded, err := json.Marshal(tc.Arguments); err == nil {
|
||||
argsJSON = string(encoded)
|
||||
}
|
||||
}
|
||||
wireCall.Function = &openaiFunctionCall{
|
||||
Name: tc.Name,
|
||||
Arguments: argsJSON,
|
||||
ThoughtSignature: thoughtSignature,
|
||||
}
|
||||
}
|
||||
|
||||
out = append(out, wireCall)
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func parseDataAudioURL(mediaURL string) (format, data string, ok bool) {
|
||||
if !strings.HasPrefix(mediaURL, "data:audio/") {
|
||||
return "", "", false
|
||||
@@ -247,7 +185,6 @@ func ParseResponse(body io.Reader) (*LLMResponse, error) {
|
||||
Google *struct {
|
||||
ThoughtSignature string `json:"thought_signature"`
|
||||
} `json:"google"`
|
||||
ToolFeedbackExplanation string `json:"tool_feedback_explanation"`
|
||||
} `json:"extra_content"`
|
||||
} `json:"tool_calls"`
|
||||
} `json:"message"`
|
||||
@@ -291,17 +228,11 @@ func ParseResponse(body io.Reader) (*LLMResponse, error) {
|
||||
ThoughtSignature: thoughtSignature,
|
||||
}
|
||||
|
||||
if tc.ExtraContent != nil {
|
||||
extraContent := &ExtraContent{
|
||||
ToolFeedbackExplanation: tc.ExtraContent.ToolFeedbackExplanation,
|
||||
}
|
||||
if thoughtSignature != "" {
|
||||
extraContent.Google = &GoogleExtra{
|
||||
if thoughtSignature != "" {
|
||||
toolCall.ExtraContent = &ExtraContent{
|
||||
Google: &GoogleExtra{
|
||||
ThoughtSignature: thoughtSignature,
|
||||
}
|
||||
}
|
||||
if extraContent.Google != nil || strings.TrimSpace(extraContent.ToolFeedbackExplanation) != "" {
|
||||
toolCall.ExtraContent = extraContent
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -162,104 +162,6 @@ func TestSerializeMessages_StripsSystemParts(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSerializeMessages_StripsInternalToolCallExtraContent(t *testing.T) {
|
||||
messages := []Message{
|
||||
{
|
||||
Role: "assistant",
|
||||
ToolCalls: []ToolCall{{
|
||||
ID: "call_1",
|
||||
Type: "function",
|
||||
Function: &FunctionCall{
|
||||
Name: "read_file",
|
||||
Arguments: `{"path":"README.md"}`,
|
||||
ThoughtSignature: "sig-1",
|
||||
},
|
||||
ExtraContent: &ExtraContent{
|
||||
Google: &GoogleExtra{
|
||||
ThoughtSignature: "sig-ignored-here",
|
||||
},
|
||||
ToolFeedbackExplanation: "Read README.md first.",
|
||||
},
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
result := SerializeMessages(messages)
|
||||
|
||||
data, err := json.Marshal(result)
|
||||
if err != nil {
|
||||
t.Fatalf("json.Marshal() error = %v", err)
|
||||
}
|
||||
payload := string(data)
|
||||
if strings.Contains(payload, "extra_content") {
|
||||
t.Fatalf("serialized payload should not include internal extra_content: %s", payload)
|
||||
}
|
||||
if !strings.Contains(payload, "thought_signature") {
|
||||
t.Fatalf("serialized payload should preserve function thought_signature: %s", payload)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSerializeMessages_PreservesTopLevelThoughtSignature(t *testing.T) {
|
||||
messages := []Message{
|
||||
{
|
||||
Role: "assistant",
|
||||
ToolCalls: []ToolCall{{
|
||||
ID: "call_1",
|
||||
Type: "function",
|
||||
ThoughtSignature: "sig-1",
|
||||
Function: &FunctionCall{
|
||||
Name: "read_file",
|
||||
Arguments: `{"path":"README.md"}`,
|
||||
},
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
result := SerializeMessages(messages)
|
||||
|
||||
data, err := json.Marshal(result)
|
||||
if err != nil {
|
||||
t.Fatalf("json.Marshal() error = %v", err)
|
||||
}
|
||||
payload := string(data)
|
||||
if !strings.Contains(payload, `"thought_signature":"sig-1"`) {
|
||||
t.Fatalf("serialized payload should preserve top-level thought signature: %s", payload)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSerializeMessages_PreservesGoogleExtraThoughtSignature(t *testing.T) {
|
||||
messages := []Message{
|
||||
{
|
||||
Role: "assistant",
|
||||
ToolCalls: []ToolCall{{
|
||||
ID: "call_1",
|
||||
Type: "function",
|
||||
Function: &FunctionCall{
|
||||
Name: "read_file",
|
||||
Arguments: `{"path":"README.md"}`,
|
||||
},
|
||||
ExtraContent: &ExtraContent{
|
||||
Google: &GoogleExtra{ThoughtSignature: "sig-1"},
|
||||
},
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
result := SerializeMessages(messages)
|
||||
|
||||
data, err := json.Marshal(result)
|
||||
if err != nil {
|
||||
t.Fatalf("json.Marshal() error = %v", err)
|
||||
}
|
||||
payload := string(data)
|
||||
if strings.Contains(payload, "extra_content") {
|
||||
t.Fatalf("serialized payload should not include extra_content: %s", payload)
|
||||
}
|
||||
if !strings.Contains(payload, `"thought_signature":"sig-1"`) {
|
||||
t.Fatalf("serialized payload should preserve google thought signature: %s", payload)
|
||||
}
|
||||
}
|
||||
|
||||
// --- ParseResponse tests ---
|
||||
|
||||
func TestParseResponse_BasicContent(t *testing.T) {
|
||||
@@ -332,27 +234,6 @@ func TestParseResponse_WithReasoningContent(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseResponse_WithToolFeedbackExplanationExtraContent(t *testing.T) {
|
||||
body := `{"choices":[{"message":{"content":"","tool_calls":[{"id":"call_1","type":"function","function":{"name":"test_tool","arguments":"{}"},"extra_content":{"tool_feedback_explanation":"Check the current config before editing."}}]},"finish_reason":"tool_calls"}]}`
|
||||
out, err := ParseResponse(strings.NewReader(body))
|
||||
if err != nil {
|
||||
t.Fatalf("ParseResponse() error = %v", err)
|
||||
}
|
||||
if len(out.ToolCalls) != 1 {
|
||||
t.Fatalf("len(ToolCalls) = %d, want 1", len(out.ToolCalls))
|
||||
}
|
||||
if out.ToolCalls[0].ExtraContent == nil {
|
||||
t.Fatal("ExtraContent is nil")
|
||||
}
|
||||
if out.ToolCalls[0].ExtraContent.ToolFeedbackExplanation != "Check the current config before editing." {
|
||||
t.Fatalf(
|
||||
"ToolFeedbackExplanation = %q, want %q",
|
||||
out.ToolCalls[0].ExtraContent.ToolFeedbackExplanation,
|
||||
"Check the current config before editing.",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseResponse_InvalidJSON(t *testing.T) {
|
||||
_, err := ParseResponse(strings.NewReader("not json"))
|
||||
if err == nil {
|
||||
|
||||
@@ -11,8 +11,7 @@ type ToolCall struct {
|
||||
}
|
||||
|
||||
type ExtraContent struct {
|
||||
Google *GoogleExtra `json:"google,omitempty"`
|
||||
ToolFeedbackExplanation string `json:"tool_feedback_explanation,omitempty"`
|
||||
Google *GoogleExtra `json:"google,omitempty"`
|
||||
}
|
||||
|
||||
type GoogleExtra struct {
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
package providers
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestNormalizeToolCall_PreservesExtraContentGoogleThoughtSignature(t *testing.T) {
|
||||
tc := NormalizeToolCall(ToolCall{
|
||||
ID: "call_1",
|
||||
Name: "search",
|
||||
Arguments: map[string]any{"q": "pico"},
|
||||
ExtraContent: &ExtraContent{
|
||||
Google: &GoogleExtra{ThoughtSignature: "sig-1"},
|
||||
},
|
||||
})
|
||||
|
||||
if tc.ThoughtSignature != "sig-1" {
|
||||
t.Fatalf("ThoughtSignature = %q, want sig-1", tc.ThoughtSignature)
|
||||
}
|
||||
if tc.Function == nil {
|
||||
t.Fatal("Function is nil")
|
||||
}
|
||||
if tc.Function.ThoughtSignature != "sig-1" {
|
||||
t.Fatalf("Function.ThoughtSignature = %q, want sig-1", tc.Function.ThoughtSignature)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user