@phuetz/code-buddy 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +160 -164
- package/dist/agent/autonomous/agentic-coding-contract.d.ts +6 -6
- package/dist/agent/codebuddy-agent.d.ts +1 -1
- package/dist/agent/codebuddy-agent.js +101 -13
- package/dist/agent/execution/agent-executor.js +122 -12
- package/dist/agent/execution/tool-dependency-graph.js +7 -0
- package/dist/agent/execution/tool-hooks.d.ts +6 -0
- package/dist/agent/execution/tool-hooks.js +13 -5
- package/dist/agent/execution/tool-selection-strategy.d.ts +11 -2
- package/dist/agent/execution/tool-selection-strategy.js +67 -10
- package/dist/agent/extended-thinking.d.ts +8 -0
- package/dist/agent/extended-thinking.js +27 -0
- package/dist/agent/hermes-browser-backends.js +151 -11
- package/dist/agent/hermes-claw-migrate.d.ts +59 -0
- package/dist/agent/hermes-claw-migrate.js +427 -26
- package/dist/agent/hermes-parity-manifest.js +78 -71
- package/dist/agent/hermes-runtime-lifecycle.d.ts +67 -0
- package/dist/agent/hermes-runtime-lifecycle.js +468 -0
- package/dist/agent/lesson-auto-proposer.js +10 -0
- package/dist/agent/middleware/index.d.ts +1 -0
- package/dist/agent/middleware/index.js +1 -0
- package/dist/agent/middleware/session-duration.d.ts +36 -0
- package/dist/agent/middleware/session-duration.js +78 -0
- package/dist/agent/middleware/visual-validation-middleware.d.ts +17 -0
- package/dist/agent/middleware/visual-validation-middleware.js +67 -0
- package/dist/agent/model-benchmark.d.ts +77 -0
- package/dist/agent/model-benchmark.js +309 -0
- package/dist/agent/model-tier.d.ts +14 -0
- package/dist/agent/model-tier.js +71 -0
- package/dist/agent/multi-agent/agents/orchestrator-agent.js +17 -6
- package/dist/agent/multi-agent/multi-agent-system.js +3 -1
- package/dist/agent/multi-agent/session-fleet-bridge.d.ts +2 -0
- package/dist/agent/multi-agent/session-fleet-bridge.js +9 -1
- package/dist/agent/multi-agent/session-tools.js +22 -5
- package/dist/agent/reasoning/mcts.js +20 -6
- package/dist/agent/session-end-flush.d.ts +71 -0
- package/dist/agent/session-end-flush.js +233 -0
- package/dist/agent/streaming/streaming-handler.d.ts +7 -0
- package/dist/agent/streaming/streaming-handler.js +8 -1
- package/dist/agent/tool-executor.js +1 -0
- package/dist/agent/tool-handler.d.ts +5 -0
- package/dist/agent/tool-handler.js +130 -4
- package/dist/browser-automation/browser-operator-executor.js +15 -0
- package/dist/browser-automation/browser-use-runner.d.ts +96 -0
- package/dist/browser-automation/browser-use-runner.js +492 -0
- package/dist/browser-automation/camofox-runner.d.ts +107 -0
- package/dist/browser-automation/camofox-runner.js +287 -0
- package/dist/channels/dingtalk/index.js +3 -0
- package/dist/channels/discord/client.d.ts +9 -0
- package/dist/channels/discord/client.js +12 -0
- package/dist/channels/feishu/index.d.ts +167 -1
- package/dist/channels/feishu/index.js +432 -7
- package/dist/channels/gateway-lifecycle.d.ts +132 -0
- package/dist/channels/gateway-lifecycle.js +219 -0
- package/dist/channels/google-chat/index.d.ts +5 -1
- package/dist/channels/google-chat/index.js +5 -1
- package/dist/channels/imessage/index.d.ts +14 -0
- package/dist/channels/imessage/index.js +64 -17
- package/dist/channels/index.d.ts +4 -0
- package/dist/channels/index.js +4 -0
- package/dist/channels/irc/index.d.ts +73 -3
- package/dist/channels/irc/index.js +446 -11
- package/dist/channels/line/index.js +3 -0
- package/dist/channels/mattermost/index.d.ts +51 -4
- package/dist/channels/mattermost/index.js +303 -20
- package/dist/channels/nextcloud-talk/index.d.ts +89 -8
- package/dist/channels/nextcloud-talk/index.js +367 -16
- package/dist/channels/nostr/index.d.ts +121 -1
- package/dist/channels/nostr/index.js +396 -8
- package/dist/channels/ntfy/index.js +3 -0
- package/dist/channels/qq/index.js +3 -0
- package/dist/channels/slash-parity.d.ts +117 -0
- package/dist/channels/slash-parity.js +185 -0
- package/dist/channels/synology-chat/index.js +3 -0
- package/dist/channels/teams/index.d.ts +3 -0
- package/dist/channels/teams/index.js +3 -0
- package/dist/channels/telegram/client.d.ts +9 -0
- package/dist/channels/telegram/client.js +12 -0
- package/dist/channels/twilio-voice/index.js +3 -0
- package/dist/channels/webchat/index.d.ts +7 -1
- package/dist/channels/webchat/index.js +7 -1
- package/dist/channels/wecom/index.js +3 -0
- package/dist/channels/weixin/index.js +3 -0
- package/dist/channels/zalo/index.js +3 -0
- package/dist/cli/config-loader.js +1 -1
- package/dist/codebuddy/client.d.ts +30 -1
- package/dist/codebuddy/client.js +167 -20
- package/dist/codebuddy/providers/provider-chatgpt-responses.d.ts +5 -0
- package/dist/codebuddy/providers/provider-chatgpt-responses.js +1 -0
- package/dist/codebuddy/providers/provider-gemini-native.js +1 -1
- package/dist/codebuddy/providers/provider-openai-compat.d.ts +5 -0
- package/dist/codebuddy/providers/provider-openai-compat.js +82 -2
- package/dist/codebuddy/tool-definitions/computer-control-tools.js +32 -2
- package/dist/codebuddy/tool-definitions/core-tools.js +3 -3
- package/dist/codebuddy/tool-definitions/index.d.ts +2 -1
- package/dist/codebuddy/tool-definitions/index.js +2 -1
- package/dist/codebuddy/tool-definitions/multimodal-tools.d.ts +1 -0
- package/dist/codebuddy/tool-definitions/multimodal-tools.js +44 -1
- package/dist/codebuddy/tool-definitions/windows-tools.d.ts +2 -0
- package/dist/codebuddy/tool-definitions/windows-tools.js +34 -0
- package/dist/codebuddy/tools.d.ts +1 -1
- package/dist/codebuddy/tools.js +27 -24
- package/dist/commands/cli/hermes-commands.js +108 -0
- package/dist/commands/cli/native-engine-commands.js +107 -3
- package/dist/commands/cli/utility-commands.js +45 -0
- package/dist/commands/enhanced-command-handler.js +5 -0
- package/dist/commands/goal-cli.d.ts +71 -0
- package/dist/commands/goal-cli.js +280 -0
- package/dist/commands/handlers/goal-handler.d.ts +34 -0
- package/dist/commands/handlers/goal-handler.js +155 -0
- package/dist/commands/handlers/index.d.ts +1 -0
- package/dist/commands/handlers/index.js +2 -0
- package/dist/commands/handlers/infra-handlers.js +36 -0
- package/dist/commands/handlers/memory-handlers.js +96 -1
- package/dist/commands/headless-slash.d.ts +2 -0
- package/dist/commands/headless-slash.js +12 -0
- package/dist/commands/llm-provider-resolution.d.ts +5 -3
- package/dist/commands/llm-provider-resolution.js +87 -33
- package/dist/commands/ollama.d.ts +25 -0
- package/dist/commands/ollama.js +100 -0
- package/dist/commands/provider.d.ts +5 -0
- package/dist/commands/provider.js +106 -55
- package/dist/commands/slash/builtin-commands.js +20 -0
- package/dist/commands/spec-next.js +2 -1
- package/dist/commands/spec-plan.js +5 -16
- package/dist/commands/tunnel.d.ts +2 -0
- package/dist/commands/tunnel.js +48 -0
- package/dist/config/config-resolver.d.ts +2 -1
- package/dist/config/config-resolver.js +54 -41
- package/dist/config/constants.d.ts +28 -0
- package/dist/config/constants.js +7 -0
- package/dist/config/env-schema.js +770 -0
- package/dist/config/feature-flags.js +7 -0
- package/dist/config/model-tools.js +4 -4
- package/dist/config/toml-config.d.ts +16 -0
- package/dist/config/toml-config.js +3 -0
- package/dist/context/context-manager-v2.d.ts +39 -0
- package/dist/context/context-manager-v2.js +91 -0
- package/dist/daemon/agent-task-executor.js +12 -1
- package/dist/daemon/autonomous-daemon.d.ts +1 -1
- package/dist/daemon/autonomous-daemon.js +5 -3
- package/dist/daemon/autonomous-loop.d.ts +21 -1
- package/dist/daemon/autonomous-loop.js +69 -0
- package/dist/daemon/colab-goal.d.ts +38 -0
- package/dist/daemon/colab-goal.js +81 -0
- package/dist/daemon/cron-agent-bridge.d.ts +12 -3
- package/dist/daemon/cron-agent-bridge.js +25 -9
- package/dist/desktop/codebuddy-engine-adapter.d.ts +32 -0
- package/dist/desktop/codebuddy-engine-adapter.js +257 -80
- package/dist/desktop/engine-adapter.d.ts +14 -0
- package/dist/desktop-automation/automation-manager.js +16 -0
- package/dist/desktop-automation/omniparser-runner.d.ts +63 -0
- package/dist/desktop-automation/omniparser-runner.js +115 -0
- package/dist/desktop-automation/smart-snapshot.d.ts +11 -0
- package/dist/desktop-automation/smart-snapshot.js +72 -5
- package/dist/doctor/index.js +40 -23
- package/dist/events/types.d.ts +11 -0
- package/dist/fleet/colab-store.d.ts +21 -0
- package/dist/fleet/colab-store.js +28 -0
- package/dist/fleet/peer-session-bridge.d.ts +1 -1
- package/dist/fleet/peer-session-bridge.js +243 -2
- package/dist/fleet/peer-session-store.d.ts +3 -0
- package/dist/fleet/peer-tool-bridge.js +14 -0
- package/dist/fleet/privacy-lint.d.ts +8 -0
- package/dist/fleet/privacy-lint.js +22 -0
- package/dist/goals/goal-decomposer.d.ts +27 -0
- package/dist/goals/goal-decomposer.js +293 -0
- package/dist/goals/goal-judge-client.d.ts +15 -0
- package/dist/goals/goal-judge-client.js +45 -0
- package/dist/goals/goal-judge.d.ts +38 -0
- package/dist/goals/goal-judge.js +158 -0
- package/dist/goals/goal-loop.d.ts +37 -0
- package/dist/goals/goal-loop.js +101 -0
- package/dist/goals/goal-manager.d.ts +77 -0
- package/dist/goals/goal-manager.js +289 -0
- package/dist/goals/goal-state.d.ts +99 -0
- package/dist/goals/goal-state.js +315 -0
- package/dist/goals/goal-store.d.ts +28 -0
- package/dist/goals/goal-store.js +87 -0
- package/dist/goals/index.d.ts +5 -0
- package/dist/goals/index.js +6 -0
- package/dist/hooks/use-input-handler.js +36 -1
- package/dist/hooks/user-hooks.js +17 -3
- package/dist/index.js +506 -25
- package/dist/input/text-to-speech.d.ts +2 -6
- package/dist/input/text-to-speech.js +2 -27
- package/dist/integrations/screenpipe/screenpipe-client.d.ts +10 -0
- package/dist/integrations/screenpipe/screenpipe-client.js +12 -2
- package/dist/integrations/tailscale.d.ts +13 -0
- package/dist/integrations/tailscale.js +87 -34
- package/dist/knowledge/workspace-indexer.js +53 -9
- package/dist/mcp/client.js +1 -0
- package/dist/mcp/mcp-desktop-tools.d.ts +23 -0
- package/dist/mcp/mcp-desktop-tools.js +158 -0
- package/dist/mcp/mcp-server.js +2 -0
- package/dist/memory/enhanced-memory.d.ts +10 -0
- package/dist/memory/enhanced-memory.js +33 -2
- package/dist/memory/index.d.ts +3 -1
- package/dist/memory/index.js +4 -1
- package/dist/memory/memory-auto-proposer.d.ts +23 -0
- package/dist/memory/memory-auto-proposer.js +308 -0
- package/dist/memory/memory-candidate-queue.d.ts +92 -0
- package/dist/memory/memory-candidate-queue.js +261 -0
- package/dist/memory/persistent-memory.d.ts +45 -2
- package/dist/memory/persistent-memory.js +236 -40
- package/dist/ml/bayesian-qualifier.d.ts +1 -1
- package/dist/ml/bayesian-qualifier.js +35 -2
- package/dist/observability/run-store.d.ts +1 -1
- package/dist/openclaw/gateway-bridge.js +5 -0
- package/dist/plugins/marketplace.d.ts +1 -0
- package/dist/plugins/marketplace.js +7 -0
- package/dist/prompts/execution-discipline.d.ts +14 -0
- package/dist/prompts/execution-discipline.js +29 -0
- package/dist/prompts/variation-injector.js +9 -2
- package/dist/protocols/acp/acp-agentic-runner.d.ts +7 -6
- package/dist/protocols/acp/acp-agentic-runner.js +115 -18
- package/dist/protocols/acp/acp-session-store.d.ts +23 -0
- package/dist/protocols/acp/acp-session-store.js +77 -0
- package/dist/protocols/acp/acp-stdio-server.d.ts +7 -0
- package/dist/protocols/acp/acp-stdio-server.js +71 -16
- package/dist/providers/active-llm-registry.d.ts +37 -0
- package/dist/providers/active-llm-registry.js +186 -0
- package/dist/providers/auxiliary-provider.d.ts +25 -0
- package/dist/providers/auxiliary-provider.js +192 -0
- package/dist/providers/codex-oauth.d.ts +1 -1
- package/dist/providers/codex-oauth.js +27 -4
- package/dist/providers/index.d.ts +3 -0
- package/dist/providers/index.js +4 -0
- package/dist/providers/provider-catalog.d.ts +70 -0
- package/dist/providers/provider-catalog.js +738 -0
- package/dist/providers/provider-fallback.d.ts +35 -0
- package/dist/providers/provider-fallback.js +171 -0
- package/dist/providers/xai-oauth.d.ts +128 -0
- package/dist/providers/xai-oauth.js +735 -0
- package/dist/scheduler/cron-scheduler.d.ts +15 -3
- package/dist/scheduler/cron-scheduler.js +53 -7
- package/dist/scheduler/script-runner.d.ts +2 -0
- package/dist/scheduler/script-runner.js +19 -4
- package/dist/scheduler/watchdog-handlers.js +7 -20
- package/dist/search/usearch-index.js +7 -2
- package/dist/security/tool-policy/tool-groups.js +2 -0
- package/dist/server/index.js +17 -2
- package/dist/server/routes/mobile.d.ts +12 -4
- package/dist/server/routes/mobile.js +116 -1
- package/dist/server/tls-config.d.ts +35 -0
- package/dist/server/tls-config.js +142 -0
- package/dist/server/tunnel-manager.d.ts +20 -0
- package/dist/server/tunnel-manager.js +58 -0
- package/dist/server/websocket/fleet-bridge.d.ts +13 -1
- package/dist/server/websocket/fleet-bridge.js +16 -0
- package/dist/services/prompt-builder.d.ts +1 -0
- package/dist/services/prompt-builder.js +49 -8
- package/dist/shared/engine-types.d.ts +15 -1
- package/dist/sidecar/sidecar-bridge.d.ts +1 -0
- package/dist/sidecar/sidecar-bridge.js +21 -10
- package/dist/spec/spec-store.js +8 -1
- package/dist/talk-mode/providers/audioreader-tts.d.ts +1 -1
- package/dist/talk-mode/providers/audioreader-tts.js +8 -8
- package/dist/templates/project-scaffolding.js +3 -2
- package/dist/themes/theme-schema.d.ts +10 -10
- package/dist/tools/application-profiles.js +38 -0
- package/dist/tools/bash/bash-tool.d.ts +1 -0
- package/dist/tools/bash/bash-tool.js +16 -2
- package/dist/tools/bash/command-validator.js +3 -0
- package/dist/tools/bash/rtk-rewrite.d.ts +16 -0
- package/dist/tools/bash/rtk-rewrite.js +100 -0
- package/dist/tools/bash/streaming-executor.js +14 -1
- package/dist/tools/computer-control-tool.d.ts +16 -1
- package/dist/tools/computer-control-tool.js +317 -5
- package/dist/tools/document-generator.d.ts +14 -0
- package/dist/tools/document-generator.js +79 -0
- package/dist/tools/execute-code-rpc-invoker.d.ts +26 -2
- package/dist/tools/execute-code-rpc-invoker.js +46 -5
- package/dist/tools/metadata.js +28 -0
- package/dist/tools/office-macro-tool.d.ts +10 -0
- package/dist/tools/office-macro-tool.js +93 -0
- package/dist/tools/registry/index.d.ts +2 -1
- package/dist/tools/registry/index.js +2 -1
- package/dist/tools/registry/memory-tools.d.ts +20 -0
- package/dist/tools/registry/memory-tools.js +225 -3
- package/dist/tools/registry/multimodal-tools.js +2 -2
- package/dist/tools/registry/vision-tools.d.ts +33 -0
- package/dist/tools/registry/vision-tools.js +308 -6
- package/dist/tools/registry/windows-tools.d.ts +2 -0
- package/dist/tools/registry/windows-tools.js +47 -0
- package/dist/tools/route-peer-tool.js +14 -0
- package/dist/tools/screenshot-tool.js +14 -2
- package/dist/tools/text-to-speech-tool.d.ts +1 -1
- package/dist/tools/text-to-speech-tool.js +2 -12
- package/dist/tools/tool-selector.js +3 -59
- package/dist/utils/config-validation/schema.d.ts +40 -7
- package/dist/utils/config-validation/schema.js +130 -1
- package/dist/utils/cost-tracker.js +21 -1
- package/dist/utils/disk-guard.d.ts +180 -0
- package/dist/utils/disk-guard.js +404 -0
- package/dist/utils/interactive-setup.js +35 -2
- package/dist/utils/model-utils.js +11 -2
- package/dist/utils/output-sanitizer.js +11 -0
- package/dist/utils/provider-detector.d.ts +8 -7
- package/dist/utils/provider-detector.js +19 -77
- package/dist/utils/settings-manager.d.ts +7 -0
- package/dist/utils/token-display.d.ts +3 -3
- package/dist/utils/token-display.js +22 -4
- package/dist/wizard/onboarding.d.ts +39 -0
- package/dist/wizard/onboarding.js +433 -21
- package/dist/wizard/provider-onboarding.d.ts +8 -23
- package/dist/wizard/provider-onboarding.js +39 -158
- package/package.json +4 -2
- package/dist/plugins/provider-onboarding.d.ts +0 -23
- package/dist/plugins/provider-onboarding.js +0 -116
- package/dist/utils/kokoro-tts.d.ts +0 -8
- package/dist/utils/kokoro-tts.js +0 -67
|
@@ -14,7 +14,7 @@ import { ToolHandler } from "./tool-handler.js";
|
|
|
14
14
|
import { BaseAgent } from "./base-agent.js";
|
|
15
15
|
import { createAgentInfrastructureSync } from "./infrastructure/index.js";
|
|
16
16
|
import { getLaneQueue } from "../concurrency/lane-queue.js";
|
|
17
|
-
import { findSkill, findStarterPack } from "../skills/index.js";
|
|
17
|
+
import { findSkill, findStarterPack, resetSkillRegistry } from "../skills/index.js";
|
|
18
18
|
import { skillMdToUnified } from "../skills/adapters/index.js";
|
|
19
19
|
import { getSkillsHub } from "../skills/hub.js";
|
|
20
20
|
import { MessageQueue } from "./message-queue.js";
|
|
@@ -24,6 +24,12 @@ import { initializeMemory, getMemoryManager } from "../memory/persistent-memory.
|
|
|
24
24
|
import { getUserHooksManager } from "../hooks/user-hooks.js";
|
|
25
25
|
import { isFeatureEnabled } from "../config/feature-flags.js";
|
|
26
26
|
import { getActiveRunStore } from "../observability/run-store.js";
|
|
27
|
+
import { resetIdentityManager } from "../identity/identity-manager.js";
|
|
28
|
+
import { resetHotReloadManager } from "../config/hot-reload/index.js";
|
|
29
|
+
import { resetConfigWatcher } from "../config/hot-reload/watcher.js";
|
|
30
|
+
import { resetPersonaManager } from "../personas/persona-manager.js";
|
|
31
|
+
import { resetEnhancedMemory } from "../memory/enhanced-memory.js";
|
|
32
|
+
import { resetPluginMarketplace } from "../plugins/marketplace.js";
|
|
27
33
|
/**
|
|
28
34
|
* Main agent class that orchestrates conversation with CodeBuddy AI and tool execution
|
|
29
35
|
*
|
|
@@ -76,9 +82,10 @@ export class CodeBuddyAgent extends BaseAgent {
|
|
|
76
82
|
* @param useRAGToolSelection - Enable RAG-based tool selection (default: true)
|
|
77
83
|
*/
|
|
78
84
|
constructor(apiKey, baseURL, model, maxToolRounds, useRAGToolSelection = true, systemPromptId, // New: external prompt ID (default, minimal, secure, etc.)
|
|
79
|
-
workingDirectory, systemPromptAppend) {
|
|
85
|
+
workingDirectory, systemPromptAppend, initialSystemPromptOverride) {
|
|
80
86
|
super();
|
|
81
87
|
this.systemPromptAppend = systemPromptAppend;
|
|
88
|
+
this.customSystemPromptOverride = initialSystemPromptOverride?.trim() || null;
|
|
82
89
|
this.visionGroundingModel = process.env.CODEBUDDY_VISION_GROUNDING_MODEL || undefined;
|
|
83
90
|
const initialWorkingDirectory = workingDirectory || process.cwd();
|
|
84
91
|
// Determine model to use
|
|
@@ -121,6 +128,11 @@ export class CodeBuddyAgent extends BaseAgent {
|
|
|
121
128
|
// This is safe because the singletons returned by getters are the concrete implementations
|
|
122
129
|
this.tokenCounter = this.infrastructure.tokenCounter;
|
|
123
130
|
this.contextManager = this.infrastructure.contextManager;
|
|
131
|
+
// WS3-T2 — periodic memory snapshot for very long sessions. Interval from
|
|
132
|
+
// CODEBUDDY_SNAPSHOT_INTERVAL_MIN (default 45 min, 0 disables); the timer
|
|
133
|
+
// is unref'd so it never keeps a finished process alive. Optional call:
|
|
134
|
+
// test doubles and custom context engines may not implement snapshots.
|
|
135
|
+
this.contextManager.startPeriodicSnapshot?.(() => this.historyManager.getMessagesRef());
|
|
124
136
|
this.checkpointManager = this.infrastructure.checkpoints;
|
|
125
137
|
this.sessionStore = this.infrastructure.sessions;
|
|
126
138
|
this.modeManager = this.infrastructure.modeManager;
|
|
@@ -295,6 +307,20 @@ export class CodeBuddyAgent extends BaseAgent {
|
|
|
295
307
|
catch (err) {
|
|
296
308
|
logger.debug('Failed to register ContextWarningMiddleware (non-critical)', { error: err instanceof Error ? err.message : String(err) });
|
|
297
309
|
}
|
|
310
|
+
// Session duration middleware (priority 35) — suggests a clean pause
|
|
311
|
+
// with a fresh resume point past CODEBUDDY_SESSION_PAUSE_HOURS (12 h)
|
|
312
|
+
try {
|
|
313
|
+
const { SessionDurationMiddleware } = await import('./middleware/session-duration.js');
|
|
314
|
+
pipeline.use(new SessionDurationMiddleware({
|
|
315
|
+
takeSnapshot: () => {
|
|
316
|
+
this.contextManager.takeSnapshot?.(this.historyManager.getMessagesRef());
|
|
317
|
+
},
|
|
318
|
+
}));
|
|
319
|
+
logger.debug('SessionDurationMiddleware registered in pipeline (priority 35)');
|
|
320
|
+
}
|
|
321
|
+
catch (err) {
|
|
322
|
+
logger.debug('Failed to register SessionDurationMiddleware (non-critical)', { error: err instanceof Error ? err.message : String(err) });
|
|
323
|
+
}
|
|
298
324
|
// Reasoning middleware (priority 42) — auto-detects complex queries
|
|
299
325
|
try {
|
|
300
326
|
const { createReasoningMiddleware } = await import('./middleware/reasoning-middleware.js');
|
|
@@ -315,6 +341,27 @@ export class CodeBuddyAgent extends BaseAgent {
|
|
|
315
341
|
catch (err) {
|
|
316
342
|
logger.debug('Failed to register AutoRepairMiddleware (non-critical)', { error: err instanceof Error ? err.message : String(err) });
|
|
317
343
|
}
|
|
344
|
+
// Verification enforcement (priority 155) — after >= 3 file changes with
|
|
345
|
+
// no task_verify/run_tests, nudges the model to verify before finishing.
|
|
346
|
+
// Closes the "loop completes on no-more-tool-calls without a verify gate"
|
|
347
|
+
// gap surfaced by the Hermes agentic-loop audit (2026-06-16).
|
|
348
|
+
try {
|
|
349
|
+
const { createVerificationEnforcementMiddleware } = await import('./middleware/verification-enforcement.js');
|
|
350
|
+
pipeline.use(createVerificationEnforcementMiddleware());
|
|
351
|
+
logger.debug('VerificationEnforcementMiddleware registered in pipeline (priority 155)');
|
|
352
|
+
}
|
|
353
|
+
catch (err) {
|
|
354
|
+
logger.debug('Failed to register VerificationEnforcementMiddleware (non-critical)', { error: err instanceof Error ? err.message : String(err) });
|
|
355
|
+
}
|
|
356
|
+
// Visual validation middleware (priority 156) — suggests taking screenshots of generated Office documents
|
|
357
|
+
try {
|
|
358
|
+
const { VisualValidationMiddleware } = await import('./middleware/visual-validation-middleware.js');
|
|
359
|
+
pipeline.use(new VisualValidationMiddleware());
|
|
360
|
+
logger.debug('VisualValidationMiddleware registered in pipeline (priority 156)');
|
|
361
|
+
}
|
|
362
|
+
catch (err) {
|
|
363
|
+
logger.debug('Failed to register VisualValidationMiddleware (non-critical)', { error: err instanceof Error ? err.message : String(err) });
|
|
364
|
+
}
|
|
318
365
|
// Quality gate middleware (priority 200) — auto-delegates to specialized agents
|
|
319
366
|
try {
|
|
320
367
|
const { createQualityGateMiddleware } = await import('./middleware/quality-gate-middleware.js');
|
|
@@ -473,18 +520,22 @@ Look at the screenshot and find the element matching the user's intent. Output o
|
|
|
473
520
|
}
|
|
474
521
|
async initializeAgentSystemPrompt(systemPromptId, modelName, customInstructions) {
|
|
475
522
|
try {
|
|
476
|
-
|
|
523
|
+
const hasInitialOverride = !!this.customSystemPromptOverride;
|
|
524
|
+
let systemPrompt = this.customSystemPromptOverride
|
|
525
|
+
?? await this.promptBuilder.buildSystemPrompt(systemPromptId, modelName, customInstructions);
|
|
477
526
|
// Inject repoProfile.contextPack if available
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
527
|
+
if (!hasInitialOverride) {
|
|
528
|
+
try {
|
|
529
|
+
const profiler = getRepoProfiler();
|
|
530
|
+
const profile = await profiler.getProfile();
|
|
531
|
+
if (profile.contextPack) {
|
|
532
|
+
systemPrompt = `${systemPrompt}\n\n[Repo] ${profile.contextPack}`;
|
|
533
|
+
logger.debug('RepoProfiler: injected contextPack into system prompt');
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
catch {
|
|
537
|
+
// Non-fatal — repo profiling is best-effort
|
|
484
538
|
}
|
|
485
|
-
}
|
|
486
|
-
catch {
|
|
487
|
-
// Non-fatal — repo profiling is best-effort
|
|
488
539
|
}
|
|
489
540
|
systemPrompt = this.applyRuntimeSystemPromptAppend(systemPrompt);
|
|
490
541
|
// Knowledge base is already injected by PromptBuilder.buildSystemPrompt() — skip duplicate injection here.
|
|
@@ -1620,7 +1671,9 @@ Look at the screenshot and find the element matching the user's intent. Output o
|
|
|
1620
1671
|
// Fire SessionEnd user hook (non-blocking). Shutdown errors should be
|
|
1621
1672
|
// visible (warn, not debug) — silent debug logs masked prior bugs.
|
|
1622
1673
|
getUserHooksManager(process.cwd()).executeHooks('SessionEnd', {}).catch((err) => logger.warn(`[user-hooks] SessionEnd error: ${err instanceof Error ? err.message : String(err)}`));
|
|
1623
|
-
|
|
1674
|
+
const skipAsyncSessionLearning = process.env.CODEBUDDY_HEADLESS === 'true' ||
|
|
1675
|
+
process.env.CODEBUDDY_HEADLESS === '1';
|
|
1676
|
+
if (!skipAsyncSessionLearning && isFeatureEnabled('USER_MODEL_DIALECTIC_ON_SESSION_END')) {
|
|
1624
1677
|
const chatHistory = this.historyManager.getChatHistory();
|
|
1625
1678
|
if (chatHistory && chatHistory.length > 0) {
|
|
1626
1679
|
import('../memory/user-model.js')
|
|
@@ -1637,6 +1690,19 @@ Look at the screenshot and find the element matching the user's intent. Output o
|
|
|
1637
1690
|
});
|
|
1638
1691
|
}
|
|
1639
1692
|
}
|
|
1693
|
+
// WS3-T1 — session-end flush: handoff + review-gated lesson candidates.
|
|
1694
|
+
// Fire-and-forget like the dialectic above; callers that need the flush
|
|
1695
|
+
// to complete before process exit await runSessionEndFlush directly.
|
|
1696
|
+
if (!skipAsyncSessionLearning) {
|
|
1697
|
+
const chatHistory = this.historyManager.getChatHistory();
|
|
1698
|
+
if (chatHistory && chatHistory.length > 0) {
|
|
1699
|
+
import('./session-end-flush.js')
|
|
1700
|
+
.then(({ runSessionEndFlush }) => runSessionEndFlush({ chatHistory, client: this.codebuddyClient }))
|
|
1701
|
+
.catch((err) => {
|
|
1702
|
+
logger.debug('[session-end-flush] dispose-path flush failed', { error: String(err) });
|
|
1703
|
+
});
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1640
1706
|
// Remove only the forwarding listeners we attached (not other listeners)
|
|
1641
1707
|
const { start, success, failed, error } = this.repairListeners;
|
|
1642
1708
|
if (start) {
|
|
@@ -1661,8 +1727,30 @@ Look at the screenshot and find the element matching the user's intent. Output o
|
|
|
1661
1727
|
error: err instanceof Error ? err.message : String(err),
|
|
1662
1728
|
});
|
|
1663
1729
|
});
|
|
1730
|
+
this.contextManager.stopPeriodicSnapshot?.();
|
|
1664
1731
|
this.peerRoutingConfig = null;
|
|
1665
1732
|
super.dispose();
|
|
1733
|
+
if (skipAsyncSessionLearning) {
|
|
1734
|
+
cleanupHeadlessSingletonWatchers();
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
1738
|
+
function cleanupHeadlessSingletonWatchers() {
|
|
1739
|
+
for (const cleanup of [
|
|
1740
|
+
resetSkillRegistry,
|
|
1741
|
+
resetIdentityManager,
|
|
1742
|
+
resetHotReloadManager,
|
|
1743
|
+
resetConfigWatcher,
|
|
1744
|
+
resetPersonaManager,
|
|
1745
|
+
resetEnhancedMemory,
|
|
1746
|
+
resetPluginMarketplace,
|
|
1747
|
+
]) {
|
|
1748
|
+
try {
|
|
1749
|
+
cleanup();
|
|
1750
|
+
}
|
|
1751
|
+
catch (error) {
|
|
1752
|
+
logger.debug('Headless watcher cleanup skipped', { error: String(error) });
|
|
1753
|
+
}
|
|
1666
1754
|
}
|
|
1667
1755
|
}
|
|
1668
1756
|
//# sourceMappingURL=codebuddy-agent.js.map
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*
|
|
8
8
|
* @module agent/execution
|
|
9
9
|
*/
|
|
10
|
+
import { normalizeHallucinatedLocalToolCall } from "../tool-handler.js";
|
|
10
11
|
import { logger } from "../../utils/logger.js";
|
|
11
12
|
import { getErrorMessage } from "../../errors/index.js";
|
|
12
13
|
import { sanitizeToolResult } from "../../utils/sanitize.js";
|
|
@@ -32,6 +33,22 @@ function withTimeout(promise, ms, fallback) {
|
|
|
32
33
|
new Promise(resolve => setTimeout(() => resolve(fallback), ms)),
|
|
33
34
|
]);
|
|
34
35
|
}
|
|
36
|
+
function isIgnorableControlToolCall(toolCall) {
|
|
37
|
+
const name = toolCall.function?.name?.trim();
|
|
38
|
+
if (!name)
|
|
39
|
+
return true;
|
|
40
|
+
// Some local models leak thinking/channel markers as tool names. Keep
|
|
41
|
+
// malformed-but-actionable aliases such as `thought-tool:execute_command`
|
|
42
|
+
// because ToolHandler normalizes those to real tools.
|
|
43
|
+
if (normalizeHallucinatedLocalToolCall(name, {}))
|
|
44
|
+
return false;
|
|
45
|
+
const lower = name.toLowerCase();
|
|
46
|
+
return (lower === 'thought' ||
|
|
47
|
+
lower === 'thought|' ||
|
|
48
|
+
lower.startsWith('thought|') ||
|
|
49
|
+
lower.includes('<|channel>') ||
|
|
50
|
+
lower.includes('<|tool_call>'));
|
|
51
|
+
}
|
|
35
52
|
// Lazy-loaded workspace context to avoid blocking tests.
|
|
36
53
|
// Includes a 3s hard timeout so git commands never stall the agent loop.
|
|
37
54
|
let _getWorkspaceContext = null;
|
|
@@ -418,6 +435,21 @@ export class AgentExecutor {
|
|
|
418
435
|
const maxToolRounds = this.config.maxToolRounds;
|
|
419
436
|
let toolRounds = 0;
|
|
420
437
|
let totalOutputTokens = 0;
|
|
438
|
+
// In-loop recovery budgets (Hermes parity): bound re-prompts WITHIN a turn
|
|
439
|
+
// so a length-truncated or post-tool-empty response is recovered instead of
|
|
440
|
+
// returned half-written. 0 disables. Per-turn counters.
|
|
441
|
+
const parseRecoveryBudget = (raw, dflt) => {
|
|
442
|
+
const n = Number.parseInt(raw ?? '', 10);
|
|
443
|
+
return Number.isFinite(n) && n >= 0 ? n : dflt;
|
|
444
|
+
};
|
|
445
|
+
const maxLengthContinuations = parseRecoveryBudget(process.env.CODEBUDDY_MAX_LENGTH_CONTINUATIONS, 3);
|
|
446
|
+
// Length-continuation ships ON (default 3, real-tested). The post-tool
|
|
447
|
+
// empty-response re-prompt is harder to trigger deterministically with a
|
|
448
|
+
// real model, so it ships OFF by default (no untested-by-default behaviour
|
|
449
|
+
// in the hot loop) — opt in with CODEBUDDY_MAX_EMPTY_RETRIES=N.
|
|
450
|
+
const maxEmptyRetries = parseRecoveryBudget(process.env.CODEBUDDY_MAX_EMPTY_RETRIES, 0);
|
|
451
|
+
let lengthContinuations = 0;
|
|
452
|
+
let emptyRetries = 0;
|
|
421
453
|
// Phase (d).21 ship 4 — start a progress session for this turn.
|
|
422
454
|
// The default sink (boot-wired) logs at 25/50/75/100. Lazy-import to
|
|
423
455
|
// avoid circular load at module init time.
|
|
@@ -485,12 +517,14 @@ export class AgentExecutor {
|
|
|
485
517
|
// shrink the tool set to ~5 with a minimal alwaysInclude — we
|
|
486
518
|
// don't want to dangle `remember`/`lessons_*` in front of a model
|
|
487
519
|
// that can't actually call tools and would inline-hallucinate them.
|
|
488
|
-
|
|
520
|
+
const activeModelName = this.deps.client.getCurrentModel() ?? '';
|
|
521
|
+
let selectionOpts = activeModelName ? { modelName: activeModelName } : {};
|
|
489
522
|
try {
|
|
490
523
|
const { getModelToolConfig } = await import('../../config/model-tools.js');
|
|
491
|
-
const cfg = getModelToolConfig(
|
|
524
|
+
const cfg = getModelToolConfig(activeModelName);
|
|
492
525
|
if (cfg.promptProfile === 'lite') {
|
|
493
526
|
selectionOpts = {
|
|
527
|
+
...selectionOpts,
|
|
494
528
|
maxTools: 5,
|
|
495
529
|
alwaysInclude: ['view_file', 'bash', 'search'],
|
|
496
530
|
};
|
|
@@ -499,8 +533,9 @@ export class AgentExecutor {
|
|
|
499
533
|
catch { /* model-tools optional, never block */ }
|
|
500
534
|
const selectionResult = await this.deps.toolSelectionStrategy.selectToolsForQuery(message, selectionOpts);
|
|
501
535
|
let tools = selectionResult.tools;
|
|
536
|
+
let forcedChatOnlyToolRunModel = null;
|
|
502
537
|
if (toolRounds === 0)
|
|
503
|
-
this.deps.toolSelectionStrategy.cacheTools(tools);
|
|
538
|
+
this.deps.toolSelectionStrategy.cacheTools(tools, activeModelName);
|
|
504
539
|
// If the active model is flagged `supportsToolCalls: false` in
|
|
505
540
|
// model-tools.ts (typical of small Ollama / LM Studio models that
|
|
506
541
|
// can't reliably emit OpenAI-style tool_call frames), drop the
|
|
@@ -515,12 +550,17 @@ export class AgentExecutor {
|
|
|
515
550
|
// `(client as { defaultModel? }).defaultModel` access always
|
|
516
551
|
// resolved to undefined because that field doesn't exist on
|
|
517
552
|
// the dispatcher class — left the guard latent for ages.
|
|
518
|
-
const modelName =
|
|
553
|
+
const modelName = activeModelName;
|
|
519
554
|
if (modelName) {
|
|
520
555
|
const cfg = getModelToolConfig(modelName);
|
|
521
556
|
if (cfg.supportsToolCalls === false && tools.length > 0) {
|
|
522
|
-
|
|
523
|
-
|
|
557
|
+
if (process.env.GROK_FORCE_TOOLS === 'true') {
|
|
558
|
+
forcedChatOnlyToolRunModel = modelName;
|
|
559
|
+
}
|
|
560
|
+
else {
|
|
561
|
+
logger.debug(`[agent-executor] supportsToolCalls=false for ${modelName} — dropping ${tools.length} tools from chat call`);
|
|
562
|
+
tools = [];
|
|
563
|
+
}
|
|
524
564
|
}
|
|
525
565
|
}
|
|
526
566
|
}
|
|
@@ -597,7 +637,7 @@ export class AgentExecutor {
|
|
|
597
637
|
yield { type: "token_count", tokenCount: inputTokens + result.tokenCount };
|
|
598
638
|
}
|
|
599
639
|
}
|
|
600
|
-
if (!this.deps.streamingHandler.hasYieldedToolCalls()) {
|
|
640
|
+
if (tools.length > 0 && !this.deps.streamingHandler.hasYieldedToolCalls()) {
|
|
601
641
|
const extracted = this.deps.streamingHandler.extractToolCalls();
|
|
602
642
|
if (extracted.toolCalls.length > 0) {
|
|
603
643
|
yield { type: "tool_calls", toolCalls: extracted.toolCalls };
|
|
@@ -605,9 +645,33 @@ export class AgentExecutor {
|
|
|
605
645
|
}
|
|
606
646
|
const accumulatedMessage = this.deps.streamingHandler.getAccumulatedMessage();
|
|
607
647
|
// Sanitize streamed assistant content: strip model control tokens and invisible chars
|
|
608
|
-
|
|
648
|
+
let toolCalls = accumulatedMessage.tool_calls;
|
|
649
|
+
if (Array.isArray(toolCalls) && toolCalls.length > 0) {
|
|
650
|
+
const filteredToolCalls = toolCalls.filter((toolCall) => !isIgnorableControlToolCall(toolCall));
|
|
651
|
+
if (filteredToolCalls.length !== toolCalls.length) {
|
|
652
|
+
logger.debug('[agent-executor] dropped hallucinated control tool calls', {
|
|
653
|
+
dropped: toolCalls.length - filteredToolCalls.length,
|
|
654
|
+
kept: filteredToolCalls.length,
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
toolCalls = filteredToolCalls.length > 0 ? filteredToolCalls : undefined;
|
|
658
|
+
}
|
|
659
|
+
const hasToolCalls = Array.isArray(toolCalls) && toolCalls.length > 0;
|
|
660
|
+
// Pre-fallback raw content — used by in-loop recovery to tell a real
|
|
661
|
+
// partial answer (retry-able) from a truly empty turn (give up).
|
|
662
|
+
const streamedContentRaw = (accumulatedMessage.content || "").trim();
|
|
663
|
+
const streamFinishReason = accumulatedMessage.finishReason;
|
|
664
|
+
let rawStreamedContent = accumulatedMessage.content || "";
|
|
665
|
+
if (forcedChatOnlyToolRunModel && !hasToolCalls && !rawStreamedContent.trim()) {
|
|
666
|
+
rawStreamedContent =
|
|
667
|
+
`Blocked: ${forcedChatOnlyToolRunModel} is configured as a chat-only local model and ` +
|
|
668
|
+
'returned no structured tool call even with GROK_FORCE_TOOLS=true. ' +
|
|
669
|
+
'Use a tool-capable model such as qwen3.5-ctx32k or gpt-5.5 for goals that need shell/tools.';
|
|
670
|
+
yield { type: "content", content: `${rawStreamedContent}\n` };
|
|
671
|
+
}
|
|
672
|
+
if (!rawStreamedContent)
|
|
673
|
+
rawStreamedContent = "Using tools to help you...";
|
|
609
674
|
const content = sanitizeAssistantOutput(rawStreamedContent);
|
|
610
|
-
const toolCalls = accumulatedMessage.tool_calls;
|
|
611
675
|
const assistantEntry = {
|
|
612
676
|
type: "assistant",
|
|
613
677
|
content: content,
|
|
@@ -616,6 +680,9 @@ export class AgentExecutor {
|
|
|
616
680
|
};
|
|
617
681
|
history.push(assistantEntry);
|
|
618
682
|
messages.push({ role: "assistant", content: content, tool_calls: toolCalls });
|
|
683
|
+
const currentOutputTokens = this.deps.streamingHandler.getTokenCount() || 0;
|
|
684
|
+
totalOutputTokens += currentOutputTokens;
|
|
685
|
+
yield { type: "token_count", tokenCount: inputTokens + totalOutputTokens };
|
|
619
686
|
if (toolCalls && toolCalls.length > 0) {
|
|
620
687
|
toolRounds++;
|
|
621
688
|
// Pre-check cost limit before executing tools (estimate only — no side effects)
|
|
@@ -703,7 +770,7 @@ export class AgentExecutor {
|
|
|
703
770
|
// Use streaming execution for tools that support it (bash, reason, + adapter-based)
|
|
704
771
|
let result;
|
|
705
772
|
const _streamToolStartMs = Date.now();
|
|
706
|
-
const STREAMING_TOOLS = ['bash', 'reason'];
|
|
773
|
+
const STREAMING_TOOLS = ['bash', 'reason', 'generate_document'];
|
|
707
774
|
if (STREAMING_TOOLS.includes(toolCall.function.name)) {
|
|
708
775
|
const gen = this.deps.toolHandler.executeToolStreaming(toolCall);
|
|
709
776
|
let genResult = await gen.next();
|
|
@@ -914,8 +981,6 @@ export class AgentExecutor {
|
|
|
914
981
|
if (terminateDetectedStreaming)
|
|
915
982
|
break;
|
|
916
983
|
inputTokens = this.deps.tokenCounter.countMessageTokens(messages);
|
|
917
|
-
const currentOutputTokens = this.deps.streamingHandler.getTokenCount() || 0;
|
|
918
|
-
totalOutputTokens += currentOutputTokens;
|
|
919
984
|
yield { type: "token_count", tokenCount: inputTokens + totalOutputTokens };
|
|
920
985
|
// Run after_turn middleware (handles cost recording + limit)
|
|
921
986
|
if (pipeline) {
|
|
@@ -942,6 +1007,51 @@ export class AgentExecutor {
|
|
|
942
1007
|
catch { /* masking is optional */ }
|
|
943
1008
|
}
|
|
944
1009
|
else {
|
|
1010
|
+
// ── In-loop recovery (Hermes parity) ─────────────────────────────
|
|
1011
|
+
// Re-prompt WITHIN the turn before accepting this as the final answer.
|
|
1012
|
+
// Only reachable in the no-tool-calls branch, so we never split a
|
|
1013
|
+
// tool_call/tool_result pair (keeps transcript-repair invariants intact).
|
|
1014
|
+
if (!abortController?.signal.aborted) {
|
|
1015
|
+
// (1) Length truncation: the model hit the output-token cap mid-prose.
|
|
1016
|
+
// Ask it to continue from where it stopped, bounded. A continuation
|
|
1017
|
+
// that produced ZERO new tokens (e.g. a too-small num_ctx) leaves
|
|
1018
|
+
// `streamedContentRaw` empty — we do NOT retry that (the fix is config,
|
|
1019
|
+
// not looping); we fall through and stop.
|
|
1020
|
+
if (streamFinishReason === 'length' &&
|
|
1021
|
+
streamedContentRaw.length > 0 &&
|
|
1022
|
+
lengthContinuations < maxLengthContinuations) {
|
|
1023
|
+
lengthContinuations++;
|
|
1024
|
+
logger.debug('[agent-executor] length-truncation continuation', {
|
|
1025
|
+
attempt: lengthContinuations,
|
|
1026
|
+
max: maxLengthContinuations,
|
|
1027
|
+
});
|
|
1028
|
+
messages.push({
|
|
1029
|
+
role: 'user',
|
|
1030
|
+
content: 'Your previous message was cut off because it reached the output length limit. ' +
|
|
1031
|
+
'Continue it from exactly where it stopped — do not repeat earlier text and do not ' +
|
|
1032
|
+
'restart. When the full response is complete, finish normally.',
|
|
1033
|
+
});
|
|
1034
|
+
continue;
|
|
1035
|
+
}
|
|
1036
|
+
// (2) Post-tool empty response: the model went silent after running
|
|
1037
|
+
// tools. Nudge it to use the results and continue, bounded.
|
|
1038
|
+
if (streamedContentRaw.length === 0 &&
|
|
1039
|
+
streamFinishReason !== 'length' &&
|
|
1040
|
+
toolRounds > 0 &&
|
|
1041
|
+
emptyRetries < maxEmptyRetries) {
|
|
1042
|
+
emptyRetries++;
|
|
1043
|
+
logger.debug('[agent-executor] empty-response re-prompt', {
|
|
1044
|
+
attempt: emptyRetries,
|
|
1045
|
+
max: maxEmptyRetries,
|
|
1046
|
+
});
|
|
1047
|
+
messages.push({
|
|
1048
|
+
role: 'user',
|
|
1049
|
+
content: 'Your last response was empty. Use the results of the tool calls you just made ' +
|
|
1050
|
+
'to continue the task and produce your answer.',
|
|
1051
|
+
});
|
|
1052
|
+
continue;
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
945
1055
|
// Fire-and-forget auto-capture on final assistant response (streaming)
|
|
946
1056
|
try {
|
|
947
1057
|
const { getAutoCaptureManager } = await import('../../memory/auto-capture.js');
|
|
@@ -183,6 +183,13 @@ export const TOOL_METADATA = {
|
|
|
183
183
|
parallelSafe: false, // Single local camera device + explicit privacy boundary
|
|
184
184
|
priority: 6,
|
|
185
185
|
},
|
|
186
|
+
camera_analyze: {
|
|
187
|
+
reads: [],
|
|
188
|
+
writes: ["file"],
|
|
189
|
+
hasSideEffects: true,
|
|
190
|
+
parallelSafe: false, // Single local camera device + network vision call
|
|
191
|
+
priority: 6,
|
|
192
|
+
},
|
|
186
193
|
diagram: {
|
|
187
194
|
reads: [],
|
|
188
195
|
writes: ["file"],
|
|
@@ -11,6 +11,12 @@
|
|
|
11
11
|
* @module agent/execution/tool-hooks
|
|
12
12
|
*/
|
|
13
13
|
import type { CodeBuddyMessage } from '../../codebuddy/client.js';
|
|
14
|
+
export type FleetEventBroadcaster = (type: any, payload: any, agentId?: string) => void;
|
|
15
|
+
/**
|
|
16
|
+
* Register the fleet event broadcaster. Called by the server at boot
|
|
17
|
+
* to wire up fleet events without introducing a circular dependency.
|
|
18
|
+
*/
|
|
19
|
+
export declare function registerFleetBroadcaster(broadcaster: FleetEventBroadcaster): void;
|
|
14
20
|
/**
|
|
15
21
|
* Emit a fleet event for tool execution. Best-effort: never throws,
|
|
16
22
|
* silently no-ops when fleet streaming is disabled or the WS server
|
|
@@ -11,11 +11,19 @@
|
|
|
11
11
|
* @module agent/execution/tool-hooks
|
|
12
12
|
*/
|
|
13
13
|
import { getUserHooksManager } from '../../hooks/user-hooks.js';
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
let _fleetBroadcaster = null;
|
|
15
|
+
/**
|
|
16
|
+
* Register the fleet event broadcaster. Called by the server at boot
|
|
17
|
+
* to wire up fleet events without introducing a circular dependency.
|
|
18
|
+
*/
|
|
19
|
+
export function registerFleetBroadcaster(broadcaster) {
|
|
20
|
+
_fleetBroadcaster = broadcaster;
|
|
21
|
+
}
|
|
22
|
+
function _broadcastFleetEvent(type, payload, agentId) {
|
|
23
|
+
if (_fleetBroadcaster) {
|
|
24
|
+
_fleetBroadcaster(type, payload, agentId);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
19
27
|
/**
|
|
20
28
|
* Phase (d).2 V0.4.1 — fleet stream opt-in. When CODEBUDDY_FLEET_STREAM=1
|
|
21
29
|
* (or =true), every tool execution emits a fleet:agent:tool_started /
|
|
@@ -37,6 +37,12 @@ export interface ToolSelectionConfig {
|
|
|
37
37
|
enableCaching: boolean;
|
|
38
38
|
/** Cache TTL in milliseconds (default: 5 minutes) */
|
|
39
39
|
cacheTTLMs: number;
|
|
40
|
+
/**
|
|
41
|
+
* Active model name. When present, model capability rules from
|
|
42
|
+
* model-tools.ts are applied to the model-facing schemas before they are
|
|
43
|
+
* cached or sent to the provider.
|
|
44
|
+
*/
|
|
45
|
+
modelName?: string;
|
|
40
46
|
}
|
|
41
47
|
/**
|
|
42
48
|
* Result of a tool selection operation
|
|
@@ -80,6 +86,7 @@ export declare class ToolSelectionStrategy {
|
|
|
80
86
|
private config;
|
|
81
87
|
private cachedTools;
|
|
82
88
|
private cachedToolNames;
|
|
89
|
+
private cacheModelName;
|
|
83
90
|
private lastQuery;
|
|
84
91
|
private lastSelection;
|
|
85
92
|
private cacheTimestamp;
|
|
@@ -109,13 +116,13 @@ export declare class ToolSelectionStrategy {
|
|
|
109
116
|
*
|
|
110
117
|
* @param tools - Tools to cache
|
|
111
118
|
*/
|
|
112
|
-
cacheTools(tools: CodeBuddyTool[]): void;
|
|
119
|
+
cacheTools(tools: CodeBuddyTool[], modelName?: string): void;
|
|
113
120
|
/**
|
|
114
121
|
* Get cached tools if available and valid
|
|
115
122
|
*
|
|
116
123
|
* @returns Cached tools or null if cache is invalid/empty
|
|
117
124
|
*/
|
|
118
|
-
getCachedTools(): CodeBuddyTool[] | null;
|
|
125
|
+
getCachedTools(modelName?: string): CodeBuddyTool[] | null;
|
|
119
126
|
/**
|
|
120
127
|
* Set the active skill for tool augmentation.
|
|
121
128
|
*
|
|
@@ -140,6 +147,8 @@ export declare class ToolSelectionStrategy {
|
|
|
140
147
|
* Check if the cache is still valid
|
|
141
148
|
*/
|
|
142
149
|
private isCacheValid;
|
|
150
|
+
private static normalizeModelName;
|
|
151
|
+
private applyModelFacingSchemaFilter;
|
|
143
152
|
/**
|
|
144
153
|
* Record a tool request for metrics tracking
|
|
145
154
|
*
|