@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.
Files changed (312) hide show
  1. package/README.md +160 -164
  2. package/dist/agent/autonomous/agentic-coding-contract.d.ts +6 -6
  3. package/dist/agent/codebuddy-agent.d.ts +1 -1
  4. package/dist/agent/codebuddy-agent.js +101 -13
  5. package/dist/agent/execution/agent-executor.js +122 -12
  6. package/dist/agent/execution/tool-dependency-graph.js +7 -0
  7. package/dist/agent/execution/tool-hooks.d.ts +6 -0
  8. package/dist/agent/execution/tool-hooks.js +13 -5
  9. package/dist/agent/execution/tool-selection-strategy.d.ts +11 -2
  10. package/dist/agent/execution/tool-selection-strategy.js +67 -10
  11. package/dist/agent/extended-thinking.d.ts +8 -0
  12. package/dist/agent/extended-thinking.js +27 -0
  13. package/dist/agent/hermes-browser-backends.js +151 -11
  14. package/dist/agent/hermes-claw-migrate.d.ts +59 -0
  15. package/dist/agent/hermes-claw-migrate.js +427 -26
  16. package/dist/agent/hermes-parity-manifest.js +78 -71
  17. package/dist/agent/hermes-runtime-lifecycle.d.ts +67 -0
  18. package/dist/agent/hermes-runtime-lifecycle.js +468 -0
  19. package/dist/agent/lesson-auto-proposer.js +10 -0
  20. package/dist/agent/middleware/index.d.ts +1 -0
  21. package/dist/agent/middleware/index.js +1 -0
  22. package/dist/agent/middleware/session-duration.d.ts +36 -0
  23. package/dist/agent/middleware/session-duration.js +78 -0
  24. package/dist/agent/middleware/visual-validation-middleware.d.ts +17 -0
  25. package/dist/agent/middleware/visual-validation-middleware.js +67 -0
  26. package/dist/agent/model-benchmark.d.ts +77 -0
  27. package/dist/agent/model-benchmark.js +309 -0
  28. package/dist/agent/model-tier.d.ts +14 -0
  29. package/dist/agent/model-tier.js +71 -0
  30. package/dist/agent/multi-agent/agents/orchestrator-agent.js +17 -6
  31. package/dist/agent/multi-agent/multi-agent-system.js +3 -1
  32. package/dist/agent/multi-agent/session-fleet-bridge.d.ts +2 -0
  33. package/dist/agent/multi-agent/session-fleet-bridge.js +9 -1
  34. package/dist/agent/multi-agent/session-tools.js +22 -5
  35. package/dist/agent/reasoning/mcts.js +20 -6
  36. package/dist/agent/session-end-flush.d.ts +71 -0
  37. package/dist/agent/session-end-flush.js +233 -0
  38. package/dist/agent/streaming/streaming-handler.d.ts +7 -0
  39. package/dist/agent/streaming/streaming-handler.js +8 -1
  40. package/dist/agent/tool-executor.js +1 -0
  41. package/dist/agent/tool-handler.d.ts +5 -0
  42. package/dist/agent/tool-handler.js +130 -4
  43. package/dist/browser-automation/browser-operator-executor.js +15 -0
  44. package/dist/browser-automation/browser-use-runner.d.ts +96 -0
  45. package/dist/browser-automation/browser-use-runner.js +492 -0
  46. package/dist/browser-automation/camofox-runner.d.ts +107 -0
  47. package/dist/browser-automation/camofox-runner.js +287 -0
  48. package/dist/channels/dingtalk/index.js +3 -0
  49. package/dist/channels/discord/client.d.ts +9 -0
  50. package/dist/channels/discord/client.js +12 -0
  51. package/dist/channels/feishu/index.d.ts +167 -1
  52. package/dist/channels/feishu/index.js +432 -7
  53. package/dist/channels/gateway-lifecycle.d.ts +132 -0
  54. package/dist/channels/gateway-lifecycle.js +219 -0
  55. package/dist/channels/google-chat/index.d.ts +5 -1
  56. package/dist/channels/google-chat/index.js +5 -1
  57. package/dist/channels/imessage/index.d.ts +14 -0
  58. package/dist/channels/imessage/index.js +64 -17
  59. package/dist/channels/index.d.ts +4 -0
  60. package/dist/channels/index.js +4 -0
  61. package/dist/channels/irc/index.d.ts +73 -3
  62. package/dist/channels/irc/index.js +446 -11
  63. package/dist/channels/line/index.js +3 -0
  64. package/dist/channels/mattermost/index.d.ts +51 -4
  65. package/dist/channels/mattermost/index.js +303 -20
  66. package/dist/channels/nextcloud-talk/index.d.ts +89 -8
  67. package/dist/channels/nextcloud-talk/index.js +367 -16
  68. package/dist/channels/nostr/index.d.ts +121 -1
  69. package/dist/channels/nostr/index.js +396 -8
  70. package/dist/channels/ntfy/index.js +3 -0
  71. package/dist/channels/qq/index.js +3 -0
  72. package/dist/channels/slash-parity.d.ts +117 -0
  73. package/dist/channels/slash-parity.js +185 -0
  74. package/dist/channels/synology-chat/index.js +3 -0
  75. package/dist/channels/teams/index.d.ts +3 -0
  76. package/dist/channels/teams/index.js +3 -0
  77. package/dist/channels/telegram/client.d.ts +9 -0
  78. package/dist/channels/telegram/client.js +12 -0
  79. package/dist/channels/twilio-voice/index.js +3 -0
  80. package/dist/channels/webchat/index.d.ts +7 -1
  81. package/dist/channels/webchat/index.js +7 -1
  82. package/dist/channels/wecom/index.js +3 -0
  83. package/dist/channels/weixin/index.js +3 -0
  84. package/dist/channels/zalo/index.js +3 -0
  85. package/dist/cli/config-loader.js +1 -1
  86. package/dist/codebuddy/client.d.ts +30 -1
  87. package/dist/codebuddy/client.js +167 -20
  88. package/dist/codebuddy/providers/provider-chatgpt-responses.d.ts +5 -0
  89. package/dist/codebuddy/providers/provider-chatgpt-responses.js +1 -0
  90. package/dist/codebuddy/providers/provider-gemini-native.js +1 -1
  91. package/dist/codebuddy/providers/provider-openai-compat.d.ts +5 -0
  92. package/dist/codebuddy/providers/provider-openai-compat.js +82 -2
  93. package/dist/codebuddy/tool-definitions/computer-control-tools.js +32 -2
  94. package/dist/codebuddy/tool-definitions/core-tools.js +3 -3
  95. package/dist/codebuddy/tool-definitions/index.d.ts +2 -1
  96. package/dist/codebuddy/tool-definitions/index.js +2 -1
  97. package/dist/codebuddy/tool-definitions/multimodal-tools.d.ts +1 -0
  98. package/dist/codebuddy/tool-definitions/multimodal-tools.js +44 -1
  99. package/dist/codebuddy/tool-definitions/windows-tools.d.ts +2 -0
  100. package/dist/codebuddy/tool-definitions/windows-tools.js +34 -0
  101. package/dist/codebuddy/tools.d.ts +1 -1
  102. package/dist/codebuddy/tools.js +27 -24
  103. package/dist/commands/cli/hermes-commands.js +108 -0
  104. package/dist/commands/cli/native-engine-commands.js +107 -3
  105. package/dist/commands/cli/utility-commands.js +45 -0
  106. package/dist/commands/enhanced-command-handler.js +5 -0
  107. package/dist/commands/goal-cli.d.ts +71 -0
  108. package/dist/commands/goal-cli.js +280 -0
  109. package/dist/commands/handlers/goal-handler.d.ts +34 -0
  110. package/dist/commands/handlers/goal-handler.js +155 -0
  111. package/dist/commands/handlers/index.d.ts +1 -0
  112. package/dist/commands/handlers/index.js +2 -0
  113. package/dist/commands/handlers/infra-handlers.js +36 -0
  114. package/dist/commands/handlers/memory-handlers.js +96 -1
  115. package/dist/commands/headless-slash.d.ts +2 -0
  116. package/dist/commands/headless-slash.js +12 -0
  117. package/dist/commands/llm-provider-resolution.d.ts +5 -3
  118. package/dist/commands/llm-provider-resolution.js +87 -33
  119. package/dist/commands/ollama.d.ts +25 -0
  120. package/dist/commands/ollama.js +100 -0
  121. package/dist/commands/provider.d.ts +5 -0
  122. package/dist/commands/provider.js +106 -55
  123. package/dist/commands/slash/builtin-commands.js +20 -0
  124. package/dist/commands/spec-next.js +2 -1
  125. package/dist/commands/spec-plan.js +5 -16
  126. package/dist/commands/tunnel.d.ts +2 -0
  127. package/dist/commands/tunnel.js +48 -0
  128. package/dist/config/config-resolver.d.ts +2 -1
  129. package/dist/config/config-resolver.js +54 -41
  130. package/dist/config/constants.d.ts +28 -0
  131. package/dist/config/constants.js +7 -0
  132. package/dist/config/env-schema.js +770 -0
  133. package/dist/config/feature-flags.js +7 -0
  134. package/dist/config/model-tools.js +4 -4
  135. package/dist/config/toml-config.d.ts +16 -0
  136. package/dist/config/toml-config.js +3 -0
  137. package/dist/context/context-manager-v2.d.ts +39 -0
  138. package/dist/context/context-manager-v2.js +91 -0
  139. package/dist/daemon/agent-task-executor.js +12 -1
  140. package/dist/daemon/autonomous-daemon.d.ts +1 -1
  141. package/dist/daemon/autonomous-daemon.js +5 -3
  142. package/dist/daemon/autonomous-loop.d.ts +21 -1
  143. package/dist/daemon/autonomous-loop.js +69 -0
  144. package/dist/daemon/colab-goal.d.ts +38 -0
  145. package/dist/daemon/colab-goal.js +81 -0
  146. package/dist/daemon/cron-agent-bridge.d.ts +12 -3
  147. package/dist/daemon/cron-agent-bridge.js +25 -9
  148. package/dist/desktop/codebuddy-engine-adapter.d.ts +32 -0
  149. package/dist/desktop/codebuddy-engine-adapter.js +257 -80
  150. package/dist/desktop/engine-adapter.d.ts +14 -0
  151. package/dist/desktop-automation/automation-manager.js +16 -0
  152. package/dist/desktop-automation/omniparser-runner.d.ts +63 -0
  153. package/dist/desktop-automation/omniparser-runner.js +115 -0
  154. package/dist/desktop-automation/smart-snapshot.d.ts +11 -0
  155. package/dist/desktop-automation/smart-snapshot.js +72 -5
  156. package/dist/doctor/index.js +40 -23
  157. package/dist/events/types.d.ts +11 -0
  158. package/dist/fleet/colab-store.d.ts +21 -0
  159. package/dist/fleet/colab-store.js +28 -0
  160. package/dist/fleet/peer-session-bridge.d.ts +1 -1
  161. package/dist/fleet/peer-session-bridge.js +243 -2
  162. package/dist/fleet/peer-session-store.d.ts +3 -0
  163. package/dist/fleet/peer-tool-bridge.js +14 -0
  164. package/dist/fleet/privacy-lint.d.ts +8 -0
  165. package/dist/fleet/privacy-lint.js +22 -0
  166. package/dist/goals/goal-decomposer.d.ts +27 -0
  167. package/dist/goals/goal-decomposer.js +293 -0
  168. package/dist/goals/goal-judge-client.d.ts +15 -0
  169. package/dist/goals/goal-judge-client.js +45 -0
  170. package/dist/goals/goal-judge.d.ts +38 -0
  171. package/dist/goals/goal-judge.js +158 -0
  172. package/dist/goals/goal-loop.d.ts +37 -0
  173. package/dist/goals/goal-loop.js +101 -0
  174. package/dist/goals/goal-manager.d.ts +77 -0
  175. package/dist/goals/goal-manager.js +289 -0
  176. package/dist/goals/goal-state.d.ts +99 -0
  177. package/dist/goals/goal-state.js +315 -0
  178. package/dist/goals/goal-store.d.ts +28 -0
  179. package/dist/goals/goal-store.js +87 -0
  180. package/dist/goals/index.d.ts +5 -0
  181. package/dist/goals/index.js +6 -0
  182. package/dist/hooks/use-input-handler.js +36 -1
  183. package/dist/hooks/user-hooks.js +17 -3
  184. package/dist/index.js +506 -25
  185. package/dist/input/text-to-speech.d.ts +2 -6
  186. package/dist/input/text-to-speech.js +2 -27
  187. package/dist/integrations/screenpipe/screenpipe-client.d.ts +10 -0
  188. package/dist/integrations/screenpipe/screenpipe-client.js +12 -2
  189. package/dist/integrations/tailscale.d.ts +13 -0
  190. package/dist/integrations/tailscale.js +87 -34
  191. package/dist/knowledge/workspace-indexer.js +53 -9
  192. package/dist/mcp/client.js +1 -0
  193. package/dist/mcp/mcp-desktop-tools.d.ts +23 -0
  194. package/dist/mcp/mcp-desktop-tools.js +158 -0
  195. package/dist/mcp/mcp-server.js +2 -0
  196. package/dist/memory/enhanced-memory.d.ts +10 -0
  197. package/dist/memory/enhanced-memory.js +33 -2
  198. package/dist/memory/index.d.ts +3 -1
  199. package/dist/memory/index.js +4 -1
  200. package/dist/memory/memory-auto-proposer.d.ts +23 -0
  201. package/dist/memory/memory-auto-proposer.js +308 -0
  202. package/dist/memory/memory-candidate-queue.d.ts +92 -0
  203. package/dist/memory/memory-candidate-queue.js +261 -0
  204. package/dist/memory/persistent-memory.d.ts +45 -2
  205. package/dist/memory/persistent-memory.js +236 -40
  206. package/dist/ml/bayesian-qualifier.d.ts +1 -1
  207. package/dist/ml/bayesian-qualifier.js +35 -2
  208. package/dist/observability/run-store.d.ts +1 -1
  209. package/dist/openclaw/gateway-bridge.js +5 -0
  210. package/dist/plugins/marketplace.d.ts +1 -0
  211. package/dist/plugins/marketplace.js +7 -0
  212. package/dist/prompts/execution-discipline.d.ts +14 -0
  213. package/dist/prompts/execution-discipline.js +29 -0
  214. package/dist/prompts/variation-injector.js +9 -2
  215. package/dist/protocols/acp/acp-agentic-runner.d.ts +7 -6
  216. package/dist/protocols/acp/acp-agentic-runner.js +115 -18
  217. package/dist/protocols/acp/acp-session-store.d.ts +23 -0
  218. package/dist/protocols/acp/acp-session-store.js +77 -0
  219. package/dist/protocols/acp/acp-stdio-server.d.ts +7 -0
  220. package/dist/protocols/acp/acp-stdio-server.js +71 -16
  221. package/dist/providers/active-llm-registry.d.ts +37 -0
  222. package/dist/providers/active-llm-registry.js +186 -0
  223. package/dist/providers/auxiliary-provider.d.ts +25 -0
  224. package/dist/providers/auxiliary-provider.js +192 -0
  225. package/dist/providers/codex-oauth.d.ts +1 -1
  226. package/dist/providers/codex-oauth.js +27 -4
  227. package/dist/providers/index.d.ts +3 -0
  228. package/dist/providers/index.js +4 -0
  229. package/dist/providers/provider-catalog.d.ts +70 -0
  230. package/dist/providers/provider-catalog.js +738 -0
  231. package/dist/providers/provider-fallback.d.ts +35 -0
  232. package/dist/providers/provider-fallback.js +171 -0
  233. package/dist/providers/xai-oauth.d.ts +128 -0
  234. package/dist/providers/xai-oauth.js +735 -0
  235. package/dist/scheduler/cron-scheduler.d.ts +15 -3
  236. package/dist/scheduler/cron-scheduler.js +53 -7
  237. package/dist/scheduler/script-runner.d.ts +2 -0
  238. package/dist/scheduler/script-runner.js +19 -4
  239. package/dist/scheduler/watchdog-handlers.js +7 -20
  240. package/dist/search/usearch-index.js +7 -2
  241. package/dist/security/tool-policy/tool-groups.js +2 -0
  242. package/dist/server/index.js +17 -2
  243. package/dist/server/routes/mobile.d.ts +12 -4
  244. package/dist/server/routes/mobile.js +116 -1
  245. package/dist/server/tls-config.d.ts +35 -0
  246. package/dist/server/tls-config.js +142 -0
  247. package/dist/server/tunnel-manager.d.ts +20 -0
  248. package/dist/server/tunnel-manager.js +58 -0
  249. package/dist/server/websocket/fleet-bridge.d.ts +13 -1
  250. package/dist/server/websocket/fleet-bridge.js +16 -0
  251. package/dist/services/prompt-builder.d.ts +1 -0
  252. package/dist/services/prompt-builder.js +49 -8
  253. package/dist/shared/engine-types.d.ts +15 -1
  254. package/dist/sidecar/sidecar-bridge.d.ts +1 -0
  255. package/dist/sidecar/sidecar-bridge.js +21 -10
  256. package/dist/spec/spec-store.js +8 -1
  257. package/dist/talk-mode/providers/audioreader-tts.d.ts +1 -1
  258. package/dist/talk-mode/providers/audioreader-tts.js +8 -8
  259. package/dist/templates/project-scaffolding.js +3 -2
  260. package/dist/themes/theme-schema.d.ts +10 -10
  261. package/dist/tools/application-profiles.js +38 -0
  262. package/dist/tools/bash/bash-tool.d.ts +1 -0
  263. package/dist/tools/bash/bash-tool.js +16 -2
  264. package/dist/tools/bash/command-validator.js +3 -0
  265. package/dist/tools/bash/rtk-rewrite.d.ts +16 -0
  266. package/dist/tools/bash/rtk-rewrite.js +100 -0
  267. package/dist/tools/bash/streaming-executor.js +14 -1
  268. package/dist/tools/computer-control-tool.d.ts +16 -1
  269. package/dist/tools/computer-control-tool.js +317 -5
  270. package/dist/tools/document-generator.d.ts +14 -0
  271. package/dist/tools/document-generator.js +79 -0
  272. package/dist/tools/execute-code-rpc-invoker.d.ts +26 -2
  273. package/dist/tools/execute-code-rpc-invoker.js +46 -5
  274. package/dist/tools/metadata.js +28 -0
  275. package/dist/tools/office-macro-tool.d.ts +10 -0
  276. package/dist/tools/office-macro-tool.js +93 -0
  277. package/dist/tools/registry/index.d.ts +2 -1
  278. package/dist/tools/registry/index.js +2 -1
  279. package/dist/tools/registry/memory-tools.d.ts +20 -0
  280. package/dist/tools/registry/memory-tools.js +225 -3
  281. package/dist/tools/registry/multimodal-tools.js +2 -2
  282. package/dist/tools/registry/vision-tools.d.ts +33 -0
  283. package/dist/tools/registry/vision-tools.js +308 -6
  284. package/dist/tools/registry/windows-tools.d.ts +2 -0
  285. package/dist/tools/registry/windows-tools.js +47 -0
  286. package/dist/tools/route-peer-tool.js +14 -0
  287. package/dist/tools/screenshot-tool.js +14 -2
  288. package/dist/tools/text-to-speech-tool.d.ts +1 -1
  289. package/dist/tools/text-to-speech-tool.js +2 -12
  290. package/dist/tools/tool-selector.js +3 -59
  291. package/dist/utils/config-validation/schema.d.ts +40 -7
  292. package/dist/utils/config-validation/schema.js +130 -1
  293. package/dist/utils/cost-tracker.js +21 -1
  294. package/dist/utils/disk-guard.d.ts +180 -0
  295. package/dist/utils/disk-guard.js +404 -0
  296. package/dist/utils/interactive-setup.js +35 -2
  297. package/dist/utils/model-utils.js +11 -2
  298. package/dist/utils/output-sanitizer.js +11 -0
  299. package/dist/utils/provider-detector.d.ts +8 -7
  300. package/dist/utils/provider-detector.js +19 -77
  301. package/dist/utils/settings-manager.d.ts +7 -0
  302. package/dist/utils/token-display.d.ts +3 -3
  303. package/dist/utils/token-display.js +22 -4
  304. package/dist/wizard/onboarding.d.ts +39 -0
  305. package/dist/wizard/onboarding.js +433 -21
  306. package/dist/wizard/provider-onboarding.d.ts +8 -23
  307. package/dist/wizard/provider-onboarding.js +39 -158
  308. package/package.json +4 -2
  309. package/dist/plugins/provider-onboarding.d.ts +0 -23
  310. package/dist/plugins/provider-onboarding.js +0 -116
  311. package/dist/utils/kokoro-tts.d.ts +0 -8
  312. 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
