mixdog 1.2.5 → 1.2.6
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/package.json +1 -1
- package/scripts/lib/gate-scheduler.mjs +2 -2
- package/scripts/lib/run-node-tests.mjs +5 -14
- package/scripts/provider-pingpong-live.mjs +9 -9
- package/src/agents/advisor/AGENT.md +4 -4
- package/src/agents/advisor/agent.json +1 -1
- package/src/agents/reviewer/AGENT.md +2 -3
- package/src/agents/reviewer/agent.json +1 -1
- package/src/defaults/shipped-history.json +10 -0
- package/src/defaults/skills/browser-use/SKILL.md +2 -1
- package/src/defaults/skills/computer-use/SKILL.md +3 -1
- package/src/defaults/skills/visualize/SKILL.md +3 -2
- package/src/lib/rules-builder.cjs +1 -1
- package/src/output-styles/common.md +22 -6
- package/src/output-styles/detailed.md +7 -5
- package/src/output-styles/minimal.md +7 -3
- package/src/output-styles/simple.md +2 -3
- package/src/rules/agent/AGENT.md +3 -1
- package/src/rules/lead/LEAD.md +4 -3
- package/src/rules/shared/10-tool-workflow.md +2 -1
- package/src/rules/shared/60-verification.md +4 -5
- package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -1
- package/src/runtime/agent/orchestrator/config.mjs +6 -0
- package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +1 -1
- package/src/runtime/agent/orchestrator/internal-agents.mjs +10 -0
- package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +53 -60
- package/src/runtime/agent/orchestrator/mcp/client.mjs +7 -4
- package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +2 -3
- package/src/runtime/agent/orchestrator/providers/account-pool.mjs +9 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +40 -19
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +3 -2
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn.mjs +3 -0
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +1 -2
- package/src/runtime/agent/orchestrator/providers/catalog-deadline.mjs +163 -0
- package/src/runtime/agent/orchestrator/providers/catalog-failures.mjs +34 -0
- package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +38 -14
- package/src/runtime/agent/orchestrator/providers/lib/oauth-page.mjs +100 -26
- package/src/runtime/agent/orchestrator/providers/lib/send-callbacks.mjs +24 -0
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +13 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +2 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +4 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +49 -4
- package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +0 -7
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +5 -1
- package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +11 -2
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +45 -16
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-connect.mjs +196 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +74 -9
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +14 -1
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +2 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go-oauth-login.mjs +194 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go-oauth-tokens.mjs +353 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +293 -0
- package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +33 -100
- package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +23 -14
- package/src/runtime/agent/orchestrator/providers/registry.mjs +41 -27
- package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +2 -3
- package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +3 -8
- package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +15 -3
- package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +74 -13
- package/src/runtime/agent/orchestrator/session/compact/forked-summary.mjs +102 -0
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +8 -2
- package/src/runtime/agent/orchestrator/session/compact/summary.mjs +16 -0
- package/src/runtime/agent/orchestrator/session/lifecycle-scan.mjs +9 -0
- package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +39 -2
- package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +9 -19
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +2 -3
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +13 -5
- package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +10 -7
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +62 -22
- package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +23 -1
- package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +81 -34
- package/src/runtime/agent/orchestrator/session/manager.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/request-fork.mjs +47 -0
- package/src/runtime/agent/orchestrator/session/side-question-store.mjs +16 -1
- package/src/runtime/agent/orchestrator/session/side-question.mjs +5 -43
- package/src/runtime/agent/orchestrator/session/store/fs-probe.mjs +10 -0
- package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +73 -6
- package/src/runtime/agent/orchestrator/session/store/load-session.mjs +40 -0
- package/src/runtime/agent/orchestrator/session/store/save-fault.mjs +15 -0
- package/src/runtime/agent/orchestrator/session/store/session-paths.mjs +12 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-header.mjs +36 -0
- package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +258 -43
- package/src/runtime/agent/orchestrator/session/store-record-strict-scan.mjs +306 -0
- package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +70 -21
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +46 -30
- package/src/runtime/agent/orchestrator/session/store-transcript-cache.mjs +144 -45
- package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +32 -13
- package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +364 -38
- package/src/runtime/agent/orchestrator/session/store.mjs +9 -2
- package/src/runtime/agent/orchestrator/session/task-wait-control.mjs +43 -12
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +23 -6
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +12 -6
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +13 -7
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/bashism-rewrite.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/benign-exit.mjs +7 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +40 -7
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +37 -34
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/inline-hoist.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +0 -4
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +6 -0
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +29 -27
- package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/find-files-tool.mjs +28 -11
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-policy.mjs +12 -3
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +203 -101
- package/src/runtime/agent/orchestrator/tools/builtin/git-repo-rw-lock.mjs +90 -41
- package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +17 -1
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-delivery.mjs +199 -0
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +165 -39
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +25 -13
- package/src/runtime/agent/orchestrator/tools/builtin/read-batch.mjs +7 -6
- package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +19 -4
- package/src/runtime/agent/orchestrator/tools/builtin/read-line-collector.mjs +5 -3
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-render.mjs +25 -7
- package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +2 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-render.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +12 -5
- package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +61 -22
- package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +32 -8
- package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +193 -19
- package/src/runtime/agent/orchestrator/tools/builtin/shell-direct-exe.mjs +57 -7
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +119 -32
- package/src/runtime/agent/orchestrator/tools/builtin/shell-lossless-compact.mjs +26 -1
- package/src/runtime/agent/orchestrator/tools/builtin/shell-output.mjs +13 -28
- package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +90 -11
- package/src/runtime/agent/orchestrator/tools/builtin/wait-budgets.mjs +23 -0
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +54 -10
- package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +22 -28
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +11 -7
- package/src/runtime/agent/orchestrator/tools/destructive-warning.mjs +126 -9
- package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
- package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +15 -6
- package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +40 -2
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promotion-results.mjs +13 -3
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +2 -0
- package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +3 -1
- package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +35 -4
- package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +7 -2
- package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +39 -23
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +6 -2
- package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +13 -13
- package/src/runtime/attachments/office-extract.mjs +11 -9
- package/src/runtime/memory/lib/embedding-tokenizer.mjs +32 -18
- package/src/runtime/memory/lib/runtime-fetcher.mjs +1 -1
- package/src/runtime/memory/lib/tool-call-handler.mjs +7 -5
- package/src/runtime/office/authoring/pptx-script-normalize.mjs +11 -8
- package/src/runtime/office/core/tabular.mjs +1 -1
- package/src/runtime/office/design/library/design-template-inspect.mjs +7 -4
- package/src/runtime/office/portable/docx-formatting.mjs +1 -1
- package/src/runtime/office/portable/docx-runs.mjs +1 -1
- package/src/runtime/office/portable/docx-tracked-edits.mjs +2 -2
- package/src/runtime/office/portable/portable-docx-edits.mjs +11 -10
- package/src/runtime/office/portable/portable-docx-operations.mjs +21 -17
- package/src/runtime/office/portable/portable-docx-parts.mjs +15 -9
- package/src/runtime/office/portable/portable-docx-styles.mjs +4 -1
- package/src/runtime/office/portable/portable-docx-xml.mjs +9 -9
- package/src/runtime/office/portable/portable-opc.mjs +27 -13
- package/src/runtime/office/portable/portable-pivot.mjs +3 -3
- package/src/runtime/office/portable/portable-pptx-chart.mjs +3 -3
- package/src/runtime/office/portable/portable-pptx-charts.mjs +24 -18
- package/src/runtime/office/portable/portable-pptx-core.mjs +5 -5
- package/src/runtime/office/portable/portable-pptx-deck.mjs +8 -4
- package/src/runtime/office/portable/portable-pptx-package.mjs +7 -4
- package/src/runtime/office/portable/portable-pptx-shapes.mjs +18 -9
- package/src/runtime/office/portable/portable-sheet-parts.mjs +9 -3
- package/src/runtime/office/portable/portable-sheet-xml.mjs +5 -5
- package/src/runtime/office/portable/portable-xlsx-charts.mjs +4 -1
- package/src/runtime/office/portable/portable-xlsx-drawings.mjs +10 -6
- package/src/runtime/office/portable/portable-xlsx-operations.mjs +8 -5
- package/src/runtime/office/portable/portable-xlsx-pivot-ops.mjs +1 -1
- package/src/runtime/office/portable/portable-xlsx-reference-shift.mjs +11 -7
- package/src/runtime/office/portable/portable-xlsx-sheet-edits.mjs +6 -3
- package/src/runtime/office/portable/portable-xml.mjs +1 -1
- package/src/runtime/shared/atomic-file.mjs +22 -13
- package/src/runtime/shared/background-tasks.mjs +60 -20
- package/src/runtime/shared/child-spawn-gate.mjs +26 -16
- package/src/runtime/shared/config.mjs +0 -10
- package/src/runtime/shared/file-lock.mjs +7 -1
- package/src/runtime/shared/file-permissions-worker.mjs +38 -0
- package/src/runtime/shared/file-permissions.d.mts +19 -4
- package/src/runtime/shared/file-permissions.mjs +310 -4
- package/src/runtime/shared/git-runner-worker.mjs +6 -78
- package/src/runtime/shared/llm/http-agent.mjs +7 -3
- package/src/runtime/shared/llm/provider-catalog-registry.mjs +10 -0
- package/src/runtime/shared/llm/usage-accounting.mjs +2 -0
- package/src/runtime/shared/llm/usage-ledger-import.mjs +32 -3
- package/src/runtime/shared/llm/usage-ledger-rollup.mjs +12 -5
- package/src/runtime/shared/llm/usage-ledger-worker.mjs +1 -1
- package/src/runtime/shared/llm/usage-ledger.mjs +20 -5
- package/src/runtime/shared/memory-snapshot.mjs +5 -1
- package/src/runtime/shared/notify-trace.mjs +8 -1
- package/src/runtime/shared/pristine-execution-contract.json +5 -1
- package/src/runtime/shared/process-runner-worker.mjs +7 -0
- package/src/runtime/shared/process-runner.mjs +38 -0
- package/src/runtime/shared/provider-accounts.mjs +2 -1
- package/src/runtime/shared/provider-api-key.mjs +0 -1
- package/src/runtime/shared/read-row-numbers.mjs +1 -1
- package/src/runtime/shared/resource-admission.mjs +60 -18
- package/src/runtime/shared/run-child.mjs +84 -0
- package/src/runtime/shared/session-activity-signal.mjs +23 -0
- package/src/runtime/shared/shell-output-summary.mjs +23 -0
- package/src/runtime/shared/singleton-owner.mjs +126 -42
- package/src/runtime/shared/tool-output-limit.mjs +4 -2
- package/src/runtime/shared/tool-output-marker.mjs +58 -0
- package/src/runtime/shared/user-data-guard.mjs +28 -9
- package/src/runtime/shared/worktrees/activity-gate.mjs +33 -8
- package/src/runtime/shared/worktrees/git-head.mjs +20 -2
- package/src/runtime/shared/worktrees/lock.mjs +3 -2
- package/src/runtime/terminal-bridge/tool-defs.mjs +1 -1
- package/src/runtime/tidy/runners/biome.mjs +3 -1
- package/src/runtime/tidy/shadow.mjs +2 -1
- package/src/runtime/web-search/index.mjs +5 -7
- package/src/runtime/web-search/lib/formatter.mjs +42 -6
- package/src/runtime/web-search/tool-defs.mjs +6 -1
- package/src/session-runtime/lifecycle/session-switch/context-switch.mjs +4 -3
- package/src/session-runtime/lifecycle/session-switch/resume.mjs +7 -4
- package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +3 -3
- package/src/session-runtime/lifecycle/shared.mjs +19 -2
- package/src/session-runtime/lifecycle/teardown/session-close.mjs +2 -0
- package/src/session-runtime/lifecycle/teardown.mjs +5 -2
- package/src/session-runtime/lifecycle-api.mjs +3 -1
- package/src/session-runtime/provider-auth/login.mjs +10 -6
- package/src/session-runtime/provider-auth/setup.mjs +19 -2
- package/src/session-runtime/provider-catalog-cache.mjs +101 -25
- package/src/session-runtime/provider-models/catalog-load.mjs +14 -3
- package/src/session-runtime/provider-models/row-hydration.mjs +4 -0
- package/src/session-runtime/provider-models.mjs +76 -10
- package/src/session-runtime/provider-readiness.mjs +4 -0
- package/src/session-runtime/services/agent-tool/close-flow.mjs +2 -1
- package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +10 -2
- package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +13 -4
- package/src/session-runtime/services/agent-tool/notify.mjs +15 -4
- package/src/session-runtime/services/agent-tool/restart-notify.mjs +134 -0
- package/src/session-runtime/services/agent-tool/send-flow.mjs +24 -1
- package/src/session-runtime/services/agent-tool/spawn-flow/deferred-spawn.mjs +2 -1
- package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +4 -3
- package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +5 -1
- package/src/session-runtime/services/agent-tool/tag-registry/tag-lookup.mjs +8 -3
- package/src/session-runtime/services/agent-tool/tag-registry.mjs +3 -0
- package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +4 -0
- package/src/session-runtime/services/agent-tool/worker-index.mjs +44 -10
- package/src/session-runtime/services/agent-tool.mjs +20 -0
- package/src/session-runtime/services/provider-admin.mjs +92 -20
- package/src/session-runtime/services/usage-dashboard-model.mjs +2 -2
- package/src/session-runtime/services/usage-dashboard.mjs +27 -69
- package/src/session-runtime/turn/session-ops.mjs +2 -2
- package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +1 -0
- package/src/session-runtime/usage-stats-api.mjs +6 -1
- package/src/standalone/channel-transport/http-routes.mjs +10 -9
- package/src/standalone/daemon-desktop-runtime.mjs +20 -7
- package/src/standalone/daemon-owner.mjs +117 -25
- package/src/standalone/daemon.mjs +43 -13
- package/src/standalone/session-call-cache.mjs +6 -0
- package/src/standalone/session-protocol.mjs +1 -1
- package/src/standalone/session-service/retention/busy.mjs +7 -2
- package/src/standalone/session-transport/routes.mjs +7 -6
- package/src/tui/app/model-options.mjs +39 -2
- package/src/tui/app/model-picker.mjs +16 -2
- package/src/tui/app/provider-setup-picker.mjs +1 -2
- package/src/tui/dist/index.mjs +385 -104
- package/src/tui/session/notice-text.mjs +0 -1
- package/src/tui/session/session-api/intake/submission.mjs +7 -13
- package/src/tui/session/session-api/integrations.mjs +1 -5
- package/src/tui/session/session-flow/drain.mjs +8 -0
- package/src/tui/session/session-flow/steering.mjs +46 -0
- package/src/tui/session/session-flow.mjs +2 -0
- package/src/tui/session/turn-stream.mjs +33 -0
- package/src/tui/session/turn.mjs +30 -3
- package/src/ui/statusline.mjs +1 -6
- package/src/ui/streaming-markdown-heal.mjs +24 -7
- package/src/vendor/statusline/bin/statusline-route.mjs +0 -1
- package/src/vendor/statusline/src/gateway/route-meta.mjs +0 -1
- package/src/workflows/default/WORKFLOW.md +9 -13
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
// tree (taskkill /T /F on Windows, SIGTERM->SIGKILL of every descendant on
|
|
10
10
|
// POSIX). No external dependencies.
|
|
11
11
|
import { spawn } from 'node:child_process';
|
|
12
|
+
import { runProcessOffThread } from '../../../shared/process-runner.mjs';
|
|
12
13
|
import { detachedSpawnOpts } from '../../../shared/spawn-flags.mjs';
|
|
13
14
|
|
|
14
15
|
const isWin = process.platform === 'win32';
|
|
@@ -44,54 +45,26 @@ function transportPid(transport) {
|
|
|
44
45
|
* settled, so enumerators never pile up whatever this value is. */
|
|
45
46
|
export const ENUMERATION_DEADLINE_MS = 20_000;
|
|
46
47
|
|
|
47
|
-
//
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if (strict) {
|
|
66
|
-
reject(error);
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
resolve('');
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
cp.stdout?.on('data', (d) => {
|
|
73
|
-
out += String(d);
|
|
74
|
-
});
|
|
75
|
-
cp.on('error', (error) => settle(() => (strict ? reject(error) : resolve(out))));
|
|
76
|
-
cp.on('close', (code) =>
|
|
77
|
-
settle(() => (strict && code !== 0 ? reject(new Error(`Process enumeration failed (${code}).`)) : resolve(out)))
|
|
78
|
-
);
|
|
79
|
-
if (timeoutMs > 0) {
|
|
80
|
-
timer = setTimeout(() => {
|
|
81
|
-
try {
|
|
82
|
-
cp.kill('SIGKILL');
|
|
83
|
-
} catch {
|
|
84
|
-
/* already gone */
|
|
85
|
-
}
|
|
86
|
-
cp.stdout?.destroy?.();
|
|
87
|
-
cp.stderr?.destroy?.();
|
|
88
|
-
settle(() =>
|
|
89
|
-
strict ? reject(new Error(`Process enumeration timed out after ${timeoutMs} ms.`)) : resolve('')
|
|
90
|
-
);
|
|
91
|
-
}, timeoutMs);
|
|
92
|
-
timer.unref?.();
|
|
48
|
+
// Output bound of one helper command: a process table is tens of KB.
|
|
49
|
+
const HELPER_MAX_BYTES = 64 * 1024 * 1024;
|
|
50
|
+
|
|
51
|
+
// Run a helper command off the event loop (process-runner.mjs: under load one
|
|
52
|
+
// PowerShell start blocked the daemon's loop for seconds) and resolve its
|
|
53
|
+
// stdout. Past `timeoutMs` (default ENUMERATION_DEADLINE_MS) the helper is
|
|
54
|
+
// killed and the call settles. Strict: a failed, non-zero or timed-out run
|
|
55
|
+
// rejects; otherwise it resolves '' (non-zero exits keep their stdout).
|
|
56
|
+
function run(cmd, args, { strict = false, timeoutMs = ENUMERATION_DEADLINE_MS } = {}) {
|
|
57
|
+
return runProcessOffThread(cmd, args, { timeoutMs, maxBytes: HELPER_MAX_BYTES }).then(
|
|
58
|
+
({ code, stdout }) => {
|
|
59
|
+
if (strict && code !== 0) throw new Error(`Process enumeration failed (${code}).`);
|
|
60
|
+
return stdout;
|
|
61
|
+
},
|
|
62
|
+
(error) => {
|
|
63
|
+
if (!strict) return '';
|
|
64
|
+
if (error?.code === 'ETIMEDOUT') throw new Error(`Process enumeration timed out after ${timeoutMs} ms.`);
|
|
65
|
+
throw error;
|
|
93
66
|
}
|
|
94
|
-
|
|
67
|
+
);
|
|
95
68
|
}
|
|
96
69
|
|
|
97
70
|
// Snapshot the whole process table once: parent map + a per-pid identity
|
|
@@ -114,21 +87,25 @@ async function enumerate({ strict = false } = {}) {
|
|
|
114
87
|
],
|
|
115
88
|
{ strict, timeoutMs: ENUMERATION_DEADLINE_MS }
|
|
116
89
|
)
|
|
117
|
-
: await run('ps', ['-A', '-o', 'pid=,ppid=,pgid=,comm=,lstart='], {
|
|
90
|
+
: await run('ps', ['-A', '-o', 'pid=,ppid=,pgid=,stat=,comm=,lstart='], {
|
|
118
91
|
strict,
|
|
119
92
|
timeoutMs: ENUMERATION_DEADLINE_MS,
|
|
120
93
|
});
|
|
121
|
-
const row = isWin ? /^(\d+)\s+(\d+)\s+()(\S+)(?:\s+(.+))?$/ : /^(\d+)\s+(\d+)\s+(\d+)\s+(\S+)(?:\s+(.+))?$/;
|
|
94
|
+
const row = isWin ? /^(\d+)\s+(\d+)\s+()()(\S+)(?:\s+(.+))?$/ : /^(\d+)\s+(\d+)\s+(\d+)\s+(\S+)\s+(\S+)(?:\s+(.+))?$/;
|
|
122
95
|
for (const line of out.split(/\r?\n/)) {
|
|
123
96
|
const m = line.trim().match(row);
|
|
124
97
|
if (!m) continue;
|
|
98
|
+
// A zombie runs nothing and holds no port or file; it only waits to be
|
|
99
|
+
// reaped (forever under an init that does not reap, e.g. a container
|
|
100
|
+
// without one). Counting it alive would hold a dead tree as running.
|
|
101
|
+
if (m[4].startsWith('Z')) continue;
|
|
125
102
|
const pid = Number(m[1]);
|
|
126
103
|
const ppid = Number(m[2]);
|
|
127
|
-
const token = (m[
|
|
104
|
+
const token = (m[6] || '').trim() || null;
|
|
128
105
|
if (!childrenOf.has(ppid)) childrenOf.set(ppid, []);
|
|
129
106
|
childrenOf.get(ppid).push(pid);
|
|
130
107
|
tokenOf.set(pid, token);
|
|
131
|
-
nameOf.set(pid, m[
|
|
108
|
+
nameOf.set(pid, m[5]);
|
|
132
109
|
if (m[3]) pgidOf.set(pid, Number(m[3]));
|
|
133
110
|
}
|
|
134
111
|
if (strict && !nameOf.has(process.pid)) throw new Error('The process snapshot could not be verified.');
|
|
@@ -142,17 +119,33 @@ async function enumerate({ strict = false } = {}) {
|
|
|
142
119
|
* `shared: true` (pre-kill captures) joins a read already in flight, so many
|
|
143
120
|
* jobs promoted together do not each spawn an enumerator; a capture taken
|
|
144
121
|
* while its root runs is valid whenever that read began. An observation after
|
|
145
|
-
* a kill
|
|
146
|
-
*
|
|
122
|
+
* a kill or exit must see a table taken AFTER it asked: a read that began
|
|
123
|
+
* before the kill would report the killed tree alive and defer the
|
|
124
|
+
* confirmation by a whole re-check. Such a caller starts a read when none
|
|
125
|
+
* runs, else joins the one queued to begin when the running read settles —
|
|
126
|
+
* every observer asking meanwhile shares it. At most one enumerator runs at
|
|
127
|
+
* a time, however many shells settle or watch at once (each one is a
|
|
128
|
+
* PowerShell process on Windows; one per settle and watch pass compounded
|
|
129
|
+
* machine load into multi-second daemon stalls). */
|
|
147
130
|
let tableInFlight = null;
|
|
131
|
+
let nextTable = null;
|
|
132
|
+
function startTableRead() {
|
|
133
|
+
const read = enumerate({ strict: true }).finally(() => {
|
|
134
|
+
if (tableInFlight === read) tableInFlight = null;
|
|
135
|
+
});
|
|
136
|
+
tableInFlight = read;
|
|
137
|
+
return read;
|
|
138
|
+
}
|
|
148
139
|
export function readProcessTable({ shared = false } = {}) {
|
|
149
|
-
if (
|
|
150
|
-
if (
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
140
|
+
if (shared && tableInFlight) return tableInFlight;
|
|
141
|
+
if (nextTable) return nextTable;
|
|
142
|
+
if (!tableInFlight) return startTableRead();
|
|
143
|
+
const settled = () => {};
|
|
144
|
+
nextTable = tableInFlight.then(settled, settled).then(() => {
|
|
145
|
+
nextTable = null;
|
|
146
|
+
return startTableRead();
|
|
147
|
+
});
|
|
148
|
+
return nextTable;
|
|
156
149
|
}
|
|
157
150
|
|
|
158
151
|
// Walk every descendant pid of rootPid (excludes rootPid).
|
|
@@ -14,7 +14,7 @@ import { basename, join, resolve } from 'node:path';
|
|
|
14
14
|
import { pathToFileURL } from 'node:url';
|
|
15
15
|
import { tmpdir } from 'node:os';
|
|
16
16
|
import { createHash, randomUUID } from 'node:crypto';
|
|
17
|
-
import {
|
|
17
|
+
import { smartReadTruncate } from '../tools/builtin/read-formatting.mjs';
|
|
18
18
|
import { shutdownStdioChild, killStdioChildTreeFast } from './child-tree.mjs';
|
|
19
19
|
import { makeToolEnvelope, normalizeToolEnvelope } from '../session/tool-envelope.mjs';
|
|
20
20
|
import { classifyResultKind } from '../session/result-classification.mjs';
|
|
@@ -308,7 +308,11 @@ function callAdmissionFor(server) {
|
|
|
308
308
|
const cfg = server?.cfg || {};
|
|
309
309
|
gate = createOwnerFairGate({
|
|
310
310
|
name: `MCP ${server.name}`,
|
|
311
|
-
|
|
311
|
+
// JSON-RPC multiplexes requests by id over one transport, so the client
|
|
312
|
+
// imposes no in-flight cap of its own; a server that needs one declares
|
|
313
|
+
// it (maxConcurrency) or the operator sets MIXDOG_MCP_MAX_INFLIGHT.
|
|
314
|
+
activeMax:
|
|
315
|
+
positiveInt(cfg.maxConcurrency ?? cfg.max_concurrency ?? process.env.MIXDOG_MCP_MAX_INFLIGHT, null) ?? Infinity,
|
|
312
316
|
queueMax: positiveInt(cfg.maxQueue ?? cfg.max_queue ?? process.env.MIXDOG_MCP_MAX_QUEUE, 256),
|
|
313
317
|
minOwnerQueue: 8,
|
|
314
318
|
waitTimeoutMs: positiveInt(
|
|
@@ -1037,7 +1041,7 @@ function capMcpOutputParts(content) {
|
|
|
1037
1041
|
const s = typeof content === 'string' ? content : String(content ?? '');
|
|
1038
1042
|
const bodyBytes = Buffer.byteLength(s, 'utf8');
|
|
1039
1043
|
const bodyLines = countTextLines(s);
|
|
1040
|
-
const { text, truncated } = smartReadTruncate(s, bodyLines, bodyBytes);
|
|
1044
|
+
const { text, truncated, marker } = smartReadTruncate(s, bodyLines, bodyBytes);
|
|
1041
1045
|
if (!truncated) return { text, spillNote: '', truncated: false };
|
|
1042
1046
|
// Spill the full body to a tmp file so the caller can recover content
|
|
1043
1047
|
// elided by the head/tail cap.
|
|
@@ -1056,7 +1060,6 @@ function capMcpOutputParts(content) {
|
|
|
1056
1060
|
/* spill best-effort */
|
|
1057
1061
|
}
|
|
1058
1062
|
const spillNote = spillPath ? `\n\n... [full output spilled to ${spillPath}] ...` : '';
|
|
1059
|
-
const marker = buildSmartReadTruncationMarker(bodyLines, bodyBytes);
|
|
1060
1063
|
const split = text.indexOf(`\n${marker}\n`);
|
|
1061
1064
|
return {
|
|
1062
1065
|
text,
|
|
@@ -70,8 +70,7 @@ export function answerOAuthCallback(req, res, { redirectUrl, state, finish, serv
|
|
|
70
70
|
});
|
|
71
71
|
res.end(html);
|
|
72
72
|
};
|
|
73
|
-
const invalid = () =>
|
|
74
|
-
page(400, oauthErrorHtml('This sign-in link is invalid or has expired.', 'Start the sign-in again from Mixdog.'));
|
|
73
|
+
const invalid = () => page(400, oauthErrorHtml('This sign-in link is invalid or has expired.'));
|
|
75
74
|
let target;
|
|
76
75
|
try {
|
|
77
76
|
target = new URL(req.url || '/', redirectUrl);
|
|
@@ -94,7 +93,7 @@ export function answerOAuthCallback(req, res, { redirectUrl, state, finish, serv
|
|
|
94
93
|
const server = serverName || 'the MCP server';
|
|
95
94
|
if (target.searchParams.has('error')) {
|
|
96
95
|
// The authorization server's error text is never reflected.
|
|
97
|
-
page(400, oauthErrorHtml(`Sign-in to ${server} was not completed
|
|
96
|
+
page(400, oauthErrorHtml(`Sign-in to ${server} was not completed.`));
|
|
98
97
|
finish(undefined);
|
|
99
98
|
return;
|
|
100
99
|
}
|
|
@@ -378,14 +378,21 @@ function poolSend(providerName, account) {
|
|
|
378
378
|
// remaining wait budget is waited out; otherwise the send fails as before.
|
|
379
379
|
const waitOrThrow = async (error, ids) => {
|
|
380
380
|
const { rows, now, all } = exhaustion(ids);
|
|
381
|
-
const
|
|
382
|
-
|
|
381
|
+
const bound = waitBoundMs(ids);
|
|
382
|
+
// Persisting a short cooldown can outlast its deadline. Release only
|
|
383
|
+
// attempts cooled by this send, and only under an enabled wait policy.
|
|
384
|
+
const expired = bound > 0 && rows.some((row) => cooled.has(row.id) && !(Number(row.blockedUntil) > now));
|
|
385
|
+
const wait = all ? null : expired ? 0 : earliestCooldownMs(rows, now);
|
|
386
|
+
if (wait == null || waitedMs + wait > bound) throw markExhausted(error, ids);
|
|
383
387
|
options.onStageChange?.('reconnecting', {
|
|
384
388
|
message: `Rate limited — every account is cooling down; retrying in ${Math.ceil(wait / 1000)}s`,
|
|
385
389
|
reason: 'rate_limited',
|
|
386
390
|
waitMs: wait,
|
|
387
391
|
retryAt: now + wait,
|
|
388
392
|
});
|
|
393
|
+
// A zero-duration sleep does not check cancellation, including on the
|
|
394
|
+
// final allowed send when no next loop iteration will check it either.
|
|
395
|
+
options.signal?.throwIfAborted();
|
|
389
396
|
await sleepWithAbort(wait, options.signal);
|
|
390
397
|
waitedMs += wait;
|
|
391
398
|
const lifted = Date.now();
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
scrubOAuthSecrets,
|
|
26
26
|
} from './lib/oauth-token-utils.mjs';
|
|
27
27
|
import { createOAuthPkce, parseOAuthCodeInput } from './lib/oauth-pkce.mjs';
|
|
28
|
+
import { OAUTH_PAGE_CONTENT_TYPE, oauthErrorHtml, oauthSuccessHtml } from './lib/oauth-page.mjs';
|
|
28
29
|
|
|
29
30
|
const SIGN_IN_EXPIRED_PREFIX = 'Anthropic sign-in expired. Sign in again from Providers.';
|
|
30
31
|
|
|
@@ -66,8 +67,6 @@ const OAUTH_CALLBACK_PATH = '/callback';
|
|
|
66
67
|
const OAUTH_REDIRECT_URI = `http://${OAUTH_CALLBACK_HOST}:${OAUTH_CALLBACK_PORT}${OAUTH_CALLBACK_PATH}`;
|
|
67
68
|
const OAUTH_MANUAL_REDIRECT_URI =
|
|
68
69
|
process.env.ANTHROPIC_OAUTH_MANUAL_REDIRECT_URI || 'https://platform.claude.com/oauth/code/callback';
|
|
69
|
-
const OAUTH_SUCCESS_REDIRECT_URL =
|
|
70
|
-
process.env.ANTHROPIC_OAUTH_SUCCESS_REDIRECT_URL || 'https://platform.claude.com/oauth/code/success?app=claude-code';
|
|
71
70
|
const OAUTH_LOGIN_TIMEOUT_MS = 5 * 60_000;
|
|
72
71
|
const OAUTH_TOKEN_TIMEOUT_MS = 30_000;
|
|
73
72
|
|
|
@@ -110,7 +109,7 @@ function _loadCredentialsFile(path) {
|
|
|
110
109
|
}
|
|
111
110
|
|
|
112
111
|
// The token endpoint names the signed-in account next to the tokens.
|
|
113
|
-
|
|
112
|
+
function identityFromTokenResponse(json) {
|
|
114
113
|
return normalizeAccountIdentity({
|
|
115
114
|
id: json?.account?.uuid,
|
|
116
115
|
email: json?.account?.email_address,
|
|
@@ -570,9 +569,11 @@ function _parseOAuthCodeInput(input) {
|
|
|
570
569
|
return parseOAuthCodeInput(input, { allowHashState: true });
|
|
571
570
|
}
|
|
572
571
|
|
|
573
|
-
async function exchangeAuthorizationCode({ pkce, code, state, redirectUri }) {
|
|
572
|
+
async function exchangeAuthorizationCode({ pkce, code, state, redirectUri, signal = null }) {
|
|
573
|
+
signal?.throwIfAborted();
|
|
574
574
|
const cleanCode = String(code || '').trim();
|
|
575
575
|
if (!cleanCode) throw new Error('[anthropic-oauth] authorization code is required');
|
|
576
|
+
const timeoutSignal = AbortSignal.timeout(OAUTH_TOKEN_TIMEOUT_MS);
|
|
576
577
|
const tokenRes = await fetch(TOKEN_URL, {
|
|
577
578
|
method: 'POST',
|
|
578
579
|
headers: tokenEndpointHeaders(),
|
|
@@ -585,7 +586,7 @@ async function exchangeAuthorizationCode({ pkce, code, state, redirectUri }) {
|
|
|
585
586
|
state,
|
|
586
587
|
}),
|
|
587
588
|
redirect: 'error',
|
|
588
|
-
signal: AbortSignal.
|
|
589
|
+
signal: signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal,
|
|
589
590
|
dispatcher: getLlmDispatcher(),
|
|
590
591
|
});
|
|
591
592
|
if (!tokenRes.ok) {
|
|
@@ -605,6 +606,8 @@ async function exchangeAuthorizationCode({ pkce, code, state, redirectUri }) {
|
|
|
605
606
|
const expiresAt = expiresAtFromTokenResponse(json);
|
|
606
607
|
const scopes = _oauthParseScopeField(json?.scope);
|
|
607
608
|
const identity = identityFromTokenResponse(json);
|
|
609
|
+
// A cancelled login never stores the account it was exchanging.
|
|
610
|
+
signal?.throwIfAborted();
|
|
608
611
|
const credPath = _oauthCredentialsWritePath();
|
|
609
612
|
const raw = _updateCredentialsFile(credPath, (current) => {
|
|
610
613
|
const base = current && typeof current === 'object' ? current : {};
|
|
@@ -664,14 +667,33 @@ export async function beginOAuthLogin({ openBrowserFn = null, openBrowser = true
|
|
|
664
667
|
}
|
|
665
668
|
};
|
|
666
669
|
|
|
670
|
+
const controller = new AbortController();
|
|
667
671
|
let server = null;
|
|
668
672
|
let timeout = null;
|
|
669
673
|
let finish = null;
|
|
674
|
+
let exchangePromise = null;
|
|
675
|
+
// Browser and manual callbacks share one exchange: an authorization code is
|
|
676
|
+
// spent once, and a duplicate joins the first instead of failing the login.
|
|
677
|
+
const acceptCode = (code, redirectUri) => {
|
|
678
|
+
if (exchangePromise) return exchangePromise;
|
|
679
|
+
controller.signal.throwIfAborted();
|
|
680
|
+
// The browser deadline ends when a code arrives; the exchange has its own.
|
|
681
|
+
if (timeout) clearTimeout(timeout);
|
|
682
|
+
timeout = null;
|
|
683
|
+
exchangePromise = exchangeAuthorizationCode({ pkce, code, state, redirectUri, signal: controller.signal });
|
|
684
|
+
exchangePromise.then(
|
|
685
|
+
(tokens) => finish(tokens),
|
|
686
|
+
(error) => finish(null, error instanceof Error ? error : new Error(String(error)))
|
|
687
|
+
);
|
|
688
|
+
return exchangePromise;
|
|
689
|
+
};
|
|
670
690
|
const waitForCallback = new Promise((resolve, reject) => {
|
|
671
691
|
let settled = false;
|
|
672
692
|
finish = (value, error = null) => {
|
|
673
693
|
if (settled) return;
|
|
674
694
|
settled = true;
|
|
695
|
+
// Work arriving after the login settled (or was cancelled) is rejected.
|
|
696
|
+
controller.abort();
|
|
675
697
|
if (timeout) clearTimeout(timeout);
|
|
676
698
|
try {
|
|
677
699
|
server?.close();
|
|
@@ -691,20 +713,20 @@ export async function beginOAuthLogin({ openBrowserFn = null, openBrowser = true
|
|
|
691
713
|
const code = u.searchParams.get('code');
|
|
692
714
|
if (!code || u.searchParams.get('state') !== state) {
|
|
693
715
|
// Reject this request only; the valid callback may still arrive.
|
|
694
|
-
res.writeHead(400);
|
|
695
|
-
res.end('
|
|
716
|
+
res.writeHead(400, { 'Content-Type': OAUTH_PAGE_CONTENT_TYPE });
|
|
717
|
+
res.end(oauthErrorHtml('The sign-in callback was invalid or did not match this login.'));
|
|
696
718
|
return;
|
|
697
719
|
}
|
|
720
|
+
// The login settles (and its server closes) before this answer is sent,
|
|
721
|
+
// so the connection must not stay open to the closed login's handler.
|
|
698
722
|
try {
|
|
699
|
-
|
|
700
|
-
res.writeHead(
|
|
701
|
-
res.end();
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
res.
|
|
706
|
-
res.end(`Claude login failed: ${error.message}`);
|
|
707
|
-
finish(null, error);
|
|
723
|
+
await acceptCode(code, OAUTH_REDIRECT_URI);
|
|
724
|
+
res.writeHead(200, { 'Content-Type': OAUTH_PAGE_CONTENT_TYPE, Connection: 'close' });
|
|
725
|
+
res.end(oauthSuccessHtml('Claude'));
|
|
726
|
+
} catch {
|
|
727
|
+
// The shared exchange reports its error through waitForCallback.
|
|
728
|
+
res.writeHead(500, { 'Content-Type': OAUTH_PAGE_CONTENT_TYPE, Connection: 'close' });
|
|
729
|
+
res.end(oauthErrorHtml('Claude could not complete the token exchange.'));
|
|
708
730
|
}
|
|
709
731
|
});
|
|
710
732
|
timeout = setTimeout(() => finish(null), OAUTH_LOGIN_TIMEOUT_MS);
|
|
@@ -730,10 +752,9 @@ export async function beginOAuthLogin({ openBrowserFn = null, openBrowser = true
|
|
|
730
752
|
completeCode: async (input) => {
|
|
731
753
|
const parsed = _parseOAuthCodeInput(input);
|
|
732
754
|
if (parsed.state && parsed.state !== state) throw new Error('[anthropic-oauth] OAuth state mismatch');
|
|
755
|
+
if (!String(parsed.code || '').trim()) throw new Error('[anthropic-oauth] authorization code is required');
|
|
733
756
|
const redirectUri = parsed.redirectUri || (parsed.state ? OAUTH_MANUAL_REDIRECT_URI : OAUTH_REDIRECT_URI);
|
|
734
|
-
|
|
735
|
-
finish?.(tokens);
|
|
736
|
-
return tokens;
|
|
757
|
+
return await acceptCode(parsed.code, redirectUri);
|
|
737
758
|
},
|
|
738
759
|
cancel: () => {
|
|
739
760
|
finish?.(null);
|
|
@@ -448,7 +448,8 @@ export class AnthropicOAuthProvider {
|
|
|
448
448
|
// a hard 400. Pairing here closes the gap regardless of caller.
|
|
449
449
|
messages = sanitizeToolPairs(messages);
|
|
450
450
|
const opts = sendOpts || {};
|
|
451
|
-
const { onStageChange, onStreamDelta, onToolCall, onTextDelta, onTextReset } =
|
|
451
|
+
const { onStageChange, onStreamDelta, onToolCall, onTextDelta, onTextReset, onStreamItemStart } =
|
|
452
|
+
streamCallbacks(opts);
|
|
452
453
|
const externalSignal = opts.signal || null;
|
|
453
454
|
// Test seam: lets the retry harness drive stream outcomes without a
|
|
454
455
|
// live OAuth session.
|
|
@@ -610,7 +611,7 @@ export class AnthropicOAuthProvider {
|
|
|
610
611
|
midState,
|
|
611
612
|
onTextDelta,
|
|
612
613
|
knownToolNames,
|
|
613
|
-
{ relayProgressUpdates: body.thinking?.display === 'updates' }
|
|
614
|
+
{ relayProgressUpdates: body.thinking?.display === 'updates', onStreamItemStart }
|
|
614
615
|
);
|
|
615
616
|
try {
|
|
616
617
|
controller?.abort?.('Anthropic SSE complete');
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
NATIVE_SERVER_TOOL_RESULT_BLOCK_TYPES,
|
|
9
9
|
} from '../../lib/anthropic-native-blocks.mjs';
|
|
10
10
|
import { parseAnthropicFallbackBlock } from '../../anthropic-server-fallback.mjs';
|
|
11
|
+
import { reportStreamItemStart } from '../../lib/send-callbacks.mjs';
|
|
11
12
|
|
|
12
13
|
// Detach the provider payload from the parser's event object without altering
|
|
13
14
|
// any field (opaque server-tool result payloads must round-trip byte-exact).
|
|
@@ -19,7 +20,7 @@ function cloneNativeBlock(block) {
|
|
|
19
20
|
}
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
export function createContentBlockStart({ turn, blocks, state, progress, seedText }) {
|
|
23
|
+
export function createContentBlockStart({ turn, blocks, state, progress, seedText, onStreamItemStart }) {
|
|
23
24
|
const seedThinkingBlock = (index, block) => {
|
|
24
25
|
if (block.type === 'redacted_thinking') {
|
|
25
26
|
// Opaque redacted payload: real reasoning content, exposed as a block.
|
|
@@ -59,6 +60,8 @@ export function createContentBlockStart({ turn, blocks, state, progress, seedTex
|
|
|
59
60
|
name: block.name || '',
|
|
60
61
|
inputJson: '',
|
|
61
62
|
});
|
|
63
|
+
// The call opened; its input still streams before onToolCall.
|
|
64
|
+
reportStreamItemStart(onStreamItemStart, { kind: 'tool' });
|
|
62
65
|
}
|
|
63
66
|
if (block?.type === 'text') {
|
|
64
67
|
// Seed the ordered text slot. An empty block still needs its slot (it
|
|
@@ -19,6 +19,7 @@ export function createTurnEvents({
|
|
|
19
19
|
onToolCall,
|
|
20
20
|
relayProgressUpdates,
|
|
21
21
|
labels,
|
|
22
|
+
onStreamItemStart,
|
|
22
23
|
}) {
|
|
23
24
|
const { onMessageStart, onMessageDelta, onMessageStop } = createMessageEvents({ turn, blocks, state });
|
|
24
25
|
const onContentBlockDelta = createContentBlockDelta({
|
|
@@ -38,6 +39,7 @@ export function createTurnEvents({
|
|
|
38
39
|
state,
|
|
39
40
|
progress,
|
|
40
41
|
seedText: onContentBlockDelta.seedText,
|
|
42
|
+
onStreamItemStart,
|
|
41
43
|
}),
|
|
42
44
|
onContentBlockDelta,
|
|
43
45
|
onContentBlockStop: createContentBlockStop({ turn, blocks, state, leak, progress, onToolCall, labels }),
|
|
@@ -24,6 +24,7 @@ import { OAUTH_STREAM_LABELS } from './lib/anthropic-stream-labels.mjs';
|
|
|
24
24
|
* @param {Iterable<string>} [deps.knownToolNames]
|
|
25
25
|
* @param {boolean} [deps.relayProgressUpdates] request used thinking.display "updates"
|
|
26
26
|
* @param {{ display: string, tag: string }} [deps.labels] provider name for errors and stderr lines
|
|
27
|
+
* @param {(detail: object) => void} [deps.onStreamItemStart] a client tool_use block opened
|
|
27
28
|
*/
|
|
28
29
|
export function createAnthropicSseTurn({
|
|
29
30
|
state,
|
|
@@ -33,6 +34,7 @@ export function createAnthropicSseTurn({
|
|
|
33
34
|
knownToolNames,
|
|
34
35
|
relayProgressUpdates = false,
|
|
35
36
|
labels = OAUTH_STREAM_LABELS,
|
|
37
|
+
onStreamItemStart = null,
|
|
36
38
|
}) {
|
|
37
39
|
const progress = (kind) => {
|
|
38
40
|
try {
|
|
@@ -64,6 +66,7 @@ export function createAnthropicSseTurn({
|
|
|
64
66
|
onToolCall,
|
|
65
67
|
relayProgressUpdates,
|
|
66
68
|
labels,
|
|
69
|
+
onStreamItemStart,
|
|
67
70
|
});
|
|
68
71
|
const outcome = createTurnOutcome({ turn, blocks, state, labels });
|
|
69
72
|
|
|
@@ -186,7 +186,7 @@ export async function parseSSEStream(
|
|
|
186
186
|
state,
|
|
187
187
|
onTextDelta,
|
|
188
188
|
knownToolNames,
|
|
189
|
-
{ relayProgressUpdates = false, labels = OAUTH_STREAM_LABELS } = {}
|
|
189
|
+
{ relayProgressUpdates = false, labels = OAUTH_STREAM_LABELS, onStreamItemStart = null } = {}
|
|
190
190
|
) {
|
|
191
191
|
// Anthropic/Claude parity: every received SSE byte proves transport
|
|
192
192
|
// activity, including comment and named ping keepalives. Content kinds
|
|
@@ -208,6 +208,7 @@ export async function parseSSEStream(
|
|
|
208
208
|
knownToolNames,
|
|
209
209
|
relayProgressUpdates,
|
|
210
210
|
labels,
|
|
211
|
+
onStreamItemStart,
|
|
211
212
|
});
|
|
212
213
|
const watchdogs = createAnthropicSseWatchdogs({
|
|
213
214
|
state,
|
|
@@ -162,7 +162,8 @@ export class AnthropicProvider {
|
|
|
162
162
|
});
|
|
163
163
|
this.fastModeBetaHeaderLatched = fastModeLatched;
|
|
164
164
|
|
|
165
|
-
const { onStageChange, onStreamDelta, onToolCall, onTextDelta, onTextReset } =
|
|
165
|
+
const { onStageChange, onStreamDelta, onToolCall, onTextDelta, onTextReset, onStreamItemStart } =
|
|
166
|
+
streamCallbacks(opts);
|
|
166
167
|
|
|
167
168
|
// No absolute wall-clock cap on streaming generation: a stream still
|
|
168
169
|
// emitting SSE deltas must not be killed by a fixed total-lifetime timer.
|
|
@@ -288,6 +289,7 @@ export class AnthropicProvider {
|
|
|
288
289
|
{
|
|
289
290
|
relayProgressUpdates: params.thinking?.display === 'updates',
|
|
290
291
|
labels: { display: 'Anthropic', tag: this.name },
|
|
292
|
+
onStreamItemStart,
|
|
291
293
|
}
|
|
292
294
|
);
|
|
293
295
|
try {
|
|
@@ -36,8 +36,7 @@ import {
|
|
|
36
36
|
|
|
37
37
|
const ONBOARD_INTERVAL_MS = 1_000;
|
|
38
38
|
const CALLBACK_FAILURE_HTML = oauthErrorHtml(
|
|
39
|
-
'Antigravity sign-in was not completed.'
|
|
40
|
-
'Return to Mixdog for the error details and any account verification link.'
|
|
39
|
+
'Antigravity sign-in was not completed. Return to Mixdog for the error details and any account verification link.'
|
|
41
40
|
);
|
|
42
41
|
|
|
43
42
|
function extractProjectId(payload) {
|