fix: null content on tool_calls messages; skip empty tool names; rollback on error
This commit is contained in:
parent
37fc5ee968
commit
92db8f88cd
|
|
@ -98,6 +98,15 @@ func Run(ctx context.Context, cfg Config, state State) error {
|
||||||
var results []ToolResult
|
var results []ToolResult
|
||||||
|
|
||||||
for _, tc := range toolCalls {
|
for _, tc := range toolCalls {
|
||||||
|
if tc.Name == "" {
|
||||||
|
results = append(results, ToolResult{
|
||||||
|
ToolCallID: tc.ID,
|
||||||
|
Name: tc.Name,
|
||||||
|
Content: "error: empty tool name",
|
||||||
|
IsError: true,
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
}
|
||||||
emit(cfg, OutputMsg{Role: "call", Name: tc.Name, Content: string(tc.Arguments)})
|
emit(cfg, OutputMsg{Role: "call", Name: tc.Name, Content: string(tc.Arguments)})
|
||||||
|
|
||||||
var result string
|
var result string
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ func NewOpenAI(baseURL, apiKey string) *OpenAIBackend {
|
||||||
|
|
||||||
type openAIMessage struct {
|
type openAIMessage struct {
|
||||||
Role string `json:"role"`
|
Role string `json:"role"`
|
||||||
Content string `json:"content,omitempty"`
|
Content *string `json:"content"`
|
||||||
ToolCalls []openAIToolCall `json:"tool_calls,omitempty"`
|
ToolCalls []openAIToolCall `json:"tool_calls,omitempty"`
|
||||||
ToolCallID string `json:"tool_call_id,omitempty"`
|
ToolCallID string `json:"tool_call_id,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
@ -99,13 +99,12 @@ type openAIStreamResponse struct {
|
||||||
func (b *OpenAIBackend) ChatStream(ctx context.Context, model string, messages []Message, tools []Tool) (<-chan StreamEvent, error) {
|
func (b *OpenAIBackend) ChatStream(ctx context.Context, model string, messages []Message, tools []Tool) (<-chan StreamEvent, error) {
|
||||||
wireMessages := make([]openAIMessage, len(messages))
|
wireMessages := make([]openAIMessage, len(messages))
|
||||||
for i, m := range messages {
|
for i, m := range messages {
|
||||||
wireMessages[i] = openAIMessage{
|
wm := openAIMessage{
|
||||||
Role: m.Role,
|
Role: m.Role,
|
||||||
Content: m.Content,
|
|
||||||
ToolCallID: m.ToolCallID,
|
ToolCallID: m.ToolCallID,
|
||||||
}
|
}
|
||||||
for _, tc := range m.ToolCalls {
|
for _, tc := range m.ToolCalls {
|
||||||
wireMessages[i].ToolCalls = append(wireMessages[i].ToolCalls, openAIToolCall{
|
wm.ToolCalls = append(wm.ToolCalls, openAIToolCall{
|
||||||
ID: tc.ID,
|
ID: tc.ID,
|
||||||
Type: "function",
|
Type: "function",
|
||||||
Function: openAIFunctionCall{
|
Function: openAIFunctionCall{
|
||||||
|
|
@ -114,6 +113,11 @@ func (b *OpenAIBackend) ChatStream(ctx context.Context, model string, messages [
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// OpenAI spec: content must be null (not "") when tool_calls is present.
|
||||||
|
if len(wm.ToolCalls) == 0 {
|
||||||
|
wm.Content = &m.Content
|
||||||
|
}
|
||||||
|
wireMessages[i] = wm
|
||||||
}
|
}
|
||||||
|
|
||||||
var wireTools []openAITool
|
var wireTools []openAITool
|
||||||
|
|
|
||||||
3
main.go
3
main.go
|
|
@ -587,6 +587,9 @@ func (m *model) apply(am agentMsg) {
|
||||||
case "error":
|
case "error":
|
||||||
m.finalizeBuf()
|
m.finalizeBuf()
|
||||||
m.appendDisplay("Error: " + am.content)
|
m.appendDisplay("Error: " + am.content)
|
||||||
|
if m.session != nil {
|
||||||
|
m.session.Rollback()
|
||||||
|
}
|
||||||
|
|
||||||
case "confirm":
|
case "confirm":
|
||||||
m.state = agentConfirming
|
m.state = agentConfirming
|
||||||
|
|
|
||||||
Reference in New Issue