- let systemPrompt = await this.promptBuilder.buildSystemPrompt(systemPromptId, modelName, customInstructions);
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
- try {
479
- const profiler = getRepoProfiler();
480
- const profile = await profiler.getProfile();
481
- if (profile.contextPack) {
482
- systemPrompt = `${systemPrompt}\n\n[Repo] ${profile.contextPack}`;
483
- logger.debug('RepoProfiler: injected contextPack into system prompt');
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
- if (isFeatureEnabled('USER_MODEL_DIALECTIC_ON_SESSION_END')) {
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
- let selectionOpts = {};
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(this.deps.client.getCurrentModel() ?? '');
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 = this.deps.client.getCurrentModel() ?? '';
553
+ const modelName = activeModelName;
519
554
  if (modelName) {
520
555
  const cfg = getModelToolConfig(modelName);
521
556
  if (cfg.supportsToolCalls === false && tools.length > 0) {
522
- logger.debug(`[agent-executor] supportsToolCalls=false for ${modelName} — dropping ${tools.length} tools from chat call`);
523
- tools = [];
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
- const rawStreamedContent = accumulatedMessage.content || "Using tools to help you...";
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
- // Phase (d).2 V0.4.1 — eager import so concurrent tool emits don't get
15
- // serialized through dynamic-import promise chains (same fix as (d).3
16
- // for workflow events). fleet-bridge stays lean; it lazy-imports its
17
- // own deps so this doesn't bloat CLI-only startup.
18
- import { broadcastFleetEvent as _broadcastFleetEvent } from '../../server/websocket/fleet-bridge.js';
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
  *