diff --git a/internal/llm/llm.go b/internal/llm/llm.go index 6d965be..582edd8 100644 --- a/internal/llm/llm.go +++ b/internal/llm/llm.go @@ -532,6 +532,19 @@ func (m *Message) Validate() error { "%q message with tool calls", m.Role, ) } + if m.ToolCallID != "" && m.Role != RoleTool { + return fmt.Errorf("%q message with tool call id", m.Role) + } + seen := map[string]bool{} + for _, call := range m.ToolCalls { + if err := call.Validate(); err != nil { + return fmt.Errorf("invalid tool call: %w", err) + } + if seen[call.ID] { + return fmt.Errorf("duplicate tool call id %q", call.ID) + } + seen[call.ID] = true + } return nil } @@ -698,6 +711,20 @@ type ToolCall struct { Type ToolType `json:"type"` } +// Validate checks conformance to the OpenAI API specification. +func (t *ToolCall) Validate() error { + if t.ID == "" { + return fmt.Errorf("missing id") + } + if t.Type != ToolTypeFunction { + return fmt.Errorf("invalid type: %q", t.Type) + } + if t.Function.Name == "" { + return fmt.Errorf("missing function name") + } + return nil +} + // ToolType identifies the kind of tool in a declaration or tool call. type ToolType string