From eb721c244766744bde39dbae5a1ca59fdc0afe31 Mon Sep 17 00:00:00 2001 From: lpf Date: Thu, 19 Feb 2026 22:53:58 +0800 Subject: [PATCH] fix loop --- README.md | 8 - README_EN.md | 8 - config.example.json | 8 - pkg/agent/loop.go | 238 +++++++++++------------------ pkg/agent/loop_run_control_test.go | 64 +------- pkg/config/config.go | 16 -- pkg/config/config_test.go | 4 - pkg/config/validate.go | 14 -- 8 files changed, 98 insertions(+), 262 deletions(-) diff --git a/README.md b/README.md index ce4cd2a..1c1d06a 100644 --- a/README.md +++ b/README.md @@ -166,10 +166,7 @@ clawgo channel test --channel telegram --to -m "ping" "defaults": { "runtime_control": { "intent_high_confidence": 0.75, - "intent_confirm_min_confidence": 0.45, "intent_max_input_chars": 1200, - "confirm_ttl_seconds": 300, - "confirm_max_clarification_turns": 2, "autonomy_tick_interval_sec": 20, "autonomy_min_run_interval_sec": 20, "autonomy_idle_threshold_sec": 20, @@ -179,11 +176,6 @@ clawgo channel test --channel telegram --to -m "ping" "autolearn_max_rounds_without_user": 200, "run_state_ttl_seconds": 1800, "run_state_max": 500, - "run_control_latest_keywords": ["latest", "last run", "recent run", "最新", "最近", "上一次", "上个"], - "run_control_wait_keywords": ["wait", "等待", "等到", "阻塞"], - "run_control_status_keywords": ["status", "状态", "进度", "running", "运行"], - "run_control_run_mention_keywords": ["run", "任务"], - "run_control_minute_units": ["分钟", "min", "mins", "minute", "minutes", "m"], "tool_parallel_safe_names": ["read_file", "list_files", "find_files", "grep_files", "memory_search", "web_search", "repo_map", "system_info"], "tool_max_parallel_calls": 2 } diff --git a/README_EN.md b/README_EN.md index 2497d14..4102fec 100644 --- a/README_EN.md +++ b/README_EN.md @@ -166,10 +166,7 @@ Runtime-control config example (intent thresholds / autonomy guards / run-state "defaults": { "runtime_control": { "intent_high_confidence": 0.75, - "intent_confirm_min_confidence": 0.45, "intent_max_input_chars": 1200, - "confirm_ttl_seconds": 300, - "confirm_max_clarification_turns": 2, "autonomy_tick_interval_sec": 20, "autonomy_min_run_interval_sec": 20, "autonomy_idle_threshold_sec": 20, @@ -179,11 +176,6 @@ Runtime-control config example (intent thresholds / autonomy guards / run-state "autolearn_max_rounds_without_user": 200, "run_state_ttl_seconds": 1800, "run_state_max": 500, - "run_control_latest_keywords": ["latest", "last run", "recent run", "最新", "最近", "上一次", "上个"], - "run_control_wait_keywords": ["wait", "等待", "等到", "阻塞"], - "run_control_status_keywords": ["status", "状态", "进度", "running", "运行"], - "run_control_run_mention_keywords": ["run", "任务"], - "run_control_minute_units": ["分钟", "min", "mins", "minute", "minutes", "m"], "tool_parallel_safe_names": ["read_file", "list_files", "find_files", "grep_files", "memory_search", "web_search", "repo_map", "system_info"], "tool_max_parallel_calls": 2 } diff --git a/config.example.json b/config.example.json index 6cb3b82..1ba0c12 100644 --- a/config.example.json +++ b/config.example.json @@ -17,10 +17,7 @@ }, "runtime_control": { "intent_high_confidence": 0.75, - "intent_confirm_min_confidence": 0.45, "intent_max_input_chars": 1200, - "confirm_ttl_seconds": 300, - "confirm_max_clarification_turns": 2, "autonomy_tick_interval_sec": 20, "autonomy_min_run_interval_sec": 20, "autonomy_idle_threshold_sec": 20, @@ -30,11 +27,6 @@ "autolearn_max_rounds_without_user": 200, "run_state_ttl_seconds": 1800, "run_state_max": 500, - "run_control_latest_keywords": ["latest", "last run", "recent run", "最新", "最近", "上一次", "上个"], - "run_control_wait_keywords": ["wait", "等待", "等到", "阻塞"], - "run_control_status_keywords": ["status", "状态", "进度", "running", "运行"], - "run_control_run_mention_keywords": ["run", "任务"], - "run_control_minute_units": ["分钟", "min", "mins", "minute", "minutes", "m"], "tool_parallel_safe_names": ["read_file", "list_files", "find_files", "grep_files", "memory_search", "web_search", "repo_map", "system_info"], "tool_max_parallel_calls": 2 } diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index 38bcac6..99f5fd0 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -109,14 +109,6 @@ type controlPolicy struct { autoLearnMaxRoundsWithoutUser int } -type runControlLexicon struct { - latestKeywords []string - waitKeywords []string - statusKeywords []string - runMentionKeywords []string - minuteUnits map[string]struct{} -} - type runtimeControlStats struct { runAccepted int64 runCompleted int64 @@ -204,7 +196,6 @@ type AgentLoop struct { controlConfirmMu sync.Mutex controlConfirm map[string]pendingControlConfirmation controlPolicy controlPolicy - runControlLex runControlLexicon parallelSafeTools map[string]struct{} maxParallelCalls int controlStats runtimeControlStats @@ -263,12 +254,15 @@ type taskExecutionDirectivesLLMResponse struct { Confidence float64 `json:"confidence"` } -var runIDPattern = regexp.MustCompile(`(?i)\b(run-\d+-\d+)\b`) -var runWaitTimeoutPattern = regexp.MustCompile(`(?i)(\d+)\s*(seconds|second|secs|sec|minutes|minute|mins|min|分钟|秒|s|m)`) -var defaultRunControlLatestKeywords = []string{"latest", "last run", "recent run", "最新", "最近", "上一次", "上个"} -var defaultRunControlWaitKeywords = []string{"wait", "等待", "等到", "阻塞"} -var defaultRunControlStatusKeywords = []string{"status", "状态", "进度", "running", "运行"} -var defaultRunControlRunMentionKeywords = []string{"run", "任务"} +type runControlIntentLLMResponse struct { + Matched bool `json:"matched"` + RunID string `json:"run_id"` + Latest bool `json:"latest"` + Wait bool `json:"wait"` + TimeoutSeconds int `json:"timeout_seconds"` + Confidence float64 `json:"confidence"` +} + var defaultParallelSafeToolNames = []string{"read_file", "list_files", "find_files", "grep_files", "memory_search", "web_search", "repo_map", "system_info"} var autonomyIntentKeywords = []string{ "autonomy", "autonomous", "autonomy mode", "self-driven", "self driven", @@ -278,14 +272,6 @@ var autoLearnIntentKeywords = []string{ "auto-learn", "autolearn", "learning loop", "learn loop", "自学习", "学习循环", "自动学习", "学习模式", } -var defaultRunWaitMinuteUnits = map[string]struct{}{ - "分钟": {}, - "min": {}, - "mins": {}, - "minute": {}, - "minutes": {}, - "m": {}, -} type stageReporter struct { onUpdate func(content string) @@ -375,18 +361,9 @@ func loadControlPolicyFromConfig(base controlPolicy, rc config.RuntimeControlCon if rc.IntentHighConfidence > 0 { p.intentHighConfidence = rc.IntentHighConfidence } - if rc.IntentConfirmMinConfidence >= 0 { - p.intentConfirmMinConfidence = rc.IntentConfirmMinConfidence - } if rc.IntentMaxInputChars > 0 { p.intentMaxInputChars = rc.IntentMaxInputChars } - if rc.ConfirmTTLSeconds > 0 { - p.confirmTTL = time.Duration(rc.ConfirmTTLSeconds) * time.Second - } - if rc.ConfirmMaxClarificationTurns >= 0 { - p.confirmMaxClarificationTurns = rc.ConfirmMaxClarificationTurns - } if rc.AutonomyTickIntervalSec > 0 { p.autonomyTickInterval = time.Duration(rc.AutonomyTickIntervalSec) * time.Second } @@ -423,42 +400,6 @@ func loadRunStatePolicyFromConfig(rc config.RuntimeControlConfig) (time.Duration return ttl, maxEntries } -func defaultRunControlLexicon() runControlLexicon { - latest := append([]string(nil), defaultRunControlLatestKeywords...) - wait := append([]string(nil), defaultRunControlWaitKeywords...) - status := append([]string(nil), defaultRunControlStatusKeywords...) - mention := append([]string(nil), defaultRunControlRunMentionKeywords...) - minutes := make(map[string]struct{}, len(defaultRunWaitMinuteUnits)) - for unit := range defaultRunWaitMinuteUnits { - minutes[unit] = struct{}{} - } - return runControlLexicon{ - latestKeywords: latest, - waitKeywords: wait, - statusKeywords: status, - runMentionKeywords: mention, - minuteUnits: minutes, - } -} - -func loadRunControlLexiconFromConfig(rc config.RuntimeControlConfig) runControlLexicon { - base := defaultRunControlLexicon() - base.latestKeywords = normalizeKeywordList(rc.RunControlLatestKeywords, base.latestKeywords) - base.waitKeywords = normalizeKeywordList(rc.RunControlWaitKeywords, base.waitKeywords) - base.statusKeywords = normalizeKeywordList(rc.RunControlStatusKeywords, base.statusKeywords) - base.runMentionKeywords = normalizeKeywordList(rc.RunControlRunMentionKeywords, base.runMentionKeywords) - - minuteUnits := normalizeKeywordList(rc.RunControlMinuteUnits, nil) - if len(minuteUnits) == 0 { - return base - } - base.minuteUnits = make(map[string]struct{}, len(minuteUnits)) - for _, unit := range minuteUnits { - base.minuteUnits[unit] = struct{}{} - } - return base -} - func normalizeKeywordList(values []string, fallback []string) []string { if len(values) == 0 { return append([]string(nil), fallback...) @@ -688,7 +629,6 @@ func NewAgentLoop(cfg *config.Config, msgBus *bus.MessageBus, provider providers defaultModel := defaultModelFromModels(modelsByProxy[primaryProxy], provider) policy := loadControlPolicyFromConfig(defaultControlPolicy(), cfg.Agents.Defaults.RuntimeControl) policy = applyLegacyControlPolicyEnvOverrides(policy) - runControlLex := loadRunControlLexiconFromConfig(cfg.Agents.Defaults.RuntimeControl) parallelSafeTools, maxParallelCalls := loadToolParallelPolicyFromConfig(cfg.Agents.Defaults.RuntimeControl) runStateTTL, runStateMax := loadRunStatePolicyFromConfig(cfg.Agents.Defaults.RuntimeControl) // Keep compatibility with older env names. @@ -722,7 +662,6 @@ func NewAgentLoop(cfg *config.Config, msgBus *bus.MessageBus, provider providers autonomyBySess: make(map[string]*autonomySession), controlConfirm: make(map[string]pendingControlConfirmation), controlPolicy: policy, - runControlLex: runControlLex, parallelSafeTools: parallelSafeTools, maxParallelCalls: maxParallelCalls, runStates: make(map[string]*runState), @@ -731,10 +670,7 @@ func NewAgentLoop(cfg *config.Config, msgBus *bus.MessageBus, provider providers } logger.InfoCF("agent", "Control policy initialized", map[string]interface{}{ "intent_high_confidence": policy.intentHighConfidence, - "intent_confirm_min_confidence": policy.intentConfirmMinConfidence, "intent_max_input_chars": policy.intentMaxInputChars, - "confirm_ttl": policy.confirmTTL.String(), - "confirm_max_clarification_turns": policy.confirmMaxClarificationTurns, "autonomy_tick_interval": policy.autonomyTickInterval.String(), "autonomy_min_run_interval": policy.autonomyMinRunInterval.String(), "autonomy_idle_threshold": policy.autonomyIdleThreshold.String(), @@ -742,11 +678,6 @@ func NewAgentLoop(cfg *config.Config, msgBus *bus.MessageBus, provider providers "autonomy_max_pending_duration": policy.autonomyMaxPendingDuration.String(), "autonomy_max_consecutive_stalls": policy.autonomyMaxConsecutiveStalls, "autolearn_max_rounds_without_user": policy.autoLearnMaxRoundsWithoutUser, - "run_control_latest_keywords": len(runControlLex.latestKeywords), - "run_control_wait_keywords": len(runControlLex.waitKeywords), - "run_control_status_keywords": len(runControlLex.statusKeywords), - "run_control_run_keywords": len(runControlLex.runMentionKeywords), - "run_control_minute_units": len(runControlLex.minuteUnits), "parallel_safe_tool_count": len(parallelSafeTools), "tool_max_parallel_calls": maxParallelCalls, "run_state_ttl": runStateTTL.String(), @@ -1697,63 +1628,9 @@ func (al *AgentLoop) waitForRun(ctx context.Context, runID string) (runState, bo } } -func detectRunControlIntent(content string) (runControlIntent, bool) { - return detectRunControlIntentWithLexicon(content, defaultRunControlLexicon()) -} - -func detectRunControlIntentWithLexicon(content string, lex runControlLexicon) (runControlIntent, bool) { - text := strings.TrimSpace(content) - if text == "" { - return runControlIntent{}, false - } - if strings.HasPrefix(text, "/") { - return runControlIntent{}, false - } - - lower := strings.ToLower(text) - intent := runControlIntent{ - timeout: defaultRunWaitTimeout, - } - if m := runIDPattern.FindStringSubmatch(text); len(m) > 1 { - intent.runID = strings.ToLower(strings.TrimSpace(m[1])) - } - intent.latest = containsAnySubstring(lower, lex.latestKeywords...) - intent.wait = containsAnySubstring(lower, lex.waitKeywords...) - isStatusQuery := containsAnySubstring(lower, lex.statusKeywords...) - isRunMentioned := containsAnySubstring(lower, lex.runMentionKeywords...) - if !intent.wait && !isStatusQuery { - if intent.runID == "" || !isRunMentioned { - return runControlIntent{}, false - } - } - if intent.runID == "" && !intent.latest { - return runControlIntent{}, false - } - if intent.wait { - intent.timeout = parseRunWaitTimeoutWithLexicon(text, lex) - } - return intent, true -} - -func parseRunWaitTimeout(content string) time.Duration { - return parseRunWaitTimeoutWithLexicon(content, defaultRunControlLexicon()) -} - -func parseRunWaitTimeoutWithLexicon(content string, lex runControlLexicon) time.Duration { - timeout := defaultRunWaitTimeout - matches := runWaitTimeoutPattern.FindStringSubmatch(content) - if len(matches) < 3 { - return timeout - } - n, err := strconv.Atoi(matches[1]) - if err != nil || n <= 0 { - return timeout - } - unit := strings.ToLower(strings.TrimSpace(matches[2])) - if _, isMinute := lex.minuteUnits[unit]; isMinute { - timeout = time.Duration(n) * time.Minute - } else { - timeout = time.Duration(n) * time.Second +func normalizeRunWaitTimeout(timeout time.Duration) time.Duration { + if timeout <= 0 { + return defaultRunWaitTimeout } if timeout < minRunWaitTimeout { return minRunWaitTimeout @@ -1887,19 +1764,86 @@ func (al *AgentLoop) executeRunControlIntent(ctx context.Context, sessionKey str return al.naturalizeUserFacingText(ctx, formatRunStateReport(rs)) } +func (al *AgentLoop) inferRunControlIntent(ctx context.Context, content string) (runControlIntent, float64, bool) { + text := strings.TrimSpace(content) + if text == "" || strings.HasPrefix(text, "/") { + return runControlIntent{}, 0, false + } + + limit := defaultControlPolicy().intentMaxInputChars + if al != nil && al.controlPolicy.intentMaxInputChars > 0 { + limit = al.controlPolicy.intentMaxInputChars + } + if len(text) > limit { + text = truncate(text, limit) + } + + systemPrompt := al.withBootstrapPolicy(`You classify run-control intent for an AI assistant. +Return JSON only. +Schema: +{"matched":true|false,"run_id":"","latest":false,"wait":false,"timeout_seconds":0,"confidence":0.0} +Rules: +- matched=true only when user asks run status/wait/latest-run control. +- run_id: use canonical form like run-123-1 if provided, else empty. +- latest=true when user asks latest/recent run. +- wait=true when user asks to wait until run completes. +- timeout_seconds: wait timeout in seconds, 0 means default. +- confidence: 0..1`) + + resp, err := al.callLLMWithModelFallback(ctx, []providers.Message{ + {Role: "system", Content: systemPrompt}, + {Role: "user", Content: text}, + }, nil, map[string]interface{}{ + "max_tokens": 220, + "temperature": 0.0, + }) + if err != nil || resp == nil { + return runControlIntent{}, 0, false + } + + raw := extractJSONObject(resp.Content) + if raw == "" { + return runControlIntent{}, 0, false + } + + var parsed runControlIntentLLMResponse + if err := json.Unmarshal([]byte(raw), &parsed); err != nil { + return runControlIntent{}, 0, false + } + if !parsed.Matched { + return runControlIntent{}, parsed.Confidence, false + } + + intent := runControlIntent{ + runID: strings.ToLower(strings.TrimSpace(parsed.RunID)), + latest: parsed.Latest, + wait: parsed.Wait, + timeout: defaultRunWaitTimeout, + } + if parsed.TimeoutSeconds > 0 { + intent.timeout = time.Duration(parsed.TimeoutSeconds) * time.Second + } + intent.timeout = normalizeRunWaitTimeout(intent.timeout) + + if intent.runID == "" && !intent.latest { + return runControlIntent{}, parsed.Confidence, false + } + return intent, parsed.Confidence, true +} + func (al *AgentLoop) handleNaturalRunControl(ctx context.Context, msg bus.InboundMessage) (bool, string) { - intent, ok := detectRunControlIntentWithLexicon(msg.Content, al.effectiveRunControlLexicon()) + intent, confidence, ok := al.inferRunControlIntent(ctx, msg.Content) if !ok { return false, "" } - return true, al.executeRunControlIntent(ctx, msg.SessionKey, intent) -} - -func (al *AgentLoop) effectiveRunControlLexicon() runControlLexicon { - if al == nil || len(al.runControlLex.latestKeywords) == 0 || len(al.runControlLex.minuteUnits) == 0 { - return defaultRunControlLexicon() + policy := defaultControlPolicy() + if al != nil { + policy = al.controlPolicy } - return al.runControlLex + if confidence < policy.intentHighConfidence { + return false, "" + } + return true, al.executeRunControlIntent(ctx, msg.SessionKey, intent) } func (al *AgentLoop) controlMetricAdd(counter *int64, delta int64) { @@ -2025,16 +1969,16 @@ func (al *AgentLoop) handleControlPlane(ctx context.Context, msg bus.InboundMess al.clearPendingControlConfirmation(msg.SessionKey) return true, al.executeAutonomyIntent(ctx, msg, intent), nil } else if outcome.needsConfirm { - al.storePendingAutonomyConfirmation(msg.SessionKey, msg.Content, intent, outcome.confidence) - return true, al.naturalizeUserFacingText(ctx, al.formatAutonomyConfirmationPrompt(intent)), nil + al.clearPendingControlConfirmation(msg.SessionKey) + return true, al.executeAutonomyIntent(ctx, msg, intent), nil } if intent, outcome := al.detectAutoLearnIntent(ctx, msg.Content); outcome.matched { al.clearPendingControlConfirmation(msg.SessionKey) return true, al.executeAutoLearnIntent(ctx, msg, intent), nil } else if outcome.needsConfirm { - al.storePendingAutoLearnConfirmation(msg.SessionKey, msg.Content, intent, outcome.confidence) - return true, al.naturalizeUserFacingText(ctx, al.formatAutoLearnConfirmationPrompt(intent)), nil + al.clearPendingControlConfirmation(msg.SessionKey) + return true, al.executeAutoLearnIntent(ctx, msg, intent), nil } return false, "", nil diff --git a/pkg/agent/loop_run_control_test.go b/pkg/agent/loop_run_control_test.go index 2cda8ac..53271a5 100644 --- a/pkg/agent/loop_run_control_test.go +++ b/pkg/agent/loop_run_control_test.go @@ -11,85 +11,35 @@ import ( func TestDetectRunControlIntent(t *testing.T) { t.Parallel() - intent, ok := detectRunControlIntent("请等待 run-123-7 120 秒后告诉我状态") - if !ok { - t.Fatalf("expected run control intent") - } - if intent.runID != "run-123-7" { - t.Fatalf("unexpected run id: %s", intent.runID) - } - if !intent.wait { - t.Fatalf("expected wait=true") - } - if intent.timeout != 120*time.Second { - t.Fatalf("unexpected timeout: %s", intent.timeout) + if got := normalizeRunWaitTimeout(0); got != defaultRunWaitTimeout { + t.Fatalf("expected default timeout, got %s", got) } } func TestDetectRunControlIntentLatest(t *testing.T) { t.Parallel() - intent, ok := detectRunControlIntent("latest run status") - if !ok { - t.Fatalf("expected latest run status intent") - } - if !intent.latest { - t.Fatalf("expected latest=true") - } - if intent.runID != "" { - t.Fatalf("expected empty run id") + if got := normalizeRunWaitTimeout(time.Second); got != minRunWaitTimeout { + t.Fatalf("expected min timeout %s, got %s", minRunWaitTimeout, got) } } func TestParseRunWaitTimeout_MinClamp(t *testing.T) { t.Parallel() - got := parseRunWaitTimeout("wait run-1-1 1 s") - if got != minRunWaitTimeout { - t.Fatalf("expected min timeout %s, got %s", minRunWaitTimeout, got) + if got := normalizeRunWaitTimeout(maxRunWaitTimeout + time.Minute); got != maxRunWaitTimeout { + t.Fatalf("expected max timeout %s, got %s", maxRunWaitTimeout, got) } } func TestParseRunWaitTimeout_MinuteUnit(t *testing.T) { t.Parallel() - got := parseRunWaitTimeout("等待 run-1-1 2 分钟") - if got != 2*time.Minute { + if got := normalizeRunWaitTimeout(2 * time.Minute); got != 2*time.Minute { t.Fatalf("expected 2m, got %s", got) } } -func TestDetectRunControlIntentIgnoresNonControlText(t *testing.T) { - t.Parallel() - - if _, ok := detectRunControlIntent("帮我写一个README"); ok { - t.Fatalf("did not expect run control intent") - } -} - -func TestDetectRunControlIntentWithCustomLexicon(t *testing.T) { - t.Parallel() - - lex := runControlLexicon{ - latestKeywords: []string{"newest"}, - waitKeywords: []string{"block"}, - statusKeywords: []string{"health"}, - runMentionKeywords: []string{"job"}, - minuteUnits: map[string]struct{}{"mins": {}}, - } - - intent, ok := detectRunControlIntentWithLexicon("block run-55-1 for 2 mins and show health", lex) - if !ok { - t.Fatalf("expected intent with custom lexicon") - } - if !intent.wait { - t.Fatalf("expected wait=true") - } - if intent.timeout != 2*time.Minute { - t.Fatalf("unexpected timeout: %s", intent.timeout) - } -} - func TestLatestRunStateBySession(t *testing.T) { t.Parallel() diff --git a/pkg/config/config.go b/pkg/config/config.go index 3035b83..cd54476 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -43,10 +43,7 @@ type AgentDefaults struct { type RuntimeControlConfig struct { IntentHighConfidence float64 `json:"intent_high_confidence" env:"CLAWGO_INTENT_HIGH_CONFIDENCE"` - IntentConfirmMinConfidence float64 `json:"intent_confirm_min_confidence" env:"CLAWGO_INTENT_CONFIRM_MIN_CONFIDENCE"` IntentMaxInputChars int `json:"intent_max_input_chars" env:"CLAWGO_INTENT_MAX_INPUT_CHARS"` - ConfirmTTLSeconds int `json:"confirm_ttl_seconds" env:"CLAWGO_CONFIRM_TTL_SECONDS"` - ConfirmMaxClarificationTurns int `json:"confirm_max_clarification_turns" env:"CLAWGO_CONFIRM_MAX_CLARIFY_TURNS"` AutonomyTickIntervalSec int `json:"autonomy_tick_interval_sec" env:"CLAWGO_AUTONOMY_TICK_INTERVAL_SEC"` AutonomyMinRunIntervalSec int `json:"autonomy_min_run_interval_sec" env:"CLAWGO_AUTONOMY_MIN_RUN_INTERVAL_SEC"` AutonomyIdleThresholdSec int `json:"autonomy_idle_threshold_sec" env:"CLAWGO_AUTONOMY_IDLE_THRESHOLD_SEC"` @@ -56,11 +53,6 @@ type RuntimeControlConfig struct { AutoLearnMaxRoundsWithoutUser int `json:"autolearn_max_rounds_without_user" env:"CLAWGO_AUTOLEARN_MAX_ROUNDS_WITHOUT_USER"` RunStateTTLSeconds int `json:"run_state_ttl_seconds" env:"CLAWGO_RUN_STATE_TTL_SECONDS"` RunStateMax int `json:"run_state_max" env:"CLAWGO_RUN_STATE_MAX"` - RunControlLatestKeywords []string `json:"run_control_latest_keywords"` - RunControlWaitKeywords []string `json:"run_control_wait_keywords"` - RunControlStatusKeywords []string `json:"run_control_status_keywords"` - RunControlRunMentionKeywords []string `json:"run_control_run_mention_keywords"` - RunControlMinuteUnits []string `json:"run_control_minute_units"` ToolParallelSafeNames []string `json:"tool_parallel_safe_names"` ToolMaxParallelCalls int `json:"tool_max_parallel_calls"` } @@ -262,10 +254,7 @@ func DefaultConfig() *Config { }, RuntimeControl: RuntimeControlConfig{ IntentHighConfidence: 0.75, - IntentConfirmMinConfidence: 0.45, IntentMaxInputChars: 1200, - ConfirmTTLSeconds: 300, - ConfirmMaxClarificationTurns: 2, AutonomyTickIntervalSec: 20, AutonomyMinRunIntervalSec: 20, AutonomyIdleThresholdSec: 20, @@ -275,11 +264,6 @@ func DefaultConfig() *Config { AutoLearnMaxRoundsWithoutUser: 200, RunStateTTLSeconds: 1800, RunStateMax: 500, - RunControlLatestKeywords: []string{"latest", "last run", "recent run", "最新", "最近", "上一次", "上个"}, - RunControlWaitKeywords: []string{"wait", "等待", "等到", "阻塞"}, - RunControlStatusKeywords: []string{"status", "状态", "进度", "running", "运行"}, - RunControlRunMentionKeywords: []string{"run", "任务"}, - RunControlMinuteUnits: []string{"分钟", "min", "mins", "minute", "minutes", "m"}, ToolParallelSafeNames: []string{"read_file", "list_files", "find_files", "grep_files", "memory_search", "web_search", "repo_map", "system_info"}, ToolMaxParallelCalls: 2, }, diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 15d0789..1503a55 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -65,7 +65,6 @@ func TestLoadConfigAllowsKnownRuntimeControlFields(t *testing.T) { "runtime_control": { "intent_high_confidence": 0.88, "run_state_max": 321, - "run_control_wait_keywords": ["wait", "block"], "tool_parallel_safe_names": ["read_file", "memory_search"], "tool_max_parallel_calls": 3 } @@ -86,9 +85,6 @@ func TestLoadConfigAllowsKnownRuntimeControlFields(t *testing.T) { if got := cfg.Agents.Defaults.RuntimeControl.RunStateMax; got != 321 { t.Fatalf("run_state_max mismatch: got %d", got) } - if got := len(cfg.Agents.Defaults.RuntimeControl.RunControlWaitKeywords); got != 2 { - t.Fatalf("run_control_wait_keywords mismatch: got %d", got) - } if got := cfg.Agents.Defaults.RuntimeControl.ToolMaxParallelCalls; got != 3 { t.Fatalf("tool_max_parallel_calls mismatch: got %d", got) } diff --git a/pkg/config/validate.go b/pkg/config/validate.go index 1071566..443176a 100644 --- a/pkg/config/validate.go +++ b/pkg/config/validate.go @@ -21,18 +21,9 @@ func Validate(cfg *Config) []error { if rc.IntentHighConfidence <= 0 || rc.IntentHighConfidence > 1 { errs = append(errs, fmt.Errorf("agents.defaults.runtime_control.intent_high_confidence must be in (0,1]")) } - if rc.IntentConfirmMinConfidence < 0 || rc.IntentConfirmMinConfidence >= rc.IntentHighConfidence { - errs = append(errs, fmt.Errorf("agents.defaults.runtime_control.intent_confirm_min_confidence must be >= 0 and < intent_high_confidence")) - } if rc.IntentMaxInputChars < 200 { errs = append(errs, fmt.Errorf("agents.defaults.runtime_control.intent_max_input_chars must be >= 200")) } - if rc.ConfirmTTLSeconds <= 0 { - errs = append(errs, fmt.Errorf("agents.defaults.runtime_control.confirm_ttl_seconds must be > 0")) - } - if rc.ConfirmMaxClarificationTurns < 0 { - errs = append(errs, fmt.Errorf("agents.defaults.runtime_control.confirm_max_clarification_turns must be >= 0")) - } if rc.AutonomyTickIntervalSec < 5 { errs = append(errs, fmt.Errorf("agents.defaults.runtime_control.autonomy_tick_interval_sec must be >= 5")) } @@ -60,11 +51,6 @@ func Validate(cfg *Config) []error { if rc.RunStateMax <= 0 { errs = append(errs, fmt.Errorf("agents.defaults.runtime_control.run_state_max must be > 0")) } - errs = append(errs, validateNonEmptyStringList("agents.defaults.runtime_control.run_control_latest_keywords", rc.RunControlLatestKeywords)...) - errs = append(errs, validateNonEmptyStringList("agents.defaults.runtime_control.run_control_wait_keywords", rc.RunControlWaitKeywords)...) - errs = append(errs, validateNonEmptyStringList("agents.defaults.runtime_control.run_control_status_keywords", rc.RunControlStatusKeywords)...) - errs = append(errs, validateNonEmptyStringList("agents.defaults.runtime_control.run_control_run_mention_keywords", rc.RunControlRunMentionKeywords)...) - errs = append(errs, validateNonEmptyStringList("agents.defaults.runtime_control.run_control_minute_units", rc.RunControlMinuteUnits)...) errs = append(errs, validateNonEmptyStringList("agents.defaults.runtime_control.tool_parallel_safe_names", rc.ToolParallelSafeNames)...) if rc.ToolMaxParallelCalls <= 0 { errs = append(errs, fmt.Errorf("agents.defaults.runtime_control.tool_max_parallel_calls must be > 0"))