mixdog 0.9.152 → 0.9.154
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/LICENSES/browser-import-NOTICE.txt +11 -0
- package/NOTICE.md +11 -0
- package/README.md +8 -10
- package/package.json +19 -3
- package/scripts/computer-task-cost-report.mjs +144 -0
- package/scripts/run-office-live-tests.mjs +32 -0
- package/src/agents/front-worker/AGENT.md +13 -0
- package/src/agents/front-worker/agent.json +6 -0
- package/src/agents/heavy-worker/AGENT.md +10 -11
- package/src/agents/heavy-worker/agent.json +1 -1
- package/src/agents/maintainer/AGENT.md +0 -2
- package/src/agents/reviewer/AGENT.md +9 -13
- package/src/agents/reviewer/agent.json +1 -1
- package/src/agents/security/AGENT.md +14 -0
- package/src/agents/security/agent.json +6 -0
- package/src/agents/worker/AGENT.md +8 -8
- package/src/agents/worker/agent.json +1 -1
- package/src/agents/writer/AGENT.md +14 -0
- package/src/agents/writer/agent.json +6 -0
- package/src/rules/agent/00-common.md +4 -7
- package/src/rules/lead/01-general.md +0 -3
- package/src/rules/shared/10-tool-workflow.md +10 -2
- package/src/rules/shared/60-verification.md +2 -0
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +183 -26
- package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +4 -0
- package/src/runtime/agent/orchestrator/cache-break-trace.mjs +109 -0
- package/src/runtime/agent/orchestrator/config.mjs +7 -2
- package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +16 -3
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +9 -1
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +30 -9
- package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +18 -26
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +25 -2
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +103 -10
- package/src/runtime/agent/orchestrator/providers/openai-turn-state.mjs +68 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +36 -11
- package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +140 -86
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +9 -13
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +72 -4
- package/src/runtime/agent/orchestrator/session/browser-snapshot-supersession.mjs +61 -0
- package/src/runtime/agent/orchestrator/session/compact/handoff.mjs +0 -22
- package/src/runtime/agent/orchestrator/session/compact/messages.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +11 -23
- package/src/runtime/agent/orchestrator/session/compact/summary.mjs +28 -269
- package/src/runtime/agent/orchestrator/session/compact.mjs +0 -6
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +86 -11
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +17 -1
- package/src/runtime/agent/orchestrator/session/image-strip-recovery.mjs +12 -8
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +110 -2
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +3 -16
- package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +80 -18
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +80 -21
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +33 -72
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +21 -2
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +25 -51
- package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +4 -110
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +39 -15
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +14 -4
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +41 -8
- package/src/runtime/agent/orchestrator/session/provider-prefix-guard.mjs +129 -12
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/store/listing.mjs +8 -1
- package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +15 -1
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +36 -2
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +157 -30
- package/src/runtime/agent/orchestrator/session/store-summary-visibility.mjs +57 -0
- package/src/runtime/agent/orchestrator/session/store.mjs +3 -1
- package/src/runtime/agent/orchestrator/session/tool-batch.mjs +22 -0
- package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +6 -6
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +4 -0
- package/src/runtime/attachments/pdf-extract.mjs +3 -0
- package/src/runtime/attachments/pdfjs-runtime.mjs +13 -0
- package/src/runtime/browser-bridge/action-schema.mjs +251 -0
- package/src/runtime/browser-bridge/client.mjs +75 -26
- package/src/runtime/browser-bridge/tool-defs.mjs +132 -15
- package/src/runtime/computer-bridge/action-schema.mjs +653 -0
- package/src/runtime/computer-bridge/client.mjs +211 -28
- package/src/runtime/computer-bridge/tool-defs.mjs +25 -45
- package/src/runtime/office/assurance-benchmark.mjs +358 -0
- package/src/runtime/office/assurance.mjs +833 -0
- package/src/runtime/office/benchmark.mjs +496 -0
- package/src/runtime/office/capabilities.mjs +551 -0
- package/src/runtime/office/com-adapter.mjs +283 -0
- package/src/runtime/office/content-model.mjs +183 -0
- package/src/runtime/office/contract-benchmark.mjs +105 -0
- package/src/runtime/office/design-library.mjs +1562 -0
- package/src/runtime/office/design-system.mjs +1966 -0
- package/src/runtime/office/index.mjs +2413 -0
- package/src/runtime/office/journal.mjs +82 -0
- package/src/runtime/office/office-com-host.ps1 +3781 -0
- package/src/runtime/office/office-com-session-host.ps1 +855 -0
- package/src/runtime/office/ooxml-validator.mjs +271 -0
- package/src/runtime/office/pagination.mjs +132 -0
- package/src/runtime/office/pdf-adapter.mjs +591 -0
- package/src/runtime/office/pdf-analysis.mjs +372 -0
- package/src/runtime/office/pdf-render.mjs +167 -0
- package/src/runtime/office/pdf-security.mjs +63 -0
- package/src/runtime/office/polish-benchmark.mjs +190 -0
- package/src/runtime/office/portable-ooxml.mjs +1867 -0
- package/src/runtime/office/quality-live-benchmark.mjs +486 -0
- package/src/runtime/office/quality-pipeline.mjs +136 -0
- package/src/runtime/office/tabular.mjs +302 -0
- package/src/runtime/office/templates/mixdog-executive.pptx +0 -0
- package/src/runtime/office/templates/mixdog-executive.pptx.mixdog.json +190 -0
- package/src/runtime/office/tool-defs.mjs +113 -0
- package/src/runtime/office/visual-diff.mjs +89 -0
- package/src/runtime/office/xlsx-assertions.mjs +172 -0
- package/src/runtime/office/xlsx-contract.mjs +147 -0
- package/src/runtime/shared/agent-route-config.mjs +9 -0
- package/src/runtime/shared/tool-execution-contract.mjs +16 -0
- package/src/runtime/shared/tool-surface.mjs +9 -0
- package/src/session-runtime/context-status.mjs +9 -3
- package/src/session-runtime/deferred-tool-delta.mjs +104 -0
- package/src/session-runtime/goal-runtime.mjs +617 -197
- package/src/session-runtime/lifecycle-api.mjs +50 -8
- package/src/session-runtime/provider-request-snapshot.mjs +33 -9
- package/src/session-runtime/resource-api.mjs +31 -94
- package/src/session-runtime/runtime-core.mjs +78 -26
- package/src/session-runtime/session-lifecycle.mjs +34 -12
- package/src/session-runtime/session-title.mjs +2 -2
- package/src/session-runtime/session-turn-api.mjs +15 -14
- package/src/session-runtime/tool-catalog-data.mjs +1 -1
- package/src/session-runtime/tool-catalog.mjs +38 -99
- package/src/session-runtime/tool-defs.mjs +6 -1
- package/src/session-runtime/tool-surface.mjs +18 -8
- package/src/session-runtime/workflow-agents-api.mjs +8 -25
- package/src/session-runtime/workflow.mjs +8 -6
- package/src/standalone/agent-tool/helpers.mjs +2 -2
- package/src/standalone/agent-tool/job-views.mjs +3 -1
- package/src/standalone/agent-tool/notify.mjs +5 -1
- package/src/standalone/agent-tool/render.mjs +3 -0
- package/src/standalone/agent-tool/spawn-flow.mjs +61 -16
- package/src/standalone/agent-tool/tool-def.mjs +1 -1
- package/src/standalone/agent-tool/worker-index.mjs +123 -0
- package/src/standalone/agent-tool/worker-rows.mjs +2 -1
- package/src/standalone/agent-tool.mjs +57 -10
- package/src/standalone/daemon.mjs +105 -6
- package/src/standalone/session-runtime-host.mjs +61 -48
- package/src/standalone/session-runtime-inline-host.mjs +34 -127
- package/src/standalone/session-runtime-worker.mjs +20 -198
- package/src/standalone/session-service.mjs +632 -7
- package/src/tui/dist/index.mjs +24 -1
- package/src/tui/lib/voice-setup.mjs +4 -1
- package/src/tui/session/context-state.mjs +2 -13
- package/src/tui/session/goal-continuation.mjs +38 -7
- package/src/tui/session/session-api-ext.mjs +9 -0
- package/src/tui/session/session-api.mjs +15 -1
- package/src/tui/session/session-flow.mjs +25 -1
- package/src/tui/session/turn.mjs +88 -16
- package/src/tui/session-local.mjs +25 -3
- package/src/vendor/statusline/src/gateway/route-meta.mjs +31 -0
- package/scripts/generate-voice-runtime-manifest.test.mjs +0 -135
- package/scripts/native-binary-arch.test.mjs +0 -111
- package/scripts/patch-replay.test.mjs +0 -94
- package/src/headless-exec.test.mjs +0 -539
- package/src/runtime/agent/orchestrator/agent-trace-timing.test.mjs +0 -57
- package/src/runtime/agent/orchestrator/context/collect-skills.test.mjs +0 -153
- package/src/runtime/agent/orchestrator/mcp/cancellation.test.mjs +0 -139
- package/src/runtime/agent/orchestrator/mcp/features.test.mjs +0 -66
- package/src/runtime/agent/orchestrator/mcp/security.test.mjs +0 -80
- package/src/runtime/agent/orchestrator/providers/anthropic-fast-mode.test.mjs +0 -90
- package/src/runtime/agent/orchestrator/providers/anthropic-server-fallback.test.mjs +0 -215
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth.test.mjs +0 -165
- package/src/runtime/agent/orchestrator/providers/media-parity.test.mjs +0 -142
- package/src/runtime/agent/orchestrator/providers/openai-codex-identity.test.mjs +0 -153
- package/src/runtime/agent/orchestrator/providers/openai-codex-model.test.mjs +0 -24
- package/src/runtime/agent/orchestrator/providers/openai-ws-delta-parity.test.mjs +0 -190
- package/src/runtime/agent/orchestrator/providers/provider-replay.test.mjs +0 -235
- package/src/runtime/agent/orchestrator/providers/sse-framing.test.mjs +0 -719
- package/src/runtime/agent/orchestrator/session/cache/prefetch-cache.test.mjs +0 -40
- package/src/runtime/agent/orchestrator/session/compact-policy.test.mjs +0 -176
- package/src/runtime/agent/orchestrator/session/compaction-read-reset.test.mjs +0 -161
- package/src/runtime/agent/orchestrator/session/eager-dispatch.test.mjs +0 -115
- package/src/runtime/agent/orchestrator/session/evidence-union.test.mjs +0 -228
- package/src/runtime/agent/orchestrator/session/image-strip-recovery.test.mjs +0 -245
- package/src/runtime/agent/orchestrator/session/lossless-tool-output.test.mjs +0 -125
- package/src/runtime/agent/orchestrator/session/manager/pending-messages-persistence.test.mjs +0 -325
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.test.mjs +0 -70
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.test.mjs +0 -457
- package/src/runtime/agent/orchestrator/session/provider-prefix-guard.test.mjs +0 -117
- package/src/runtime/agent/orchestrator/session/reduction-metrics.test.mjs +0 -87
- package/src/runtime/agent/orchestrator/session/store/serialize.test.mjs +0 -60
- package/src/runtime/agent/orchestrator/session/store-summary-reader.test.mjs +0 -583
- package/src/runtime/agent/orchestrator/session/task-wait-control.test.mjs +0 -78
- package/src/runtime/agent/orchestrator/tools/builtin/absence-absorption.test.mjs +0 -43
- package/src/runtime/agent/orchestrator/tools/builtin/absolute-glob-expand.test.mjs +0 -63
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool-cwd-env.test.mjs +0 -14
- package/src/runtime/agent/orchestrator/tools/builtin/edit-encoding-eol.test.mjs +0 -224
- package/src/runtime/agent/orchestrator/tools/builtin/edit-sequential-occupation.test.mjs +0 -224
- package/src/runtime/agent/orchestrator/tools/builtin/enoent-outside-project.test.mjs +0 -56
- package/src/runtime/agent/orchestrator/tools/builtin/find-search-budget.test.mjs +0 -103
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-policy.test.mjs +0 -30
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.test.mjs +0 -390
- package/src/runtime/agent/orchestrator/tools/builtin/git-repo-rw-lock.test.mjs +0 -83
- package/src/runtime/agent/orchestrator/tools/builtin/grep-output-budget.test.mjs +0 -31
- package/src/runtime/agent/orchestrator/tools/builtin/grep-single-file-rescue.test.mjs +0 -106
- package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.test.mjs +0 -102
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool-integrity.test.mjs +0 -152
- package/src/runtime/agent/orchestrator/tools/builtin/native-search-health.test.mjs +0 -24
- package/src/runtime/agent/orchestrator/tools/builtin/native-search-transport.test.mjs +0 -24
- package/src/runtime/agent/orchestrator/tools/builtin/noise-dir-visibility.test.mjs +0 -69
- package/src/runtime/agent/orchestrator/tools/builtin/read-glob-survey.test.mjs +0 -71
- package/src/runtime/agent/orchestrator/tools/builtin/runtime-capabilities.test.mjs +0 -56
- package/src/runtime/agent/orchestrator/tools/builtin/search-builders.test.mjs +0 -16
- package/src/runtime/agent/orchestrator/tools/builtin/search-glob-top-k.test.mjs +0 -39
- package/src/runtime/agent/orchestrator/tools/builtin/write-symlink.test.mjs +0 -153
- package/src/runtime/agent/orchestrator/tools/code-graph/aggregate-anchor-relocation.test.mjs +0 -55
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.test.mjs +0 -88
- package/src/runtime/agent/orchestrator/tools/code-graph/loose-file-target.test.mjs +0 -72
- package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.test.mjs +0 -54
- package/src/runtime/agent/orchestrator/tools/code-graph/search-references.test.mjs +0 -20
- package/src/runtime/agent/orchestrator/tools/code-graph/symbol-search-scope.test.mjs +0 -55
- package/src/runtime/agent/orchestrator/tools/code-graph/text-span-mask.test.mjs +0 -268
- package/src/runtime/agent/orchestrator/tools/env-scrub.test.mjs +0 -57
- package/src/runtime/agent/orchestrator/tools/graph-binary-fetcher.test.mjs +0 -19
- package/src/runtime/agent/orchestrator/tools/lib/native-spawn-client.test.mjs +0 -104
- package/src/runtime/agent/orchestrator/tools/patch/engine-contract-gate.test.mjs +0 -661
- package/src/runtime/agent/orchestrator/tools/patch/patch-codec-eol.test.mjs +0 -552
- package/src/runtime/agent/orchestrator/tools/patch/patch-symlink.test.mjs +0 -141
- package/src/runtime/agent/orchestrator/tools/patch/v4a-pure-move.test.mjs +0 -57
- package/src/runtime/agent/orchestrator/tools/patch/v4a-section-coalesce.test.mjs +0 -81
- package/src/runtime/agent/orchestrator/tools/spawn-binary-fetcher.test.mjs +0 -52
- package/src/runtime/attachments/store.test.mjs +0 -209
- package/src/runtime/channels/lib/voice-runtime-fetcher.test.mjs +0 -17
- package/src/runtime/channels/lib/webhook/deliveries.test.mjs +0 -18
- package/src/runtime/channels/lib/webhook/relay-tunnel.test.mjs +0 -68
- package/src/runtime/media/adapters/codex-image.test.mjs +0 -22
- package/src/runtime/media/download.test.mjs +0 -52
- package/src/runtime/media/renditions.test.mjs +0 -99
- package/src/runtime/media/store.test.mjs +0 -159
- package/src/runtime/memory/lib/archive-security.test.mjs +0 -128
- package/src/runtime/memory/lib/embedding-model-config.test.mjs +0 -33
- package/src/runtime/memory/lib/http-wire.test.mjs +0 -15
- package/src/runtime/memory/lib/memory-cycle-packets.test.mjs +0 -49
- package/src/runtime/memory/lib/memory-cycle2-shared.test.mjs +0 -78
- package/src/runtime/memory/lib/memory-embedding-migration.test.mjs +0 -50
- package/src/runtime/memory/lib/pg/process.test.mjs +0 -36
- package/src/runtime/memory/lib/trace-store.test.mjs +0 -57
- package/src/runtime/memory/lib/transcript-ingest.test.mjs +0 -52
- package/src/runtime/shared/background-tasks.test.mjs +0 -78
- package/src/runtime/shared/bounded-download.test.mjs +0 -41
- package/src/runtime/shared/channel-notification-routing.test.mjs +0 -25
- package/src/runtime/shared/child-spawn-remote.test.mjs +0 -124
- package/src/runtime/shared/remote-intent.test.mjs +0 -40
- package/src/runtime/shared/resource-admission.test.mjs +0 -43
- package/src/runtime/shared/runtime-root.test.mjs +0 -34
- package/src/runtime/shared/schedule-time.test.mjs +0 -29
- package/src/runtime/shared/session-runtime-health.test.mjs +0 -83
- package/src/runtime/shared/skill-document.test.mjs +0 -81
- package/src/runtime/shared/tool-surface.test.mjs +0 -87
- package/src/runtime/shared/update-checker.test.mjs +0 -33
- package/src/runtime/shared/user-cwd.test.mjs +0 -43
- package/src/runtime/shared/webhook-session-run.test.mjs +0 -14
- package/src/session-runtime/agent-disable.test.mjs +0 -123
- package/src/session-runtime/cwd-plugins.test.mjs +0 -75
- package/src/session-runtime/cwd-tool-routing.test.mjs +0 -61
- package/src/session-runtime/global-extensions.test.mjs +0 -28
- package/src/session-runtime/goal-runtime.test.mjs +0 -108
- package/src/session-runtime/lifecycle-api.test.mjs +0 -21
- package/src/session-runtime/model-settings-persist.test.mjs +0 -105
- package/src/session-runtime/notification-bus.test.mjs +0 -148
- package/src/session-runtime/plugin-mcp-standard.test.mjs +0 -177
- package/src/session-runtime/prewarm.test.mjs +0 -52
- package/src/session-runtime/provider-request-snapshot.test.mjs +0 -37
- package/src/session-runtime/resource-api-global.test.mjs +0 -69
- package/src/session-runtime/session-lifecycle.test.mjs +0 -125
- package/src/session-runtime/session-title.test.mjs +0 -36
- package/src/session-runtime/skills-api.test.mjs +0 -99
- package/src/session-runtime/tool-policy-surface.test.mjs +0 -331
- package/src/standalone/agent-tool/helpers.test.mjs +0 -62
- package/src/standalone/agent-tool/notify.test.mjs +0 -37
- package/src/standalone/agent-tool/spawn-flow.test.mjs +0 -63
- package/src/standalone/channel-restart.test.mjs +0 -145
- package/src/standalone/channel-session-router.test.mjs +0 -37
- package/src/standalone/channel-worker-heartbeat.test.mjs +0 -30
- package/src/standalone/hook-bus/handlers.test.mjs +0 -88
- package/src/standalone/plugin-admin.test.mjs +0 -173
- package/src/standalone/session-runtime-agent-control-client.test.mjs +0 -71
- package/src/standalone/session-runtime-dispatch-cancel.test.mjs +0 -139
- package/src/standalone/session-runtime-host-factory.test.mjs +0 -31
- package/src/standalone/session-runtime-host-health.test.mjs +0 -160
- package/src/standalone/session-runtime-inline-host.test.mjs +0 -83
- package/src/standalone/session-runtime-provider-cooldown.test.mjs +0 -80
- package/src/standalone/session-runtime-shard-host.test.mjs +0 -569
- package/src/standalone/session-runtime-shard-router.test.mjs +0 -101
- package/src/tui/app/live-spinner-visibility.test.mjs +0 -44
- package/src/tui/app/panel-epoch.test.mjs +0 -1009
- package/src/tui/app/panel-handoff.test.mjs +0 -311
- package/src/tui/app/prompt-submit.test.mjs +0 -206
- package/src/tui/session/completion-card-restore.test.mjs +0 -111
- package/src/tui/session/goal-continuation.test.mjs +0 -84
- package/src/tui/session/oauth-flows.test.mjs +0 -134
- package/src/tui/session/queue-helpers.test.mjs +0 -46
- package/src/tui/session/session-action-surface.test.mjs +0 -108
- package/src/tui/session/task-wait-submit.test.mjs +0 -80
- package/src/tui/session/tool-result-status.test.mjs +0 -131
- package/src/tui/session/tui-steering-persist.test.mjs +0 -104
|
@@ -179,20 +179,128 @@ function maintenanceRouteToPreset(routeOrName, agent) {
|
|
|
179
179
|
return out;
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
+
const AGENT_DISPATCH_LIVE_CALLBACKS = Object.freeze([
|
|
183
|
+
'onSessionStart',
|
|
184
|
+
'onStageChange',
|
|
185
|
+
'onReasoningDelta',
|
|
186
|
+
'onTextDelta',
|
|
187
|
+
'onTextReset',
|
|
188
|
+
'onAssistantText',
|
|
189
|
+
'onAssistantMessageCommitted',
|
|
190
|
+
'onToolCall',
|
|
191
|
+
'onToolResult',
|
|
192
|
+
]);
|
|
193
|
+
|
|
194
|
+
function pickDispatchCallback(factoryOpts, callArgs, name) {
|
|
195
|
+
if (typeof callArgs?.[name] === 'function') return callArgs[name];
|
|
196
|
+
if (typeof factoryOpts?.[name] === 'function') return factoryOpts[name];
|
|
197
|
+
return undefined;
|
|
198
|
+
}
|
|
199
|
+
|
|
182
200
|
/**
|
|
183
|
-
*
|
|
201
|
+
* Resolve live Agent-dispatch callbacks.
|
|
184
202
|
*
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
*
|
|
190
|
-
* @param {
|
|
191
|
-
* @param {
|
|
192
|
-
*
|
|
193
|
-
|
|
194
|
-
|
|
203
|
+
* `liveProjection` is a send-opt. It is true when the caller explicitly
|
|
204
|
+
* sets it or supplies a live-text callback (onTextDelta / onAssistantText /
|
|
205
|
+
* onTextReset). Tool/stage/reasoning observers do not un-suppress provider
|
|
206
|
+
* streaming. The flag must never be written onto the session object.
|
|
207
|
+
*
|
|
208
|
+
* @param {object} [factoryOpts]
|
|
209
|
+
* @param {object} [callArgs]
|
|
210
|
+
* @returns {{ callbacks: object, liveProjection: boolean }}
|
|
211
|
+
*/
|
|
212
|
+
export function resolveAgentDispatchLiveCallbacks(factoryOpts = {}, callArgs = {}) {
|
|
213
|
+
const callbacks = {};
|
|
214
|
+
for (const name of AGENT_DISPATCH_LIVE_CALLBACKS) {
|
|
215
|
+
const fn = pickDispatchCallback(factoryOpts, callArgs, name);
|
|
216
|
+
if (fn) callbacks[name] = fn;
|
|
217
|
+
}
|
|
218
|
+
const liveProjection = factoryOpts.liveProjection === true
|
|
219
|
+
|| callArgs.liveProjection === true
|
|
220
|
+
|| typeof callbacks.onTextDelta === 'function'
|
|
221
|
+
|| typeof callbacks.onAssistantText === 'function'
|
|
222
|
+
|| typeof callbacks.onTextReset === 'function';
|
|
223
|
+
return { callbacks, liveProjection };
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Adapt askSession's session-less callback signatures to the host contract
|
|
228
|
+
* by prepending the prepared session on every call:
|
|
229
|
+
* onSessionStart(session)
|
|
230
|
+
* onStageChange(session, stage, detail)
|
|
231
|
+
* onReasoningDelta(session, chunk)
|
|
232
|
+
* onTextDelta(session, chunk)
|
|
233
|
+
* onTextReset(session, detail) — return value is passed through unchanged
|
|
234
|
+
* onAssistantText(session, text)
|
|
235
|
+
* onAssistantMessageCommitted(session)
|
|
236
|
+
* onToolCall(session, iteration, calls)
|
|
237
|
+
* onToolResult(session, message)
|
|
238
|
+
*/
|
|
239
|
+
export function bindAgentDispatchHostCallbacks(hostCallbacks = {}, session) {
|
|
240
|
+
const bound = {};
|
|
241
|
+
if (typeof hostCallbacks.onSessionStart === 'function') {
|
|
242
|
+
bound.onSessionStart = () => hostCallbacks.onSessionStart(session);
|
|
243
|
+
}
|
|
244
|
+
if (typeof hostCallbacks.onStageChange === 'function') {
|
|
245
|
+
bound.onStageChange = (stage, detail) => hostCallbacks.onStageChange(session, stage, detail);
|
|
246
|
+
}
|
|
247
|
+
if (typeof hostCallbacks.onReasoningDelta === 'function') {
|
|
248
|
+
bound.onReasoningDelta = (chunk) => hostCallbacks.onReasoningDelta(session, chunk);
|
|
249
|
+
}
|
|
250
|
+
if (typeof hostCallbacks.onTextDelta === 'function') {
|
|
251
|
+
bound.onTextDelta = (chunk) => hostCallbacks.onTextDelta(session, chunk);
|
|
252
|
+
}
|
|
253
|
+
if (typeof hostCallbacks.onTextReset === 'function') {
|
|
254
|
+
bound.onTextReset = (detail) => hostCallbacks.onTextReset(session, detail);
|
|
255
|
+
}
|
|
256
|
+
if (typeof hostCallbacks.onAssistantText === 'function') {
|
|
257
|
+
bound.onAssistantText = (text) => hostCallbacks.onAssistantText(session, text);
|
|
258
|
+
}
|
|
259
|
+
if (typeof hostCallbacks.onAssistantMessageCommitted === 'function') {
|
|
260
|
+
bound.onAssistantMessageCommitted = () => hostCallbacks.onAssistantMessageCommitted(session);
|
|
261
|
+
}
|
|
262
|
+
if (typeof hostCallbacks.onToolCall === 'function') {
|
|
263
|
+
bound.onToolCall = (iteration, calls) => hostCallbacks.onToolCall(session, iteration, calls);
|
|
264
|
+
}
|
|
265
|
+
if (typeof hostCallbacks.onToolResult === 'function') {
|
|
266
|
+
bound.onToolResult = (message) => hostCallbacks.onToolResult(session, message);
|
|
267
|
+
}
|
|
268
|
+
return bound;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Build the positional `onToolCall` + askOpts bag forwarded to askSession.
|
|
273
|
+
* `interactiveSessionSurface` is intentionally dropped — that in-memory
|
|
274
|
+
* hint is owned by the standalone surface and must not be persisted or
|
|
275
|
+
* re-homed onto a dispatch session.
|
|
195
276
|
*/
|
|
277
|
+
export function buildAgentDispatchAskSessionArgs(factoryOpts = {}, callArgs = {}, extraAskOpts = {}, session = null) {
|
|
278
|
+
const { callbacks, liveProjection } = resolveAgentDispatchLiveCallbacks(factoryOpts, callArgs);
|
|
279
|
+
const bound = session && typeof session === 'object'
|
|
280
|
+
? bindAgentDispatchHostCallbacks(callbacks, session)
|
|
281
|
+
: callbacks;
|
|
282
|
+
const onToolCall = typeof bound.onToolCall === 'function' ? bound.onToolCall : null;
|
|
283
|
+
const askOpts = { liveProjection };
|
|
284
|
+
for (const name of AGENT_DISPATCH_LIVE_CALLBACKS) {
|
|
285
|
+
if (name === 'onToolCall') continue;
|
|
286
|
+
if (typeof bound[name] === 'function') askOpts[name] = bound[name];
|
|
287
|
+
}
|
|
288
|
+
const extraCompact = extraAskOpts.onCompactEvent;
|
|
289
|
+
if (typeof extraCompact === 'function') {
|
|
290
|
+
const callerCompact = askOpts.onCompactEvent;
|
|
291
|
+
askOpts.onCompactEvent = (event) => {
|
|
292
|
+
extraCompact(event);
|
|
293
|
+
try { callerCompact?.(event); } catch { /* best-effort */ }
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
for (const [key, value] of Object.entries(extraAskOpts)) {
|
|
297
|
+
if (key === 'onCompactEvent' || key === 'liveProjection') continue;
|
|
298
|
+
if (key === 'interactiveSessionSurface') continue;
|
|
299
|
+
if (value !== undefined) askOpts[key] = value;
|
|
300
|
+
}
|
|
301
|
+
return { onToolCall, askOpts };
|
|
302
|
+
}
|
|
303
|
+
|
|
196
304
|
// runtime-liveness keeps one parent link per session because askSession swaps
|
|
197
305
|
// its controller at turn start. Agent dispatch can have several independent
|
|
198
306
|
// cancellation sources, so collapse them before installing that one link.
|
|
@@ -227,16 +335,59 @@ export function composeAgentDispatchAbortSignal(signals) {
|
|
|
227
335
|
};
|
|
228
336
|
}
|
|
229
337
|
|
|
338
|
+
/**
|
|
339
|
+
* Build an agent-backed dispatch callback.
|
|
340
|
+
*
|
|
341
|
+
* @param {object} opts
|
|
342
|
+
* @param {string} opts.agent — REQUIRED; canonical agent name (worker, cycle1-agent, ...)
|
|
343
|
+
* @param {string} [opts.taskType] — optional internal classification stamped on the session
|
|
344
|
+
* @param {string} [opts.preset] — explicit preset override (bypasses agent → preset lookup)
|
|
345
|
+
* @param {string} [opts.parentSessionId] — parent agent session for trace aggregation
|
|
346
|
+
* @param {string|null} [opts.ownerSessionId] — owning Mixdog session for statusline isolation
|
|
347
|
+
* @param {AbortSignal} [opts.parentSignal] — optional AbortSignal from the fan-out coordinator;
|
|
348
|
+
* when aborted the agent session's own controller is also aborted so the
|
|
349
|
+
* provider call tears down promptly (parent→child cascade).
|
|
350
|
+
* @param {boolean} [opts.liveProjection] — request provider onTextDelta / mid-turn
|
|
351
|
+
* text for this Agent. Never persisted on the session.
|
|
352
|
+
* @param {function} [opts.onSessionStart]
|
|
353
|
+
* @param {function} [opts.onStageChange]
|
|
354
|
+
* @param {function} [opts.onReasoningDelta]
|
|
355
|
+
* @param {function} [opts.onTextDelta]
|
|
356
|
+
* @param {function} [opts.onTextReset] — must return `true` to ack a retry retraction
|
|
357
|
+
* @param {function} [opts.onAssistantText]
|
|
358
|
+
* @param {function} [opts.onAssistantMessageCommitted]
|
|
359
|
+
* @param {function} [opts.onToolCall]
|
|
360
|
+
* @param {function} [opts.onToolResult]
|
|
361
|
+
* @returns {(args: { prompt, preset?, sourceName?, liveProjection?, onSessionStart?, onStageChange?, onReasoningDelta?, onTextDelta?, onTextReset?, onAssistantText?, onAssistantMessageCommitted?, onToolCall?, onToolResult? }) => Promise<string>}
|
|
362
|
+
*/
|
|
230
363
|
export function makeAgentDispatch(opts = {}) {
|
|
231
364
|
if (!opts.agent || typeof opts.agent !== 'string') {
|
|
232
365
|
throw new Error('[agent-dispatch] opts.agent is required');
|
|
233
366
|
}
|
|
234
367
|
const agent = opts.agent;
|
|
235
368
|
|
|
236
|
-
return async function agentDispatch(
|
|
369
|
+
return async function agentDispatch(callArgs = {}) {
|
|
370
|
+
const {
|
|
371
|
+
prompt,
|
|
372
|
+
preset: presetArg,
|
|
373
|
+
sourceName: sourceNameArg,
|
|
374
|
+
parentSignal: callParentSignal,
|
|
375
|
+
idleTimeoutMs: callIdleTimeoutMs,
|
|
376
|
+
cwd: callCwd,
|
|
377
|
+
sessionId: callSessionId,
|
|
378
|
+
} = callArgs;
|
|
237
379
|
if (typeof prompt !== 'string' || !prompt) {
|
|
238
380
|
throw new Error(`[agent-dispatch] prompt required for agent "${agent}"`);
|
|
239
381
|
}
|
|
382
|
+
const prepare = typeof opts.prepareAgentSession === 'function'
|
|
383
|
+
? opts.prepareAgentSession
|
|
384
|
+
: prepareAgentSession;
|
|
385
|
+
const ask = typeof opts.askSession === 'function' ? opts.askSession : askSession;
|
|
386
|
+
const updateStatus = typeof opts.updateSessionStatus === 'function'
|
|
387
|
+
? opts.updateSessionStatus
|
|
388
|
+
: updateSessionStatus;
|
|
389
|
+
const close = typeof opts.closeSession === 'function' ? opts.closeSession : closeSession;
|
|
390
|
+
const readSession = typeof opts.getSession === 'function' ? opts.getSession : getSession;
|
|
240
391
|
const admission = opts.resourceAdmission || resourceAdmission;
|
|
241
392
|
const admissionAbortLink = composeAgentDispatchAbortSignal([
|
|
242
393
|
opts.parentSignal,
|
|
@@ -334,7 +485,7 @@ export function makeAgentDispatch(opts = {}) {
|
|
|
334
485
|
// pooled or resumed. Cache prefix matching happens at the provider
|
|
335
486
|
// layer (account-level), not the session level.
|
|
336
487
|
const finalPrompt = prompt;
|
|
337
|
-
const { session } =
|
|
488
|
+
const { session } = prepare({
|
|
338
489
|
agent,
|
|
339
490
|
presetName,
|
|
340
491
|
preset,
|
|
@@ -359,7 +510,7 @@ export function makeAgentDispatch(opts = {}) {
|
|
|
359
510
|
process.stderr.write(`[agent-dispatch] agent=${agent} tool-list (${_toolNames.length}): ${_toolNames.join(',')}\n`);
|
|
360
511
|
} catch { /* best-effort diagnostic */ }
|
|
361
512
|
|
|
362
|
-
await
|
|
513
|
+
await updateStatus(session.id, 'running');
|
|
363
514
|
// Parent→child abort cascade: when opts.parentSignal (factory) or
|
|
364
515
|
// callParentSignal (per-call) fires, abort the sub-session's own
|
|
365
516
|
// controller so the provider call tears down promptly. Best-effort:
|
|
@@ -368,7 +519,7 @@ export function makeAgentDispatch(opts = {}) {
|
|
|
368
519
|
const _linkSignal = _managerMod?.linkParentSignalToSession;
|
|
369
520
|
const _getProgressSnapshot = _managerMod?.getSessionProgressSnapshot;
|
|
370
521
|
const _getLastProgressAt = _managerMod?.getSessionLastProgressAt;
|
|
371
|
-
const _getSession = _managerMod?.getSession ||
|
|
522
|
+
const _getSession = _managerMod?.getSession || readSession;
|
|
372
523
|
// Watchdog policy is split:
|
|
373
524
|
// - firstResponseTimeoutMs cuts quickly only when the model produces no
|
|
374
525
|
// first stream/tool activity at all.
|
|
@@ -442,12 +593,13 @@ export function makeAgentDispatch(opts = {}) {
|
|
|
442
593
|
: null;
|
|
443
594
|
if (_idleTimer && typeof _idleTimer.unref === 'function') _idleTimer.unref();
|
|
444
595
|
let terminalStatus = 'idle';
|
|
596
|
+
let closeReason = 'ephemeral-done';
|
|
445
597
|
process.stderr.write(`[agent-dispatch] agent=${agent} preset=${presetName} model=${preset.model} provider=${preset.provider} session=${session.id}\n`);
|
|
446
598
|
const _agentDispatchT0 = Date.now();
|
|
447
599
|
let _handoffMsgStart = 0;
|
|
448
600
|
try {
|
|
449
|
-
_handoffMsgStart = resolveHandoffMessageStartIndex(
|
|
450
|
-
const
|
|
601
|
+
_handoffMsgStart = resolveHandoffMessageStartIndex(readSession(session.id));
|
|
602
|
+
const { onToolCall, askOpts } = buildAgentDispatchAskSessionArgs(opts, callArgs, {
|
|
451
603
|
onCompactEvent: (event) => {
|
|
452
604
|
try {
|
|
453
605
|
const label = agentCompactEventLabel(event);
|
|
@@ -458,7 +610,10 @@ export function makeAgentDispatch(opts = {}) {
|
|
|
458
610
|
);
|
|
459
611
|
} catch { /* best-effort compact visibility */ }
|
|
460
612
|
},
|
|
461
|
-
});
|
|
613
|
+
}, session);
|
|
614
|
+
// liveProjection is a send-opt on askOpts only. Do not stamp it
|
|
615
|
+
// (or interactiveSessionSurface) onto `session`.
|
|
616
|
+
const result = await ask(session.id, finalPrompt, null, onToolCall, cwd, undefined, askOpts);
|
|
462
617
|
process.stderr.write(`[agent-dispatch] agent=${agent} session=${session.id} elapsed=${Date.now() - _agentDispatchT0}ms\n`);
|
|
463
618
|
const raw = result?.content || '';
|
|
464
619
|
// Brief cap. Agent role answers (recall/search)
|
|
@@ -468,25 +623,23 @@ export function makeAgentDispatch(opts = {}) {
|
|
|
468
623
|
// majority of answers untouched. Opt-out via `brief:false` when
|
|
469
624
|
// the caller explicitly wants the full synthesis.
|
|
470
625
|
if (opts.brief === false) {
|
|
471
|
-
try { closeSession(session.id, 'ephemeral-done'); } catch { /* ignore */ }
|
|
472
626
|
return raw;
|
|
473
627
|
}
|
|
474
628
|
const out = applyBriefCap(raw);
|
|
475
|
-
try { closeSession(session.id, 'ephemeral-done'); } catch { /* ignore */ }
|
|
476
629
|
return out;
|
|
477
630
|
} catch (err) {
|
|
478
|
-
|
|
631
|
+
terminalStatus = 'error';
|
|
632
|
+
closeReason = 'ephemeral-error';
|
|
633
|
+
const partial = watchdogPartialHandoffFromError(err, readSession(session.id), _handoffMsgStart)
|
|
479
634
|
?? (salvagePartialRequested(err, _abortLink?.signal)
|
|
480
|
-
? partialHandoffTextFromSession(
|
|
635
|
+
? partialHandoffTextFromSession(readSession(session.id), _handoffMsgStart)
|
|
481
636
|
: null);
|
|
482
637
|
if (partial) {
|
|
483
638
|
terminalStatus = 'idle';
|
|
484
|
-
|
|
639
|
+
closeReason = 'ephemeral-done';
|
|
485
640
|
if (opts.brief === false) return partial;
|
|
486
641
|
return applyBriefCap(partial);
|
|
487
642
|
}
|
|
488
|
-
terminalStatus = 'error';
|
|
489
|
-
try { closeSession(session.id, 'ephemeral-error'); } catch { /* ignore */ }
|
|
490
643
|
throw err;
|
|
491
644
|
} finally {
|
|
492
645
|
_abortLink.dispose();
|
|
@@ -496,7 +649,11 @@ export function makeAgentDispatch(opts = {}) {
|
|
|
496
649
|
// Always flip out of 'running' before returning so the sweep never
|
|
497
650
|
// leaves a stateless Pool C session stuck in 'running' when the
|
|
498
651
|
// try/catch falls through in unexpected ways.
|
|
499
|
-
try { await
|
|
652
|
+
try { await updateStatus(session.id, terminalStatus); } catch { /* ignore */ }
|
|
653
|
+
// closeSession plants a tombstone, after which status writes are
|
|
654
|
+
// rejected. Publish the terminal projection before closing so
|
|
655
|
+
// live Agent panes cannot retain their preceding busy:true state.
|
|
656
|
+
try { close(session.id, closeReason); } catch { /* ignore */ }
|
|
500
657
|
}
|
|
501
658
|
});
|
|
502
659
|
} finally {
|
|
@@ -59,6 +59,7 @@ function normalizeAgentCompactionConfig(value = {}) {
|
|
|
59
59
|
* @param {number} [opts.maxLoopIterations]
|
|
60
60
|
* @param {string} [opts.parentSessionId]
|
|
61
61
|
* @param {string|null} [opts.ownerSessionId] - owning Mixdog MCP instance id for statusline isolation
|
|
62
|
+
* @param {string|null} [opts.visibility] - catalog visibility scope
|
|
62
63
|
* @param {string|null} [opts.mcpScopeId] - owning session-runtime MCP registry scope
|
|
63
64
|
* @returns {{ session: object, effectiveCwd: string|null }}
|
|
64
65
|
*/
|
|
@@ -77,6 +78,7 @@ export function prepareAgentSession({
|
|
|
77
78
|
maxLoopIterations,
|
|
78
79
|
parentSessionId,
|
|
79
80
|
ownerSessionId,
|
|
81
|
+
visibility,
|
|
80
82
|
clientHostPid,
|
|
81
83
|
agentTag,
|
|
82
84
|
cacheKeyOverride,
|
|
@@ -115,7 +117,9 @@ export function prepareAgentSession({
|
|
|
115
117
|
maxLoopIterations: Number.isFinite(effectiveMaxLoopIterations) ? effectiveMaxLoopIterations : undefined,
|
|
116
118
|
sourceType: sourceType || undefined,
|
|
117
119
|
sourceName: sourceName || undefined,
|
|
120
|
+
parentSessionId: parentSessionId || null,
|
|
118
121
|
ownerSessionId: effectiveOwnerSessionId || null,
|
|
122
|
+
visibility: visibility || null,
|
|
119
123
|
clientHostPid: clientHostPid || null,
|
|
120
124
|
compaction: compaction || undefined,
|
|
121
125
|
mcpScopeId: mcpScopeId || null,
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { appendAgentTrace } from './agent-trace.mjs';
|
|
2
|
+
|
|
3
|
+
const HASH_CHARS = 16;
|
|
4
|
+
|
|
5
|
+
function cleanText(value, max = 120) {
|
|
6
|
+
if (value == null || value === '') return null;
|
|
7
|
+
return String(value).replace(/[\r\n\t]+/g, ' ').slice(0, max);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function cleanHash(value) {
|
|
11
|
+
const text = cleanText(value, 128);
|
|
12
|
+
return text ? text.slice(0, HASH_CHARS) : null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function finiteNumber(value) {
|
|
16
|
+
const number = Number(value);
|
|
17
|
+
return Number.isFinite(number) ? number : null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function buildCacheBreakPayload(record = {}) {
|
|
21
|
+
const payload = {
|
|
22
|
+
classification: cleanText(record.classification) || 'unknown',
|
|
23
|
+
reason: cleanText(record.reason) || 'unknown',
|
|
24
|
+
source: cleanText(record.source),
|
|
25
|
+
provider: cleanText(record.provider),
|
|
26
|
+
model: cleanText(record.model),
|
|
27
|
+
transport: cleanText(record.transport),
|
|
28
|
+
intentional_transition: cleanText(record.intentionalTransition),
|
|
29
|
+
index: finiteNumber(record.index),
|
|
30
|
+
previous_count: finiteNumber(record.previousCount),
|
|
31
|
+
next_count: finiteNumber(record.nextCount),
|
|
32
|
+
previous_hash: cleanHash(record.previousHash),
|
|
33
|
+
next_hash: cleanHash(record.nextHash),
|
|
34
|
+
previous_request_prefix_hash: cleanHash(record.previousRequestPrefixHash),
|
|
35
|
+
next_request_prefix_hash: cleanHash(record.nextRequestPrefixHash),
|
|
36
|
+
request_prefix_changed: record.requestPrefixChanged === true,
|
|
37
|
+
cached_tokens: finiteNumber(record.cachedTokens),
|
|
38
|
+
prompt_tokens: finiteNumber(record.promptTokens),
|
|
39
|
+
uncached_tokens: finiteNumber(record.uncachedTokens),
|
|
40
|
+
cache_ratio: finiteNumber(record.cacheRatio),
|
|
41
|
+
actual_cache_miss: record.actualCacheMiss === true,
|
|
42
|
+
input_prefix_mismatch_index: finiteNumber(record.inputPrefixMismatchIndex),
|
|
43
|
+
input_prefix_mismatch_previous_count: finiteNumber(record.inputPrefixMismatchPreviousCount),
|
|
44
|
+
input_prefix_mismatch_current_count: finiteNumber(record.inputPrefixMismatchCurrentCount),
|
|
45
|
+
input_prefix_mismatch_expected_type: cleanText(record.inputPrefixMismatchExpectedType),
|
|
46
|
+
input_prefix_mismatch_expected_hash: cleanHash(record.inputPrefixMismatchExpectedHash),
|
|
47
|
+
input_prefix_mismatch_actual_type: cleanText(record.inputPrefixMismatchActualType),
|
|
48
|
+
input_prefix_mismatch_actual_hash: cleanHash(record.inputPrefixMismatchActualHash),
|
|
49
|
+
};
|
|
50
|
+
return Object.fromEntries(Object.entries(payload).filter(([, value]) => value !== null));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function formatCacheBreakLine(record = {}) {
|
|
54
|
+
const payload = buildCacheBreakPayload(record);
|
|
55
|
+
const fields = [
|
|
56
|
+
['classification', payload.classification],
|
|
57
|
+
['reason', payload.reason],
|
|
58
|
+
['source', payload.source],
|
|
59
|
+
['session', cleanText(record.sessionId, 160)],
|
|
60
|
+
['provider', payload.provider],
|
|
61
|
+
['model', payload.model],
|
|
62
|
+
['iteration', finiteNumber(record.iteration)],
|
|
63
|
+
['index', payload.index],
|
|
64
|
+
['previousCount', payload.previous_count],
|
|
65
|
+
['nextCount', payload.next_count],
|
|
66
|
+
['previousHash', payload.previous_hash],
|
|
67
|
+
['nextHash', payload.next_hash],
|
|
68
|
+
['inputMismatchIndex', payload.input_prefix_mismatch_index],
|
|
69
|
+
['intent', payload.intentional_transition],
|
|
70
|
+
['cachedTokens', payload.cached_tokens],
|
|
71
|
+
['promptTokens', payload.prompt_tokens],
|
|
72
|
+
].filter(([, value]) => value !== null && value !== undefined);
|
|
73
|
+
return `[cache-break] ${fields.map(([key, value]) => (
|
|
74
|
+
typeof value === 'string' ? `${key}=${JSON.stringify(value)}` : `${key}=${value}`
|
|
75
|
+
)).join(' ')}`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function traceCacheBreak(record = {}, options = {}) {
|
|
79
|
+
const payload = buildCacheBreakPayload(record);
|
|
80
|
+
const traceFn = options.traceFn === null
|
|
81
|
+
? null
|
|
82
|
+
: (typeof options.traceFn === 'function' ? options.traceFn : appendAgentTrace);
|
|
83
|
+
if (traceFn) {
|
|
84
|
+
try {
|
|
85
|
+
traceFn({
|
|
86
|
+
sessionId: record.sessionId || null,
|
|
87
|
+
iteration: finiteNumber(record.iteration),
|
|
88
|
+
kind: 'cache_break',
|
|
89
|
+
classification: payload.classification,
|
|
90
|
+
reason: payload.reason,
|
|
91
|
+
source: payload.source || null,
|
|
92
|
+
provider: payload.provider || null,
|
|
93
|
+
model: payload.model || null,
|
|
94
|
+
transport: payload.transport || null,
|
|
95
|
+
payload,
|
|
96
|
+
});
|
|
97
|
+
} catch { /* cache diagnostics never affect provider execution */ }
|
|
98
|
+
}
|
|
99
|
+
const explicitStderr = typeof options.stderrFn === 'function';
|
|
100
|
+
if (options.stderr !== false && (explicitStderr || !process.env.NODE_TEST_CONTEXT)) {
|
|
101
|
+
try {
|
|
102
|
+
const write = explicitStderr
|
|
103
|
+
? options.stderrFn
|
|
104
|
+
: (line) => process.stderr.write(line);
|
|
105
|
+
write(`${formatCacheBreakLine(record)}\n`);
|
|
106
|
+
} catch { /* cache diagnostics never affect provider execution */ }
|
|
107
|
+
}
|
|
108
|
+
return payload;
|
|
109
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { resolvePluginData } from '../../shared/plugin-paths.mjs';
|
|
2
2
|
import { readSection, updateSection, updateSectionAsync, getAgentApiKey, AGENT_PROVIDER_ENV } from '../../shared/config.mjs';
|
|
3
3
|
import {
|
|
4
|
+
DEFAULT_DISABLED_AGENT_IDS,
|
|
4
5
|
agentRouteStorageNeedsMigration,
|
|
5
6
|
canonicalizeAgentRouteStorage,
|
|
6
7
|
} from '../../shared/agent-route-config.mjs';
|
|
@@ -147,7 +148,7 @@ export const DEFAULT_PRESETS = Object.freeze([
|
|
|
147
148
|
Object.freeze({ id: 'opus-mid', name: 'OPUS MID', type: 'agent', provider: 'anthropic-oauth', model: resolveAnthropicFamilyModel('opus'), effort: 'medium', tools: 'full' }),
|
|
148
149
|
Object.freeze({ id: 'opus-high', name: 'OPUS HIGH', type: 'agent', provider: 'anthropic-oauth', model: resolveAnthropicFamilyModel('opus'), effort: 'high', tools: 'full' }),
|
|
149
150
|
]);
|
|
150
|
-
function buildDefaultConfig(options = {}) {
|
|
151
|
+
export function buildDefaultConfig(options = {}) {
|
|
151
152
|
const detectCredentials = options.detectCredentials !== false;
|
|
152
153
|
const providers = {};
|
|
153
154
|
// API providers — enabled if env key exists
|
|
@@ -196,7 +197,11 @@ function buildDefaultConfig(options = {}) {
|
|
|
196
197
|
// Local providers — opt-in via setup UI after HTTP ping confirms server is running
|
|
197
198
|
providers.ollama = { enabled: false, baseURL: 'http://localhost:11434/v1' };
|
|
198
199
|
providers.lmstudio = { enabled: false, baseURL: 'http://localhost:1234/v1' };
|
|
199
|
-
return {
|
|
200
|
+
return {
|
|
201
|
+
providers,
|
|
202
|
+
disabledAgents: [...DEFAULT_DISABLED_AGENT_IDS],
|
|
203
|
+
workflow: { active: 'default' },
|
|
204
|
+
};
|
|
200
205
|
}
|
|
201
206
|
|
|
202
207
|
function hasKeys(value) {
|
|
@@ -201,7 +201,12 @@ export class ProviderAdmissionScheduler {
|
|
|
201
201
|
// owns a slot, so reacquiring the same lane could deadlock a full wave.
|
|
202
202
|
const current = this.context.getStore();
|
|
203
203
|
if (current?.scheduler === this && current.key === laneKey) {
|
|
204
|
-
return Promise.resolve().then(() => task(signal
|
|
204
|
+
return Promise.resolve().then(() => task(signal, {
|
|
205
|
+
queueWaitMs: 0,
|
|
206
|
+
active: current.lane.active,
|
|
207
|
+
queued: current.lane.queue.length,
|
|
208
|
+
limit: Number.isFinite(current.lane.limit) ? current.lane.limit : null,
|
|
209
|
+
}));
|
|
205
210
|
}
|
|
206
211
|
if (this.closedReason) return Promise.reject(this.closedReason);
|
|
207
212
|
if (signal?.aborted) return Promise.reject(abortError(signal));
|
|
@@ -323,7 +328,14 @@ export class ProviderAdmissionScheduler {
|
|
|
323
328
|
priority: item.priority,
|
|
324
329
|
rateLimited: false,
|
|
325
330
|
};
|
|
326
|
-
|
|
331
|
+
const admissionMetrics = {
|
|
332
|
+
queueWaitMs: Math.max(0, this.now() - item.queuedAt),
|
|
333
|
+
active: lane.active,
|
|
334
|
+
queued: lane.queue.length,
|
|
335
|
+
limit: Number.isFinite(lane.limit) ? lane.limit : null,
|
|
336
|
+
};
|
|
337
|
+
this.context.run(admission, () => Promise.resolve().then(() =>
|
|
338
|
+
item.task(controller.signal, admissionMetrics)))
|
|
327
339
|
.then((value) => {
|
|
328
340
|
// A retry that eventually succeeds is not evidence that
|
|
329
341
|
// the lane should begin recovery from the 429 it just saw.
|
|
@@ -582,7 +594,7 @@ export function wrapProviderAdmission(provider, providerName, scheduler = provid
|
|
|
582
594
|
// resource controller reacquires the agent lease before model output
|
|
583
595
|
// continues through local context/tool processing.
|
|
584
596
|
return resourceAdmission.runYielded(() =>
|
|
585
|
-
scheduler.run(key, (admissionSignal) => {
|
|
597
|
+
scheduler.run(key, (admissionSignal, admissionMetrics) => {
|
|
586
598
|
// Admission is the common request-clock boundary for WS/SSE/HTTP.
|
|
587
599
|
// Queue wait therefore cannot consume first-byte or agent-watchdog
|
|
588
600
|
// time. Provider-local retry remains the sole retry owner.
|
|
@@ -590,6 +602,7 @@ export function wrapProviderAdmission(provider, providerName, scheduler = provid
|
|
|
590
602
|
return originalSend.call(this, messages, model, tools, {
|
|
591
603
|
...opts,
|
|
592
604
|
signal: admissionSignal,
|
|
605
|
+
_providerAdmission: admissionMetrics,
|
|
593
606
|
});
|
|
594
607
|
}, {
|
|
595
608
|
signal,
|
|
@@ -325,7 +325,15 @@ export function deferredAnthropicTools(activeTools, messages, opts, provider) {
|
|
|
325
325
|
if (key) discovered.add(key);
|
|
326
326
|
}
|
|
327
327
|
}
|
|
328
|
-
const
|
|
328
|
+
const catalogByName = new Map();
|
|
329
|
+
for (const tool of [
|
|
330
|
+
...(Array.isArray(opts.session.deferredToolCatalog) ? opts.session.deferredToolCatalog : []),
|
|
331
|
+
...(Array.isArray(opts.session.deferredLateToolCatalog) ? opts.session.deferredLateToolCatalog : []),
|
|
332
|
+
]) {
|
|
333
|
+
const name = String(tool?.name || '').trim();
|
|
334
|
+
if (name) catalogByName.set(name, tool);
|
|
335
|
+
}
|
|
336
|
+
const catalog = [...catalogByName.values()];
|
|
329
337
|
return catalog
|
|
330
338
|
.filter((tool) => tool?.name && discovered.has(String(tool.name)) && !active.has(String(tool.name)))
|
|
331
339
|
.map((tool) => ({ ...tool, deferLoading: true }));
|
|
@@ -35,11 +35,25 @@ function geminiInlineInfo(block) {
|
|
|
35
35
|
return { data, mimeType: cleanMimeType(inline.mimeType || inline.mime_type || inline.mediaType || inline.media_type) };
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
// Inline document/file
|
|
39
|
-
//
|
|
40
|
-
//
|
|
38
|
+
// Inline document/file parts arrive in two canonical runtime shapes:
|
|
39
|
+
// - desktop attachments: { type: 'file', data, mimeType, filename? }
|
|
40
|
+
// - read(PDF): { type: 'document', source: { type: 'base64', media_type, data } }
|
|
41
|
+
// Providers receive both as their native document shape; estimators and stored
|
|
42
|
+
// history must never serialize either base64 payload as text.
|
|
41
43
|
function fileInfo(block) {
|
|
42
|
-
if (!block || typeof block !== 'object'
|
|
44
|
+
if (!block || typeof block !== 'object') return null;
|
|
45
|
+
if (block.type === 'document') {
|
|
46
|
+
const source = block.source;
|
|
47
|
+
if (source?.type !== 'base64' || typeof source.data !== 'string' || !source.data) return null;
|
|
48
|
+
const mimeType = String(
|
|
49
|
+
source.media_type || source.mediaType || block.mimeType || block.mediaType || 'application/pdf',
|
|
50
|
+
).trim().toLowerCase() || 'application/pdf';
|
|
51
|
+
const filename = typeof block.title === 'string' && block.title
|
|
52
|
+
? block.title
|
|
53
|
+
: (typeof block.filename === 'string' && block.filename ? block.filename : '');
|
|
54
|
+
return { data: source.data, mimeType, filename };
|
|
55
|
+
}
|
|
56
|
+
if (block.type !== 'file') return null;
|
|
43
57
|
const data = isAttachmentReference(block)
|
|
44
58
|
? readAttachmentBase64(block)
|
|
45
59
|
: (typeof block.data === 'string' ? block.data : '');
|
|
@@ -496,11 +510,18 @@ export function splitToolContentForOpenAIResponses(content) {
|
|
|
496
510
|
}
|
|
497
511
|
|
|
498
512
|
export function splitToolContentForXaiResponses(content) {
|
|
499
|
-
const
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
513
|
+
const normalized = normalizeContentForOpenAIResponses(content, { role: 'user' });
|
|
514
|
+
const mediaContent = mediaPartsOnly(normalized, new Set(['input_image']));
|
|
515
|
+
if (!mediaContent.length) {
|
|
516
|
+
const hasDocument = normalized.some((part) => part?.type === 'input_file');
|
|
517
|
+
return {
|
|
518
|
+
output: contentToText(
|
|
519
|
+
content,
|
|
520
|
+
hasDocument ? '[tool result included document content unavailable to xAI Responses]' : '',
|
|
521
|
+
),
|
|
522
|
+
mediaContent: null,
|
|
523
|
+
};
|
|
524
|
+
}
|
|
504
525
|
return {
|
|
505
526
|
// xAI documents function_call_output as text/JSON; media remains a
|
|
506
527
|
// following user input, without replaying the tool-result text there.
|
|
@@ -6,6 +6,7 @@ import { createHash, randomUUID } from 'crypto';
|
|
|
6
6
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
7
7
|
import { join } from 'path';
|
|
8
8
|
import { getPluginData } from '../config.mjs';
|
|
9
|
+
import { activateCodexTurnState } from './openai-turn-state.mjs';
|
|
9
10
|
|
|
10
11
|
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
11
12
|
let _installationId = null;
|
|
@@ -206,39 +207,30 @@ export function _codexWsCompatibilityHeaders(context = {}) {
|
|
|
206
207
|
export function _withCodexWsClientMetadata(frame, entry, enabled, context = {}) {
|
|
207
208
|
if (!enabled || !frame || typeof frame !== 'object') return frame;
|
|
208
209
|
const base = _codexMetadataBase(entry, context);
|
|
209
|
-
const
|
|
210
|
-
|
|
210
|
+
const explicitLogicalTurnId = _cleanMetaString(
|
|
211
|
+
context?.sendOpts?.turnId
|
|
212
|
+
|| context?.sendOpts?.codexTurnId
|
|
213
|
+
|| context?.sendOpts?.session?.turnId,
|
|
214
|
+
);
|
|
215
|
+
const logicalTurnId = explicitLogicalTurnId
|
|
216
|
+
? _codexUuidV7(explicitLogicalTurnId)
|
|
217
|
+
: base.turn_id;
|
|
218
|
+
const turnStateScope = _cleanMetaString(context?.poolKey);
|
|
211
219
|
const metadata = {
|
|
212
220
|
...base,
|
|
213
221
|
...(frame.client_metadata && typeof frame.client_metadata === 'object' ? frame.client_metadata : {}),
|
|
214
222
|
'x-codex-ws-stream-request-start-ms': String(Date.now()),
|
|
215
223
|
};
|
|
216
224
|
if (entry && typeof entry === 'object') {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
if (entry.turnState) {
|
|
223
|
-
if (entry.turnStateTurnId == null) {
|
|
224
|
-
entry.turnStateTurnId = base.turn_id;
|
|
225
|
-
} else if (entry.turnStateTurnId !== base.turn_id) {
|
|
226
|
-
// Codex startup prewarm owns the handshake turn-state until
|
|
227
|
-
// the first real turn consumes that prewarmed client session.
|
|
228
|
-
// Adopt it once across prewarm→turn; ordinary turn changes
|
|
229
|
-
// still retire the old token.
|
|
230
|
-
if (entry.turnStateFromPrewarm === true && !isPrewarmRequest) {
|
|
231
|
-
entry.turnStateTurnId = base.turn_id;
|
|
232
|
-
} else {
|
|
233
|
-
entry.turnState = null;
|
|
234
|
-
entry.turnStateTurnId = null;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
if (!isPrewarmRequest && entry.turnStateFromPrewarm === true) {
|
|
239
|
-
entry.turnStateFromPrewarm = false;
|
|
225
|
+
const priorTurnId = entry.turnStateTurnId;
|
|
226
|
+
if (turnStateScope && logicalTurnId) {
|
|
227
|
+
entry.turnState = activateCodexTurnState(turnStateScope, logicalTurnId, entry);
|
|
228
|
+
} else if (priorTurnId != null && priorTurnId !== logicalTurnId) {
|
|
229
|
+
entry.turnState = null;
|
|
240
230
|
}
|
|
241
|
-
entry.
|
|
231
|
+
entry.turnStateScope = turnStateScope || null;
|
|
232
|
+
entry.turnStateTurnId = logicalTurnId || null;
|
|
233
|
+
entry.currentTurnId = logicalTurnId || null;
|
|
242
234
|
}
|
|
243
235
|
if (entry?.turnState) metadata['x-codex-turn-state'] = String(entry.turnState);
|
|
244
236
|
return { ...frame, client_metadata: metadata };
|