From 3dd63e553024b1868e579b9be4e7d6dbd58d6c3e Mon Sep 17 00:00:00 2001 From: Max Date: Tue, 2 Dec 2025 11:33:09 +0800 Subject: [PATCH] Refactor model capabilities to use OpenAI struct - Updated the model capabilities throughout the agent to utilize the new gouOpenAI.Capabilities struct instead of the previous ModelCapabilities. - Adjusted related methods and types to ensure compatibility with the new capabilities structure, enhancing clarity and maintainability. - Improved context handling and message processing by directly integrating OpenAI capabilities, streamlining the overall architecture. --- agent/assistant/agent.go | 68 +++-------- agent/assistant/load.go | 5 +- agent/assistant/trace.go | 3 +- agent/assistant/types.go | 13 -- agent/context/output.go | 15 +-- agent/context/types.go | 3 +- agent/context/types_llm.go | 17 ++- agent/llm/adapters/reasoning.go | 7 +- agent/llm/providers/base/base.go | 17 +-- agent/llm/providers/openai/claude_test.go | 103 +++++++--------- .../llm/providers/openai/deepseek_r1_test.go | 47 ++++---- .../llm/providers/openai/deepseek_v3_test.go | 47 ++++---- agent/llm/providers/openai/gpt5_test.go | 45 ++++--- agent/llm/providers/openai/openai.go | 35 +++--- agent/llm/providers/openai/openai_test.go | 111 ++++++++---------- .../llm/providers/openai/temperature_test.go | 42 +++---- agent/load.go | 3 +- agent/output/adapters/openai/types.go | 2 +- agent/output/adapters/openai/writer.go | 5 +- agent/output/message/types.go | 16 +-- agent/types/types.go | 3 +- 21 files changed, 244 insertions(+), 363 deletions(-) diff --git a/agent/assistant/agent.go b/agent/assistant/agent.go index c6cdb31b..bcb3af53 100644 --- a/agent/assistant/agent.go +++ b/agent/assistant/agent.go @@ -6,6 +6,7 @@ import ( jsoniter "github.com/json-iterator/go" "github.com/yaoapp/gou/connector" + "github.com/yaoapp/gou/connector/openai" "github.com/yaoapp/kun/log" "github.com/yaoapp/yao/agent/assistant/handlers" "github.com/yaoapp/yao/agent/context" @@ -303,7 +304,7 @@ func (ast *Assistant) Stream(ctx *context.Context, inputMessages []context.Messa // GetConnector get the connector object, capabilities, and error with priority: createResponse > ctx > ast // Note: createResponse.Connector is already applied to ctx.Connector by applyContextAdjustments in create.go // Returns: (connector, capabilities, error) -func (ast *Assistant) GetConnector(ctx *context.Context) (connector.Connector, *context.ModelCapabilities, error) { +func (ast *Assistant) GetConnector(ctx *context.Context) (connector.Connector, *openai.Capabilities, error) { // Determine connector ID with priority connectorID := ast.Connector if ctx.Connector != "" { @@ -328,62 +329,27 @@ func (ast *Assistant) GetConnector(ctx *context.Context) (connector.Connector, * } // getConnectorCapabilities get the capabilities of a connector from settings -func (ast *Assistant) getConnectorCapabilities(connectorID string) *context.ModelCapabilities { - // Initialize with default capabilities (all disabled) - falseVal := false - capabilities := &context.ModelCapabilities{ - Vision: falseVal, - ToolCalls: &falseVal, - Audio: &falseVal, - Reasoning: &falseVal, - Streaming: &falseVal, - } - +func (ast *Assistant) getConnectorCapabilities(connectorID string) *openai.Capabilities { // Get model capabilities from global configuration modelCaps, exists := modelCapabilities[connectorID] if !exists { // Return default capabilities if model not found in configuration - return capabilities + falseVal := false + return &openai.Capabilities{ + Vision: falseVal, + ToolCalls: false, + Audio: false, + Reasoning: false, + Streaming: false, + JSON: false, + Multimodal: false, + TemperatureAdjustable: true, // Default to true for non-reasoning models + } } - // Update capabilities based on model configuration - // Vision can be bool or string (VisionFormat) - if modelCaps.Vision != nil { - capabilities.Vision = modelCaps.Vision - } - - // Handle both Tools (deprecated) and ToolCalls - if modelCaps.ToolCalls || modelCaps.Tools { - v := true - capabilities.ToolCalls = &v - } - - if modelCaps.Audio { - v := true - capabilities.Audio = &v - } - - if modelCaps.Reasoning { - v := true - capabilities.Reasoning = &v - } - - if modelCaps.Streaming { - v := true - capabilities.Streaming = &v - } - - if modelCaps.JSON { - v := true - capabilities.JSON = &v - } - - if modelCaps.Multimodal { - v := true - capabilities.Multimodal = &v - } - - return capabilities + // Return capabilities directly + // Note: TemperatureAdjustable is automatically set in connector.Setting() based on Reasoning flag + return &modelCaps } // Info get the assistant information diff --git a/agent/assistant/load.go b/agent/assistant/load.go index cf98ad55..718d6303 100644 --- a/agent/assistant/load.go +++ b/agent/assistant/load.go @@ -11,6 +11,7 @@ import ( jsoniter "github.com/json-iterator/go" "github.com/spf13/cast" "github.com/yaoapp/gou/application" + gouOpenAI "github.com/yaoapp/gou/connector/openai" "github.com/yaoapp/gou/fs" v8 "github.com/yaoapp/gou/runtime/v8" "github.com/yaoapp/yao/agent/assistant/hook" @@ -26,7 +27,7 @@ import ( var loaded = NewCache(200) // 200 is the default capacity var storage store.Store = nil var search interface{} = nil -var modelCapabilities map[string]ModelCapabilities = map[string]ModelCapabilities{} +var modelCapabilities map[string]gouOpenAI.Capabilities = map[string]gouOpenAI.Capabilities{} var defaultConnector string = "" // default connector var globalUses *context.Uses = nil // global uses configuration from agent.yml @@ -131,7 +132,7 @@ func SetStorage(s store.Store) { } // SetModelCapabilities set the model capabilities configuration -func SetModelCapabilities(capabilities map[string]ModelCapabilities) { +func SetModelCapabilities(capabilities map[string]gouOpenAI.Capabilities) { modelCapabilities = capabilities } diff --git a/agent/assistant/trace.go b/agent/assistant/trace.go index c8807f60..61ea2b7e 100644 --- a/agent/assistant/trace.go +++ b/agent/assistant/trace.go @@ -3,6 +3,7 @@ package assistant import ( "fmt" + "github.com/yaoapp/gou/connector/openai" "github.com/yaoapp/kun/log" "github.com/yaoapp/yao/agent/context" "github.com/yaoapp/yao/agent/i18n" @@ -48,7 +49,7 @@ func (ast *Assistant) traceCreateHook(agentNode types.Node, createResponse *cont } // traceConnectorCapabilities logs the connector capabilities to the agent trace node -func (ast *Assistant) traceConnectorCapabilities(agentNode types.Node, capabilities *context.ModelCapabilities) { +func (ast *Assistant) traceConnectorCapabilities(agentNode types.Node, capabilities *openai.Capabilities) { if agentNode == nil { return } diff --git a/agent/assistant/types.go b/agent/assistant/types.go index 542e76d6..6345930d 100644 --- a/agent/assistant/types.go +++ b/agent/assistant/types.go @@ -40,19 +40,6 @@ type Assistant struct { // toolCalls bool // Whether this assistant supports tool_calls } -// ModelCapabilities defines the capabilities of a language model -// This configuration is loaded from agent/models.yml -type ModelCapabilities struct { - Vision interface{} `json:"vision,omitempty" yaml:"vision,omitempty"` // Supports vision/image input: bool or VisionFormat string ("openai", "claude"/"base64", "default") - Tools bool `json:"tools,omitempty" yaml:"tools,omitempty"` // Supports tool/function calling (deprecated, use ToolCalls) - ToolCalls bool `json:"tool_calls,omitempty" yaml:"tool_calls,omitempty"` // Supports tool/function calling - Audio bool `json:"audio,omitempty" yaml:"audio,omitempty"` // Supports audio input/output - Reasoning bool `json:"reasoning,omitempty" yaml:"reasoning,omitempty"` // Supports reasoning/thinking mode (o1, DeepSeek R1) - Streaming bool `json:"streaming,omitempty" yaml:"streaming,omitempty"` // Supports streaming responses - JSON bool `json:"json,omitempty" yaml:"json,omitempty"` // Supports JSON mode - Multimodal bool `json:"multimodal,omitempty" yaml:"multimodal,omitempty"` // Supports multimodal input -} - // VisionCapableModels list of LLM models that support vision capabilities var VisionCapableModels = map[string]bool{ // OpenAI Models diff --git a/agent/context/output.go b/agent/context/output.go index 23683a60..e50bdc54 100644 --- a/agent/context/output.go +++ b/agent/context/output.go @@ -3,6 +3,7 @@ package context import ( "time" + "github.com/yaoapp/gou/connector/openai" "github.com/yaoapp/yao/agent/output" "github.com/yaoapp/yao/agent/output/message" ) @@ -290,18 +291,10 @@ func (ctx *Context) getOutput() (*output.Output, error) { Accept: string(ctx.Accept), } - // Convert ModelCapabilities to message.ModelCapabilities + // Set ModelCapabilities (now using openai.Capabilities directly) if ctx.Capabilities != nil { - options.Capabilities = &message.ModelCapabilities{ - Vision: ctx.Capabilities.Vision, - ToolCalls: ctx.Capabilities.ToolCalls, - Audio: ctx.Capabilities.Audio, - Reasoning: ctx.Capabilities.Reasoning, - Streaming: ctx.Capabilities.Streaming, - JSON: ctx.Capabilities.JSON, - Multimodal: ctx.Capabilities.Multimodal, - TemperatureAdjustable: ctx.Capabilities.TemperatureAdjustable, - } + caps := openai.Capabilities(*ctx.Capabilities) + options.Capabilities = &caps } var err error diff --git a/agent/context/types.go b/agent/context/types.go index 1e6ecc82..4a5f6587 100644 --- a/agent/context/types.go +++ b/agent/context/types.go @@ -5,6 +5,7 @@ import ( "sync" "time" + "github.com/yaoapp/gou/connector/openai" "github.com/yaoapp/gou/plan" "github.com/yaoapp/gou/store" "github.com/yaoapp/yao/agent/output" @@ -238,7 +239,7 @@ type Context struct { Skip *Skip `json:"skip,omitempty"` // Skip configuration (history, trace, etc.), nil means don't skip anything // Model capabilities (set by assistant, used by output adapters) - Capabilities *ModelCapabilities `json:"-"` // Model capabilities for the current connector + Capabilities *openai.Capabilities `json:"-"` // Model capabilities for the current connector // Interrupt control (all interrupt-related logic is encapsulated in InterruptController) Interrupt *InterruptController `json:"-"` // Interrupt controller for handling user interrupts during streaming diff --git a/agent/context/types_llm.go b/agent/context/types_llm.go index 64cc9ea0..541e51b8 100644 --- a/agent/context/types_llm.go +++ b/agent/context/types_llm.go @@ -1,6 +1,9 @@ package context -import "github.com/yaoapp/yao/agent/output/message" +import ( + "github.com/yaoapp/gou/connector/openai" + "github.com/yaoapp/yao/agent/output/message" +) // Uses represents the wrapper configurations for assistant // Used to specify which assistant or MCP server to use for vision, audio, search, and fetch operations @@ -28,17 +31,13 @@ const ( VisionFormatDefault VisionFormat = "default" ) -// ModelCapabilities defines the capabilities of a language model -// Used by LLM to select appropriate provider and validate requests -type ModelCapabilities message.ModelCapabilities - // GetVisionSupport returns whether vision is supported and the format -func (m *ModelCapabilities) GetVisionSupport() (bool, VisionFormat) { - if m == nil || m.Vision == nil { +func GetVisionSupport(cap *openai.Capabilities) (bool, VisionFormat) { + if cap == nil || cap.Vision == nil { return false, VisionFormatNone } - switch v := m.Vision.(type) { + switch v := cap.Vision.(type) { case bool: // Legacy bool format return v, VisionFormatDefault @@ -65,7 +64,7 @@ func (m *ModelCapabilities) GetVisionSupport() (bool, VisionFormat) { type CompletionOptions struct { // Model capabilities (used by LLM to select appropriate provider) // nil means capabilities are not specified/checked - Capabilities *ModelCapabilities `json:"capabilities,omitempty"` + Capabilities *openai.Capabilities `json:"capabilities,omitempty"` // User-specified tools for vision, audio, search, and fetch processing Uses *Uses `json:"uses,omitempty"` diff --git a/agent/llm/adapters/reasoning.go b/agent/llm/adapters/reasoning.go index 62a45474..a864e6a0 100644 --- a/agent/llm/adapters/reasoning.go +++ b/agent/llm/adapters/reasoning.go @@ -1,6 +1,7 @@ package adapters import ( + "github.com/yaoapp/gou/connector/openai" "github.com/yaoapp/yao/agent/context" ) @@ -28,7 +29,7 @@ type ReasoningAdapter struct { // NewReasoningAdapter creates a new reasoning adapter // If cap.TemperatureAdjustable is provided, it overrides the default behavior -func NewReasoningAdapter(format ReasoningFormat, cap *context.ModelCapabilities) *ReasoningAdapter { +func NewReasoningAdapter(format ReasoningFormat, cap *openai.Capabilities) *ReasoningAdapter { supportsEffort := false supportsTemperature := true @@ -49,8 +50,8 @@ func NewReasoningAdapter(format ReasoningFormat, cap *context.ModelCapabilities) } // Override with explicit capability if provided - if cap != nil && cap.TemperatureAdjustable != nil { - supportsTemperature = *cap.TemperatureAdjustable + if cap != nil { + supportsTemperature = cap.TemperatureAdjustable } return &ReasoningAdapter{ diff --git a/agent/llm/providers/base/base.go b/agent/llm/providers/base/base.go index 1f281888..10ebc12e 100644 --- a/agent/llm/providers/base/base.go +++ b/agent/llm/providers/base/base.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/yaoapp/gou/connector" + "github.com/yaoapp/gou/connector/openai" "github.com/yaoapp/yao/agent/context" ) @@ -11,11 +12,11 @@ import ( // Provides common functionality for all LLM providers type Provider struct { Connector connector.Connector - Capabilities *context.ModelCapabilities + Capabilities *openai.Capabilities } // NewProvider create a new base provider -func NewProvider(conn connector.Connector, capabilities *context.ModelCapabilities) *Provider { +func NewProvider(conn connector.Connector, capabilities *openai.Capabilities) *Provider { return &Provider{ Connector: conn, Capabilities: capabilities, @@ -74,33 +75,33 @@ func (p *Provider) SupportsVision() bool { if p.Capabilities == nil { return false } - supported, _ := p.Capabilities.GetVisionSupport() + supported, _ := context.GetVisionSupport(p.Capabilities) return supported } // SupportsAudio check if this provider supports audio func (p *Provider) SupportsAudio() bool { - return p.Capabilities != nil && p.Capabilities.Audio != nil && *p.Capabilities.Audio + return p.Capabilities != nil && p.Capabilities.Audio } // SupportsTools check if this provider supports tool calls func (p *Provider) SupportsTools() bool { - return p.Capabilities != nil && p.Capabilities.ToolCalls != nil && *p.Capabilities.ToolCalls + return p.Capabilities != nil && p.Capabilities.ToolCalls } // SupportsStreaming check if this provider supports streaming func (p *Provider) SupportsStreaming() bool { - return p.Capabilities != nil && p.Capabilities.Streaming != nil && *p.Capabilities.Streaming + return p.Capabilities != nil && p.Capabilities.Streaming } // SupportsJSON check if this provider supports JSON mode func (p *Provider) SupportsJSON() bool { - return p.Capabilities != nil && p.Capabilities.JSON != nil && *p.Capabilities.JSON + return p.Capabilities != nil && p.Capabilities.JSON } // SupportsReasoning check if this provider supports reasoning mode func (p *Provider) SupportsReasoning() bool { - return p.Capabilities != nil && p.Capabilities.Reasoning != nil && *p.Capabilities.Reasoning + return p.Capabilities != nil && p.Capabilities.Reasoning } // GetConnectorSetting gets a setting value from the connector diff --git a/agent/llm/providers/openai/claude_test.go b/agent/llm/providers/openai/claude_test.go index 3b31566f..d0b1e2bd 100644 --- a/agent/llm/providers/openai/claude_test.go +++ b/agent/llm/providers/openai/claude_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/yaoapp/gou/connector" + "github.com/yaoapp/gou/connector/openai" "github.com/yaoapp/gou/plan" "github.com/yaoapp/yao/agent/context" "github.com/yaoapp/yao/agent/llm" @@ -60,15 +61,13 @@ func TestClaudeSonnet4StreamBasic(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true - falseVal := false options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Streaming: &trueVal, - Reasoning: &falseVal, // Claude Sonnet 4 (non-thinking) doesn't expose reasoning - ToolCalls: &trueVal, - Vision: &trueVal, - Multimodal: &trueVal, + Capabilities: &openai.Capabilities{ + Streaming: true, + Reasoning: false, // Claude Sonnet 4 (non-thinking) doesn't expose reasoning + ToolCalls: true, + Vision: "claude", // Claude requires base64 format + Multimodal: true, }, } @@ -140,15 +139,13 @@ func TestClaudeSonnet4PostBasic(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true - falseVal := false options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Streaming: &falseVal, - Reasoning: &falseVal, - ToolCalls: &trueVal, - Vision: &trueVal, - Multimodal: &trueVal, + Capabilities: &openai.Capabilities{ + Streaming: false, + Reasoning: false, + ToolCalls: true, + Vision: "claude", // Claude requires base64 format + Multimodal: true, }, } @@ -206,15 +203,13 @@ func TestClaudeSonnet4WithToolCalls(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true - falseVal := false options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Streaming: &falseVal, - Reasoning: &falseVal, - ToolCalls: &trueVal, - Vision: &trueVal, - Multimodal: &trueVal, + Capabilities: &openai.Capabilities{ + Streaming: false, + Reasoning: false, + ToolCalls: true, + Vision: "claude", // Claude requires base64 format + Multimodal: true, }, } @@ -244,8 +239,8 @@ func TestClaudeSonnet4WithToolCalls(t *testing.T) { options.Tools = []map[string]interface{}{simpleTool} options.ToolChoice = "auto" - // Set lower max_tokens for faster response - maxTokens := 50 + // Set enough tokens for tool call response + maxTokens := 150 options.MaxTokens = &maxTokens llmInstance, err := llm.New(conn, options) @@ -256,7 +251,7 @@ func TestClaudeSonnet4WithToolCalls(t *testing.T) { messages := []context.Message{ { Role: context.RoleUser, - Content: "Call get_info with query='A' and count=1", + Content: "Please use the get_info function to retrieve information. Pass 'A' as the query parameter and 1 as the count parameter.", }, } @@ -299,15 +294,13 @@ func TestClaudeSonnet4Vision(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true - falseVal := false options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Streaming: &falseVal, - Reasoning: &falseVal, - ToolCalls: &trueVal, - Vision: &trueVal, - Multimodal: &trueVal, + Capabilities: &openai.Capabilities{ + Streaming: false, + Reasoning: false, + ToolCalls: true, + Vision: "claude", // Claude requires base64 format + Multimodal: true, }, } @@ -376,15 +369,13 @@ func TestClaudeSonnet4ThinkingStream(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true - falseVal := false options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Streaming: &trueVal, - Reasoning: &trueVal, // Claude Thinking mode exposes reasoning - ToolCalls: &falseVal, - Vision: &trueVal, - Multimodal: &trueVal, + Capabilities: &openai.Capabilities{ + Streaming: true, + Reasoning: true, // Claude Thinking mode exposes reasoning + ToolCalls: false, + Vision: "claude", // Claude requires base64 format + Multimodal: true, }, } @@ -456,15 +447,13 @@ func TestClaudeSonnet4ThinkingPost(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true - falseVal := false options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Streaming: &falseVal, - Reasoning: &trueVal, - ToolCalls: &falseVal, - Vision: &trueVal, - Multimodal: &trueVal, + Capabilities: &openai.Capabilities{ + Streaming: false, + Reasoning: true, + ToolCalls: false, + Vision: "claude", // Claude requires base64 format + Multimodal: true, }, } @@ -550,14 +539,12 @@ func TestClaudeTemperatureHandling(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true - falseVal := false options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Streaming: &falseVal, - Reasoning: &tt.reasoning, - ToolCalls: &trueVal, - Vision: &trueVal, + Capabilities: &openai.Capabilities{ + Streaming: false, + Reasoning: tt.reasoning, + ToolCalls: true, + Vision: true, }, } diff --git a/agent/llm/providers/openai/deepseek_r1_test.go b/agent/llm/providers/openai/deepseek_r1_test.go index 4d8a3a3a..839fe642 100644 --- a/agent/llm/providers/openai/deepseek_r1_test.go +++ b/agent/llm/providers/openai/deepseek_r1_test.go @@ -7,6 +7,7 @@ import ( jsoniter "github.com/json-iterator/go" "github.com/yaoapp/gou/connector" + "github.com/yaoapp/gou/connector/openai" "github.com/yaoapp/gou/plan" "github.com/yaoapp/yao/agent/context" "github.com/yaoapp/yao/agent/llm" @@ -28,16 +29,14 @@ func TestDeepSeekR1StreamBasic(t *testing.T) { } // Create LLM instance with capabilities - trueVal := true - falseVal := false options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Streaming: &trueVal, - Reasoning: &trueVal, // DeepSeek R1 supports reasoning - ToolCalls: &falseVal, // R1 doesn't support native tool calls - Vision: &falseVal, - Audio: &falseVal, - Multimodal: &falseVal, + Capabilities: &openai.Capabilities{ + Streaming: true, + Reasoning: true, // DeepSeek R1 supports reasoning + ToolCalls: false, // R1 doesn't support native tool calls + Vision: false, + Audio: false, + Multimodal: false, }, } @@ -207,15 +206,13 @@ func TestDeepSeekR1PostBasic(t *testing.T) { } // Create LLM instance - trueVal := true - falseVal := false options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Reasoning: &trueVal, - ToolCalls: &falseVal, - Vision: &falseVal, - Audio: &falseVal, - Multimodal: &falseVal, + Capabilities: &openai.Capabilities{ + Reasoning: true, + ToolCalls: false, + Vision: false, + Audio: false, + Multimodal: false, }, } @@ -295,16 +292,14 @@ func TestDeepSeekR1LogicPuzzle(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true - falseVal := false options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Streaming: &trueVal, - Reasoning: &trueVal, - ToolCalls: &falseVal, - Vision: &falseVal, - Audio: &falseVal, - Multimodal: &falseVal, + Capabilities: &openai.Capabilities{ + Streaming: true, + Reasoning: true, + ToolCalls: false, + Vision: false, + Audio: false, + Multimodal: false, }, } diff --git a/agent/llm/providers/openai/deepseek_v3_test.go b/agent/llm/providers/openai/deepseek_v3_test.go index f9194ad6..d593d473 100644 --- a/agent/llm/providers/openai/deepseek_v3_test.go +++ b/agent/llm/providers/openai/deepseek_v3_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/yaoapp/gou/connector" + "github.com/yaoapp/gou/connector/openai" "github.com/yaoapp/gou/plan" "github.com/yaoapp/yao/agent/context" "github.com/yaoapp/yao/agent/llm" @@ -24,16 +25,14 @@ func TestDeepSeekV3StreamBasic(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true - falseVal := false options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Streaming: &trueVal, - Reasoning: &falseVal, // V3 doesn't support reasoning - ToolCalls: &trueVal, // V3 supports tool calls - Vision: &falseVal, - Audio: &falseVal, - Multimodal: &falseVal, + Capabilities: &openai.Capabilities{ + Streaming: true, + Reasoning: false, // V3 doesn't support reasoning + ToolCalls: true, // V3 supports tool calls + Vision: false, + Audio: false, + Multimodal: false, }, } @@ -135,15 +134,13 @@ func TestDeepSeekV3PostBasic(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true - falseVal := false options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Reasoning: &falseVal, - ToolCalls: &trueVal, - Vision: &falseVal, - Audio: &falseVal, - Multimodal: &falseVal, + Capabilities: &openai.Capabilities{ + Reasoning: false, + ToolCalls: true, + Vision: false, + Audio: false, + Multimodal: false, }, } @@ -226,12 +223,10 @@ func TestDeepSeekV3WithToolCalls(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true - falseVal := false options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Reasoning: &falseVal, - ToolCalls: &trueVal, + Capabilities: &openai.Capabilities{ + Reasoning: false, + ToolCalls: true, }, } @@ -318,13 +313,11 @@ func TestDeepSeekV3NoReasoningEffort(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true - falseVal := false effort := "high" options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Reasoning: &falseVal, // V3 doesn't support reasoning - ToolCalls: &trueVal, + Capabilities: &openai.Capabilities{ + Reasoning: false, // V3 doesn't support reasoning + ToolCalls: true, }, ReasoningEffort: &effort, // Should be ignored by adapter } diff --git a/agent/llm/providers/openai/gpt5_test.go b/agent/llm/providers/openai/gpt5_test.go index 5e2d709c..b71b0a8c 100644 --- a/agent/llm/providers/openai/gpt5_test.go +++ b/agent/llm/providers/openai/gpt5_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/yaoapp/gou/connector" + "github.com/yaoapp/gou/connector/openai" "github.com/yaoapp/gou/plan" "github.com/yaoapp/yao/agent/context" "github.com/yaoapp/yao/agent/llm" @@ -24,14 +25,13 @@ func TestGPT5StreamBasic(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Streaming: &trueVal, - Reasoning: &trueVal, // GPT-5 supports reasoning - ToolCalls: &trueVal, - Vision: &trueVal, - Multimodal: &trueVal, + Capabilities: &openai.Capabilities{ + Streaming: true, + Reasoning: true, // GPT-5 supports reasoning + ToolCalls: true, + Vision: true, + Multimodal: true, }, } @@ -105,11 +105,10 @@ func TestGPT5ReasoningEffort(t *testing.T) { for _, effort := range effortLevels { t.Run("effort_"+effort, func(t *testing.T) { - trueVal := true options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Reasoning: &trueVal, - ToolCalls: &trueVal, + Capabilities: &openai.Capabilities{ + Reasoning: true, + ToolCalls: true, }, ReasoningEffort: &effort, } @@ -172,11 +171,10 @@ func TestGPT5PostWithToolCalls(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Reasoning: &trueVal, - ToolCalls: &trueVal, + Capabilities: &openai.Capabilities{ + Reasoning: true, + ToolCalls: true, }, } @@ -259,12 +257,11 @@ func TestGPT5Vision(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Reasoning: &trueVal, - Vision: &trueVal, - Multimodal: &trueVal, + Capabilities: &openai.Capabilities{ + Reasoning: true, + Vision: true, + Multimodal: true, }, } @@ -331,13 +328,11 @@ func TestGPT5ReasoningEffortWithGPT4o(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true - falseVal := false effort := "high" options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Reasoning: &falseVal, // GPT-4o doesn't support reasoning - ToolCalls: &trueVal, + Capabilities: &openai.Capabilities{ + Reasoning: false, // GPT-4o doesn't support reasoning + ToolCalls: true, }, ReasoningEffort: &effort, // Should be ignored by adapter } diff --git a/agent/llm/providers/openai/openai.go b/agent/llm/providers/openai/openai.go index 6f60886b..637aa7b0 100644 --- a/agent/llm/providers/openai/openai.go +++ b/agent/llm/providers/openai/openai.go @@ -8,6 +8,7 @@ import ( jsoniter "github.com/json-iterator/go" "github.com/yaoapp/gou/connector" + gouOpenAI "github.com/yaoapp/gou/connector/openai" "github.com/yaoapp/gou/http" "github.com/yaoapp/kun/log" "github.com/yaoapp/yao/agent/context" @@ -142,7 +143,7 @@ func buildAPIURL(host, endpoint string) string { } // New create a new OpenAI provider with capability adapters -func New(conn connector.Connector, capabilities *context.ModelCapabilities) *Provider { +func New(conn connector.Connector, capabilities *gouOpenAI.Capabilities) *Provider { return &Provider{ Provider: base.NewProvider(conn, capabilities), adapters: buildAdapters(capabilities), @@ -150,7 +151,7 @@ func New(conn connector.Connector, capabilities *context.ModelCapabilities) *Pro } // buildAdapters builds capability adapters based on model capabilities -func buildAdapters(cap *context.ModelCapabilities) []adapters.CapabilityAdapter { +func buildAdapters(cap *gouOpenAI.Capabilities) []adapters.CapabilityAdapter { if cap == nil { return []adapters.CapabilityAdapter{} } @@ -158,12 +159,10 @@ func buildAdapters(cap *context.ModelCapabilities) []adapters.CapabilityAdapter result := make([]adapters.CapabilityAdapter, 0) // Tool call adapter - if cap.ToolCalls != nil { - result = append(result, adapters.NewToolCallAdapter(*cap.ToolCalls)) - } + result = append(result, adapters.NewToolCallAdapter(cap.ToolCalls)) // Vision adapter - visionSupport, visionFormat := cap.GetVisionSupport() + visionSupport, visionFormat := context.GetVisionSupport(cap) if visionSupport { result = append(result, adapters.NewVisionAdapter(true, visionFormat)) } else if cap.Vision != nil { @@ -172,31 +171,27 @@ func buildAdapters(cap *context.ModelCapabilities) []adapters.CapabilityAdapter } // Audio adapter - if cap.Audio != nil { - result = append(result, adapters.NewAudioAdapter(*cap.Audio)) - } + result = append(result, adapters.NewAudioAdapter(cap.Audio)) // Reasoning adapter (always add to handle reasoning_effort and temperature parameters) // Even if the model doesn't support reasoning, we need the adapter to strip reasoning_effort - if cap.Reasoning != nil { - if *cap.Reasoning { - // Detect reasoning format based on capabilities - format := detectReasoningFormat(cap) - result = append(result, adapters.NewReasoningAdapter(format, cap)) - } else { - // Model doesn't support reasoning, use None format to strip reasoning parameters - result = append(result, adapters.NewReasoningAdapter(adapters.ReasoningFormatNone, cap)) - } + if cap.Reasoning { + // Detect reasoning format based on capabilities + format := detectReasoningFormat(cap) + result = append(result, adapters.NewReasoningAdapter(format, cap)) + } else { + // Model doesn't support reasoning, use None format to strip reasoning parameters + result = append(result, adapters.NewReasoningAdapter(adapters.ReasoningFormatNone, cap)) } return result } // detectReasoningFormat detects the reasoning format based on capabilities -func detectReasoningFormat(cap *context.ModelCapabilities) adapters.ReasoningFormat { +func detectReasoningFormat(cap *gouOpenAI.Capabilities) adapters.ReasoningFormat { // TODO: Implement better detection logic // For now, default to OpenAI o1 format if reasoning is supported - if cap.Reasoning != nil && *cap.Reasoning { + if cap.Reasoning { return adapters.ReasoningFormatOpenAI } return adapters.ReasoningFormatNone diff --git a/agent/llm/providers/openai/openai_test.go b/agent/llm/providers/openai/openai_test.go index 36d44b2a..b4195137 100644 --- a/agent/llm/providers/openai/openai_test.go +++ b/agent/llm/providers/openai/openai_test.go @@ -8,6 +8,7 @@ import ( "time" "github.com/yaoapp/gou/connector" + "github.com/yaoapp/gou/connector/openai" "github.com/yaoapp/gou/plan" "github.com/yaoapp/yao/agent/context" "github.com/yaoapp/yao/agent/llm" @@ -29,11 +30,10 @@ func TestOpenAIStreamBasic(t *testing.T) { } // Create LLM instance with capabilities - trueVal := true options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Streaming: &trueVal, - ToolCalls: &trueVal, + Capabilities: &openai.Capabilities{ + Streaming: true, + ToolCalls: true, }, } @@ -117,10 +117,9 @@ func TestOpenAIPostBasic(t *testing.T) { } // Create LLM instance - trueVal := true options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - ToolCalls: &trueVal, + Capabilities: &openai.Capabilities{ + ToolCalls: true, }, } @@ -192,11 +191,10 @@ func TestOpenAIStreamWithToolCalls(t *testing.T) { } // Create LLM instance with tool call capabilities - trueVal := true options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Streaming: &trueVal, - ToolCalls: &trueVal, + Capabilities: &openai.Capabilities{ + Streaming: true, + ToolCalls: true, }, } @@ -307,10 +305,9 @@ func TestOpenAIPostWithToolCalls(t *testing.T) { } // Create LLM instance with tool call capabilities - trueVal := true options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - ToolCalls: &trueVal, + Capabilities: &openai.Capabilities{ + ToolCalls: true, }, } @@ -424,11 +421,10 @@ func TestOpenAIStreamWithInvalidToolCall(t *testing.T) { } // Create LLM instance - trueVal := true options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Streaming: &trueVal, - ToolCalls: &trueVal, + Capabilities: &openai.Capabilities{ + Streaming: true, + ToolCalls: true, }, } @@ -523,11 +519,10 @@ func TestOpenAIStreamRetry(t *testing.T) { } // Create LLM instance - trueVal := true options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Streaming: &trueVal, - ToolCalls: &trueVal, // Need this to select OpenAI provider + Capabilities: &openai.Capabilities{ + Streaming: true, + ToolCalls: true, // Need this to select OpenAI provider }, } @@ -582,11 +577,10 @@ func TestOpenAIStreamChunkTypes(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Streaming: &trueVal, - ToolCalls: &trueVal, + Capabilities: &openai.Capabilities{ + Streaming: true, + ToolCalls: true, }, } @@ -649,11 +643,10 @@ func TestOpenAIStreamErrorCallback(t *testing.T) { t.Fatalf("Failed to create test connector: %v", err) } - trueVal := true options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Streaming: &trueVal, - ToolCalls: &trueVal, + Capabilities: &openai.Capabilities{ + Streaming: true, + ToolCalls: true, }, } @@ -711,11 +704,10 @@ func TestOpenAIToolCallValidationRetry(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Streaming: &trueVal, - ToolCalls: &trueVal, + Capabilities: &openai.Capabilities{ + Streaming: true, + ToolCalls: true, }, Tools: []map[string]interface{}{ { @@ -815,11 +807,10 @@ func TestOpenAIJSONMode(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Streaming: &trueVal, - ToolCalls: &trueVal, + Capabilities: &openai.Capabilities{ + Streaming: true, + ToolCalls: true, }, ResponseFormat: &context.ResponseFormat{ Type: context.ResponseFormatJSON, @@ -902,10 +893,9 @@ func TestOpenAIJSONModePost(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - ToolCalls: &trueVal, + Capabilities: &openai.Capabilities{ + ToolCalls: true, }, ResponseFormat: &context.ResponseFormat{ Type: context.ResponseFormatJSON, @@ -973,8 +963,6 @@ func TestOpenAIJSONSchema(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true - // Define a strict JSON schema // Note: For OpenAI strict mode, 'required' must include ALL properties schema := map[string]interface{}{ @@ -1009,9 +997,9 @@ func TestOpenAIJSONSchema(t *testing.T) { } options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Streaming: &trueVal, - ToolCalls: &trueVal, + Capabilities: &openai.Capabilities{ + Streaming: true, + ToolCalls: true, }, ResponseFormat: &context.ResponseFormat{ Type: context.ResponseFormatJSONSchema, @@ -1019,7 +1007,7 @@ func TestOpenAIJSONSchema(t *testing.T) { Name: "user_info", Description: "User information schema", Schema: schema, - Strict: &trueVal, + Strict: func() *bool { v := true; return &v }(), }, }, } @@ -1121,8 +1109,6 @@ func TestOpenAIJSONSchemaPost(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true - // Simple schema for testing // Note: For OpenAI strict mode, 'required' must include ALL properties schema := map[string]interface{}{ @@ -1144,8 +1130,8 @@ func TestOpenAIJSONSchemaPost(t *testing.T) { } options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - ToolCalls: &trueVal, + Capabilities: &openai.Capabilities{ + ToolCalls: true, }, ResponseFormat: &context.ResponseFormat{ Type: context.ResponseFormatJSONSchema, @@ -1153,7 +1139,7 @@ func TestOpenAIJSONSchemaPost(t *testing.T) { Name: "api_response", Description: "API response format", Schema: schema, - Strict: &trueVal, + Strict: func() *bool { v := true; return &v }(), }, }, } @@ -1263,11 +1249,10 @@ func TestOpenAIStreamLifecycleEvents(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Streaming: &trueVal, - ToolCalls: &trueVal, + Capabilities: &openai.Capabilities{ + Streaming: true, + ToolCalls: true, }, } @@ -1369,11 +1354,10 @@ func TestOpenAIStreamContextCancellation(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Streaming: &trueVal, - ToolCalls: &trueVal, + Capabilities: &openai.Capabilities{ + Streaming: true, + ToolCalls: true, }, } @@ -1443,13 +1427,12 @@ func TestOpenAIStreamWithTemperature(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true temperature := 0.7 // Moderate temperature options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Streaming: &trueVal, - ToolCalls: &trueVal, // Need this to select OpenAI provider + Capabilities: &openai.Capabilities{ + Streaming: true, + ToolCalls: true, // Need this to select OpenAI provider }, Temperature: &temperature, } diff --git a/agent/llm/providers/openai/temperature_test.go b/agent/llm/providers/openai/temperature_test.go index 83b5f6be..d648a74f 100644 --- a/agent/llm/providers/openai/temperature_test.go +++ b/agent/llm/providers/openai/temperature_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/yaoapp/gou/connector" + "github.com/yaoapp/gou/connector/openai" "github.com/yaoapp/gou/plan" "github.com/yaoapp/yao/agent/context" "github.com/yaoapp/yao/agent/llm" @@ -23,11 +24,10 @@ func TestTemperatureGPT5AutoReset(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true invalidTemp := 0.7 // GPT-5 doesn't support this options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Reasoning: &trueVal, + Capabilities: &openai.Capabilities{ + Reasoning: true, }, Temperature: &invalidTemp, // Should be reset to 1.0 } @@ -73,11 +73,10 @@ func TestTemperatureDeepSeekR1AutoReset(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true invalidTemp := 0.5 // DeepSeek R1 doesn't support this options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Reasoning: &trueVal, + Capabilities: &openai.Capabilities{ + Reasoning: true, }, Temperature: &invalidTemp, // Should be reset to 1.0 } @@ -126,13 +125,11 @@ func TestTemperatureGPT4oPreserved(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true - falseVal := false customTemp := 0.3 // GPT-4o should preserve this options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Reasoning: &falseVal, // Not a reasoning model - ToolCalls: &trueVal, + Capabilities: &openai.Capabilities{ + Reasoning: false, // Not a reasoning model + ToolCalls: true, }, Temperature: &customTemp, // Should be preserved } @@ -178,13 +175,11 @@ func TestTemperatureDeepSeekV3Preserved(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true - falseVal := false customTemp := 0.8 // DeepSeek V3 should preserve this options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Reasoning: &falseVal, // Not a reasoning model - ToolCalls: &trueVal, + Capabilities: &openai.Capabilities{ + Reasoning: false, // Not a reasoning model + ToolCalls: true, }, Temperature: &customTemp, // Should be preserved } @@ -230,11 +225,10 @@ func TestTemperatureGPT5Default(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true defaultTemp := 1.0 // GPT-5's valid temperature options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Reasoning: &trueVal, + Capabilities: &openai.Capabilities{ + Reasoning: true, }, Temperature: &defaultTemp, // Should work fine } @@ -293,16 +287,14 @@ func TestTemperatureNoTemperatureProvided(t *testing.T) { t.Fatalf("Failed to select connector: %v", err) } - trueVal := true - falseVal := false options := &context.CompletionOptions{ - Capabilities: &context.ModelCapabilities{ - Reasoning: &falseVal, - ToolCalls: &trueVal, + Capabilities: &openai.Capabilities{ + Reasoning: false, + ToolCalls: true, }, } if tc.reasoning { - options.Capabilities.Reasoning = &trueVal + options.Capabilities.Reasoning = true } // Temperature not set - should use API default diff --git a/agent/load.go b/agent/load.go index b03819c5..d5c56f24 100644 --- a/agent/load.go +++ b/agent/load.go @@ -6,6 +6,7 @@ import ( "github.com/yaoapp/gou/application" "github.com/yaoapp/gou/connector" + gouOpenAI "github.com/yaoapp/gou/connector/openai" "github.com/yaoapp/yao/agent/assistant" "github.com/yaoapp/yao/agent/context" "github.com/yaoapp/yao/agent/i18n" @@ -116,7 +117,7 @@ func initModelCapabilities() error { return err } - var models map[string]assistant.ModelCapabilities = map[string]assistant.ModelCapabilities{} + var models map[string]gouOpenAI.Capabilities = map[string]gouOpenAI.Capabilities{} err = application.Parse("models.yml", bytes, &models) if err != nil { return err diff --git a/agent/output/adapters/openai/types.go b/agent/output/adapters/openai/types.go index 0a154bd6..c2da4598 100644 --- a/agent/output/adapters/openai/types.go +++ b/agent/output/adapters/openai/types.go @@ -35,7 +35,7 @@ type AdapterConfig struct { Locale string } -// ModelCapabilities is a simplified version of context.ModelCapabilities +// ModelCapabilities is a simplified version of openai.Capabilities // We use a local type to avoid circular dependencies type ModelCapabilities struct { Reasoning *bool // Supports reasoning/thinking mode (o1, DeepSeek R1) diff --git a/agent/output/adapters/openai/writer.go b/agent/output/adapters/openai/writer.go index 40ab8be8..05a40404 100644 --- a/agent/output/adapters/openai/writer.go +++ b/agent/output/adapters/openai/writer.go @@ -22,9 +22,10 @@ type Writer struct { func NewWriter(options message.Options) (*Writer, error) { // Get model capabilities from context (set by assistant) var capabilities *ModelCapabilities - if options.Capabilities != nil && options.Capabilities.Reasoning != nil { + if options.Capabilities != nil && options.Capabilities.Reasoning { + v := true capabilities = &ModelCapabilities{ - Reasoning: options.Capabilities.Reasoning, + Reasoning: &v, } } diff --git a/agent/output/message/types.go b/agent/output/message/types.go index 0f752d46..41ac872e 100644 --- a/agent/output/message/types.go +++ b/agent/output/message/types.go @@ -3,6 +3,7 @@ package message import ( "net/http" + "github.com/yaoapp/gou/connector/openai" traceTypes "github.com/yaoapp/yao/trace/types" ) @@ -12,23 +13,10 @@ type Options struct { Accept string Writer http.ResponseWriter Trace traceTypes.Manager - Capabilities *ModelCapabilities + Capabilities *openai.Capabilities Locale string } -// ModelCapabilities defines the capabilities of a language model -// Used by LLM to select appropriate provider and validate requests -type ModelCapabilities struct { - Vision interface{} `json:"vision,omitempty"` // Supports vision/image input: bool or VisionFormat string ("openai", "claude"/"base64", "default") - ToolCalls *bool `json:"tool_calls,omitempty"` // Supports tool/function calling - Audio *bool `json:"audio,omitempty"` // Supports audio input/output - Reasoning *bool `json:"reasoning,omitempty"` // Supports reasoning/thinking mode (o1, DeepSeek R1) - Streaming *bool `json:"streaming,omitempty"` // Supports streaming responses - JSON *bool `json:"json,omitempty"` // Supports JSON mode - Multimodal *bool `json:"multimodal,omitempty"` // Supports multimodal input (text + images + audio) - TemperatureAdjustable *bool `json:"temperature_adjustable,omitempty"` // Supports temperature adjustment (reasoning models typically don't) -} - // Message represents a universal message structure (DSL) // All messages are expressed through Type + Props, without predefining specific types type Message struct { diff --git a/agent/types/types.go b/agent/types/types.go index 427c9c33..38d980dd 100644 --- a/agent/types/types.go +++ b/agent/types/types.go @@ -1,6 +1,7 @@ package types import ( + "github.com/yaoapp/gou/connector/openai" "github.com/yaoapp/yao/agent/assistant" store "github.com/yaoapp/yao/agent/store/types" ) @@ -16,7 +17,7 @@ type DSL struct { // Global External Settings - model capabilities, tools, etc. // =============================== - Models map[string]assistant.ModelCapabilities `json:"models,omitempty" yaml:"models,omitempty"` // The model capabilities configuration + Models map[string]openai.Capabilities `json:"models,omitempty" yaml:"models,omitempty"` // The model capabilities configuration // Internal // ===============================