@phuetz/code-buddy 1.1.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 -165
- 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 +69 -14
- 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/middleware/index.d.ts +1 -0
- package/dist/agent/middleware/index.js +1 -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 +6 -1
- package/dist/agent/session-end-flush.js +20 -4
- 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 +102 -3
- package/dist/commands/cli/utility-commands.js +45 -0
- package/dist/commands/enhanced-command-handler.js +1 -1
- package/dist/commands/goal-cli.d.ts +30 -0
- package/dist/commands/goal-cli.js +210 -27
- package/dist/commands/handlers/goal-handler.d.ts +9 -2
- package/dist/commands/handlers/goal-handler.js +36 -9
- 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/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 +756 -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.js +1 -0
- package/dist/daemon/autonomous-daemon.d.ts +1 -1
- package/dist/daemon/autonomous-daemon.js +3 -3
- package/dist/daemon/autonomous-loop.js +11 -2
- package/dist/daemon/colab-goal.js +9 -1
- 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.js +14 -2
- package/dist/fleet/peer-session-bridge.js +50 -12
- package/dist/fleet/peer-tool-bridge.js +14 -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 +2 -0
- package/dist/goals/goal-judge.js +35 -6
- package/dist/goals/goal-loop.d.ts +14 -0
- package/dist/goals/goal-loop.js +47 -2
- package/dist/goals/goal-manager.d.ts +6 -0
- package/dist/goals/goal-manager.js +67 -14
- package/dist/goals/goal-state.d.ts +13 -0
- package/dist/goals/goal-state.js +83 -13
- package/dist/goals/goal-store.d.ts +3 -0
- package/dist/goals/goal-store.js +31 -15
- package/dist/hooks/user-hooks.js +17 -3
- package/dist/index.js +464 -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/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.js +5 -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
|
@@ -9,7 +9,10 @@
|
|
|
9
9
|
* 2. reusable lesson candidates via the existing review-gated
|
|
10
10
|
* auto-proposer (PENDING only — a human approves them into lessons.md,
|
|
11
11
|
* which the per-turn `<lessons_context>` injection then re-injects on
|
|
12
|
-
* future runs)
|
|
12
|
+
* future runs);
|
|
13
|
+
* 3. declarative long-term memory candidates via the review-gated memory
|
|
14
|
+
* queue. These do not enter prompt-injected persistent memory until a
|
|
15
|
+
* human accepts them.
|
|
13
16
|
*
|
|
14
17
|
* Guard-rails: trivial sessions are skipped (no LLM call, no file), and
|
|
15
18
|
* everything written here passes the privacy lint first (PII/secret spans
|
|
@@ -145,7 +148,7 @@ export function writeHandoffSync(history, workDir = process.cwd(), options = {})
|
|
|
145
148
|
}
|
|
146
149
|
lines.push('', '## Reprise', '', risks.length > 0
|
|
147
150
|
? '- Commencer par lever les risques ouverts ci-dessus.'
|
|
148
|
-
: '- Continuer le dernier objectif, ou `buddy --continue` pour recharger la session.', '- Leçons en attente de revue : `buddy lessons` (candidats proposés en fin de session).', '');
|
|
151
|
+
: '- Continuer le dernier objectif, ou `buddy --continue` pour recharger la session.', '- Leçons en attente de revue : `buddy lessons` (candidats proposés en fin de session).', '- Mémoires en attente de revue : `/memory candidates` puis `/memory accept <id> <reviewer>`.', '');
|
|
149
152
|
const content = redactSecrets(lines.join('\n'));
|
|
150
153
|
const dir = path.join(workDir, '.codebuddy');
|
|
151
154
|
const target = path.join(dir, 'HANDOFF.md');
|
|
@@ -168,7 +171,7 @@ export function writeHandoffSync(history, workDir = process.cwd(), options = {})
|
|
|
168
171
|
* no-ops on trivial sessions, never throws.
|
|
169
172
|
*/
|
|
170
173
|
export async function runSessionEndFlush(input) {
|
|
171
|
-
const empty = { proposedLessons: 0, openRisks: [] };
|
|
174
|
+
const empty = { proposedLessons: 0, proposedMemories: 0, openRisks: [] };
|
|
172
175
|
try {
|
|
173
176
|
if (!isFeatureEnabled('SESSION_END_FLUSH')) {
|
|
174
177
|
return { ...empty, skipped: 'disabled' };
|
|
@@ -195,12 +198,25 @@ export async function runSessionEndFlush(input) {
|
|
|
195
198
|
catch (err) {
|
|
196
199
|
logger.debug('[session-end-flush] lesson proposal failed', { err: String(err) });
|
|
197
200
|
}
|
|
198
|
-
|
|
201
|
+
let proposedMemories = 0;
|
|
202
|
+
if (process.env.CODEBUDDY_MEMORY_AUTO_PROPOSE !== 'false') {
|
|
203
|
+
try {
|
|
204
|
+
const { proposeMemoryCandidatesFromSession } = await import('../memory/memory-auto-proposer.js');
|
|
205
|
+
const proposed = await proposeMemoryCandidatesFromSession(history, workDir, input.client, input.sessionId);
|
|
206
|
+
proposedMemories = proposed.length;
|
|
207
|
+
}
|
|
208
|
+
catch (err) {
|
|
209
|
+
logger.debug('[session-end-flush] memory proposal failed', { err: String(err) });
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (proposedLessons > 0 || proposedMemories > 0 || handoffPath) {
|
|
199
213
|
logger.info(`[session-end-flush] ${proposedLessons} lesson candidate(s) proposed` +
|
|
214
|
+
`, ${proposedMemories} memory candidate(s) proposed` +
|
|
200
215
|
(handoffPath ? `, handoff written to ${path.relative(workDir, handoffPath)}` : ''));
|
|
201
216
|
}
|
|
202
217
|
return {
|
|
203
218
|
proposedLessons,
|
|
219
|
+
proposedMemories,
|
|
204
220
|
...(handoffPath ? { handoffPath } : {}),
|
|
205
221
|
openRisks,
|
|
206
222
|
};
|
|
@@ -118,6 +118,12 @@ export interface AccumulatedMessage {
|
|
|
118
118
|
content?: string;
|
|
119
119
|
/** Accumulated tool calls */
|
|
120
120
|
tool_calls?: CodeBuddyToolCall[];
|
|
121
|
+
/**
|
|
122
|
+
* The terminal `finish_reason`/`stop_reason` reported by the provider on the
|
|
123
|
+
* final chunk (`'stop'` | `'length'` | `'tool_calls'` | …). Used by the
|
|
124
|
+
* executor's in-loop recovery to detect a length-truncated turn.
|
|
125
|
+
*/
|
|
126
|
+
finishReason?: string | null;
|
|
121
127
|
/** Any additional fields from the API */
|
|
122
128
|
[key: string]: unknown;
|
|
123
129
|
}
|
|
@@ -153,6 +159,7 @@ export declare class StreamingHandler {
|
|
|
153
159
|
private accumulatedMessage;
|
|
154
160
|
private accumulatedRawContent;
|
|
155
161
|
private accumulatedReasoningContent;
|
|
162
|
+
private accumulatedFinishReason;
|
|
156
163
|
private tokenCounter;
|
|
157
164
|
private lastTokenUpdate;
|
|
158
165
|
private toolCallsYielded;
|
|
@@ -42,6 +42,7 @@ export class StreamingHandler {
|
|
|
42
42
|
accumulatedMessage = {};
|
|
43
43
|
accumulatedRawContent = '';
|
|
44
44
|
accumulatedReasoningContent = '';
|
|
45
|
+
accumulatedFinishReason = null;
|
|
45
46
|
tokenCounter = null;
|
|
46
47
|
lastTokenUpdate = 0;
|
|
47
48
|
toolCallsYielded = false;
|
|
@@ -86,6 +87,11 @@ export class StreamingHandler {
|
|
|
86
87
|
}
|
|
87
88
|
// Accumulate the message using reducer
|
|
88
89
|
this.accumulatedMessage = reduceStreamChunk(this.accumulatedMessage, chunk);
|
|
90
|
+
// Capture the terminal finish_reason (present on the final chunk). The last
|
|
91
|
+
// non-null value wins so a trailing usage-only chunk can't clear it.
|
|
92
|
+
if (chunk.choices[0].finish_reason) {
|
|
93
|
+
this.accumulatedFinishReason = chunk.choices[0].finish_reason;
|
|
94
|
+
}
|
|
89
95
|
// Extract content delta
|
|
90
96
|
const rawContentDelta = chunk.choices[0].delta?.content || '';
|
|
91
97
|
this.accumulatedRawContent += rawContentDelta;
|
|
@@ -208,7 +214,7 @@ export class StreamingHandler {
|
|
|
208
214
|
* @returns The accumulated message with all processed content and tool calls
|
|
209
215
|
*/
|
|
210
216
|
getAccumulatedMessage() {
|
|
211
|
-
return { ...this.accumulatedMessage };
|
|
217
|
+
return { ...this.accumulatedMessage, finishReason: this.accumulatedFinishReason };
|
|
212
218
|
}
|
|
213
219
|
/**
|
|
214
220
|
* Gets the raw accumulated content before sanitization.
|
|
@@ -261,6 +267,7 @@ export class StreamingHandler {
|
|
|
261
267
|
this.accumulatedMessage = {};
|
|
262
268
|
this.accumulatedRawContent = '';
|
|
263
269
|
this.accumulatedReasoningContent = '';
|
|
270
|
+
this.accumulatedFinishReason = null;
|
|
264
271
|
this.lastTokenUpdate = 0;
|
|
265
272
|
this.toolCallsYielded = false;
|
|
266
273
|
}
|
|
@@ -37,6 +37,11 @@ export interface ToolHandlerDependencies {
|
|
|
37
37
|
/** Coordinates auto-repair attempts for failed commands */
|
|
38
38
|
repairCoordinator: RepairCoordinator;
|
|
39
39
|
}
|
|
40
|
+
export interface NormalizedHallucinatedToolCall {
|
|
41
|
+
toolName: string;
|
|
42
|
+
args: Record<string, unknown>;
|
|
43
|
+
}
|
|
44
|
+
export declare function normalizeHallucinatedLocalToolCall(toolName: string, args: Record<string, unknown>): NormalizedHallucinatedToolCall | null;
|
|
40
45
|
/**
|
|
41
46
|
* ToolHandler manages tool instantiation and execution
|
|
42
47
|
*
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* Tool instances are lazy-loaded on first access for optimal startup time.
|
|
17
17
|
*/
|
|
18
18
|
import { TextEditorTool, MorphEditorTool, ImageTool, BashTool, } from "../tools/index.js";
|
|
19
|
-
import { getFormalToolRegistry, createTextEditorTools, createBashTools, createLsTools, createSearchTools, createWebTools, createTodoTools, createCronjobTools, createDockerTools, createKubernetesTools, createGitTools, createMiscTools, createBrowserTools, createProcessTools, createVisionTools, createScriptTools, createPlanTools, createKnowledgeTools, createRelationshipIntelligenceTools, createInternetScoutTools, createLeadScoutTools, createBrowserOperatorTools, createMemoryTools, createParallelTools, createAttentionTools, createSkillsInspectionTools, createLessonsTools, createUserModelTools, createAliasTools, createMultimodalTools, createAdvancedTools, createCanvasTools, createLspTools, createMergeConflictTools, createVulnScannerTools, createCodebaseReplaceTools, createAdvisorTools, createFleetTools, createAskUserQuestionTools, createExitPlanModeTools, createGuiTools, createSessionTools, createGitNexusTools, createScreenpipeTools, } from "../tools/registry/index.js";
|
|
19
|
+
import { getFormalToolRegistry, createTextEditorTools, createBashTools, createLsTools, createSearchTools, createWebTools, createTodoTools, createCronjobTools, createDockerTools, createKubernetesTools, createGitTools, createMiscTools, createBrowserTools, createProcessTools, createVisionTools, createScriptTools, createPlanTools, createKnowledgeTools, createRelationshipIntelligenceTools, createInternetScoutTools, createLeadScoutTools, createBrowserOperatorTools, createWindowsTools, createMemoryTools, createParallelTools, createAttentionTools, createSkillsInspectionTools, createLessonsTools, createUserModelTools, createAliasTools, createMultimodalTools, createAdvancedTools, createCanvasTools, createLspTools, createMergeConflictTools, createVulnScannerTools, createCodebaseReplaceTools, createAdvisorTools, createFleetTools, createAskUserQuestionTools, createExitPlanModeTools, createGuiTools, createSessionTools, createGitNexusTools, createScreenpipeTools, } from "../tools/registry/index.js";
|
|
20
20
|
import { getMCPManager } from "../codebuddy/tools.js";
|
|
21
21
|
import { getErrorMessage } from "../errors/index.js";
|
|
22
22
|
import { logger } from "../utils/logger.js";
|
|
@@ -44,6 +44,67 @@ const READ_ONLY_FILE_TOOLS = new Set([
|
|
|
44
44
|
'find_definition',
|
|
45
45
|
'search_multi',
|
|
46
46
|
]);
|
|
47
|
+
export function normalizeHallucinatedLocalToolCall(toolName, args) {
|
|
48
|
+
const normalizedName = toolName.toLowerCase().replace(/\s+/g, '');
|
|
49
|
+
const thoughtToolCallSuffix = normalizedName.match(/^thought_tool_call_\d+(?:_\d+)*\.(bash|create_file|write_file|view_file|read_file)$/)?.[1];
|
|
50
|
+
if (thoughtToolCallSuffix === 'bash') {
|
|
51
|
+
const command = firstStringValue(args.command, args.cmd, args.shell_command, args.command_to_execute, args.code);
|
|
52
|
+
return {
|
|
53
|
+
toolName: 'bash',
|
|
54
|
+
args: command ? { ...args, command } : args,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
if (thoughtToolCallSuffix === 'create_file' || thoughtToolCallSuffix === 'write_file') {
|
|
58
|
+
const path = firstStringValue(args.path, args.file_path, args.target_file, args.filename, args.file);
|
|
59
|
+
const content = firstStringValue(args.content, args.file_content, args.contents, args.text);
|
|
60
|
+
return {
|
|
61
|
+
toolName: 'create_file',
|
|
62
|
+
args: {
|
|
63
|
+
...args,
|
|
64
|
+
...(path ? { path } : {}),
|
|
65
|
+
...(content !== undefined ? { content } : {}),
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (thoughtToolCallSuffix === 'view_file' || thoughtToolCallSuffix === 'read_file') {
|
|
70
|
+
const path = firstStringValue(args.path, args.file_path, args.target_file, args.filename, args.file);
|
|
71
|
+
return {
|
|
72
|
+
toolName: 'view_file',
|
|
73
|
+
args: path ? { ...args, path } : args,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
if (normalizedName.includes('bash_tool:execute') ||
|
|
77
|
+
normalizedName.includes('thought-tool:execute_command') ||
|
|
78
|
+
normalizedName === 'execute_command') {
|
|
79
|
+
const command = firstStringValue(args.command, args.cmd, args.shell_command, args.command_to_execute, args.code);
|
|
80
|
+
return {
|
|
81
|
+
toolName: 'bash',
|
|
82
|
+
args: command ? { ...args, command } : args,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
if (normalizedName.includes('bash_tool:write_file') ||
|
|
86
|
+
normalizedName.includes('thought-tool:write_file') ||
|
|
87
|
+
normalizedName.includes('call:bash_tool:write_file')) {
|
|
88
|
+
const path = firstStringValue(args.path, args.file_path, args.target_file, args.filename, args.file);
|
|
89
|
+
const content = firstStringValue(args.content, args.file_content, args.contents, args.text);
|
|
90
|
+
return {
|
|
91
|
+
toolName: 'create_file',
|
|
92
|
+
args: {
|
|
93
|
+
...args,
|
|
94
|
+
...(path ? { path } : {}),
|
|
95
|
+
...(content !== undefined ? { content } : {}),
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
function firstStringValue(...values) {
|
|
102
|
+
for (const value of values) {
|
|
103
|
+
if (typeof value === 'string' && value.trim())
|
|
104
|
+
return value;
|
|
105
|
+
}
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
47
108
|
/**
|
|
48
109
|
* ToolHandler manages tool instantiation and execution
|
|
49
110
|
*
|
|
@@ -156,6 +217,7 @@ export class ToolHandler {
|
|
|
156
217
|
...createInternetScoutTools(),
|
|
157
218
|
...createLeadScoutTools(),
|
|
158
219
|
...createBrowserOperatorTools(),
|
|
220
|
+
...(process.platform === 'win32' ? createWindowsTools() : []),
|
|
159
221
|
...createMemoryTools(),
|
|
160
222
|
...createParallelTools(),
|
|
161
223
|
...createAttentionTools(),
|
|
@@ -244,8 +306,25 @@ export class ToolHandler {
|
|
|
244
306
|
const startTime = Date.now();
|
|
245
307
|
const hooksManager = getToolHooksManager();
|
|
246
308
|
try {
|
|
247
|
-
|
|
248
|
-
|
|
309
|
+
let args = JSON.parse(toolCall.function.arguments);
|
|
310
|
+
let toolName = toolCall.function.name;
|
|
311
|
+
const normalized = normalizeHallucinatedLocalToolCall(toolName, args);
|
|
312
|
+
if (normalized) {
|
|
313
|
+
logger.debug('Normalized hallucinated local tool name', {
|
|
314
|
+
from: toolName,
|
|
315
|
+
to: normalized.toolName,
|
|
316
|
+
});
|
|
317
|
+
toolName = normalized.toolName;
|
|
318
|
+
args = normalized.args;
|
|
319
|
+
toolCall = {
|
|
320
|
+
...toolCall,
|
|
321
|
+
function: {
|
|
322
|
+
...toolCall.function,
|
|
323
|
+
name: toolName,
|
|
324
|
+
arguments: JSON.stringify(args),
|
|
325
|
+
},
|
|
326
|
+
};
|
|
327
|
+
}
|
|
249
328
|
// Create hook context
|
|
250
329
|
let hookContext = {
|
|
251
330
|
toolName,
|
|
@@ -693,6 +772,12 @@ export class ToolHandler {
|
|
|
693
772
|
*/
|
|
694
773
|
async executeBashWithHooks(args, context) {
|
|
695
774
|
const command = args.command;
|
|
775
|
+
if (typeof command !== 'string' || command.trim() === '') {
|
|
776
|
+
return {
|
|
777
|
+
success: false,
|
|
778
|
+
error: 'bash: missing a non-empty "command" string argument. Put the shell command to run in the "command" field.',
|
|
779
|
+
};
|
|
780
|
+
}
|
|
696
781
|
// Execute pre-bash hooks
|
|
697
782
|
try {
|
|
698
783
|
await this.deps.hooksManager.executeHooks("pre-bash", { command });
|
|
@@ -754,6 +839,15 @@ export class ToolHandler {
|
|
|
754
839
|
const args = JSON.parse(toolCall.function.arguments);
|
|
755
840
|
const command = args.command;
|
|
756
841
|
const timeout = args.timeout || 30000;
|
|
842
|
+
// A weaker model can emit a `bash` call without a `command` (or a
|
|
843
|
+
// non-string one). Fail with a clear, recoverable message instead of
|
|
844
|
+
// crashing downstream on `command.trim()` (auto-repair can then re-prompt).
|
|
845
|
+
if (typeof command !== 'string' || command.trim() === '') {
|
|
846
|
+
return {
|
|
847
|
+
success: false,
|
|
848
|
+
error: 'bash: missing a non-empty "command" string argument. Put the shell command to run in the "command" field.',
|
|
849
|
+
};
|
|
850
|
+
}
|
|
757
851
|
const gen = this.bash.executeStreaming(command, timeout);
|
|
758
852
|
let result = await gen.next();
|
|
759
853
|
while (!result.done) {
|
|
@@ -778,8 +872,15 @@ export class ToolHandler {
|
|
|
778
872
|
mode: mode,
|
|
779
873
|
});
|
|
780
874
|
reasoner.setMode(mode);
|
|
875
|
+
const problem = args.problem;
|
|
876
|
+
if (typeof problem !== 'string' || problem.trim() === '') {
|
|
877
|
+
return {
|
|
878
|
+
success: false,
|
|
879
|
+
error: 'reason: missing a non-empty "problem" string argument. Put the problem to reason about in the "problem" field.',
|
|
880
|
+
};
|
|
881
|
+
}
|
|
781
882
|
const gen = reasoner.solveStreaming({
|
|
782
|
-
description:
|
|
883
|
+
description: problem,
|
|
783
884
|
context: args.context,
|
|
784
885
|
constraints: args.constraints,
|
|
785
886
|
});
|
|
@@ -796,6 +897,31 @@ export class ToolHandler {
|
|
|
796
897
|
return { success: false, error: `Reasoning error: ${getErrorMessage(error)}` };
|
|
797
898
|
}
|
|
798
899
|
}
|
|
900
|
+
// generate_document: stream the build phases (prepare → parse → build →
|
|
901
|
+
// write → verify → done) so the UI shows the steps unfold one by one
|
|
902
|
+
// instead of a single opaque "Created X" at the end.
|
|
903
|
+
if (toolName === 'generate_document') {
|
|
904
|
+
try {
|
|
905
|
+
const args = JSON.parse(toolCall.function.arguments);
|
|
906
|
+
const { executeGenerateDocumentStreaming } = await import('../tools/document-generator.js');
|
|
907
|
+
const gen = executeGenerateDocumentStreaming({
|
|
908
|
+
type: args.type,
|
|
909
|
+
title: args.title,
|
|
910
|
+
content: args.content,
|
|
911
|
+
outputPath: args.outputPath ?? args.output_path,
|
|
912
|
+
theme: args.theme,
|
|
913
|
+
});
|
|
914
|
+
let r = await gen.next();
|
|
915
|
+
while (!r.done) {
|
|
916
|
+
yield r.value;
|
|
917
|
+
r = await gen.next();
|
|
918
|
+
}
|
|
919
|
+
return r.value ?? { success: false, error: 'Document tool returned no result' };
|
|
920
|
+
}
|
|
921
|
+
catch (error) {
|
|
922
|
+
return { success: false, error: `Document streaming error: ${getErrorMessage(error)}` };
|
|
923
|
+
}
|
|
924
|
+
}
|
|
799
925
|
// Fallback: non-streaming execution
|
|
800
926
|
return await this.executeTool(toolCall);
|
|
801
927
|
}
|
|
@@ -189,12 +189,27 @@ export class BrowserOperatorExecutor {
|
|
|
189
189
|
'access denied',
|
|
190
190
|
'security checkpoint',
|
|
191
191
|
];
|
|
192
|
+
const sensitivePlatforms = [
|
|
193
|
+
'yandex.com',
|
|
194
|
+
'yandex.ru',
|
|
195
|
+
'login.microsoftonline.com',
|
|
196
|
+
'zoom.us',
|
|
197
|
+
];
|
|
192
198
|
for (const indicator of antiBotIndicators) {
|
|
193
199
|
if (lower.includes(indicator)) {
|
|
194
200
|
raiseCheckpoint(`Security checkpoint detected: "${indicator}"`);
|
|
195
201
|
break;
|
|
196
202
|
}
|
|
197
203
|
}
|
|
204
|
+
if (!checkpointDetected) {
|
|
205
|
+
const currentUrl = String(this.page.url?.() ?? '').toLowerCase();
|
|
206
|
+
for (const platform of sensitivePlatforms) {
|
|
207
|
+
if (currentUrl.includes(platform)) {
|
|
208
|
+
raiseCheckpoint(`OSINT Policy Violation: Target-specific exploit scripts are strictly declined for "${platform}"`);
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
198
213
|
}
|
|
199
214
|
catch {
|
|
200
215
|
// Ignore polling errors while pages are navigating or closing.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser Use Runner
|
|
3
|
+
*
|
|
4
|
+
* browser-use is an open-source agentic browser-automation library. This runner
|
|
5
|
+
* routes a task through one of three paths, in precedence order:
|
|
6
|
+
*
|
|
7
|
+
* 1. The Browser Use **managed API** (via `BROWSER_USE_API_KEY`), or
|
|
8
|
+
* 2. The **Nous Tool Gateway** (`CODEBUDDY_NOUS_TOOL_GATEWAY_URL`), or
|
|
9
|
+
* 3. A **local** browser-use install driven against a local Ollama model
|
|
10
|
+
* (no paid account required). Enabled with `CODEBUDDY_BROWSER_USE_LOCAL=1`
|
|
11
|
+
* or auto-detected when the `browser_use` Python package is importable and
|
|
12
|
+
* neither managed path is configured.
|
|
13
|
+
*
|
|
14
|
+
* The managed paths (1 and 2) speak HTTP via `fetch`. The local path (3) spawns
|
|
15
|
+
* a Python subprocess that runs `Agent(task=..., llm=ChatOllama(...)).run()` and
|
|
16
|
+
* prints a sentinel-delimited JSON result line, which we parse and normalise
|
|
17
|
+
* back into the same `BrowserUseActionResult` shape.
|
|
18
|
+
*
|
|
19
|
+
* Returns structured results with optional screenshot data. Falls back
|
|
20
|
+
* gracefully (typed error result, never throws) when nothing is configured.
|
|
21
|
+
*/
|
|
22
|
+
export interface BrowserUseRunnerOptions {
|
|
23
|
+
/** Browser Use API key (falls back to `BROWSER_USE_API_KEY` env). */
|
|
24
|
+
apiKey?: string;
|
|
25
|
+
/** Nous Tool Gateway URL (falls back to `CODEBUDDY_NOUS_TOOL_GATEWAY_URL` env). */
|
|
26
|
+
gatewayUrl?: string;
|
|
27
|
+
/** Request/run timeout in milliseconds (default: 60 000 managed, 180 000 local). */
|
|
28
|
+
timeout?: number;
|
|
29
|
+
/**
|
|
30
|
+
* Force/disable the local browser-use path explicitly. When undefined it is
|
|
31
|
+
* read from `CODEBUDDY_BROWSER_USE_LOCAL` and otherwise auto-detected.
|
|
32
|
+
*/
|
|
33
|
+
local?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Python interpreter that has the `browser_use` package installed.
|
|
36
|
+
* Defaults to `$CODEBUDDY_BROWSER_USE_PYTHON`, then `python3`.
|
|
37
|
+
*/
|
|
38
|
+
pythonPath?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Ollama model the local browser-use agent should drive. Defaults to
|
|
41
|
+
* `$CODEBUDDY_BROWSER_USE_MODEL`, then `qwen2.5:7b-instruct` (a tool-calling
|
|
42
|
+
* capable model — browser-use relies on structured tool calls).
|
|
43
|
+
*/
|
|
44
|
+
model?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Ollama host the local agent should connect to. Defaults to `$OLLAMA_HOST`,
|
|
47
|
+
* then `http://localhost:11434`.
|
|
48
|
+
*/
|
|
49
|
+
ollamaHost?: string;
|
|
50
|
+
/**
|
|
51
|
+
* Path to a Chrome/Chromium binary for browser-use to launch
|
|
52
|
+
* (`BrowserProfile.executable_path`). Defaults to `$CODEBUDDY_BROWSER_USE_CHROME`.
|
|
53
|
+
* On sandboxed Linux/CI hosts the snap-confined chromium often fails the
|
|
54
|
+
* 30 s browser-start watchdog; pointing at a plain Chromium binary (e.g. the
|
|
55
|
+
* Playwright cache) plus `chromiumSandbox: false` is what makes launch work.
|
|
56
|
+
*/
|
|
57
|
+
chromePath?: string;
|
|
58
|
+
/**
|
|
59
|
+
* Disable Chromium's sandbox and add `--no-sandbox` (needed inside most
|
|
60
|
+
* containers / sandboxed CI). Defaults from `$CODEBUDDY_BROWSER_USE_NO_SANDBOX`
|
|
61
|
+
* (truthy), else true on Linux where the sandbox commonly blocks launch.
|
|
62
|
+
*/
|
|
63
|
+
noSandbox?: boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Whether browser-use should send screenshots to the model. browser-use sends
|
|
66
|
+
* them by default, which 400s on text-only Ollama models
|
|
67
|
+
* (`Multimodal data provided, but model does not support multimodal requests`).
|
|
68
|
+
* Defaults to `false` so the default text model works; set true with a vision
|
|
69
|
+
* model. Read from `$CODEBUDDY_BROWSER_USE_VISION` when undefined.
|
|
70
|
+
*/
|
|
71
|
+
useVision?: boolean;
|
|
72
|
+
/** Max agent steps for the local run (default: 6). */
|
|
73
|
+
maxSteps?: number;
|
|
74
|
+
}
|
|
75
|
+
export interface BrowserUseActionResult {
|
|
76
|
+
ok: boolean;
|
|
77
|
+
/** Extracted page content or action result text. */
|
|
78
|
+
content?: string;
|
|
79
|
+
/** Base64-encoded screenshot, when the service provides one. */
|
|
80
|
+
screenshot?: string;
|
|
81
|
+
error?: string;
|
|
82
|
+
}
|
|
83
|
+
/** Pull the last sentinel-prefixed JSON object out of accumulated stdout. */
|
|
84
|
+
export declare function parseLocalResult(stdout: string): BrowserUseActionResult | null;
|
|
85
|
+
/**
|
|
86
|
+
* Execute a browser action through the Browser Use service.
|
|
87
|
+
*
|
|
88
|
+
* ```ts
|
|
89
|
+
* const result = await executeBrowserUseAction(
|
|
90
|
+
* 'Extract the main heading',
|
|
91
|
+
* 'https://example.com',
|
|
92
|
+
* );
|
|
93
|
+
* if (result.ok) console.log(result.content);
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export declare function executeBrowserUseAction(action: string, url: string, options?: BrowserUseRunnerOptions): Promise<BrowserUseActionResult>;
|