mixdog 0.8.1 → 0.9.1
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 +47 -23
- package/package.json +34 -28
- package/scripts/_test-folder-dialog.mjs +30 -0
- package/scripts/agent-parallel-smoke.mjs +388 -0
- package/scripts/agent-tag-reuse-smoke.mjs +183 -0
- package/scripts/background-task-meta-smoke.mjs +38 -0
- package/scripts/boot-smoke.mjs +52 -9
- package/scripts/build-runtime-linux.sh +348 -0
- package/scripts/build-runtime-macos.sh +217 -0
- package/scripts/build-runtime-windows.ps1 +242 -0
- package/scripts/compact-active-turn-test.mjs +68 -0
- package/scripts/compact-smoke.mjs +859 -129
- package/scripts/compact-trigger-migration-smoke.mjs +187 -0
- package/scripts/fix-brief-fn.mjs +35 -0
- package/scripts/fix-format-tool-surface.mjs +24 -0
- package/scripts/fix-tool-exec-visible.mjs +42 -0
- package/scripts/generate-runtime-manifest.mjs +166 -0
- package/scripts/hook-bus-test.mjs +330 -0
- package/scripts/lead-workflow-smoke.mjs +33 -39
- package/scripts/live-worker-smoke.mjs +43 -37
- package/scripts/llm-trace-summary.mjs +315 -0
- package/scripts/memory-meta-concurrency-test.mjs +20 -0
- package/scripts/output-style-smoke.mjs +56 -15
- package/scripts/parent-abort-link-test.mjs +44 -0
- package/scripts/patch-agent-brief.mjs +48 -0
- package/scripts/patch-app.mjs +21 -0
- package/scripts/patch-app2.mjs +18 -0
- package/scripts/patch-dist-brief.mjs +96 -0
- package/scripts/patch-tool-exec.mjs +70 -0
- package/scripts/pretool-ask-runtime-test.mjs +54 -0
- package/scripts/provider-toolcall-test.mjs +376 -0
- package/scripts/reactive-compact-persist-smoke.mjs +124 -0
- package/scripts/sanitize-tool-pairs-test.mjs +260 -0
- package/scripts/session-context-bench.mjs +205 -33
- package/scripts/session-ingest-smoke.mjs +177 -0
- package/scripts/set-effort-config-test.mjs +41 -0
- package/scripts/smoke-runtime-negative.ps1 +106 -0
- package/scripts/smoke-runtime-negative.sh +97 -0
- package/scripts/smoke.mjs +25 -0
- package/scripts/tool-result-hook-test.mjs +48 -0
- package/scripts/tool-smoke.mjs +1222 -90
- package/scripts/toolcall-args-test.mjs +150 -0
- package/scripts/tui-background-failure-smoke.mjs +73 -0
- package/scripts/usage-metrics-epoch-smoke.mjs +114 -0
- package/src/agents/debugger/AGENT.md +8 -0
- package/src/agents/explore/AGENT.md +4 -0
- package/src/agents/heavy-worker/AGENT.md +9 -3
- package/src/agents/maintainer/AGENT.md +4 -0
- package/src/agents/reviewer/AGENT.md +8 -0
- package/src/agents/scheduler-task/AGENT.md +12 -0
- package/src/agents/scheduler-task/agent.json +6 -0
- package/src/agents/webhook-handler/AGENT.md +12 -0
- package/src/agents/webhook-handler/agent.json +6 -0
- package/src/agents/worker/AGENT.md +9 -3
- package/src/app.mjs +77 -3
- package/src/defaults/hidden-roles.json +17 -12
- package/src/headless-role.mjs +117 -0
- package/src/help.mjs +30 -0
- package/src/hooks/lib/permission-evaluator.cjs +11 -475
- package/src/lib/keychain-cjs.cjs +9 -1
- package/src/lib/mixdog-debug.cjs +0 -29
- package/src/lib/plugin-paths.cjs +1 -7
- package/src/lib/rules-builder.cjs +242 -98
- package/src/lib/text-utils.cjs +1 -1
- package/src/mixdog-session-runtime.mjs +2211 -446
- package/src/output-styles/default.md +12 -28
- package/src/output-styles/extreme-simple.md +9 -6
- package/src/output-styles/simple.md +22 -9
- package/src/repl.mjs +108 -59
- package/src/rules/agent/00-common.md +15 -0
- package/src/rules/{bridge → agent}/20-skip-protocol.md +1 -2
- package/src/rules/agent/30-explorer.md +22 -0
- package/src/rules/{bridge → agent}/40-cycle1-agent.md +7 -0
- package/src/rules/{bridge → agent}/41-cycle2-agent.md +7 -0
- package/src/rules/{bridge → agent}/42-cycle3-agent.md +7 -0
- package/src/rules/lead/01-general.md +9 -5
- package/src/rules/lead/04-workflow.md +51 -12
- package/src/rules/lead/lead-tool.md +6 -0
- package/src/rules/shared/01-tool.md +12 -1
- package/src/runtime/agent/orchestrator/activity-bus.mjs +7 -18
- package/src/runtime/agent/orchestrator/agent-owner.mjs +11 -0
- package/src/runtime/agent/orchestrator/{smart-bridge/bridge-llm.mjs → agent-runtime/agent-dispatch.mjs} +138 -111
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +94 -0
- package/src/runtime/agent/orchestrator/{smart-bridge → agent-runtime}/cache-strategy.mjs +32 -23
- package/src/runtime/agent/orchestrator/{smart-bridge → agent-runtime}/session-builder.mjs +33 -27
- package/src/runtime/agent/orchestrator/{bridge-trace.mjs → agent-trace.mjs} +132 -81
- package/src/runtime/agent/orchestrator/cache-mtime.mjs +0 -21
- package/src/runtime/agent/orchestrator/config.mjs +174 -55
- package/src/runtime/agent/orchestrator/context/collect.mjs +195 -487
- package/src/runtime/agent/orchestrator/dispatch-persist.mjs +1 -1
- package/src/runtime/agent/orchestrator/internal-roles.mjs +77 -29
- package/src/runtime/agent/orchestrator/internal-tools.mjs +5 -6
- package/src/runtime/agent/orchestrator/mcp/client.mjs +15 -9
- package/src/runtime/agent/orchestrator/providers/anthropic-betas.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +380 -268
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +131 -93
- package/src/runtime/agent/orchestrator/providers/api-usage.mjs +236 -4
- package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +49 -0
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +58 -13
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +67 -149
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +132 -2
- package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +45 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +61 -116
- package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +25 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +79 -255
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +203 -71
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +512 -312
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +343 -518
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +6 -6
- package/src/runtime/agent/orchestrator/providers/registry.mjs +88 -51
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +289 -11
- package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +41 -8
- package/src/runtime/agent/orchestrator/session/compact.mjs +1173 -267
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +199 -36
- package/src/runtime/agent/orchestrator/session/loop.mjs +840 -612
- package/src/runtime/agent/orchestrator/session/manager.mjs +1574 -459
- package/src/runtime/agent/orchestrator/session/manager.reactive-persist.test.mjs +107 -0
- package/src/runtime/agent/orchestrator/session/store.mjs +67 -29
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +2 -2
- package/src/runtime/agent/orchestrator/stall-policy.mjs +31 -16
- package/src/runtime/agent/orchestrator/tool-loop-guard.mjs +3 -219
- package/src/runtime/agent/orchestrator/tools/bash-session.mjs +35 -8
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +19 -8
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +10 -53
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +60 -37
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +21 -2
- package/src/runtime/agent/orchestrator/tools/builtin/device-paths.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -7
- package/src/runtime/agent/orchestrator/tools/builtin/glob-walk.mjs +1 -3
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +36 -12
- package/src/runtime/agent/orchestrator/tools/builtin/read-args.mjs +2 -0
- package/src/runtime/agent/orchestrator/tools/builtin/read-constants.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +5 -12
- package/src/runtime/agent/orchestrator/tools/builtin/read-image-resize.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +4 -36
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +2 -40
- package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +148 -27
- package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +43 -75
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +90 -20
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +59 -5
- package/src/runtime/agent/orchestrator/tools/code-graph-state.mjs +86 -0
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +11 -11
- package/src/runtime/agent/orchestrator/tools/code-graph.mjs +4106 -4019
- package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +33 -4
- package/src/runtime/agent/orchestrator/tools/patch.mjs +90 -6
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +6 -4
- package/src/runtime/agent/orchestrator/tools/result-compression.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +8 -1
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +4 -4
- package/src/runtime/channels/index.mjs +149 -51
- package/src/runtime/channels/lib/cli-worker-host.mjs +1 -8
- package/src/runtime/channels/lib/config.mjs +0 -1
- package/src/runtime/channels/lib/drop-trace.mjs +1 -1
- package/src/runtime/channels/lib/executor.mjs +0 -3
- package/src/runtime/channels/lib/memory-client.mjs +0 -38
- package/src/runtime/channels/lib/output-forwarder.mjs +1 -8
- package/src/runtime/channels/lib/runtime-paths.mjs +0 -6
- package/src/runtime/channels/lib/scheduler.mjs +18 -14
- package/src/runtime/channels/lib/session-discovery.mjs +3 -6
- package/src/runtime/channels/lib/tool-format.mjs +0 -1
- package/src/runtime/channels/lib/transcript-discovery.mjs +4 -12
- package/src/runtime/channels/lib/webhook.mjs +1 -1
- package/src/runtime/channels/tool-defs.mjs +29 -29
- package/src/runtime/lib/keychain-cjs.cjs +0 -1
- package/src/runtime/memory/data/runtime-manifest.json +6 -7
- package/src/runtime/memory/index.mjs +519 -118
- package/src/runtime/memory/lib/agent-ipc.mjs +29 -12
- package/src/runtime/memory/lib/core-memory-store.mjs +2 -2
- package/src/runtime/memory/lib/embedding-model-config.mjs +55 -0
- package/src/runtime/memory/lib/embedding-provider.mjs +31 -4
- package/src/runtime/memory/lib/embedding-worker.mjs +19 -10
- package/src/runtime/memory/lib/llm-worker-host.mjs +0 -4
- package/src/runtime/memory/lib/memory-cycle1.mjs +28 -7
- package/src/runtime/memory/lib/memory-cycle2.mjs +4 -5
- package/src/runtime/memory/lib/memory-cycle3.mjs +2 -2
- package/src/runtime/memory/lib/memory-ops-policy.mjs +2 -2
- package/src/runtime/memory/lib/memory-session-merge.mjs +38 -0
- package/src/runtime/memory/lib/memory.mjs +88 -9
- package/src/runtime/memory/lib/model-profile.mjs +1 -1
- package/src/runtime/memory/lib/pg/adapter.mjs +1 -1
- package/src/runtime/memory/lib/pg/supervisor.mjs +12 -0
- package/src/runtime/memory/lib/runtime-fetcher.mjs +80 -21
- package/src/runtime/memory/lib/session-ingest.mjs +196 -0
- package/src/runtime/memory/lib/trace-store.mjs +96 -51
- package/src/runtime/memory/tool-defs.mjs +46 -37
- package/src/runtime/search/index.mjs +104 -473
- package/src/runtime/search/lib/config.mjs +0 -4
- package/src/runtime/search/lib/state.mjs +1 -15
- package/src/runtime/search/lib/web-tools.mjs +44 -25
- package/src/runtime/search/tool-defs.mjs +16 -23
- package/src/runtime/shared/abort-controller.mjs +1 -1
- package/src/runtime/shared/atomic-file.mjs +4 -3
- package/src/runtime/shared/background-tasks.mjs +122 -11
- package/src/runtime/shared/child-spawn-gate.mjs +139 -0
- package/src/runtime/shared/config.mjs +7 -4
- package/src/runtime/shared/err-text.mjs +131 -4
- package/src/runtime/shared/llm/cost.mjs +2 -2
- package/src/runtime/shared/llm/http-agent.mjs +23 -7
- package/src/runtime/shared/llm/index.mjs +34 -11
- package/src/runtime/shared/llm/usage-log.mjs +4 -4
- package/src/runtime/shared/markdown-frontmatter.mjs +56 -0
- package/src/runtime/shared/singleton-owner.mjs +104 -0
- package/src/runtime/shared/tool-execution-contract.mjs +199 -20
- package/src/runtime/shared/tool-execution-contract.test.mjs +183 -0
- package/src/runtime/shared/tool-surface.mjs +624 -95
- package/src/runtime/shared/user-data-guard.mjs +0 -2
- package/src/standalone/agent-task-status.mjs +203 -0
- package/src/standalone/agent-task-status.test.mjs +76 -0
- package/src/standalone/agent-tool.mjs +1913 -0
- package/src/standalone/channel-worker.mjs +370 -14
- package/src/standalone/explore-tool.mjs +165 -70
- package/src/standalone/folder-dialog.mjs +314 -0
- package/src/standalone/hook-bus.mjs +898 -22
- package/src/standalone/memory-runtime-proxy.mjs +320 -0
- package/src/standalone/projects.mjs +226 -0
- package/src/standalone/provider-admin.mjs +41 -24
- package/src/standalone/seeds.mjs +1 -78
- package/src/standalone/usage-dashboard.mjs +96 -8
- package/src/tui/App.jsx +4800 -2140
- package/src/tui/components/AnsiText.jsx +39 -28
- package/src/tui/components/ContextPanel.jsx +14 -4
- package/src/tui/components/Markdown.jsx +43 -77
- package/src/tui/components/MarkdownTable.jsx +9 -184
- package/src/tui/components/Message.jsx +28 -11
- package/src/tui/components/Picker.jsx +95 -56
- package/src/tui/components/PromptInput.jsx +428 -239
- package/src/tui/components/QueuedCommands.jsx +1 -1
- package/src/tui/components/SlashCommandPalette.jsx +27 -21
- package/src/tui/components/Spinner.jsx +67 -38
- package/src/tui/components/StatusLine.jsx +606 -38
- package/src/tui/components/TextEntryPanel.jsx +128 -9
- package/src/tui/components/ToolExecution.jsx +597 -362
- package/src/tui/components/TurnDone.jsx +3 -3
- package/src/tui/components/UsagePanel.jsx +3 -5
- package/src/tui/components/tool-output-format.mjs +499 -0
- package/src/tui/components/tool-output-format.test.mjs +312 -0
- package/src/tui/dist/index.mjs +9192 -2399
- package/src/tui/engine-runtime-notification.test.mjs +115 -0
- package/src/tui/engine-tool-result-text.test.mjs +75 -0
- package/src/tui/engine.mjs +1455 -279
- package/src/tui/figures.mjs +21 -40
- package/src/tui/index.jsx +75 -31
- package/src/tui/input-editing.mjs +25 -0
- package/src/tui/markdown/format-token.mjs +671 -69
- package/src/tui/markdown/format-token.test.mjs +312 -0
- package/src/tui/markdown/render-ansi.mjs +94 -0
- package/src/tui/markdown/render-ansi.test.mjs +108 -0
- package/src/tui/markdown/stream-fence.mjs +34 -0
- package/src/tui/markdown/stream-fence.test.mjs +26 -0
- package/src/tui/markdown/table-layout.mjs +250 -0
- package/src/tui/paste-attachments.mjs +0 -7
- package/src/tui/spinner-verbs.mjs +1 -2
- package/src/tui/statusline-ansi-bridge.mjs +172 -0
- package/src/tui/statusline-ansi-bridge.test.mjs +159 -0
- package/src/tui/theme.mjs +756 -24
- package/src/tui/time-format.mjs +1 -1
- package/src/tui/transcript-tool-failures.mjs +67 -0
- package/src/tui/transcript-tool-failures.test.mjs +111 -0
- package/src/ui/ansi.mjs +1 -2
- package/src/ui/markdown.mjs +85 -26
- package/src/ui/markdown.test.mjs +70 -0
- package/src/ui/model-display.mjs +121 -0
- package/src/ui/session-stats.mjs +44 -0
- package/src/ui/statusline-context-label.test.mjs +15 -0
- package/src/ui/statusline.mjs +386 -178
- package/src/ui/tool-card.mjs +2 -13
- package/src/vendor/statusline/bin/statusline-lib.mjs +1 -620
- package/src/vendor/statusline/bin/statusline-route.mjs +169 -37
- package/src/vendor/statusline/bin/statusline-route.test.mjs +80 -0
- package/src/vendor/statusline/scripts/lib/gateway-settings.mjs +3 -3
- package/src/vendor/statusline/src/gateway/claude-current.mjs +1 -1
- package/src/vendor/statusline/src/gateway/route-meta.mjs +44 -6
- package/src/vendor/statusline/src/gateway/session-routes.mjs +1 -1
- package/src/workflows/default/WORKFLOW.md +12 -5
- package/src/workflows/default/workflow.json +0 -1
- package/src/workflows/solo/WORKFLOW.md +15 -0
- package/src/workflows/solo/workflow.json +7 -0
- package/vendor/ink/build/ink.js +54 -8
- package/vendor/ink/build/output.js +6 -1
- package/src/agents/scheduler-task.md +0 -3
- package/src/agents/web-researcher/AGENT.md +0 -3
- package/src/agents/web-researcher/agent.json +0 -6
- package/src/agents/webhook-handler.md +0 -3
- package/src/hooks/lib/permission-rules.cjs +0 -170
- package/src/hooks/lib/settings-loader.cjs +0 -112
- package/src/lib/hook-pipe-path.cjs +0 -10
- package/src/rules/bridge/00-common.md +0 -5
- package/src/rules/bridge/30-explorer.md +0 -4
- package/src/rules/lead/00-tool-lead.md +0 -5
- package/src/rules/shared/00-language.md +0 -3
- package/src/runtime/agent/orchestrator/tools/builtin/native-edit-runner.mjs +0 -110
- package/src/runtime/agent/orchestrator/tools/mutation-content-cache.mjs +0 -67
- package/src/runtime/channels/lib/hook-pipe-server.mjs +0 -671
- package/src/runtime/memory/lib/bridge-trace-queries.mjs +0 -120
- package/src/runtime/shared/llm/pid-cleanup.mjs +0 -27
- package/src/standalone/bridge-tool.mjs +0 -1414
- package/src/tui/runtime/shared/process-shutdown.mjs +0 -1
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
providerTimeoutError,
|
|
7
7
|
} from '../stall-policy.mjs';
|
|
8
8
|
import { populateHttpStatusFromMessage } from './retry-classifier.mjs';
|
|
9
|
+
import { customToolCallFromResponseItem } from './custom-tool-wire.mjs';
|
|
9
10
|
|
|
10
11
|
function truncatedCompatStreamError(label, detail) {
|
|
11
12
|
return Object.assign(
|
|
@@ -14,245 +15,30 @@ function truncatedCompatStreamError(label, detail) {
|
|
|
14
15
|
);
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
// Salvage malformed tool_call argument JSON emitted by weaker models.
|
|
31
|
-
//
|
|
32
|
-
// Observed failure mode (deepseek-v4-flash and similar): a string value is
|
|
33
|
-
// emitted as an unquoted scalar with the surrounding quotes dropped, e.g.
|
|
34
|
-
// {"pattern": dispatchAiWrapped, "path": "src/agent"}
|
|
35
|
-
// ^^^^^^^^^^^^^^^^^ should be "dispatchAiWrapped"
|
|
36
|
-
// {"query": claude-code PromptInput borderRight, "site": "github.com"}
|
|
37
|
-
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ should be one string
|
|
38
|
-
// The structure is otherwise well-formed. This is deterministic and common in
|
|
39
|
-
// code-search workloads where the model passes identifiers/symbols as values.
|
|
40
|
-
//
|
|
41
|
-
// Strategy: walk the text tracking object/array context and JSON strings
|
|
42
|
-
// (honoring backslash escapes). OUTSIDE a string, only value slots are repaired.
|
|
43
|
-
// A value slot is the token after `:` in an object, after `[` in an array, after
|
|
44
|
-
// `,` in an array, or after `,` followed by the next object key. If the value is
|
|
45
|
-
// not already a complete JSON scalar/container, quote the whole unquoted scalar
|
|
46
|
-
// up to the next syntactic value boundary. Characters inside string literals are
|
|
47
|
-
// never touched, so a `:` or `,` appearing inside a legitimately-quoted value
|
|
48
|
-
// can't trigger a rewrite.
|
|
49
|
-
//
|
|
50
|
-
// Returns the parsed object on success, or null if salvage did not produce
|
|
51
|
-
// valid JSON (caller then falls through to the original error path).
|
|
52
|
-
function salvageBarewordJson(text) {
|
|
53
|
-
if (typeof text !== 'string' || !text.length) return null;
|
|
54
|
-
let out = '';
|
|
55
|
-
let inStr = false;
|
|
56
|
-
let i = 0;
|
|
57
|
-
const n = text.length;
|
|
58
|
-
const stack = [];
|
|
59
|
-
// expectValue=true means the next non-space char begins a value slot
|
|
60
|
-
// (just after `:` `[` `,` or at the very start).
|
|
61
|
-
let expectValue = true;
|
|
62
|
-
const matchingClose = (open) => open === '{' ? '}' : (open === '[' ? ']' : '');
|
|
63
|
-
const skipWs = (pos) => {
|
|
64
|
-
while (pos < n && /\s/.test(text[pos])) pos++;
|
|
65
|
-
return pos;
|
|
66
|
-
};
|
|
67
|
-
const scanStringEnd = (pos) => {
|
|
68
|
-
if (text[pos] !== '"') return -1;
|
|
69
|
-
for (let j = pos + 1; j < n; j++) {
|
|
70
|
-
if (text[j] === '\\') { j++; continue; }
|
|
71
|
-
if (text[j] === '"') return j;
|
|
72
|
-
}
|
|
73
|
-
return -1;
|
|
74
|
-
};
|
|
75
|
-
const isBoundaryAfter = (pos) => {
|
|
76
|
-
const j = skipWs(pos);
|
|
77
|
-
return j >= n || text[j] === ',' || text[j] === '}' || text[j] === ']';
|
|
78
|
-
};
|
|
79
|
-
const quotedKeyAfterComma = (commaPos) => {
|
|
80
|
-
let j = skipWs(commaPos + 1);
|
|
81
|
-
if (text[j] !== '"') return false;
|
|
82
|
-
const end = scanStringEnd(j);
|
|
83
|
-
if (end < 0) return false;
|
|
84
|
-
j = skipWs(end + 1);
|
|
85
|
-
return text[j] === ':';
|
|
86
|
-
};
|
|
87
|
-
const quotedKeyAt = (pos) => {
|
|
88
|
-
const end = scanStringEnd(pos);
|
|
89
|
-
if (end < 0) return false;
|
|
90
|
-
return text[skipWs(end + 1)] === ':';
|
|
91
|
-
};
|
|
92
|
-
const structuralEnd = (pos) => {
|
|
93
|
-
const open = text[pos];
|
|
94
|
-
const close = matchingClose(open);
|
|
95
|
-
if (!close) return -1;
|
|
96
|
-
const local = [open];
|
|
97
|
-
let localInStr = false;
|
|
98
|
-
for (let j = pos + 1; j < n; j++) {
|
|
99
|
-
const ch = text[j];
|
|
100
|
-
if (localInStr) {
|
|
101
|
-
if (ch === '\\') { j++; continue; }
|
|
102
|
-
if (ch === '"') localInStr = false;
|
|
103
|
-
continue;
|
|
104
|
-
}
|
|
105
|
-
if (ch === '"') { localInStr = true; continue; }
|
|
106
|
-
if (ch === '{' || ch === '[') { local.push(ch); continue; }
|
|
107
|
-
if (ch === '}' || ch === ']') {
|
|
108
|
-
if (matchingClose(local[local.length - 1]) !== ch) return -1;
|
|
109
|
-
local.pop();
|
|
110
|
-
if (!local.length) return j;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
return -1;
|
|
114
|
-
};
|
|
115
|
-
// Find where the unquoted scalar value at `pos` ends. Returns the boundary
|
|
116
|
-
// index, or -1 when the surrounding object structure itself is malformed
|
|
117
|
-
// (so salvage must fail rather than quote over it and change structure).
|
|
118
|
-
//
|
|
119
|
-
// Bracket/brace depth is tracked so a `,` or `:` that belongs to regex/glob
|
|
120
|
-
// value text (e.g. `[,:]`, `{a,b,c}`) is correctly kept INSIDE the scalar,
|
|
121
|
-
// while depth-0 object-member separators are treated as structure. Quotes are
|
|
122
|
-
// NOT treated as string delimiters here: we are inside an unquoted value, so
|
|
123
|
-
// any `"` is literal value text (e.g. a regex char class `["']`), and the
|
|
124
|
-
// whole run is re-quoted via JSON.stringify by appendQuotedScalar.
|
|
125
|
-
const scalarEnd = (pos) => {
|
|
126
|
-
const ctx = stack[stack.length - 1] || '';
|
|
127
|
-
let depth = 0;
|
|
128
|
-
for (let j = pos; j < n; j++) {
|
|
129
|
-
const ch = text[j];
|
|
130
|
-
if (ch === '[' || ch === '{') { depth++; continue; }
|
|
131
|
-
if (ch === ']' || ch === '}') {
|
|
132
|
-
if (depth > 0) { depth--; continue; }
|
|
133
|
-
return j; // depth-0 closer ends our container, so ends the value
|
|
134
|
-
}
|
|
135
|
-
if (depth > 0) continue; // inside nested brackets — part of the value
|
|
136
|
-
// A depth-0 quoted key before any separator means a comma is missing
|
|
137
|
-
// between members: malformed object structure, not value text.
|
|
138
|
-
if (ctx === '{' && ch === '"' && quotedKeyAt(j)) return -1;
|
|
139
|
-
if (ctx === '{' && ch === ':') {
|
|
140
|
-
const before = text.slice(pos, j);
|
|
141
|
-
const next = skipWs(j + 1);
|
|
142
|
-
// A depth-0 colon with whitespace on either side looks like an
|
|
143
|
-
// object member separator that was swallowed into the scalar
|
|
144
|
-
// because a comma is missing (e.g. `foo b: 1`, `foo : 1`).
|
|
145
|
-
// Keep compact colon-bearing scalars such as `C:/x`, `http://x`,
|
|
146
|
-
// or `key:value` recoverable.
|
|
147
|
-
if (!before.trim() || /\s/.test(before) || next !== j + 1) return -1;
|
|
148
|
-
}
|
|
149
|
-
if (ch === ',') {
|
|
150
|
-
if (ctx === '[') return j; // array element separator
|
|
151
|
-
if (ctx === '{') return quotedKeyAfterComma(j) ? j : -1;
|
|
152
|
-
return j;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
return n;
|
|
156
|
-
};
|
|
157
|
-
const appendQuotedScalar = (start, end) => {
|
|
158
|
-
const run = text.slice(start, end);
|
|
159
|
-
const leadLen = run.length - run.trimStart().length;
|
|
160
|
-
const trailLen = run.length - run.trimEnd().length;
|
|
161
|
-
const lead = run.slice(0, leadLen);
|
|
162
|
-
const body = run.slice(leadLen, run.length - trailLen);
|
|
163
|
-
const trail = trailLen ? run.slice(run.length - trailLen) : '';
|
|
164
|
-
if (!body) return false;
|
|
165
|
-
out += lead + JSON.stringify(body) + trail;
|
|
166
|
-
return true;
|
|
167
|
-
};
|
|
168
|
-
const readJsonScalar = (pos) => {
|
|
169
|
-
const tail = text.slice(pos);
|
|
170
|
-
const literal = /^(?:true|false|null)\b/.exec(tail);
|
|
171
|
-
if (literal && isBoundaryAfter(pos + literal[0].length)) return literal[0].length;
|
|
172
|
-
const number = /^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/.exec(tail);
|
|
173
|
-
if (number && isBoundaryAfter(pos + number[0].length)) return number[0].length;
|
|
174
|
-
return 0;
|
|
18
|
+
// Invalid-tool-args marker. Native-provider convergence (openai-oauth /
|
|
19
|
+
// opencode): completed-but-malformed tool_call arguments JSON must NOT throw
|
|
20
|
+
// (kills the turn) NOR be silently swallowed to `{}`. Instead the parse
|
|
21
|
+
// failure is carried as data on the tool call's `arguments` slot so the
|
|
22
|
+
// dispatch loop can turn it into an is_error tool_result and let the model
|
|
23
|
+
// re-issue the call with valid JSON in the SAME turn (follow-up retry).
|
|
24
|
+
// { __invalidToolArgs: true, __rawArguments: <raw string>, __parseError: <msg> }
|
|
25
|
+
export function makeInvalidToolArgsMarker(rawArguments, parseError) {
|
|
26
|
+
return {
|
|
27
|
+
__invalidToolArgs: true,
|
|
28
|
+
__rawArguments: typeof rawArguments === 'string' ? rawArguments : String(rawArguments ?? ''),
|
|
29
|
+
__parseError: typeof parseError === 'string' ? parseError : String(parseError ?? 'parse error'),
|
|
175
30
|
};
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
}
|
|
188
|
-
if (c === '"') { inStr = true; out += c; expectValue = false; i++; continue; }
|
|
189
|
-
if (c === ':') { out += c; expectValue = true; i++; continue; }
|
|
190
|
-
if (c === '{') {
|
|
191
|
-
stack.push(c);
|
|
192
|
-
out += c;
|
|
193
|
-
expectValue = false;
|
|
194
|
-
i++;
|
|
195
|
-
continue;
|
|
196
|
-
}
|
|
197
|
-
if (c === '[') {
|
|
198
|
-
if (expectValue) {
|
|
199
|
-
const end = structuralEnd(i);
|
|
200
|
-
if (end >= 0 && isBoundaryAfter(end + 1)) {
|
|
201
|
-
const segment = text.slice(i, end + 1);
|
|
202
|
-
try { JSON.parse(segment); out += segment; i = end + 1; expectValue = false; continue; } catch {}
|
|
203
|
-
}
|
|
204
|
-
const valueEnd = scalarEnd(i);
|
|
205
|
-
if (valueEnd < 0) return null;
|
|
206
|
-
if (!appendQuotedScalar(i, valueEnd)) return null;
|
|
207
|
-
i = valueEnd;
|
|
208
|
-
expectValue = false;
|
|
209
|
-
continue;
|
|
210
|
-
}
|
|
211
|
-
stack.push(c);
|
|
212
|
-
out += c;
|
|
213
|
-
expectValue = c === '[';
|
|
214
|
-
i++;
|
|
215
|
-
continue;
|
|
216
|
-
}
|
|
217
|
-
if (c === ',') {
|
|
218
|
-
out += c;
|
|
219
|
-
expectValue = stack[stack.length - 1] === '[' || quotedKeyAfterComma(i);
|
|
220
|
-
i++;
|
|
221
|
-
continue;
|
|
222
|
-
}
|
|
223
|
-
if (c === '}' || c === ']') {
|
|
224
|
-
if (matchingClose(stack[stack.length - 1]) === c) stack.pop();
|
|
225
|
-
out += c;
|
|
226
|
-
expectValue = false;
|
|
227
|
-
i++;
|
|
228
|
-
continue;
|
|
229
|
-
}
|
|
230
|
-
if (/\s/.test(c)) { out += c; i++; continue; }
|
|
231
|
-
// Non-space, non-structural char in a value slot.
|
|
232
|
-
if (expectValue) {
|
|
233
|
-
const scalarLen = readJsonScalar(i);
|
|
234
|
-
if (scalarLen) {
|
|
235
|
-
out += text.slice(i, i + scalarLen);
|
|
236
|
-
i += scalarLen;
|
|
237
|
-
expectValue = false;
|
|
238
|
-
continue;
|
|
239
|
-
}
|
|
240
|
-
const end = scalarEnd(i);
|
|
241
|
-
if (end < 0) return null;
|
|
242
|
-
if (!appendQuotedScalar(i, end)) return null;
|
|
243
|
-
i = end;
|
|
244
|
-
expectValue = false;
|
|
245
|
-
continue;
|
|
246
|
-
}
|
|
247
|
-
out += c;
|
|
248
|
-
i++;
|
|
249
|
-
}
|
|
250
|
-
if (inStr) return null; // unbalanced string — don't risk a bad parse
|
|
251
|
-
try {
|
|
252
|
-
return JSON.parse(out);
|
|
253
|
-
} catch {
|
|
254
|
-
return null;
|
|
255
|
-
}
|
|
31
|
+
}
|
|
32
|
+
export function isInvalidToolArgsMarker(value) {
|
|
33
|
+
return !!value && typeof value === 'object' && value.__invalidToolArgs === true;
|
|
34
|
+
}
|
|
35
|
+
/** Model-facing tool_result text for a tool call whose arguments failed to
|
|
36
|
+
* parse. Mirrors opencode `The arguments provided to the tool are invalid` and
|
|
37
|
+
* `failed to parse function arguments` — instructs an in-turn retry. */
|
|
38
|
+
export function formatInvalidToolArgsResult(call) {
|
|
39
|
+
const name = call?.name || 'tool';
|
|
40
|
+
const detail = call?.arguments?.__parseError || 'arguments were not valid JSON';
|
|
41
|
+
return `The arguments provided to \`${name}\` are invalid JSON and could not be parsed: ${detail}. Re-issue this tool call with valid JSON arguments.`;
|
|
256
42
|
}
|
|
257
43
|
|
|
258
44
|
/** Completed tool_call.arguments must be valid JSON; empty/missing → {}.
|
|
@@ -267,15 +53,7 @@ export function parseCompletedToolCallArgumentsJson(raw, label, meta) {
|
|
|
267
53
|
const src = text === '' ? '{}' : text;
|
|
268
54
|
try {
|
|
269
55
|
return JSON.parse(src);
|
|
270
|
-
} catch {
|
|
271
|
-
// Salvage the common weak-model failure: a string value emitted as a
|
|
272
|
-
// bare (unquoted) word. Deterministic and structure-preserving, so a
|
|
273
|
-
// successful salvage yields the exact arguments the model intended.
|
|
274
|
-
const salvaged = salvageBarewordJson(text);
|
|
275
|
-
if (salvaged !== null) {
|
|
276
|
-
try { process.stderr.write(`[toolcall-salvage] label=${label} recovered bareword JSON (len=${text.length})\n`); } catch {}
|
|
277
|
-
return salvaged;
|
|
278
|
-
}
|
|
56
|
+
} catch (err) {
|
|
279
57
|
const preview = text.length <= 64
|
|
280
58
|
? text
|
|
281
59
|
: text.slice(0, 32) + '...' + text.slice(-32);
|
|
@@ -291,10 +69,13 @@ export function parseCompletedToolCallArgumentsJson(raw, label, meta) {
|
|
|
291
69
|
// Invariant: a completion/finish signal was observed for this tool call
|
|
292
70
|
// (finish_reason present, or a per-call/response "done" event fired), so
|
|
293
71
|
// the arguments are NOT mid-stream-truncated — they are complete but
|
|
294
|
-
// malformed.
|
|
295
|
-
//
|
|
72
|
+
// malformed. Native convergence: return an invalid-args MARKER (not a
|
|
73
|
+
// throw) so the dispatch loop feeds the parse error back to the model as
|
|
74
|
+
// a tool_result and the model self-corrects in the same turn. Only an
|
|
75
|
+
// unfinished stream (no finishReason) stays the retryable truncation
|
|
76
|
+
// case — that transient behavior is deliberately preserved.
|
|
296
77
|
if (meta?.finishReason) {
|
|
297
|
-
|
|
78
|
+
return makeInvalidToolArgsMarker(text, err instanceof Error ? err.message : String(err));
|
|
298
79
|
}
|
|
299
80
|
throw truncatedCompatStreamError(label, detailParts.join(' '));
|
|
300
81
|
}
|
|
@@ -591,6 +372,27 @@ export async function consumeCompatChatCompletionStream(stream, { signal, label,
|
|
|
591
372
|
|
|
592
373
|
function handleCompatResponsesStreamEvent(event, state, { label, parseResponsesToolCalls, responseOutputText, onStreamDelta, onToolCall, onTextDelta }) {
|
|
593
374
|
if (!event || typeof event.type !== 'string') return;
|
|
375
|
+
const pushToolSearchCall = (item) => {
|
|
376
|
+
if (!item || item.type !== 'tool_search_call') return;
|
|
377
|
+
const callId = item.call_id || item.id || '';
|
|
378
|
+
if (!callId || state.toolCalls.some((call) => call.id === callId)) return;
|
|
379
|
+
const call = {
|
|
380
|
+
id: callId,
|
|
381
|
+
name: 'tool_search',
|
|
382
|
+
arguments: item.arguments && typeof item.arguments === 'object'
|
|
383
|
+
? item.arguments
|
|
384
|
+
: parseCompletedToolCallArgumentsJson(item.arguments || '{}', label, { id: callId, name: 'tool_search', finishReason: 'done' }),
|
|
385
|
+
nativeType: 'tool_search_call',
|
|
386
|
+
};
|
|
387
|
+
state.toolCalls.push(call);
|
|
388
|
+
emitCompatToolCallOnce(state, call, onToolCall);
|
|
389
|
+
};
|
|
390
|
+
const pushCustomToolCall = (item) => {
|
|
391
|
+
const call = customToolCallFromResponseItem(item);
|
|
392
|
+
if (!call || state.toolCalls.some((existing) => existing.id === call.id)) return;
|
|
393
|
+
state.toolCalls.push(call);
|
|
394
|
+
emitCompatToolCallOnce(state, call, onToolCall);
|
|
395
|
+
};
|
|
594
396
|
switch (event.type) {
|
|
595
397
|
case 'response.created':
|
|
596
398
|
if (event.response?.model) state.model = event.response.model;
|
|
@@ -617,6 +419,9 @@ function handleCompatResponsesStreamEvent(event, state, { label, parseResponsesT
|
|
|
617
419
|
case 'response.function_call_arguments.delta':
|
|
618
420
|
try { onStreamDelta?.(); } catch {}
|
|
619
421
|
break;
|
|
422
|
+
case 'response.custom_tool_call_input.delta':
|
|
423
|
+
try { onStreamDelta?.(); } catch {}
|
|
424
|
+
break;
|
|
620
425
|
case 'response.function_call_arguments.done': {
|
|
621
426
|
const itemId = event.item_id || '';
|
|
622
427
|
const pending = state.pendingCalls.get(itemId);
|
|
@@ -654,6 +459,10 @@ function handleCompatResponsesStreamEvent(event, state, { label, parseResponsesT
|
|
|
654
459
|
state.toolCalls.push(call);
|
|
655
460
|
emitCompatToolCallOnce(state, call, onToolCall);
|
|
656
461
|
}
|
|
462
|
+
} else if (item.type === 'tool_search_call') {
|
|
463
|
+
pushToolSearchCall(item);
|
|
464
|
+
} else if (item.type === 'custom_tool_call') {
|
|
465
|
+
pushCustomToolCall(item);
|
|
657
466
|
}
|
|
658
467
|
try { onStreamDelta?.(); } catch {}
|
|
659
468
|
break;
|
|
@@ -665,14 +474,29 @@ function handleCompatResponsesStreamEvent(event, state, { label, parseResponsesT
|
|
|
665
474
|
if (!state.model && resp.model) state.model = resp.model;
|
|
666
475
|
if (!state.responseId && resp.id) state.responseId = resp.id;
|
|
667
476
|
if (!state.content) state.content = responseOutputText(resp);
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
477
|
+
for (const item of resp.output || []) {
|
|
478
|
+
if (item?.type === 'function_call') {
|
|
479
|
+
const itemId = item.id || '';
|
|
480
|
+
const tc = state.toolCalls.find(t => t._pendingItemId === itemId)
|
|
481
|
+
|| (item.call_id ? state.toolCalls.find(t => t.id === item.call_id) : null);
|
|
482
|
+
if (tc) {
|
|
483
|
+
if (!tc.id && item.call_id) tc.id = item.call_id;
|
|
484
|
+
if (!tc.name && item.name) tc.name = item.name;
|
|
485
|
+
if (tc.id && tc.name) delete tc._pendingItemId;
|
|
486
|
+
emitCompatToolCallOnce(state, tc, onToolCall);
|
|
487
|
+
} else if (item.call_id && item.name) {
|
|
488
|
+
const call = {
|
|
489
|
+
id: item.call_id,
|
|
490
|
+
name: item.name,
|
|
491
|
+
arguments: parseCompletedToolCallArgumentsJson(item.arguments, label, { id: item.call_id, name: item.name, finishReason: 'done' }),
|
|
492
|
+
};
|
|
673
493
|
state.toolCalls.push(call);
|
|
674
494
|
emitCompatToolCallOnce(state, call, onToolCall);
|
|
675
495
|
}
|
|
496
|
+
} else if (item?.type === 'tool_search_call') {
|
|
497
|
+
pushToolSearchCall(item);
|
|
498
|
+
} else if (item?.type === 'custom_tool_call') {
|
|
499
|
+
pushCustomToolCall(item);
|
|
676
500
|
}
|
|
677
501
|
}
|
|
678
502
|
try { onStreamDelta?.(); } catch {}
|