mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-08-15 15:40:38 +02:00
Add files via upload
This commit is contained in:
+106
-6
@@ -36,7 +36,7 @@ func ApplyPlanExecutePlannerModelConfig(cfg *einoopenai.ChatModelConfig, oa *con
|
|||||||
}
|
}
|
||||||
mergeExtraRequestFields(cfg, oa.Reasoning.ExtraRequestFields)
|
mergeExtraRequestFields(cfg, oa.Reasoning.ExtraRequestFields)
|
||||||
clearReasoningFromChatModelConfig(cfg)
|
clearReasoningFromChatModelConfig(cfg)
|
||||||
if resolveWireProfile(oa, &oa.Reasoning) == wireDeepseek {
|
if resolveWireProfile(oa, &oa.Reasoning) == wireDeepseek || oa.IsDeepSeekEndpointOrModel() {
|
||||||
// DeepSeek enables thinking by default, so omission would not actually
|
// DeepSeek enables thinking by default, so omission would not actually
|
||||||
// disable it for the planner's forced tool-choice requests.
|
// disable it for the planner's forced tool-choice requests.
|
||||||
applyThinkingDisabled(cfg)
|
applyThinkingDisabled(cfg)
|
||||||
@@ -88,8 +88,9 @@ func ApplyToEinoChatModelConfig(cfg *einoopenai.ChatModelConfig, oa *config.Open
|
|||||||
clearReasoningFromChatModelConfig(cfg)
|
clearReasoningFromChatModelConfig(cfg)
|
||||||
// Strict OpenAI endpoints reject unknown `thinking` fields, whereas the
|
// Strict OpenAI endpoints reject unknown `thinking` fields, whereas the
|
||||||
// DeepSeek API enables thinking by default and requires an explicit
|
// DeepSeek API enables thinking by default and requires an explicit
|
||||||
// thinking.type=disabled switch. Keep that wire difference profile-scoped.
|
// thinking.type=disabled switch. Detect the actual DeepSeek target even
|
||||||
if resolveWireProfile(oa, sr) == wireDeepseek {
|
// when the configured reasoning profile was left as openai_compat.
|
||||||
|
if resolveWireProfile(oa, sr) == wireDeepseek || oa.IsDeepSeekEndpointOrModel() {
|
||||||
applyThinkingDisabled(cfg)
|
applyThinkingDisabled(cfg)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@@ -118,6 +119,107 @@ func ApplyToEinoChatModelConfig(cfg *einoopenai.ChatModelConfig, oa *config.Open
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AgenticOpenAIExtraFields returns reasoning-related request fields for
|
||||||
|
// agenticopenai.ChatConfig. The agentic chat backend currently exposes provider
|
||||||
|
// extensions through ExtraFields instead of typed ReasoningEffort fields.
|
||||||
|
func AgenticOpenAIExtraFields(oa *config.OpenAIConfig, client *ClientIntent) map[string]any {
|
||||||
|
if oa == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
sr := &oa.Reasoning
|
||||||
|
allowClient := sr.AllowClientReasoningEffective()
|
||||||
|
mode := effectiveMode(sr, client, allowClient)
|
||||||
|
fields := cloneExtraRequestFields(sr.ExtraRequestFields)
|
||||||
|
if mode == "off" {
|
||||||
|
clearReasoningExtraFields(fields)
|
||||||
|
if resolveWireProfile(oa, sr) == wireDeepseek || oa.IsDeepSeekEndpointOrModel() {
|
||||||
|
if fields == nil {
|
||||||
|
fields = make(map[string]any)
|
||||||
|
}
|
||||||
|
fields["thinking"] = map[string]any{"type": "disabled"}
|
||||||
|
}
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
if strings.EqualFold(strings.TrimSpace(oa.Provider), "claude") ||
|
||||||
|
strings.EqualFold(strings.TrimSpace(oa.Provider), "anthropic") {
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
effort := effectiveEffort(sr, client, allowClient)
|
||||||
|
switch resolveWireProfile(oa, sr) {
|
||||||
|
case wireDeepseek:
|
||||||
|
if mode == "auto" || mode == "on" {
|
||||||
|
if fields == nil {
|
||||||
|
fields = make(map[string]any)
|
||||||
|
}
|
||||||
|
fields["thinking"] = map[string]any{"type": "enabled"}
|
||||||
|
}
|
||||||
|
if effort != "" {
|
||||||
|
if fields == nil {
|
||||||
|
fields = make(map[string]any)
|
||||||
|
}
|
||||||
|
fields["reasoning_effort"] = effortStringForAPI(effort)
|
||||||
|
}
|
||||||
|
case wireOutputConfig:
|
||||||
|
e := effort
|
||||||
|
if mode == "on" && e == "" {
|
||||||
|
e = "high"
|
||||||
|
}
|
||||||
|
if e != "" {
|
||||||
|
if fields == nil {
|
||||||
|
fields = make(map[string]any)
|
||||||
|
}
|
||||||
|
fields["output_config"] = map[string]any{"effort": effortStringForAPI(e)}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
e := effort
|
||||||
|
if mode == "on" && e == "" {
|
||||||
|
e = "medium"
|
||||||
|
}
|
||||||
|
if e != "" {
|
||||||
|
if fields == nil {
|
||||||
|
fields = make(map[string]any)
|
||||||
|
}
|
||||||
|
fields["reasoning_effort"] = effortStringForAPI(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
|
// AgenticOpenAIPlannerExtraFields mirrors ApplyPlanExecutePlannerModelConfig for
|
||||||
|
// agenticopenai.ChatConfig: keep admin extras, strip reasoning controls, and
|
||||||
|
// explicitly disable DeepSeek thinking where omission would still think.
|
||||||
|
func AgenticOpenAIPlannerExtraFields(oa *config.OpenAIConfig) map[string]any {
|
||||||
|
if oa == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
fields := cloneExtraRequestFields(oa.Reasoning.ExtraRequestFields)
|
||||||
|
clearReasoningExtraFields(fields)
|
||||||
|
if resolveWireProfile(oa, &oa.Reasoning) == wireDeepseek || oa.IsDeepSeekEndpointOrModel() {
|
||||||
|
if fields == nil {
|
||||||
|
fields = make(map[string]any)
|
||||||
|
}
|
||||||
|
fields["thinking"] = map[string]any{"type": "disabled"}
|
||||||
|
}
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
|
func cloneExtraRequestFields(fields map[string]interface{}) map[string]any {
|
||||||
|
if len(fields) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := make(map[string]any, len(fields))
|
||||||
|
for k, v := range fields {
|
||||||
|
out[k] = v
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func clearReasoningExtraFields(fields map[string]any) {
|
||||||
|
for _, key := range []string{"thinking", "reasoning_effort", "output_config", "reasoning"} {
|
||||||
|
delete(fields, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// applyClaudeExtendedThinking sets Anthropic Messages API fields per official guidance:
|
// applyClaudeExtendedThinking sets Anthropic Messages API fields per official guidance:
|
||||||
// - Adaptive models (4.6+): thinking.type=adaptive; output_config.effort only when user sets effort (API default is high).
|
// - Adaptive models (4.6+): thinking.type=adaptive; output_config.effort only when user sets effort (API default is high).
|
||||||
// - Sonnet 3.7: thinking.type=enabled + budget_tokens=10000 (doc example); effort is not mapped — use extra_request_fields for custom budget.
|
// - Sonnet 3.7: thinking.type=enabled + budget_tokens=10000 (doc example); effort is not mapped — use extra_request_fields for custom budget.
|
||||||
@@ -240,9 +342,7 @@ func resolveWireProfile(oa *config.OpenAIConfig, sr *config.OpenAIReasoningConfi
|
|||||||
case "deepseek", "deepseek_compat":
|
case "deepseek", "deepseek_compat":
|
||||||
return wireDeepseek
|
return wireDeepseek
|
||||||
case "auto", "":
|
case "auto", "":
|
||||||
bu := strings.ToLower(oa.BaseURL)
|
if oa.IsDeepSeekEndpointOrModel() {
|
||||||
mo := strings.ToLower(oa.Model)
|
|
||||||
if strings.Contains(bu, "deepseek") || strings.Contains(mo, "deepseek") {
|
|
||||||
return wireDeepseek
|
return wireDeepseek
|
||||||
}
|
}
|
||||||
return wireOpenAI
|
return wireOpenAI
|
||||||
|
|||||||
@@ -69,6 +69,104 @@ func TestApplyOpenAICompat_xhighExtraField(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAgenticOpenAIExtraFields_openAICompatReasoningEffort(t *testing.T) {
|
||||||
|
oa := &config.OpenAIConfig{
|
||||||
|
Reasoning: config.OpenAIReasoningConfig{
|
||||||
|
Profile: "openai_compat",
|
||||||
|
Mode: "on",
|
||||||
|
Effort: "high",
|
||||||
|
ExtraRequestFields: map[string]interface{}{
|
||||||
|
"vendor_option": true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
got := AgenticOpenAIExtraFields(oa, nil)
|
||||||
|
if got["reasoning_effort"] != "high" {
|
||||||
|
t.Fatalf("reasoning_effort=%#v, want high in %#v", got["reasoning_effort"], got)
|
||||||
|
}
|
||||||
|
if got["vendor_option"] != true {
|
||||||
|
t.Fatalf("vendor option not preserved: %#v", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAgenticOpenAIExtraFields_reasoningOffPreservesUnrelatedFields(t *testing.T) {
|
||||||
|
oa := &config.OpenAIConfig{
|
||||||
|
Model: "gpt-4o-mini",
|
||||||
|
Reasoning: config.OpenAIReasoningConfig{
|
||||||
|
Profile: "openai_compat",
|
||||||
|
Mode: "off",
|
||||||
|
Effort: "high",
|
||||||
|
ExtraRequestFields: map[string]interface{}{
|
||||||
|
"reasoning_effort": "high",
|
||||||
|
"thinking": map[string]any{"type": "enabled"},
|
||||||
|
"vendor_option": true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
got := AgenticOpenAIExtraFields(oa, nil)
|
||||||
|
for _, key := range reasoningPayloadKeysForTest {
|
||||||
|
if _, ok := got[key]; ok {
|
||||||
|
t.Fatalf("agentic fields unexpectedly contain %q: %#v", key, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if got["vendor_option"] != true {
|
||||||
|
t.Fatalf("vendor option not preserved: %#v", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAgenticOpenAIPlannerExtraFields_deepseekDisablesThinking(t *testing.T) {
|
||||||
|
oa := &config.OpenAIConfig{
|
||||||
|
BaseURL: "https://api.deepseek.com",
|
||||||
|
Model: "deepseek-chat",
|
||||||
|
Reasoning: config.OpenAIReasoningConfig{
|
||||||
|
Profile: "auto",
|
||||||
|
Mode: "on",
|
||||||
|
ExtraRequestFields: map[string]interface{}{
|
||||||
|
"reasoning_effort": "high",
|
||||||
|
"vendor_option": true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
got := AgenticOpenAIPlannerExtraFields(oa)
|
||||||
|
if got["reasoning_effort"] != nil {
|
||||||
|
t.Fatalf("planner should strip reasoning_effort: %#v", got)
|
||||||
|
}
|
||||||
|
thinking, ok := got["thinking"].(map[string]any)
|
||||||
|
if !ok || thinking["type"] != "disabled" {
|
||||||
|
t.Fatalf("expected deepseek thinking disabled, got %#v", got)
|
||||||
|
}
|
||||||
|
if got["vendor_option"] != true {
|
||||||
|
t.Fatalf("vendor option not preserved: %#v", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAgenticOpenAIPlannerExtraFields_deepseekEndpointWinsOverOpenAIProfile(t *testing.T) {
|
||||||
|
oa := &config.OpenAIConfig{
|
||||||
|
BaseURL: "https://api.deepseek.com/v1",
|
||||||
|
Model: "deepseek-v4-flash",
|
||||||
|
Reasoning: config.OpenAIReasoningConfig{
|
||||||
|
Profile: "openai_compat",
|
||||||
|
Mode: "on",
|
||||||
|
Effort: "high",
|
||||||
|
ExtraRequestFields: map[string]interface{}{
|
||||||
|
"reasoning_effort": "high",
|
||||||
|
"vendor_option": true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
got := AgenticOpenAIPlannerExtraFields(oa)
|
||||||
|
if _, ok := got["reasoning_effort"]; ok {
|
||||||
|
t.Fatalf("planner should strip reasoning_effort: %#v", got)
|
||||||
|
}
|
||||||
|
thinking, ok := got["thinking"].(map[string]any)
|
||||||
|
if !ok || thinking["type"] != "disabled" {
|
||||||
|
t.Fatalf("expected deepseek thinking disabled despite openai_compat profile, got %#v", got)
|
||||||
|
}
|
||||||
|
if got["vendor_option"] != true {
|
||||||
|
t.Fatalf("vendor option not preserved: %#v", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestApplyPlanExecutePlannerModelConfig_stripsReasoningWhenGlobalOn(t *testing.T) {
|
func TestApplyPlanExecutePlannerModelConfig_stripsReasoningWhenGlobalOn(t *testing.T) {
|
||||||
cfg := &einoopenai.ChatModelConfig{ExtraFields: map[string]any{
|
cfg := &einoopenai.ChatModelConfig{ExtraFields: map[string]any{
|
||||||
"thinking": map[string]any{"type": "enabled"},
|
"thinking": map[string]any{"type": "enabled"},
|
||||||
@@ -91,6 +189,37 @@ func TestApplyPlanExecutePlannerModelConfig_stripsReasoningWhenGlobalOn(t *testi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestApplyPlanExecutePlannerModelConfig_deepseekEndpointWinsOverOpenAIProfile(t *testing.T) {
|
||||||
|
cfg := &einoopenai.ChatModelConfig{ExtraFields: map[string]any{
|
||||||
|
"thinking": map[string]any{"type": "enabled"},
|
||||||
|
"reasoning_effort": "high",
|
||||||
|
"vendor_option": true,
|
||||||
|
}}
|
||||||
|
oa := &config.OpenAIConfig{
|
||||||
|
BaseURL: "https://api.deepseek.com/v1",
|
||||||
|
Model: "deepseek-v4-flash",
|
||||||
|
Reasoning: config.OpenAIReasoningConfig{
|
||||||
|
Profile: "openai_compat",
|
||||||
|
Mode: "on",
|
||||||
|
Effort: "high",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
ApplyPlanExecutePlannerModelConfig(cfg, oa)
|
||||||
|
if cfg.ReasoningEffort != "" {
|
||||||
|
t.Fatalf("expected ReasoningEffort omitted, got %q", cfg.ReasoningEffort)
|
||||||
|
}
|
||||||
|
if _, ok := cfg.ExtraFields["reasoning_effort"]; ok {
|
||||||
|
t.Fatalf("expected reasoning_effort omitted, got %#v", cfg.ExtraFields)
|
||||||
|
}
|
||||||
|
thinking, ok := cfg.ExtraFields["thinking"].(map[string]any)
|
||||||
|
if !ok || thinking["type"] != "disabled" {
|
||||||
|
t.Fatalf("expected deepseek thinking disabled despite openai_compat profile, got %#v", cfg.ExtraFields)
|
||||||
|
}
|
||||||
|
if cfg.ExtraFields["vendor_option"] != true {
|
||||||
|
t.Fatalf("expected unrelated extra field preserved, got %#v", cfg.ExtraFields)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestApplyReasoningOff_omitsAllReasoningFields(t *testing.T) {
|
func TestApplyReasoningOff_omitsAllReasoningFields(t *testing.T) {
|
||||||
cfg := &einoopenai.ChatModelConfig{ExtraFields: map[string]any{
|
cfg := &einoopenai.ChatModelConfig{ExtraFields: map[string]any{
|
||||||
"thinking": map[string]any{"type": "enabled"},
|
"thinking": map[string]any{"type": "enabled"},
|
||||||
@@ -127,7 +256,7 @@ func TestApplyReasoningOff_clientOverrideOmit(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestApplyReasoningOff_deepseekExplicitlyDisablesDefaultThinking(t *testing.T) {
|
func TestApplyReasoningOff_deepseekExplicitlyDisablesDefaultThinking(t *testing.T) {
|
||||||
for _, profile := range []string{"deepseek_compat", "auto"} {
|
for _, profile := range []string{"deepseek_compat", "auto", "openai_compat"} {
|
||||||
t.Run(profile, func(t *testing.T) {
|
t.Run(profile, func(t *testing.T) {
|
||||||
cfg := &einoopenai.ChatModelConfig{ExtraFields: map[string]any{
|
cfg := &einoopenai.ChatModelConfig{ExtraFields: map[string]any{
|
||||||
"reasoning_effort": "high",
|
"reasoning_effort": "high",
|
||||||
|
|||||||
Reference in New Issue
Block a user