@gajae-code/coding-agent 0.17.1 → 0.17.4
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/CHANGELOG.md +266 -0
- package/dist/types/async/job-manager.d.ts +7 -6
- package/dist/types/cli/daemon-cli.d.ts +3 -1
- package/dist/types/cli/github-release.d.ts +17 -0
- package/dist/types/cli/public-command-entry.d.ts +56 -0
- package/dist/types/cli/public-command-errors.d.ts +126 -0
- package/dist/types/cli/public-command-evidence.d.ts +99 -0
- package/dist/types/cli/public-command-help.d.ts +65 -0
- package/dist/types/cli/public-command-registry.d.ts +69 -0
- package/dist/types/cli/session-picker.d.ts +1 -1
- package/dist/types/cli/setup-cli.d.ts +1 -0
- package/dist/types/cli/skills-cli.d.ts +5 -0
- package/dist/types/cli.d.ts +3 -0
- package/dist/types/commands/daemon.d.ts +4 -50
- package/dist/types/commands/sdk.d.ts +20 -37
- package/dist/types/commands/setup.d.ts +3 -0
- package/dist/types/commands/skills.d.ts +9 -0
- package/dist/types/config/autorouting-tier-map.d.ts +24 -0
- package/dist/types/config/file-lock.d.ts +10 -1
- package/dist/types/config/model-profile-activation.d.ts +63 -4
- package/dist/types/config/model-registry.d.ts +20 -2
- package/dist/types/config/settings-schema.d.ts +11 -0
- package/dist/types/coordinator-mcp/question-state.d.ts +6 -1
- package/dist/types/coordinator-mcp/server.d.ts +3 -0
- package/dist/types/daemon/operator-contract.d.ts +5 -1
- package/dist/types/eval/js/worker-protocol.d.ts +2 -0
- package/dist/types/extensibility/extensions/types.d.ts +12 -0
- package/dist/types/extensibility/gjc-plugins/registry.d.ts +4 -0
- package/dist/types/extensibility/runtime-skill-discovery.d.ts +18 -0
- package/dist/types/extensibility/shared-events.d.ts +3 -1
- package/dist/types/gjc-runtime/session-state-lock.d.ts +61 -0
- package/dist/types/internal-urls/embedded-protocol.d.ts +9 -0
- package/dist/types/internal-urls/index.d.ts +1 -0
- package/dist/types/internal-urls/parse.d.ts +9 -1
- package/dist/types/main.d.ts +22 -0
- package/dist/types/modes/acp/acp-agent.d.ts +94 -1
- package/dist/types/modes/acp/startup-provenance.d.ts +16 -0
- package/dist/types/modes/components/custom-provider-wizard.d.ts +19 -1
- package/dist/types/modes/components/session-selector.d.ts +5 -2
- package/dist/types/modes/components/thinking-selector.d.ts +2 -1
- package/dist/types/modes/components/user-message-selector.d.ts +5 -2
- package/dist/types/modes/controllers/command-controller.d.ts +1 -1
- package/dist/types/modes/controllers/selector-controller.d.ts +1 -1
- package/dist/types/modes/interactive-mode.d.ts +1 -1
- package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +11 -1
- package/dist/types/modes/shared/agent-wire/workflow-gate-types.d.ts +14 -1
- package/dist/types/modes/types.d.ts +2 -2
- package/dist/types/runtime/process-lifecycle.d.ts +2 -0
- package/dist/types/runtime-mcp/manager.d.ts +56 -0
- package/dist/types/runtime-mcp/pool.d.ts +17 -0
- package/dist/types/runtime-mcp/redaction.d.ts +20 -0
- package/dist/types/runtime-mcp/startup-policy.d.ts +6 -0
- package/dist/types/runtime-mcp/tool-bridge.d.ts +9 -0
- package/dist/types/runtime-mcp/transports/http.d.ts +11 -0
- package/dist/types/sdk/acp/adapter.d.ts +27 -0
- package/dist/types/sdk/acp/final-text.d.ts +8 -0
- package/dist/types/sdk/broker/broker.d.ts +13 -2
- package/dist/types/sdk/broker/ensure.d.ts +46 -1
- package/dist/types/sdk/broker/identity.d.ts +3 -1
- package/dist/types/sdk/broker/lifecycle-ledger.d.ts +23 -3
- package/dist/types/sdk/broker/lifecycle.d.ts +15 -8
- package/dist/types/sdk/broker/runtime.d.ts +1 -1
- package/dist/types/sdk/broker/session-index.d.ts +22 -3
- package/dist/types/sdk/broker/spawn-authority.d.ts +4 -0
- package/dist/types/sdk/broker/stderr-drainer.d.ts +13 -0
- package/dist/types/sdk/bus/index.d.ts +19 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +3 -1
- package/dist/types/sdk/bus/telegram-daemon.d.ts +5 -0
- package/dist/types/sdk/cli/master-cli.d.ts +6 -10
- package/dist/types/sdk/cli/rows.d.ts +19 -1
- package/dist/types/sdk/cli/session-cli.d.ts +22 -5
- package/dist/types/sdk/client/client.d.ts +2 -0
- package/dist/types/sdk/guides/cli.d.ts +3 -4
- package/dist/types/sdk/guides/verify.d.ts +2 -0
- package/dist/types/sdk/host/host.d.ts +9 -0
- package/dist/types/sdk/host/session-runtime.d.ts +31 -0
- package/dist/types/sdk/host/types.d.ts +10 -0
- package/dist/types/sdk/index.d.ts +1 -0
- package/dist/types/sdk/prompt-deadline-flush.d.ts +83 -0
- package/dist/types/sdk/prompt-deadline-manager.d.ts +38 -1
- package/dist/types/sdk/prompt-failure.d.ts +30 -1
- package/dist/types/sdk/prompt-status.d.ts +8 -0
- package/dist/types/sdk/prompt-tool-boundary.d.ts +73 -0
- package/dist/types/sdk/router/replay-retention-gap-cache.d.ts +13 -0
- package/dist/types/sdk/router/session-router.d.ts +2 -0
- package/dist/types/sdk/startup-capability.d.ts +2 -0
- package/dist/types/sdk/transport/relay.d.ts +1 -0
- package/dist/types/sdk/transport/serve-cli.d.ts +73 -2
- package/dist/types/sdk/transport/stdio.d.ts +5 -1
- package/dist/types/session/agent-session.d.ts +168 -21
- package/dist/types/session/fallback-chain-controller.d.ts +6 -6
- package/dist/types/session/fold-coordinator.d.ts +17 -3
- package/dist/types/session/internal/managed-session-storage.d.ts +7 -1
- package/dist/types/session/session-manager.d.ts +64 -1
- package/dist/types/session/session-work-lease.d.ts +14 -0
- package/dist/types/setup/model-onboarding-guidance.d.ts +1 -1
- package/dist/types/setup/provider-onboarding.d.ts +81 -1
- package/dist/types/thinking.d.ts +3 -1
- package/dist/types/tools/bash.d.ts +37 -11
- package/dist/types/tools/job.d.ts +1 -1
- package/dist/types/tools/steer-fold.d.ts +31 -0
- package/dist/types/utils/git.d.ts +28 -2
- package/dist/types/utils/mupdf-embedded.d.ts +2 -0
- package/dist/types/utils/mupdf-wasm-embedded.d.ts +2 -0
- package/dist/types/utils/mupdf.d.ts +4 -0
- package/dist/types/utils/session-title-generation.d.ts +6 -0
- package/dist/types/utils/title-generator.d.ts +11 -2
- package/dist/types/web/scrapers/types.d.ts +3 -0
- package/package.json +18 -10
- package/scripts/build-binary.ts +9 -3
- package/scripts/compile-args.ts +0 -9
- package/scripts/embed-mupdf.ts +52 -0
- package/scripts/generate-sdk-operation-inventory.ts +31 -1
- package/scripts/vendor-markit.ts +196 -0
- package/src/async/job-manager.ts +60 -9
- package/src/cli/daemon-cli.ts +53 -18
- package/src/cli/github-release.ts +87 -5
- package/src/cli/mcp-cli.ts +38 -4
- package/src/cli/public-command-entry.ts +450 -0
- package/src/cli/public-command-errors.ts +581 -0
- package/src/cli/public-command-evidence.ts +717 -0
- package/src/cli/public-command-help.ts +360 -0
- package/src/cli/public-command-registry.ts +535 -0
- package/src/cli/session-picker.ts +2 -1
- package/src/cli/setup-cli.ts +9 -1
- package/src/cli/skills-cli.ts +46 -2
- package/src/cli.ts +61 -1
- package/src/commands/daemon.ts +65 -69
- package/src/commands/sdk.ts +232 -100
- package/src/commands/setup.ts +2 -0
- package/src/commands/skills.ts +11 -0
- package/src/config/autorouting-tier-map.ts +16 -0
- package/src/config/file-lock.ts +199 -68
- package/src/config/model-profile-activation.ts +406 -53
- package/src/config/model-registry.ts +204 -25
- package/src/config/settings-schema.ts +26 -2
- package/src/coordinator-mcp/policy.ts +10 -5
- package/src/coordinator-mcp/question-gate-codec.ts +17 -0
- package/src/coordinator-mcp/question-state.ts +175 -8
- package/src/coordinator-mcp/server.ts +528 -87
- package/src/coordinator-mcp/session-reaper.ts +6 -4
- package/src/crash/record-loader.ts +6 -2
- package/src/daemon/operator-contract.ts +26 -12
- package/src/debug/report-bundle.ts +114 -24
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +1 -1
- package/src/eval/js/context-manager.ts +8 -8
- package/src/eval/js/worker-core.ts +9 -4
- package/src/eval/js/worker-protocol.ts +2 -0
- package/src/extensibility/extensions/runner.ts +52 -4
- package/src/extensibility/extensions/types.ts +10 -0
- package/src/extensibility/gjc-plugins/registry.ts +196 -37
- package/src/extensibility/runtime-skill-discovery.ts +61 -3
- package/src/extensibility/shared-events.ts +3 -1
- package/src/gjc-runtime/managed-owner-admission.ts +67 -50
- package/src/gjc-runtime/session-state-lock.ts +165 -24
- package/src/gjc-runtime/ultragoal-succession.ts +31 -3
- package/src/internal-urls/docs-index.generated.ts +21 -19
- package/src/internal-urls/embedded-protocol.ts +83 -0
- package/src/internal-urls/index.ts +1 -0
- package/src/internal-urls/parse.ts +21 -1
- package/src/internal-urls/router.ts +4 -2
- package/src/main.ts +123 -55
- package/src/modes/acp/acp-agent.ts +593 -47
- package/src/modes/acp/acp-event-mapper.ts +9 -0
- package/src/modes/acp/startup-provenance.ts +59 -0
- package/src/modes/components/custom-provider-wizard.ts +308 -7
- package/src/modes/components/model-selector.ts +31 -15
- package/src/modes/components/oauth-selector.ts +9 -0
- package/src/modes/components/session-selector.ts +47 -4
- package/src/modes/components/status-line/segments.ts +6 -1
- package/src/modes/components/thinking-selector.ts +7 -3
- package/src/modes/components/user-message-selector.ts +57 -15
- package/src/modes/controllers/command-controller.ts +58 -32
- package/src/modes/controllers/extension-ui-controller.ts +33 -7
- package/src/modes/controllers/input-controller.ts +4 -0
- package/src/modes/controllers/selector-controller.ts +177 -18
- package/src/modes/interactive-mode.ts +21 -7
- package/src/modes/runtime-init.ts +1 -0
- package/src/modes/shared/agent-wire/workflow-gate-broker.ts +124 -7
- package/src/modes/shared/agent-wire/workflow-gate-types.ts +16 -2
- package/src/modes/types.ts +2 -2
- package/src/prompts/agent-fragments/browser-aside.md +1 -0
- package/src/prompts/system/title-system.md +1 -1
- package/src/prompts/tools/bash.md +1 -1
- package/src/prompts/tools/job.md +1 -1
- package/src/prompts/tools/read.md +2 -0
- package/src/runtime/network-prewarm-service.test.ts +36 -1
- package/src/runtime/network-prewarm-service.ts +28 -3
- package/src/runtime/process-lifecycle.ts +22 -11
- package/src/runtime-mcp/config.ts +16 -1
- package/src/runtime-mcp/manager.ts +689 -55
- package/src/runtime-mcp/pool.test.ts +31 -0
- package/src/runtime-mcp/pool.ts +304 -28
- package/src/runtime-mcp/redaction.ts +42 -0
- package/src/runtime-mcp/startup-policy.ts +7 -0
- package/src/runtime-mcp/tool-bridge.ts +71 -0
- package/src/runtime-mcp/transports/http.ts +108 -25
- package/src/sdk/acp/adapter.ts +90 -9
- package/src/sdk/acp/final-text.ts +19 -2
- package/src/sdk/broker/broker.ts +378 -52
- package/src/sdk/broker/ensure.ts +97 -19
- package/src/sdk/broker/identity.ts +9 -1
- package/src/sdk/broker/lifecycle-ledger.ts +95 -31
- package/src/sdk/broker/lifecycle.ts +690 -141
- package/src/sdk/broker/runtime.ts +1 -1
- package/src/sdk/broker/session-index.ts +97 -4
- package/src/sdk/broker/spawn-authority.ts +35 -7
- package/src/sdk/broker/stderr-drainer.ts +59 -0
- package/src/sdk/bus/chat-daemon-control.ts +2 -2
- package/src/sdk/bus/chat-daemon-runtime.ts +1 -0
- package/src/sdk/bus/index.ts +721 -84
- package/src/sdk/bus/telegram-daemon-cli.ts +31 -2
- package/src/sdk/bus/telegram-daemon-contract.ts +3 -1
- package/src/sdk/bus/telegram-daemon.ts +10 -3
- package/src/sdk/cli/master-cli.ts +47 -36
- package/src/sdk/cli/rows.ts +30 -7
- package/src/sdk/cli/session-cli.ts +687 -184
- package/src/sdk/client/client.ts +18 -0
- package/src/sdk/guides/catalog.ts +2 -2
- package/src/sdk/guides/cli.ts +20 -62
- package/src/sdk/guides/verify.ts +14 -0
- package/src/sdk/host/host.ts +49 -5
- package/src/sdk/host/session-runtime.test.ts +636 -9
- package/src/sdk/host/session-runtime.ts +499 -118
- package/src/sdk/host/types.ts +12 -1
- package/src/sdk/host/websocket-transport.lifecycle.test.ts +84 -0
- package/src/sdk/host/websocket-transport.ts +40 -6
- package/src/sdk/index.ts +11 -0
- package/src/sdk/prompt-deadline-flush.ts +334 -0
- package/src/sdk/prompt-deadline-manager.ts +136 -4
- package/src/sdk/prompt-failure.ts +43 -1
- package/src/sdk/prompt-status.ts +8 -0
- package/src/sdk/prompt-tool-boundary.ts +121 -0
- package/src/sdk/protocol/operation-inventory.generated.json +106 -0
- package/src/sdk/router/replay-retention-gap-cache.ts +27 -0
- package/src/sdk/router/session-router.ts +31 -4
- package/src/sdk/session.ts +194 -16
- package/src/sdk/startup-capability.ts +1 -1
- package/src/sdk/transport/relay.ts +71 -6
- package/src/sdk/transport/serve-cli.ts +494 -49
- package/src/sdk/transport/socket.ts +12 -11
- package/src/sdk/transport/stdio.ts +7 -3
- package/src/session/agent-session.ts +2437 -400
- package/src/session/fallback-chain-controller.ts +6 -7
- package/src/session/fold-coordinator.ts +24 -5
- package/src/session/internal/managed-session-scope.ts +58 -18
- package/src/session/internal/managed-session-storage.ts +304 -11
- package/src/session/session-manager.ts +382 -44
- package/src/session/session-work-lease.ts +34 -0
- package/src/session-import/codex.ts +12 -3
- package/src/setup/model-onboarding-guidance.ts +1 -1
- package/src/setup/provider-onboarding.ts +397 -24
- package/src/slash-commands/builtin-registry.ts +258 -14
- package/src/task/index.ts +14 -2
- package/src/thinking.ts +21 -2
- package/src/tools/bash.ts +98 -78
- package/src/tools/fetch.ts +119 -20
- package/src/tools/job.ts +151 -25
- package/src/tools/output-meta.ts +15 -2
- package/src/tools/path-utils.ts +27 -3
- package/src/tools/read.ts +3 -3
- package/src/tools/steer-fold.ts +107 -0
- package/src/tools/tool-catalog.generated.ts +29 -2
- package/src/tools/tool-errors.ts +4 -0
- package/src/utils/git.ts +53 -3
- package/src/utils/markit.ts +55 -41
- package/src/utils/mupdf-assets.d.ts +4 -0
- package/src/utils/mupdf-embedded.ts +4 -0
- package/src/utils/mupdf-wasm-embedded.ts +3 -0
- package/src/utils/mupdf-wasm.ts +24 -2
- package/src/utils/mupdf.ts +129 -0
- package/src/utils/session-title-generation.ts +29 -0
- package/src/utils/title-generator.ts +46 -2
- package/src/web/scrapers/types.ts +24 -3
- package/vendor/markit-ai/LICENSE +21 -0
- package/vendor/markit-ai/MANIFEST.json +412 -0
- package/vendor/markit-ai/dist/commands/config.d.ts +4 -0
- package/vendor/markit-ai/dist/commands/config.js +139 -0
- package/vendor/markit-ai/dist/commands/convert.d.ts +6 -0
- package/vendor/markit-ai/dist/commands/convert.js +113 -0
- package/vendor/markit-ai/dist/commands/formats.d.ts +2 -0
- package/vendor/markit-ai/dist/commands/formats.js +92 -0
- package/vendor/markit-ai/dist/commands/init.d.ts +2 -0
- package/vendor/markit-ai/dist/commands/init.js +29 -0
- package/vendor/markit-ai/dist/commands/onboard.d.ts +2 -0
- package/vendor/markit-ai/dist/commands/onboard.js +61 -0
- package/vendor/markit-ai/dist/commands/plugin.d.ts +4 -0
- package/vendor/markit-ai/dist/commands/plugin.js +58 -0
- package/vendor/markit-ai/dist/config.d.ts +26 -0
- package/vendor/markit-ai/dist/config.js +42 -0
- package/vendor/markit-ai/dist/converters/audio.d.ts +7 -0
- package/vendor/markit-ai/dist/converters/audio.js +104 -0
- package/vendor/markit-ai/dist/converters/csv.d.ts +7 -0
- package/vendor/markit-ai/dist/converters/csv.js +83 -0
- package/vendor/markit-ai/dist/converters/docx.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/docx.js +57 -0
- package/vendor/markit-ai/dist/converters/epub.d.ts +8 -0
- package/vendor/markit-ai/dist/converters/epub.js +128 -0
- package/vendor/markit-ai/dist/converters/github.d.ts +18 -0
- package/vendor/markit-ai/dist/converters/github.js +148 -0
- package/vendor/markit-ai/dist/converters/html.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/html.js +30 -0
- package/vendor/markit-ai/dist/converters/image.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/image.js +124 -0
- package/vendor/markit-ai/dist/converters/ipynb.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/ipynb.js +75 -0
- package/vendor/markit-ai/dist/converters/iwork.d.ts +20 -0
- package/vendor/markit-ai/dist/converters/iwork.js +391 -0
- package/vendor/markit-ai/dist/converters/json.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/json.js +21 -0
- package/vendor/markit-ai/dist/converters/pdf/columns.d.ts +35 -0
- package/vendor/markit-ai/dist/converters/pdf/columns.js +93 -0
- package/vendor/markit-ai/dist/converters/pdf/extract.d.ts +19 -0
- package/vendor/markit-ai/dist/converters/pdf/extract.js +514 -0
- package/vendor/markit-ai/dist/converters/pdf/grid.d.ts +25 -0
- package/vendor/markit-ai/dist/converters/pdf/grid.js +795 -0
- package/vendor/markit-ai/dist/converters/pdf/headers.d.ts +24 -0
- package/vendor/markit-ai/dist/converters/pdf/headers.js +108 -0
- package/vendor/markit-ai/dist/converters/pdf/index.d.ts +19 -0
- package/vendor/markit-ai/dist/converters/pdf/index.js +136 -0
- package/vendor/markit-ai/dist/converters/pdf/mupdf-loader.js +9 -0
- package/vendor/markit-ai/dist/converters/pdf/render.d.ts +24 -0
- package/vendor/markit-ai/dist/converters/pdf/render.js +513 -0
- package/vendor/markit-ai/dist/converters/pdf/types.d.ts +75 -0
- package/vendor/markit-ai/dist/converters/pdf/types.js +1 -0
- package/vendor/markit-ai/dist/converters/plain-text.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/plain-text.js +87 -0
- package/vendor/markit-ai/dist/converters/pptx.d.ts +8 -0
- package/vendor/markit-ai/dist/converters/pptx.js +289 -0
- package/vendor/markit-ai/dist/converters/rss.d.ts +11 -0
- package/vendor/markit-ai/dist/converters/rss.js +138 -0
- package/vendor/markit-ai/dist/converters/wikipedia.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/wikipedia.js +33 -0
- package/vendor/markit-ai/dist/converters/xlsx.d.ts +8 -0
- package/vendor/markit-ai/dist/converters/xlsx.js +147 -0
- package/vendor/markit-ai/dist/converters/xml.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/xml.js +18 -0
- package/vendor/markit-ai/dist/converters/yaml.d.ts +6 -0
- package/vendor/markit-ai/dist/converters/yaml.js +17 -0
- package/vendor/markit-ai/dist/converters/zip.d.ts +8 -0
- package/vendor/markit-ai/dist/converters/zip.js +57 -0
- package/vendor/markit-ai/dist/index.d.ts +30 -0
- package/vendor/markit-ai/dist/index.js +26 -0
- package/vendor/markit-ai/dist/main.d.ts +2 -0
- package/vendor/markit-ai/dist/main.js +191 -0
- package/vendor/markit-ai/dist/markit.d.ts +45 -0
- package/vendor/markit-ai/dist/markit.js +267 -0
- package/vendor/markit-ai/dist/plugins/api.d.ts +7 -0
- package/vendor/markit-ai/dist/plugins/api.js +42 -0
- package/vendor/markit-ai/dist/plugins/index.d.ts +4 -0
- package/vendor/markit-ai/dist/plugins/index.js +3 -0
- package/vendor/markit-ai/dist/plugins/installer.d.ts +25 -0
- package/vendor/markit-ai/dist/plugins/installer.js +176 -0
- package/vendor/markit-ai/dist/plugins/loader.d.ts +6 -0
- package/vendor/markit-ai/dist/plugins/loader.js +61 -0
- package/vendor/markit-ai/dist/plugins/types.d.ts +25 -0
- package/vendor/markit-ai/dist/plugins/types.js +1 -0
- package/vendor/markit-ai/dist/providers/anthropic.d.ts +2 -0
- package/vendor/markit-ai/dist/providers/anthropic.js +47 -0
- package/vendor/markit-ai/dist/providers/index.d.ts +21 -0
- package/vendor/markit-ai/dist/providers/index.js +56 -0
- package/vendor/markit-ai/dist/providers/openai.d.ts +2 -0
- package/vendor/markit-ai/dist/providers/openai.js +76 -0
- package/vendor/markit-ai/dist/providers/types.d.ts +26 -0
- package/vendor/markit-ai/dist/providers/types.js +1 -0
- package/vendor/markit-ai/dist/types.d.ts +36 -0
- package/vendor/markit-ai/dist/types.js +1 -0
- package/vendor/markit-ai/dist/utils/exit-codes.d.ts +4 -0
- package/vendor/markit-ai/dist/utils/exit-codes.js +4 -0
- package/vendor/markit-ai/dist/utils/output.d.ts +22 -0
- package/vendor/markit-ai/dist/utils/output.js +31 -0
- package/vendor/markit-ai/dist/utils/turndown.d.ts +8 -0
- package/vendor/markit-ai/dist/utils/turndown.js +70 -0
- package/vendor/markit-ai/package.json +74 -0
- package/vendor/markit-ai.patch +49 -0
|
@@ -43,6 +43,13 @@ export interface MCPToolOptions {
|
|
|
43
43
|
* owning manager/runtime. Resolved per call so late registration still applies.
|
|
44
44
|
*/
|
|
45
45
|
inputHandler?: () => MCPInputRequestHandler | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Exact MCP session control: false while the owning manager has this server
|
|
48
|
+
* suspended. Checked alongside `#sessionControlInvalidated` so a wrapper that
|
|
49
|
+
* outlives a resume/reconnect still fails locally instead of reaching the
|
|
50
|
+
* transport for a server this session no longer has active.
|
|
51
|
+
*/
|
|
52
|
+
isAvailable?: () => boolean;
|
|
46
53
|
}
|
|
47
54
|
|
|
48
55
|
function connectionForTool(target: MCPToolTarget): MCPServerConnection {
|
|
@@ -235,6 +242,7 @@ export function parseMCPToolName(name: string): { serverName: string; toolName:
|
|
|
235
242
|
* CustomTool wrapping an MCP tool with an active connection.
|
|
236
243
|
*/
|
|
237
244
|
export class MCPTool implements CustomTool<TSchema, MCPToolDetails> {
|
|
245
|
+
// Exact MCP stale wrappers fail before transport RPC.
|
|
238
246
|
readonly name: string;
|
|
239
247
|
readonly label: string;
|
|
240
248
|
readonly description: string;
|
|
@@ -247,6 +255,14 @@ export class MCPTool implements CustomTool<TSchema, MCPToolDetails> {
|
|
|
247
255
|
private connection: MCPServerConnection;
|
|
248
256
|
#noReplay = false;
|
|
249
257
|
#inputHandlerResolver: (() => MCPInputRequestHandler | undefined) | undefined;
|
|
258
|
+
#isAvailable: (() => boolean) | undefined;
|
|
259
|
+
#sessionControlInvalidated = false;
|
|
260
|
+
invalidateForSessionControl(): void {
|
|
261
|
+
this.#sessionControlInvalidated = true;
|
|
262
|
+
}
|
|
263
|
+
#isAvailableForSessionControl(): boolean {
|
|
264
|
+
return !this.#sessionControlInvalidated && this.#isAvailable?.() !== false;
|
|
265
|
+
}
|
|
250
266
|
|
|
251
267
|
#callOptions(signal?: AbortSignal): MCPRequestOptions {
|
|
252
268
|
const inputHandler = this.#inputHandlerResolver?.();
|
|
@@ -272,6 +288,7 @@ export class MCPTool implements CustomTool<TSchema, MCPToolDetails> {
|
|
|
272
288
|
this.connection = resolvedConnection;
|
|
273
289
|
this.#noReplay = options?.noReplay === true;
|
|
274
290
|
this.#inputHandlerResolver = options?.inputHandler;
|
|
291
|
+
this.#isAvailable = options?.isAvailable;
|
|
275
292
|
this.name = createMCPToolName(resolvedConnection.name, tool.name);
|
|
276
293
|
this.label = `${resolvedConnection.name}/${tool.name}`;
|
|
277
294
|
this.description = tool.description ?? `MCP tool from ${resolvedConnection.name}`;
|
|
@@ -299,6 +316,15 @@ export class MCPTool implements CustomTool<TSchema, MCPToolDetails> {
|
|
|
299
316
|
const args = normalizeToolArgs(params);
|
|
300
317
|
const provider = this.connection._source?.provider;
|
|
301
318
|
const providerName = this.connection._source?.providerName;
|
|
319
|
+
if (!this.#isAvailableForSessionControl()) {
|
|
320
|
+
return buildErrorResult(
|
|
321
|
+
new Error("MCP server is suspended for this session"),
|
|
322
|
+
this.connection.name,
|
|
323
|
+
this.tool.name,
|
|
324
|
+
provider,
|
|
325
|
+
providerName,
|
|
326
|
+
);
|
|
327
|
+
}
|
|
302
328
|
|
|
303
329
|
try {
|
|
304
330
|
const result = await callTool(this.connection, this.tool.name, args, this.#callOptions(signal));
|
|
@@ -308,6 +334,15 @@ export class MCPTool implements CustomTool<TSchema, MCPToolDetails> {
|
|
|
308
334
|
if (this.reconnect && isRetriableConnectionError(error)) {
|
|
309
335
|
const newConn = await reconnectWithAbort(this.reconnect, signal);
|
|
310
336
|
if (newConn) {
|
|
337
|
+
if (!this.#isAvailableForSessionControl()) {
|
|
338
|
+
return buildErrorResult(
|
|
339
|
+
new Error("MCP server is suspended for this session"),
|
|
340
|
+
this.connection.name,
|
|
341
|
+
this.tool.name,
|
|
342
|
+
provider,
|
|
343
|
+
providerName,
|
|
344
|
+
);
|
|
345
|
+
}
|
|
311
346
|
if (this.#noReplay)
|
|
312
347
|
return buildErrorResult(error, this.connection.name, this.tool.name, provider, providerName);
|
|
313
348
|
// Rebind so subsequent calls on this instance use the fresh connection
|
|
@@ -350,6 +385,14 @@ export class DeferredMCPTool implements CustomTool<TSchema, MCPToolDetails> {
|
|
|
350
385
|
readonly #fallbackProviderName: string | undefined;
|
|
351
386
|
#noReplay = false;
|
|
352
387
|
#inputHandlerResolver: (() => MCPInputRequestHandler | undefined) | undefined;
|
|
388
|
+
#isAvailable: (() => boolean) | undefined;
|
|
389
|
+
#sessionControlInvalidated = false;
|
|
390
|
+
invalidateForSessionControl(): void {
|
|
391
|
+
this.#sessionControlInvalidated = true;
|
|
392
|
+
}
|
|
393
|
+
#isAvailableForSessionControl(): boolean {
|
|
394
|
+
return !this.#sessionControlInvalidated && this.#isAvailable?.() !== false;
|
|
395
|
+
}
|
|
353
396
|
|
|
354
397
|
#callOptions(signal?: AbortSignal): MCPRequestOptions {
|
|
355
398
|
const inputHandler = this.#inputHandlerResolver?.();
|
|
@@ -386,6 +429,7 @@ export class DeferredMCPTool implements CustomTool<TSchema, MCPToolDetails> {
|
|
|
386
429
|
this.#fallbackProviderName = source?.providerName;
|
|
387
430
|
this.#noReplay = options?.noReplay === true;
|
|
388
431
|
this.#inputHandlerResolver = options?.inputHandler;
|
|
432
|
+
this.#isAvailable = options?.isAvailable;
|
|
389
433
|
}
|
|
390
434
|
|
|
391
435
|
renderCall(args: unknown, _options: RenderResultOptions, theme: Theme) {
|
|
@@ -407,6 +451,15 @@ export class DeferredMCPTool implements CustomTool<TSchema, MCPToolDetails> {
|
|
|
407
451
|
const args = normalizeToolArgs(params);
|
|
408
452
|
const provider = this.#fallbackProvider;
|
|
409
453
|
const providerName = this.#fallbackProviderName;
|
|
454
|
+
if (!this.#isAvailableForSessionControl()) {
|
|
455
|
+
return buildErrorResult(
|
|
456
|
+
new Error("MCP server is suspended for this session"),
|
|
457
|
+
this.serverName,
|
|
458
|
+
this.tool.name,
|
|
459
|
+
provider,
|
|
460
|
+
providerName,
|
|
461
|
+
);
|
|
462
|
+
}
|
|
410
463
|
|
|
411
464
|
try {
|
|
412
465
|
const connection = await untilAborted(signal, () => this.getConnection());
|
|
@@ -425,6 +478,15 @@ export class DeferredMCPTool implements CustomTool<TSchema, MCPToolDetails> {
|
|
|
425
478
|
if (this.reconnect && isRetriableConnectionError(callError)) {
|
|
426
479
|
const newConn = await reconnectWithAbort(this.reconnect, signal);
|
|
427
480
|
if (newConn) {
|
|
481
|
+
if (!this.#isAvailableForSessionControl()) {
|
|
482
|
+
return buildErrorResult(
|
|
483
|
+
new Error("MCP server is suspended for this session"),
|
|
484
|
+
this.serverName,
|
|
485
|
+
this.tool.name,
|
|
486
|
+
provider,
|
|
487
|
+
providerName,
|
|
488
|
+
);
|
|
489
|
+
}
|
|
428
490
|
if (this.#noReplay)
|
|
429
491
|
return buildErrorResult(callError, this.serverName, this.tool.name, provider, providerName);
|
|
430
492
|
const retryProvider = newConn._source?.provider ?? provider;
|
|
@@ -453,6 +515,15 @@ export class DeferredMCPTool implements CustomTool<TSchema, MCPToolDetails> {
|
|
|
453
515
|
rethrowIfAborted(connError, signal);
|
|
454
516
|
if (this.reconnect) {
|
|
455
517
|
const newConn = await reconnectWithAbort(this.reconnect, signal);
|
|
518
|
+
if (newConn && !this.#isAvailableForSessionControl()) {
|
|
519
|
+
return buildErrorResult(
|
|
520
|
+
new Error("MCP server is suspended for this session"),
|
|
521
|
+
this.serverName,
|
|
522
|
+
this.tool.name,
|
|
523
|
+
provider,
|
|
524
|
+
providerName,
|
|
525
|
+
);
|
|
526
|
+
}
|
|
456
527
|
if (newConn && !this.#noReplay) {
|
|
457
528
|
try {
|
|
458
529
|
const result = await callTool(newConn, this.tool.name, args, this.#callOptions(signal));
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* no sessions, no standalone stream, no replay. See ../protocol.ts.
|
|
9
9
|
*/
|
|
10
10
|
import { logger, readSseJson, Snowflake } from "@gajae-code/utils";
|
|
11
|
+
import { isResourceOwnerDisposalActive, registerResourceOwner } from "../../runtime/process-lifecycle";
|
|
11
12
|
import type {
|
|
12
13
|
JsonRpcError,
|
|
13
14
|
JsonRpcMessage,
|
|
@@ -30,6 +31,51 @@ import {
|
|
|
30
31
|
import { fetchPluginMcpRequest, isPluginMcpPublicNetworkBound } from "../plugin-network-boundary";
|
|
31
32
|
import { buildModernMcpHeaders, type MCPModernClientContext, type MCPProtocolEra, withModernMeta } from "../protocol";
|
|
32
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Postmortem release of live HTTP/SSE MCP sessions.
|
|
36
|
+
*
|
|
37
|
+
* A stdio server dies with the agent because it is a `spawnOwnedProcess` child, but an
|
|
38
|
+
* HTTP/SSE server is a separate, already-running process that only learns a client is gone
|
|
39
|
+
* from the session-termination `DELETE`. A signal kill (`SIGINT`/`SIGTERM`/`SIGHUP`) or a
|
|
40
|
+
* fatal exit bypasses session dispose, so without this sweep the server keeps the
|
|
41
|
+
* `Mcp-Session-Id` and everything hanging off it for every agent run that ever died -
|
|
42
|
+
* unbounded growth on the server side. Mirrors the LSP/Python/browser owners.
|
|
43
|
+
*/
|
|
44
|
+
const liveHttpTransports = new Set<HttpTransport>();
|
|
45
|
+
let httpTransportOwnerRelease: (() => void) | undefined;
|
|
46
|
+
/** Exit must not wait on a wedged endpoint; the per-request timeout is up to 30s. */
|
|
47
|
+
const POSTMORTEM_CLOSE_TIMEOUT_MS = 2_000;
|
|
48
|
+
|
|
49
|
+
function trackHttpTransport(transport: HttpTransport): void {
|
|
50
|
+
liveHttpTransports.add(transport);
|
|
51
|
+
httpTransportOwnerRelease ??= registerResourceOwner("mcp:http-transports", closeLiveHttpTransports);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function untrackHttpTransport(transport: HttpTransport): void {
|
|
55
|
+
if (!liveHttpTransports.delete(transport) || liveHttpTransports.size > 0) return;
|
|
56
|
+
// Nothing left to release: drop the registration so a long-lived host does not
|
|
57
|
+
// retain dead transports through the owner map.
|
|
58
|
+
httpTransportOwnerRelease?.();
|
|
59
|
+
httpTransportOwnerRelease = undefined;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function closeLiveHttpTransports(): Promise<void> {
|
|
63
|
+
await Promise.all(
|
|
64
|
+
[...liveHttpTransports].map(async transport => {
|
|
65
|
+
try {
|
|
66
|
+
await transport.releaseForPostmortem(AbortSignal.timeout(POSTMORTEM_CLOSE_TIMEOUT_MS));
|
|
67
|
+
} catch (error) {
|
|
68
|
+
logger.debug("MCP HTTP postmortem release failed", { error });
|
|
69
|
+
}
|
|
70
|
+
}),
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Live HTTP/SSE MCP transports awaiting postmortem release. Exposed for leak assertions/tests. */
|
|
75
|
+
export function liveHttpTransportCount(): number {
|
|
76
|
+
return liveHttpTransports.size;
|
|
77
|
+
}
|
|
78
|
+
|
|
33
79
|
/** Best-effort JSON parse of an error body for structured era classification. */
|
|
34
80
|
function tryParseJsonBody(text: string): unknown {
|
|
35
81
|
try {
|
|
@@ -101,7 +147,11 @@ export class HttpTransport implements MCPTransport {
|
|
|
101
147
|
*/
|
|
102
148
|
async connect(): Promise<void> {
|
|
103
149
|
if (this.#connected) return;
|
|
150
|
+
if (isResourceOwnerDisposalActive()) {
|
|
151
|
+
throw new Error("Cannot connect MCP HTTP transport during process resource disposal");
|
|
152
|
+
}
|
|
104
153
|
this.#connected = true;
|
|
154
|
+
trackHttpTransport(this);
|
|
105
155
|
}
|
|
106
156
|
|
|
107
157
|
#fetch(init: BunFetchRequestInit): Promise<Response> {
|
|
@@ -601,11 +651,8 @@ export class HttpTransport implements MCPTransport {
|
|
|
601
651
|
}
|
|
602
652
|
}
|
|
603
653
|
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
this.#connected = false;
|
|
607
|
-
|
|
608
|
-
// Abort all SSE/background readers and wait for them to settle.
|
|
654
|
+
/** Abort every SSE/background reader. Does not wait for them to settle. */
|
|
655
|
+
#abortStreams(): void {
|
|
609
656
|
for (const controller of this.#streamControllers) {
|
|
610
657
|
controller.abort();
|
|
611
658
|
}
|
|
@@ -613,30 +660,66 @@ export class HttpTransport implements MCPTransport {
|
|
|
613
660
|
this.#sseConnection.abort();
|
|
614
661
|
this.#sseConnection = null;
|
|
615
662
|
}
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
/**
|
|
666
|
+
* Send session termination (legacy era only; the modern era has no protocol
|
|
667
|
+
* session to terminate). This DELETE is the only signal an already-running
|
|
668
|
+
* HTTP/SSE server gets that its session may be dropped.
|
|
669
|
+
*/
|
|
670
|
+
async #terminateSession(signal?: AbortSignal): Promise<void> {
|
|
671
|
+
if (this.#era === "modern") return;
|
|
672
|
+
const sessionId = this.#sessionId;
|
|
673
|
+
if (!sessionId) return;
|
|
674
|
+
// Claim the server session before awaiting the wire request. Graceful close
|
|
675
|
+
// and postmortem disposal can overlap during shutdown; only the caller that
|
|
676
|
+
// detached this id may emit its termination DELETE.
|
|
677
|
+
this.#sessionId = null;
|
|
678
|
+
try {
|
|
679
|
+
const timeout = this.config.timeout ?? 30000;
|
|
680
|
+
const headers: Record<string, string> = {
|
|
681
|
+
...this.config.headers,
|
|
682
|
+
"Mcp-Session-Id": sessionId,
|
|
683
|
+
};
|
|
684
|
+
|
|
685
|
+
const timeoutSignal = AbortSignal.timeout(timeout);
|
|
686
|
+
await this.#fetch({
|
|
687
|
+
method: "DELETE",
|
|
688
|
+
headers,
|
|
689
|
+
signal: signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal,
|
|
690
|
+
});
|
|
691
|
+
} catch {
|
|
692
|
+
// Ignore termination errors
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
/**
|
|
697
|
+
* Terminate the server-side session on a signal or fatal exit, without the
|
|
698
|
+
* reader drain `close()` does: postmortem runs inside the signal handler,
|
|
699
|
+
* where an aborted SSE body read is never observed by JS, so awaiting the
|
|
700
|
+
* readers there never settles and the DELETE stays unreachable. `onClose` is
|
|
701
|
+
* deliberately not fired - the manager reacts to it by reconnecting, which
|
|
702
|
+
* would open a fresh server session on the way out.
|
|
703
|
+
*/
|
|
704
|
+
async releaseForPostmortem(signal: AbortSignal): Promise<void> {
|
|
705
|
+
untrackHttpTransport(this);
|
|
706
|
+
this.#connected = false;
|
|
707
|
+
this.#abortStreams();
|
|
708
|
+
await this.#terminateSession(signal);
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
async close(): Promise<void> {
|
|
712
|
+
untrackHttpTransport(this);
|
|
713
|
+
const wasConnected = this.#connected;
|
|
714
|
+
this.#connected = false;
|
|
715
|
+
|
|
716
|
+
// Abort all SSE/background readers and wait for them to settle.
|
|
717
|
+
this.#abortStreams();
|
|
616
718
|
await Promise.allSettled(Array.from(this.#streamReaders));
|
|
617
719
|
|
|
618
720
|
if (!wasConnected && !this.#sessionId) return;
|
|
619
721
|
|
|
620
|
-
|
|
621
|
-
// the modern era has no protocol session to terminate)
|
|
622
|
-
if (this.#era !== "modern" && this.#sessionId) {
|
|
623
|
-
try {
|
|
624
|
-
const timeout = this.config.timeout ?? 30000;
|
|
625
|
-
const headers: Record<string, string> = {
|
|
626
|
-
...this.config.headers,
|
|
627
|
-
"Mcp-Session-Id": this.#sessionId,
|
|
628
|
-
};
|
|
629
|
-
|
|
630
|
-
await this.#fetch({
|
|
631
|
-
method: "DELETE",
|
|
632
|
-
headers,
|
|
633
|
-
signal: AbortSignal.timeout(timeout),
|
|
634
|
-
});
|
|
635
|
-
} catch {
|
|
636
|
-
// Ignore termination errors
|
|
637
|
-
}
|
|
638
|
-
this.#sessionId = null;
|
|
639
|
-
}
|
|
722
|
+
await this.#terminateSession();
|
|
640
723
|
|
|
641
724
|
this.onClose?.();
|
|
642
725
|
this.onClose = undefined;
|
package/src/sdk/acp/adapter.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
type SessionReconcileUncertainTarget,
|
|
10
10
|
validateSessionReconcileUncertainTarget,
|
|
11
11
|
} from "../lifecycle/service";
|
|
12
|
+
import { ACP_PROMPT_INACTIVITY_TIMEOUT_MS } from "../prompt-watchdog";
|
|
12
13
|
import {
|
|
13
14
|
validateAdapterControl,
|
|
14
15
|
validateAdapterSecretFields,
|
|
@@ -19,11 +20,47 @@ import { type SessionAttachment, type SessionRouter, SessionRouterError } from "
|
|
|
19
20
|
import { ACP_SESSION_RECONNECT, SESSION_ABORT_TIMEOUT_MS } from "../session-reconnect";
|
|
20
21
|
import type { SessionLifecycleMcpServer } from "./mcp";
|
|
21
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Registration rounds one provider activation may spend chasing a moving attachment.
|
|
25
|
+
*
|
|
26
|
+
* The activation loop restarts whenever the Router attachment changes identity while it
|
|
27
|
+
* is registering, because the leases it just took belong to a connection that no longer
|
|
28
|
+
* exists. One reconnect costs one restart, so a handful covers any churn that is actually
|
|
29
|
+
* converging; beyond that the attachment is rotating faster than registration completes
|
|
30
|
+
* and another round only re-takes leases that will be invalidated again. Bounding this is
|
|
31
|
+
* what turns "many session hosts contend for one agent dir" from an unbounded spin into a
|
|
32
|
+
* reported failure (issue #5658).
|
|
33
|
+
*/
|
|
34
|
+
export const PROVIDER_ACTIVATION_MAX_ATTEMPTS = 8;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Wall-clock budget for the same loop.
|
|
38
|
+
*
|
|
39
|
+
* The attempt cap alone bounds rounds, not time: every round is a `#requestSession` round
|
|
40
|
+
* trip per provider, so under lease contention attempts are slow rather than fast-spinning
|
|
41
|
+
* and eight of them can still outlast the caller. The budget is sized to a third of
|
|
42
|
+
* {@link ACP_PROMPT_INACTIVITY_TIMEOUT_MS} so a prompt stalled in provider preflight fails
|
|
43
|
+
* with this error — which names the contended capability — with room to spare before the
|
|
44
|
+
* ACP prompt watchdog reports the same stall as undifferentiated silence.
|
|
45
|
+
*
|
|
46
|
+
* It gates *starting* another round, never interrupting one in flight: a single slow but
|
|
47
|
+
* healthy registration keeps whatever time it needs, and only a retry decided after the
|
|
48
|
+
* deadline is refused.
|
|
49
|
+
*/
|
|
50
|
+
export const PROVIDER_ACTIVATION_BUDGET_MS = Math.floor(ACP_PROMPT_INACTIVITY_TIMEOUT_MS / 3);
|
|
51
|
+
|
|
22
52
|
type JsonObject = Record<string, unknown>;
|
|
23
53
|
function object(value: unknown): JsonObject | undefined {
|
|
24
54
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? (value as JsonObject) : undefined;
|
|
25
55
|
}
|
|
26
56
|
|
|
57
|
+
function preservePromptFailureMetadata(target: Error, source: JsonObject | undefined): void {
|
|
58
|
+
if (!source) return;
|
|
59
|
+
const providerCode = source.providerCode ?? object(source.transportFailure)?.providerCode;
|
|
60
|
+
if (providerCode !== undefined) Object.assign(target, { providerCode });
|
|
61
|
+
if (source.phase !== undefined) Object.assign(target, { phase: source.phase });
|
|
62
|
+
}
|
|
63
|
+
|
|
27
64
|
function providerErrorCode(error: unknown): string | undefined {
|
|
28
65
|
if (error instanceof AcpSdkAdapterError || error instanceof SdkClientError || error instanceof ReverseLeaseError)
|
|
29
66
|
return error.code;
|
|
@@ -445,10 +482,16 @@ export class AcpSdkAdapter {
|
|
|
445
482
|
const envelope = object(response);
|
|
446
483
|
if (envelope?.ok === false) {
|
|
447
484
|
const error = object(envelope.error);
|
|
448
|
-
|
|
485
|
+
const adapterError = new AcpSdkAdapterError(
|
|
449
486
|
typeof error?.code === "string" ? error.code : "request_failed",
|
|
450
487
|
typeof error?.message === "string" ? error.message : "SDK session request failed.",
|
|
451
488
|
);
|
|
489
|
+
// Prompt failures may carry the bounded classifier computed by the host. Keep
|
|
490
|
+
// those fields on the adapter error so the ACP boundary can project them instead
|
|
491
|
+
// of reconstructing a bare `{ code, details }` pair. `acpRequestFailure` performs
|
|
492
|
+
// the final safe-token validation before anything reaches the wire.
|
|
493
|
+
preservePromptFailureMetadata(adapterError, error);
|
|
494
|
+
throw adapterError;
|
|
452
495
|
}
|
|
453
496
|
return envelope?.result ?? response;
|
|
454
497
|
}
|
|
@@ -464,13 +507,19 @@ export class AcpSdkAdapter {
|
|
|
464
507
|
const sessionId = this.#sessionId;
|
|
465
508
|
if (!attachment || !sessionId || !attachment.isCurrent())
|
|
466
509
|
throw new SessionRouterError("pre_send", "SDK session attachment is stale.");
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
510
|
+
let response: Record<string, unknown>;
|
|
511
|
+
try {
|
|
512
|
+
response = await router.request(
|
|
513
|
+
sessionId,
|
|
514
|
+
{ ...frame, id: randomUUID() },
|
|
515
|
+
attachment.generation,
|
|
516
|
+
attachment,
|
|
517
|
+
options,
|
|
518
|
+
);
|
|
519
|
+
} catch (error) {
|
|
520
|
+
if (error instanceof SdkClientError) preservePromptFailureMetadata(error, object(error.details));
|
|
521
|
+
throw error;
|
|
522
|
+
}
|
|
474
523
|
if (!attachment.isCurrent())
|
|
475
524
|
throw new SessionRouterError("ambiguous", "SDK session attachment changed while awaiting command response.");
|
|
476
525
|
return raw ? response : this.#unwrapSessionResponse(response);
|
|
@@ -600,7 +649,12 @@ export class AcpSdkAdapter {
|
|
|
600
649
|
}
|
|
601
650
|
|
|
602
651
|
const activation = (async () => {
|
|
603
|
-
|
|
652
|
+
const startedAt = Date.now();
|
|
653
|
+
// Exhaustion is checked here, outside the try below, so the throw cannot be caught
|
|
654
|
+
// by the same `continue` branch that spent the budget.
|
|
655
|
+
for (let attempt = 1; ; attempt++) {
|
|
656
|
+
if (attempt > PROVIDER_ACTIVATION_MAX_ATTEMPTS || Date.now() - startedAt >= PROVIDER_ACTIVATION_BUDGET_MS)
|
|
657
|
+
throw this.#providerActivationExhausted(attempt - 1, startedAt);
|
|
604
658
|
const attachment = this.#attachment;
|
|
605
659
|
const connectionId = attachment?.connectionId;
|
|
606
660
|
try {
|
|
@@ -652,6 +706,33 @@ export class AcpSdkAdapter {
|
|
|
652
706
|
}
|
|
653
707
|
}
|
|
654
708
|
|
|
709
|
+
/**
|
|
710
|
+
* Names what the exhausted activation loop was still fighting over, so a stalled
|
|
711
|
+
* preflight is attributable to a capability instead of surfacing as generic silence.
|
|
712
|
+
*/
|
|
713
|
+
#providerActivationExhausted(attempts: number, startedAt: number): AcpSdkAdapterError {
|
|
714
|
+
const elapsedMs = Date.now() - startedAt;
|
|
715
|
+
const contended = this.#providers
|
|
716
|
+
.filter(provider => !this.#leases.has(provider.capability))
|
|
717
|
+
.map(provider => provider.capability);
|
|
718
|
+
const detail =
|
|
719
|
+
contended.length > 0
|
|
720
|
+
? `still unleased: ${contended.join(", ")}`
|
|
721
|
+
: "the SDK session attachment changed identity on every attempt";
|
|
722
|
+
logger.error("acp_provider_activation_exhausted", {
|
|
723
|
+
sessionId: this.#sessionId,
|
|
724
|
+
attempts,
|
|
725
|
+
elapsedMs,
|
|
726
|
+
contended,
|
|
727
|
+
leaseCount: this.#leases.size,
|
|
728
|
+
});
|
|
729
|
+
return new AcpSdkAdapterError(
|
|
730
|
+
"provider_activation_exhausted",
|
|
731
|
+
`SDK provider activation did not converge after ${attempts} attempts over ${Math.round(elapsedMs / 1_000)}s ` +
|
|
732
|
+
`(${detail}). The session host is contending for provider leases it cannot hold.`,
|
|
733
|
+
);
|
|
734
|
+
}
|
|
735
|
+
|
|
655
736
|
#assertGenericDisposition(kind: "control" | "global", sdkId: string): void {
|
|
656
737
|
const operation = OPERATIONS.find(candidate => candidate.kind === kind && candidate.sdkId === sdkId);
|
|
657
738
|
if (!operation) throw new AcpSdkAdapterError("unknown_operation", `Unknown SDK ${kind}: ${sdkId}`);
|
|
@@ -31,10 +31,27 @@ export function acpFinalTextFromMessage(message: unknown): BoundedAcpFinalText {
|
|
|
31
31
|
return boundAcpFinalText(parts.join(""));
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Assistant-content presence is trimmed everywhere in the prompt pipeline: whitespace carries no
|
|
36
|
+
* assistant content. The ACP retry gate, prompt reconciliation
|
|
37
|
+
* (`sdk/bus/prompt-reconciliation.ts`) and terminal publication must agree, otherwise a terminal
|
|
38
|
+
* the retry gate treats as "no output" can still publish a whitespace chunk alongside the retry's
|
|
39
|
+
* real answer (review P2 on #5628).
|
|
40
|
+
*/
|
|
41
|
+
export function hasAcpFinalTextContent(value: string): boolean {
|
|
42
|
+
return value.trim().length > 0;
|
|
43
|
+
}
|
|
44
|
+
|
|
34
45
|
export function resolveAcpFinalText(streamed: string, finalText: string): AcpFinalTextResolution {
|
|
35
46
|
const final = boundAcpFinalText(finalText);
|
|
36
|
-
if (!final.text || streamed === final.text || streamed.includes(final.text))
|
|
47
|
+
if (!hasAcpFinalTextContent(final.text) || streamed === final.text || streamed.includes(final.text))
|
|
48
|
+
return { kind: "none", final };
|
|
37
49
|
if (!streamed) return { kind: "emit", final, text: final.text };
|
|
38
|
-
if (final.text.startsWith(streamed))
|
|
50
|
+
if (final.text.startsWith(streamed)) {
|
|
51
|
+
// A pure-whitespace delta is the same defect class as whitespace-only final text: it adds no
|
|
52
|
+
// assistant content, so it must not reach consumers either.
|
|
53
|
+
const tail = final.text.slice(streamed.length);
|
|
54
|
+
return hasAcpFinalTextContent(tail) ? { kind: "emit", final, text: tail } : { kind: "none", final };
|
|
55
|
+
}
|
|
39
56
|
return { kind: "divergent", final };
|
|
40
57
|
}
|