@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
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { logger } from "@gajae-code/utils";
|
|
1
2
|
import type { KindAwareReconciliation } from "./bus/kind-aware-reconciliation";
|
|
2
3
|
import type { InvocationCorrelation, InvocationReconciliation } from "./host/session-runtime";
|
|
3
4
|
import {
|
|
@@ -16,6 +17,56 @@ const MAX_UNCERTAINTY_RETRIES = 3;
|
|
|
16
17
|
const EXPIRY_RETRY_DELAY_MS = 1_000;
|
|
17
18
|
const UNCERTAINTY_RETRY_DELAY_MS = 1_000;
|
|
18
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Hard real-time bound on the best-effort durability hook, shared with
|
|
22
|
+
* `prompt-deadline-flush` so the manager's race and the flush's own abort
|
|
23
|
+
* signal cannot drift apart.
|
|
24
|
+
*/
|
|
25
|
+
export const DEADLINE_FLUSH_TIMEOUT_MS = 10_000;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Run a best-effort durability flush under a hard real-time bound that ALWAYS
|
|
29
|
+
* settles, and never let its result reach the caller.
|
|
30
|
+
*
|
|
31
|
+
* Shared by both expiry paths — this manager and the notification bus's own
|
|
32
|
+
* terminalization (#5583) — so there is one bound, one abort, and one warning,
|
|
33
|
+
* with no drift between them. A rejection is swallowed; a `run` that never
|
|
34
|
+
* settles is abandoned after `timeoutMs` with its signal aborted so any git
|
|
35
|
+
* subprocess dies. The signal alone is not sufficient: `git.withRepoLock`
|
|
36
|
+
* awaits its predecessor before honouring it, so a hung predecessor in the
|
|
37
|
+
* per-repo write chain is cut only by this outer race.
|
|
38
|
+
*/
|
|
39
|
+
export async function runBoundedDeadlineFlush(
|
|
40
|
+
run: (signal: AbortSignal) => unknown,
|
|
41
|
+
timeoutMs: number = DEADLINE_FLUSH_TIMEOUT_MS,
|
|
42
|
+
): Promise<void> {
|
|
43
|
+
const controller = new AbortController();
|
|
44
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
45
|
+
// An async wrapper so a `run` that throws synchronously becomes a rejection.
|
|
46
|
+
const flushed = (async () => {
|
|
47
|
+
await run(controller.signal);
|
|
48
|
+
})();
|
|
49
|
+
// The abandoned promise may still reject long after we stop awaiting it.
|
|
50
|
+
flushed.catch(() => {});
|
|
51
|
+
try {
|
|
52
|
+
const bound = new Promise<"timeout">(resolve => {
|
|
53
|
+
timer = setTimeout(() => resolve("timeout"), timeoutMs);
|
|
54
|
+
// Never let a pending bound keep the process alive.
|
|
55
|
+
(timer as unknown as { unref?: () => void }).unref?.();
|
|
56
|
+
});
|
|
57
|
+
if ((await Promise.race([flushed.then(() => "flushed" as const), bound])) === "timeout") {
|
|
58
|
+
controller.abort(new Error(`prompt deadline flush exceeded ${timeoutMs}ms`));
|
|
59
|
+
logger.warn(
|
|
60
|
+
`sdk: prompt deadline flush exceeded its ${timeoutMs}ms bound; abandoning it and continuing teardown`,
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
} catch {
|
|
64
|
+
// A failing flush never changes the deadline outcome.
|
|
65
|
+
} finally {
|
|
66
|
+
if (timer !== undefined) clearTimeout(timer);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
19
70
|
type DeadlineReconciliation = InvocationReconciliation | KindAwareReconciliation;
|
|
20
71
|
|
|
21
72
|
export type PromptDeadlineOutcome = Extract<SdkPromptTerminalOutcome, { kind: "failed" }> & {
|
|
@@ -48,20 +99,69 @@ export class PromptDeadlineManager {
|
|
|
48
99
|
readonly #getLeaseMs: () => number;
|
|
49
100
|
readonly #getMaxMs: () => number;
|
|
50
101
|
readonly #now: () => number;
|
|
51
|
-
readonly #onExpired?: (correlation: InvocationCorrelation) => void;
|
|
102
|
+
readonly #onExpired?: (correlation: InvocationCorrelation, outcome?: PromptDeadlineOutcome) => void;
|
|
103
|
+
readonly #onDeadlineExceeded?: (
|
|
104
|
+
correlation: InvocationCorrelation,
|
|
105
|
+
signal: AbortSignal,
|
|
106
|
+
isCurrent?: () => boolean,
|
|
107
|
+
) => void | Promise<void>;
|
|
108
|
+
readonly #deadlineFlushTimeoutMs: number;
|
|
52
109
|
|
|
53
110
|
constructor(options: {
|
|
54
111
|
reconciliation: DeadlineReconciliation;
|
|
55
112
|
getLeaseMs: () => number;
|
|
56
113
|
getMaxMs: () => number;
|
|
57
114
|
now?: () => number;
|
|
58
|
-
onExpired?: (correlation: InvocationCorrelation) => void;
|
|
115
|
+
onExpired?: (correlation: InvocationCorrelation, outcome?: PromptDeadlineOutcome) => void;
|
|
116
|
+
/**
|
|
117
|
+
* Best-effort durability hook for the single path that genuinely retires a
|
|
118
|
+
* prompt as `prompt_deadline_exceeded` (#5583). Awaited after the durable
|
|
119
|
+
* pending claim but BEFORE the durable terminal, so a crash in that window
|
|
120
|
+
* leaves the record pending and recovery retries the prompt; a
|
|
121
|
+
* rejection is swallowed and never changes the deadline outcome. Not called
|
|
122
|
+
* when a real terminal transition or a real failure won the race, nor when
|
|
123
|
+
* renewed progress supersedes this expiry instance. The hook receives an
|
|
124
|
+
* abort signal that fires when it outruns `deadlineFlushTimeoutMs`, plus a
|
|
125
|
+
* generation fence for irreversible worktree adoption.
|
|
126
|
+
*/
|
|
127
|
+
onDeadlineExceeded?: (
|
|
128
|
+
correlation: InvocationCorrelation,
|
|
129
|
+
signal: AbortSignal,
|
|
130
|
+
isCurrent?: () => boolean,
|
|
131
|
+
) => void | Promise<void>;
|
|
132
|
+
/**
|
|
133
|
+
* Hard bound on `onDeadlineExceeded`. Measured with a real timer, not
|
|
134
|
+
* `now`, because it guards real subprocesses — which is also why it is a
|
|
135
|
+
* constructor option: a fake clock cannot shorten it for tests.
|
|
136
|
+
*/
|
|
137
|
+
deadlineFlushTimeoutMs?: number;
|
|
59
138
|
}) {
|
|
60
139
|
this.#reconciliation = options.reconciliation;
|
|
61
140
|
this.#getLeaseMs = options.getLeaseMs;
|
|
62
141
|
this.#getMaxMs = options.getMaxMs;
|
|
63
142
|
this.#now = options.now ?? Date.now;
|
|
64
143
|
this.#onExpired = options.onExpired;
|
|
144
|
+
this.#onDeadlineExceeded = options.onDeadlineExceeded;
|
|
145
|
+
this.#deadlineFlushTimeoutMs = options.deadlineFlushTimeoutMs ?? DEADLINE_FLUSH_TIMEOUT_MS;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** Run the durability hook under the shared bound; see `runBoundedDeadlineFlush`. */
|
|
149
|
+
async #runDeadlineFlush(
|
|
150
|
+
correlation: InvocationCorrelation,
|
|
151
|
+
lease: PromptDeadlineLease,
|
|
152
|
+
generation: number,
|
|
153
|
+
): Promise<void> {
|
|
154
|
+
const hook = this.#onDeadlineExceeded;
|
|
155
|
+
if (hook === undefined) return;
|
|
156
|
+
const key = leaseKey(correlation);
|
|
157
|
+
await runBoundedDeadlineFlush(
|
|
158
|
+
signal =>
|
|
159
|
+
hook(correlation, signal, () => {
|
|
160
|
+
const current = this.#leases.get(key);
|
|
161
|
+
return current === lease && current.generation === generation;
|
|
162
|
+
}),
|
|
163
|
+
this.#deadlineFlushTimeoutMs,
|
|
164
|
+
);
|
|
65
165
|
}
|
|
66
166
|
|
|
67
167
|
#clearTimer(key: string): void {
|
|
@@ -165,16 +265,48 @@ export class PromptDeadlineManager {
|
|
|
165
265
|
provenance: "deadline",
|
|
166
266
|
evidence: {},
|
|
167
267
|
}) as PromptDeadlineOutcome;
|
|
268
|
+
let winner: SdkPromptTerminalOutcome = outcome;
|
|
168
269
|
try {
|
|
169
|
-
await this.#reconciliation.claimPendingOutcome("prompt", correlation, outcome);
|
|
270
|
+
const claimed = await this.#reconciliation.claimPendingOutcome("prompt", correlation, outcome);
|
|
271
|
+
if (claimed !== undefined) winner = claimed;
|
|
170
272
|
} catch {
|
|
171
273
|
// claim may fail if already claimed (e.g., cancellation won); ignore.
|
|
172
274
|
}
|
|
275
|
+
// A real terminal may win between lookup and this claim. Its existing
|
|
276
|
+
// pending outcome is authoritative: release this expiry fence without
|
|
277
|
+
// running the deadline-only durability hook or publishing a deadline result.
|
|
278
|
+
if (winner.kind !== "failed" || winner.code !== "prompt_deadline_exceeded" || winner.provenance !== "deadline") {
|
|
279
|
+
this.#expiring.delete(key);
|
|
280
|
+
this.#expiryRetries.delete(key);
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
173
283
|
// Re-verify the captured lease is still authoritative after the claim
|
|
174
284
|
// await (exact-head review P2): fresh attributable progress during the
|
|
175
285
|
// claim must cancel this expiry instance instead of surfacing an exceeded
|
|
176
286
|
// outcome for a prompt that is demonstrably alive.
|
|
177
287
|
if (this.#backOffIfSuperseded(key, lease, generation)) return;
|
|
288
|
+
// Durability BEFORE the durable terminal (#5583, #5623 review round 4). The
|
|
289
|
+
// claim above is already the durable pending marker, so a process death
|
|
290
|
+
// anywhere in this window leaves the record PENDING and restart recovery
|
|
291
|
+
// retries the prompt — work that was never autosaved is never reported as
|
|
292
|
+
// finished. Running the flush after `finalizeOutcome` instead made the
|
|
293
|
+
// autosave the one step a crash could silently skip, which is the whole
|
|
294
|
+
// durability guarantee of this change. The cost is that the durable terminal
|
|
295
|
+
// is delayed by at most the flush's bound.
|
|
296
|
+
//
|
|
297
|
+
// The wait is BOUNDED, not just guarded (#5623 review round 2): a hook that
|
|
298
|
+
// never settles — a blocking git lock, a credential prompt — would leave the
|
|
299
|
+
// finalize, `#onExpired` and `clear` below unreachable, stranding the prompt
|
|
300
|
+
// with neither a terminal nor an owner. A try/catch cannot rescue a promise
|
|
301
|
+
// that never settles, so the flush is raced against a real timer and
|
|
302
|
+
// abandoned if it outruns it.
|
|
303
|
+
await this.#runDeadlineFlush(correlation, lease, generation);
|
|
304
|
+
// Fence again AFTER the flush (#5623 review round 2): the flush is an await
|
|
305
|
+
// like any other here, and up to ten seconds long, so progress can land and
|
|
306
|
+
// renew the lease while it runs. A renewed prompt must not be terminalized as
|
|
307
|
+
// deadline-exceeded by this stale pass; `#backOffIfSuperseded` reschedules on
|
|
308
|
+
// the way out, so it keeps a live deadline.
|
|
309
|
+
if (this.#backOffIfSuperseded(key, lease, generation)) return;
|
|
178
310
|
try {
|
|
179
311
|
await this.#reconciliation.finalizeOutcome("prompt", correlation, outcome, () => {
|
|
180
312
|
const current = this.#leases.get(key);
|
|
@@ -197,7 +329,7 @@ export class PromptDeadlineManager {
|
|
|
197
329
|
// accepted/in-flight invocation without an owner, retry, or deadline
|
|
198
330
|
// recovery path.
|
|
199
331
|
try {
|
|
200
|
-
this.#onExpired?.(correlation);
|
|
332
|
+
this.#onExpired?.(correlation, outcome);
|
|
201
333
|
} catch {}
|
|
202
334
|
this.#expiryRetries.delete(key);
|
|
203
335
|
this.clear(correlation);
|
|
@@ -3,7 +3,12 @@
|
|
|
3
3
|
* Provider error text is retained only in the local diagnostic log; wire and
|
|
4
4
|
* persisted reconciliation details expose a fixed redacted message.
|
|
5
5
|
*/
|
|
6
|
-
import type {
|
|
6
|
+
import type {
|
|
7
|
+
SdkPromptFailureCategory,
|
|
8
|
+
SdkPromptFailurePhase,
|
|
9
|
+
SdkPromptFailureRetryability,
|
|
10
|
+
SdkPromptTerminalOutcome,
|
|
11
|
+
} from "./prompt-status";
|
|
7
12
|
|
|
8
13
|
export const PROMPT_FAILURE_CODE_MAX = 64;
|
|
9
14
|
const LOCAL_FAILURE_LOG_MAX = 16_384;
|
|
@@ -79,6 +84,43 @@ export function promptFailureCategory(
|
|
|
79
84
|
return "unknown";
|
|
80
85
|
}
|
|
81
86
|
|
|
87
|
+
/**
|
|
88
|
+
* Whether the bounded category says an identical re-submission could still
|
|
89
|
+
* succeed. Read off the category alone, so it cannot drift from the sets above.
|
|
90
|
+
*
|
|
91
|
+
* `provider_transport` is the only transient class: every classifier in
|
|
92
|
+
* `PROVIDER_TRANSPORT_CODES` (and the 5xx range) describes the link to the
|
|
93
|
+
* provider failing, never a judgement about the request, so the same bytes may
|
|
94
|
+
* well succeed on a second attempt. That is exactly the class the shipped
|
|
95
|
+
* first-turn gate (`isStartupReadinessFailure`, issue #5574) already treats as
|
|
96
|
+
* re-submittable, so the wire signal and the internal gate stay in agreement.
|
|
97
|
+
*
|
|
98
|
+
* Everything else is terminal for this turn: `provider_rejected` is the provider
|
|
99
|
+
* judging this request (quota, refusal, 4xx) and re-sending it reproduces the
|
|
100
|
+
* rejection; `deadline` means the turn's budget is spent, which a re-submit does
|
|
101
|
+
* not restore; `agent_runtime` is a local fault that re-running the same prompt
|
|
102
|
+
* re-enters. `unknown` stays `unknown` — the module's standing contract is to
|
|
103
|
+
* preserve uncertain attribution rather than guess a recovery for it.
|
|
104
|
+
*
|
|
105
|
+
* This is advisory classification for the caller, not a retry gate: nothing in
|
|
106
|
+
* this repo's retry paths consults it.
|
|
107
|
+
*/
|
|
108
|
+
export function promptFailureRetryability(category: SdkPromptFailureCategory): SdkPromptFailureRetryability {
|
|
109
|
+
if (category === "provider_transport") return "transient";
|
|
110
|
+
if (category === "unknown") return "unknown";
|
|
111
|
+
return "terminal";
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Whether a value is a safe bounded classifier token — the same rule
|
|
116
|
+
* `sanitizePromptFailure` and `assistantFailureCode` apply before retaining one.
|
|
117
|
+
* Anything else is provider text rather than a classifier and must not be
|
|
118
|
+
* forwarded to a caller.
|
|
119
|
+
*/
|
|
120
|
+
export function isSafePromptFailureCode(value: unknown): value is string {
|
|
121
|
+
return typeof value === "string" && value.length <= PROMPT_FAILURE_CODE_MAX && /^[A-Za-z0-9._-]+$/.test(value);
|
|
122
|
+
}
|
|
123
|
+
|
|
82
124
|
/**
|
|
83
125
|
* Phase- and category-aware safe wording. A post-start failure is never
|
|
84
126
|
* described as a submission rejection; the wording says only what the bounded
|
package/src/sdk/prompt-status.ts
CHANGED
|
@@ -75,6 +75,14 @@ export type SdkPromptFailureCategory =
|
|
|
75
75
|
| "agent_runtime"
|
|
76
76
|
| "deadline"
|
|
77
77
|
| "unknown";
|
|
78
|
+
/**
|
|
79
|
+
* Whether the failure class says an identical re-submission could still succeed.
|
|
80
|
+
* Derived from `SdkPromptFailureCategory` alone (see `promptFailureRetryability`)
|
|
81
|
+
* so a consumer never has to re-implement the category matrix or parse a message.
|
|
82
|
+
* `unknown` is preserved rather than collapsed into `terminal`: an uncertain
|
|
83
|
+
* attribution is not evidence that the turn is unrecoverable.
|
|
84
|
+
*/
|
|
85
|
+
export type SdkPromptFailureRetryability = "transient" | "terminal" | "unknown";
|
|
78
86
|
export type SdkPromptTerminalOutcome =
|
|
79
87
|
| { kind: "stopped"; reason: SdkPromptStopReason; provenance: "agent" | "client_cancel" }
|
|
80
88
|
| {
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded wait for an in-flight dispatched tool call to reach its boundary
|
|
3
|
+
* before an expired prompt deadline force-terminates the run (#5637).
|
|
4
|
+
*
|
|
5
|
+
* Terminal fencing aborts the run's cancellation domain FIRST and only proves
|
|
6
|
+
* settlement afterwards (`RunResourceLedger.waitForSettlement` resolves once the
|
|
7
|
+
* run is sealed and its tracked `kind: "tool"` resources have settled), so a
|
|
8
|
+
* tool that was mid-write when the deadline expired observes the aborted signal
|
|
9
|
+
* DURING its write and leaves a torn artifact behind. Waiting for that call's
|
|
10
|
+
* own `tool_execution_end` — under a short, finite grace — turns the kill into a
|
|
11
|
+
* boundary abort. When the grace is exhausted the run is force-terminated
|
|
12
|
+
* exactly as before, and the fact that a tool was still executing is returned as
|
|
13
|
+
* structured evidence rather than dropped.
|
|
14
|
+
*
|
|
15
|
+
* Deliberately dependency-light and clock-injectable: the contended bus module
|
|
16
|
+
* takes only a call, and the behaviour is testable without a live transport.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Hard bound on how long deadline expiry will wait for an in-flight tool call to
|
|
21
|
+
* reach its boundary before force-terminating. This guards a real subprocess, so
|
|
22
|
+
* it is a real timer rather than the lease clock — and a parameter rather than a
|
|
23
|
+
* bare module constant, so a test may shorten it explicitly instead of a fake
|
|
24
|
+
* clock silently shortening it for production code too.
|
|
25
|
+
*/
|
|
26
|
+
export const TOOL_CALL_BOUNDARY_GRACE_MS = 5_000;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Re-check interval for the pending set while the grace runs.
|
|
30
|
+
*
|
|
31
|
+
* The authoritative source of "is a tool running?" is the run resource ledger,
|
|
32
|
+
* a SYNCHRONOUS snapshot with no completion signal of its own, so the wait has
|
|
33
|
+
* to look again rather than being told. `whenIdle` only wakes the check early
|
|
34
|
+
* when the event-derived view happens to drain first. Bounded by the grace, so
|
|
35
|
+
* this costs at most `graceMs / pollMs` array reads on the rare expiry-with-a-
|
|
36
|
+
* tool-running path and nothing at all on the idle path.
|
|
37
|
+
*/
|
|
38
|
+
export const TOOL_CALL_BOUNDARY_POLL_MS = 25;
|
|
39
|
+
|
|
40
|
+
export type ToolBoundaryOutcome = "idle" | "settled" | "forced";
|
|
41
|
+
|
|
42
|
+
export interface ToolBoundaryWaitResult {
|
|
43
|
+
outcome: ToolBoundaryOutcome;
|
|
44
|
+
waitedMs: number;
|
|
45
|
+
/**
|
|
46
|
+
* Non-empty ONLY for "forced": the dispatched tool calls still running when
|
|
47
|
+
* the grace expired. Ids only — never tool arguments, output or paths.
|
|
48
|
+
*/
|
|
49
|
+
pendingToolCallIds: string[];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Shared result for the common case of no dispatched tool running at expiry.
|
|
54
|
+
* Frozen because it is handed to every idle caller: the deadline path must stay
|
|
55
|
+
* byte-identical to its pre-#5637 behaviour, which includes allocating nothing
|
|
56
|
+
* and arming no timer.
|
|
57
|
+
*/
|
|
58
|
+
export const IDLE_TOOL_BOUNDARY_RESULT: ToolBoundaryWaitResult = Object.freeze({
|
|
59
|
+
outcome: "idle" as const,
|
|
60
|
+
waitedMs: 0,
|
|
61
|
+
pendingToolCallIds: Object.freeze([]) as unknown as string[],
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Wait for the pending dispatched tool calls to drain, bounded by `graceMs`.
|
|
66
|
+
*
|
|
67
|
+
* Never composed with an abort signal: at the only call site nothing has been
|
|
68
|
+
* aborted yet, and a signal that was already aborted would make this wait
|
|
69
|
+
* unreachable — which is precisely the mid-tool kill being fixed.
|
|
70
|
+
*/
|
|
71
|
+
export async function waitForToolCallBoundary(input: {
|
|
72
|
+
pending: () => readonly string[];
|
|
73
|
+
/**
|
|
74
|
+
* Resolves when the event-derived view of the pending set drains. A wake-up
|
|
75
|
+
* HINT only: `pending()` is re-read before the wait is allowed to settle,
|
|
76
|
+
* because the authoritative source may still hold a call this signal knows
|
|
77
|
+
* nothing about. Expected never to reject.
|
|
78
|
+
*/
|
|
79
|
+
whenIdle: () => Promise<void>;
|
|
80
|
+
graceMs?: number;
|
|
81
|
+
pollMs?: number;
|
|
82
|
+
now?: () => number;
|
|
83
|
+
}): Promise<ToolBoundaryWaitResult> {
|
|
84
|
+
const now = input.now ?? Date.now;
|
|
85
|
+
// Idle prompts pay nothing: no timer, no allocation, no extra microtask turn
|
|
86
|
+
// beyond the caller's own await.
|
|
87
|
+
if (input.pending().length === 0) return IDLE_TOOL_BOUNDARY_RESULT;
|
|
88
|
+
const graceMs = Math.max(0, input.graceMs ?? TOOL_CALL_BOUNDARY_GRACE_MS);
|
|
89
|
+
const pollMs = Math.max(1, input.pollMs ?? TOOL_CALL_BOUNDARY_POLL_MS);
|
|
90
|
+
const startedAt = now();
|
|
91
|
+
let graceTimer: ReturnType<typeof setTimeout> | undefined;
|
|
92
|
+
let pollTimer: ReturnType<typeof setInterval> | undefined;
|
|
93
|
+
try {
|
|
94
|
+
const settled = new Promise<"settled">(resolve => {
|
|
95
|
+
// `pending()` is the single arbiter of settlement; the idle signal and
|
|
96
|
+
// the poll only decide WHEN it is consulted.
|
|
97
|
+
const check = () => {
|
|
98
|
+
if (input.pending().length === 0) resolve("settled");
|
|
99
|
+
};
|
|
100
|
+
// The loser of the race is abandoned rather than cancelled, so a rejection
|
|
101
|
+
// from it must be swallowed here or it surfaces as an unhandled rejection
|
|
102
|
+
// and takes the host down. A rejected idle simply leaves the poll and the
|
|
103
|
+
// grace timer as the arbiters.
|
|
104
|
+
void input.whenIdle().then(check, () => {});
|
|
105
|
+
pollTimer = setInterval(check, pollMs);
|
|
106
|
+
pollTimer?.unref?.();
|
|
107
|
+
});
|
|
108
|
+
const forced = new Promise<"forced">(resolve => {
|
|
109
|
+
graceTimer = setTimeout(() => resolve("forced"), graceMs);
|
|
110
|
+
// Never hold the process open for a tool that will not come back.
|
|
111
|
+
graceTimer?.unref?.();
|
|
112
|
+
});
|
|
113
|
+
const outcome = await Promise.race([settled, forced]);
|
|
114
|
+
return outcome === "settled"
|
|
115
|
+
? { outcome: "settled", waitedMs: now() - startedAt, pendingToolCallIds: [] }
|
|
116
|
+
: { outcome: "forced", waitedMs: now() - startedAt, pendingToolCallIds: [...input.pending()] };
|
|
117
|
+
} finally {
|
|
118
|
+
clearTimeout(graceTimer);
|
|
119
|
+
clearInterval(pollTimer);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -2144,6 +2144,17 @@
|
|
|
2144
2144
|
"packages/coding-agent/test/sdk-operation-inventory.test.ts"
|
|
2145
2145
|
]
|
|
2146
2146
|
},
|
|
2147
|
+
{
|
|
2148
|
+
"sourceId": "slash_command:mcp",
|
|
2149
|
+
"sourceFile": "packages/coding-agent/src/slash-commands/builtin-registry.ts",
|
|
2150
|
+
"sourceKind": "slash_command",
|
|
2151
|
+
"decision": "exclude",
|
|
2152
|
+
"rationale": "interactive exact-config MCP status and session control command; terminal-only handleTui surface is not dispatched through ACP or the public SDK",
|
|
2153
|
+
"exclusionMetadata": {
|
|
2154
|
+
"adapterMappings": "not_applicable",
|
|
2155
|
+
"testIds": "not_applicable"
|
|
2156
|
+
}
|
|
2157
|
+
},
|
|
2147
2158
|
{
|
|
2148
2159
|
"sourceId": "slash_command:agents",
|
|
2149
2160
|
"sourceFile": "packages/coding-agent/src/slash-commands/builtin-registry.ts",
|
|
@@ -2188,6 +2199,24 @@
|
|
|
2188
2199
|
"testIds": "not_applicable"
|
|
2189
2200
|
}
|
|
2190
2201
|
},
|
|
2202
|
+
{
|
|
2203
|
+
"sourceId": "slash_command:fork",
|
|
2204
|
+
"sourceFile": "packages/coding-agent/src/slash-commands/builtin-registry.ts",
|
|
2205
|
+
"sourceKind": "slash_command",
|
|
2206
|
+
"decision": "include",
|
|
2207
|
+
"sdkId": "session.branch",
|
|
2208
|
+
"adapterMappings": {
|
|
2209
|
+
"telegram": "prohibited",
|
|
2210
|
+
"discord": "prohibited",
|
|
2211
|
+
"slack": "prohibited",
|
|
2212
|
+
"mcp": "prohibited",
|
|
2213
|
+
"acp": "prohibited",
|
|
2214
|
+
"daemonCli": "prohibited"
|
|
2215
|
+
},
|
|
2216
|
+
"testIds": [
|
|
2217
|
+
"packages/coding-agent/test/sdk-operation-inventory.test.ts"
|
|
2218
|
+
]
|
|
2219
|
+
},
|
|
2191
2220
|
{
|
|
2192
2221
|
"sourceId": "slash_command:provider",
|
|
2193
2222
|
"sourceFile": "packages/coding-agent/src/slash-commands/builtin-registry.ts",
|
|
@@ -3202,6 +3231,28 @@
|
|
|
3202
3231
|
"packages/coding-agent/test/sdk-operation-inventory.test.ts"
|
|
3203
3232
|
]
|
|
3204
3233
|
},
|
|
3234
|
+
{
|
|
3235
|
+
"sourceId": "agent_session:getExactMcpStatusSnapshot",
|
|
3236
|
+
"sourceFile": "packages/coding-agent/src/session/agent-session.ts",
|
|
3237
|
+
"sourceKind": "agent_session",
|
|
3238
|
+
"decision": "exclude",
|
|
3239
|
+
"rationale": "internal exact-config MCP status accessor used only by the terminal-only /mcp command; its capability is granted only to root interactive --mcp-config sessions, not a public SDK query",
|
|
3240
|
+
"exclusionMetadata": {
|
|
3241
|
+
"adapterMappings": "not_applicable",
|
|
3242
|
+
"testIds": "not_applicable"
|
|
3243
|
+
}
|
|
3244
|
+
},
|
|
3245
|
+
{
|
|
3246
|
+
"sourceId": "agent_session:controlExactMcpServer",
|
|
3247
|
+
"sourceFile": "packages/coding-agent/src/session/agent-session.ts",
|
|
3248
|
+
"sourceKind": "agent_session",
|
|
3249
|
+
"decision": "exclude",
|
|
3250
|
+
"rationale": "internal session-local exact-config MCP suspend/resume/reconnect mutation used only by the terminal-only /mcp command; runtime suppression is not persistent user authority or a public SDK control",
|
|
3251
|
+
"exclusionMetadata": {
|
|
3252
|
+
"adapterMappings": "not_applicable",
|
|
3253
|
+
"testIds": "not_applicable"
|
|
3254
|
+
}
|
|
3255
|
+
},
|
|
3205
3256
|
{
|
|
3206
3257
|
"sourceId": "agent_session:getSelectedMCPToolNames",
|
|
3207
3258
|
"sourceFile": "packages/coding-agent/src/session/agent-session.ts",
|
|
@@ -3891,6 +3942,17 @@
|
|
|
3891
3942
|
"packages/coding-agent/test/sdk-operation-inventory.test.ts"
|
|
3892
3943
|
]
|
|
3893
3944
|
},
|
|
3945
|
+
{
|
|
3946
|
+
"sourceId": "agent_session:submitUserMessage",
|
|
3947
|
+
"sourceFile": "packages/coding-agent/src/session/agent-session.ts",
|
|
3948
|
+
"sourceKind": "agent_session",
|
|
3949
|
+
"decision": "exclude",
|
|
3950
|
+
"rationale": "public in-process embedder lifecycle API; direct handle surface, not an SDK transport operation",
|
|
3951
|
+
"exclusionMetadata": {
|
|
3952
|
+
"adapterMappings": "not_applicable",
|
|
3953
|
+
"testIds": "not_applicable"
|
|
3954
|
+
}
|
|
3955
|
+
},
|
|
3894
3956
|
{
|
|
3895
3957
|
"sourceId": "agent_session:clearQueue",
|
|
3896
3958
|
"sourceFile": "packages/coding-agent/src/session/agent-session.ts",
|
|
@@ -4182,6 +4244,17 @@
|
|
|
4182
4244
|
"testIds": "not_applicable"
|
|
4183
4245
|
}
|
|
4184
4246
|
},
|
|
4247
|
+
{
|
|
4248
|
+
"sourceId": "agent_session:pendingToolExecutions",
|
|
4249
|
+
"sourceFile": "packages/coding-agent/src/session/agent-session.ts",
|
|
4250
|
+
"sourceKind": "agent_session",
|
|
4251
|
+
"decision": "exclude",
|
|
4252
|
+
"rationale": "internal read-only run-resource-ledger view, threaded via terminalAbortSeams so the prompt deadline can find a tool-call boundary; not a user-facing SDK control seam",
|
|
4253
|
+
"exclusionMetadata": {
|
|
4254
|
+
"adapterMappings": "not_applicable",
|
|
4255
|
+
"testIds": "not_applicable"
|
|
4256
|
+
}
|
|
4257
|
+
},
|
|
4185
4258
|
{
|
|
4186
4259
|
"sourceId": "agent_session:abortPromptAndWait",
|
|
4187
4260
|
"sourceFile": "packages/coding-agent/src/session/agent-session.ts",
|
|
@@ -4466,6 +4539,39 @@
|
|
|
4466
4539
|
"testIds": "not_applicable"
|
|
4467
4540
|
}
|
|
4468
4541
|
},
|
|
4542
|
+
{
|
|
4543
|
+
"sourceId": "agent_session:installRecoveredDefaultFallbackChain",
|
|
4544
|
+
"sourceFile": "packages/coding-agent/src/session/agent-session.ts",
|
|
4545
|
+
"sourceKind": "agent_session",
|
|
4546
|
+
"decision": "exclude",
|
|
4547
|
+
"rationale": "internal recovered fallback-chain installation during session startup, not a user-facing SDK control seam",
|
|
4548
|
+
"exclusionMetadata": {
|
|
4549
|
+
"adapterMappings": "not_applicable",
|
|
4550
|
+
"testIds": "not_applicable"
|
|
4551
|
+
}
|
|
4552
|
+
},
|
|
4553
|
+
{
|
|
4554
|
+
"sourceId": "agent_session:markStartupRecoveryBindingsRequired",
|
|
4555
|
+
"sourceFile": "packages/coding-agent/src/session/agent-session.ts",
|
|
4556
|
+
"sourceKind": "agent_session",
|
|
4557
|
+
"decision": "exclude",
|
|
4558
|
+
"rationale": "internal startup recovery binding marker, not a user-facing SDK control seam",
|
|
4559
|
+
"exclusionMetadata": {
|
|
4560
|
+
"adapterMappings": "not_applicable",
|
|
4561
|
+
"testIds": "not_applicable"
|
|
4562
|
+
}
|
|
4563
|
+
},
|
|
4564
|
+
{
|
|
4565
|
+
"sourceId": "agent_session:hasRecoveredDefaultFallbackChain",
|
|
4566
|
+
"sourceFile": "packages/coding-agent/src/session/agent-session.ts",
|
|
4567
|
+
"sourceKind": "agent_session",
|
|
4568
|
+
"decision": "exclude",
|
|
4569
|
+
"rationale": "internal recovered fallback-chain state query, not a user-facing SDK control seam",
|
|
4570
|
+
"exclusionMetadata": {
|
|
4571
|
+
"adapterMappings": "not_applicable",
|
|
4572
|
+
"testIds": "not_applicable"
|
|
4573
|
+
}
|
|
4574
|
+
},
|
|
4469
4575
|
{
|
|
4470
4576
|
"sourceId": "agent_session:seedDefaultFallbackResolution",
|
|
4471
4577
|
"sourceFile": "packages/coding-agent/src/session/agent-session.ts",
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retention-gap concessions are durable stream facts, but a Router can observe
|
|
3
|
+
* many streams over its lifetime. Keep the warning memo bounded while retaining
|
|
4
|
+
* enough recent coordinates to suppress reconnect/poll duplicates.
|
|
5
|
+
*/
|
|
6
|
+
export const REPLAY_CONCESSION_CACHE_LIMIT = 1_024;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Records one stream/gap coordinate in an LRU memo.
|
|
10
|
+
*
|
|
11
|
+
* `undefined` means this is the first observation; a number is the duplicate
|
|
12
|
+
* count after the coordinate was already observed.
|
|
13
|
+
*/
|
|
14
|
+
export function rememberReplayRetentionGap(cache: Map<string, number>, key: string): number | undefined {
|
|
15
|
+
const previous = cache.get(key);
|
|
16
|
+
if (previous !== undefined) {
|
|
17
|
+
cache.delete(key);
|
|
18
|
+
cache.set(key, previous + 1);
|
|
19
|
+
return previous + 1;
|
|
20
|
+
}
|
|
21
|
+
cache.set(key, 0);
|
|
22
|
+
if (cache.size > REPLAY_CONCESSION_CACHE_LIMIT) {
|
|
23
|
+
const oldest = cache.keys().next().value;
|
|
24
|
+
if (oldest !== undefined) cache.delete(oldest);
|
|
25
|
+
}
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
readSdkSessionEndpoint,
|
|
26
26
|
type SdkSessionEndpoint,
|
|
27
27
|
} from "../client/discovery";
|
|
28
|
+
import { SESSION_HOST_OBSERVER_CAPABILITY, TURN_STREAM_CAPABILITY } from "../host/host";
|
|
28
29
|
import {
|
|
29
30
|
type ActivatedPreparedSession,
|
|
30
31
|
type PreparedSessionActivationClient,
|
|
@@ -33,6 +34,7 @@ import {
|
|
|
33
34
|
} from "../session-activation";
|
|
34
35
|
import type { SessionBindingAuthority } from "../session-authority";
|
|
35
36
|
import { ACP_SESSION_RECONNECT, SESSION_REQUEST_TIMEOUT_MS } from "../session-reconnect";
|
|
37
|
+
import { rememberReplayRetentionGap } from "./replay-retention-gap-cache";
|
|
36
38
|
|
|
37
39
|
export type { SessionBindingAuthority, SessionEndpointAuthority } from "../session-authority";
|
|
38
40
|
|
|
@@ -285,6 +287,8 @@ export interface SessionRouterOptions {
|
|
|
285
287
|
agentDir: string;
|
|
286
288
|
/** Limits attachment to exact ids selected by a Broker-scoped operation. */
|
|
287
289
|
sessionIds?: readonly string[];
|
|
290
|
+
/** Marks default SDK clients as notification-only observers; demanding by default. */
|
|
291
|
+
observer?: boolean;
|
|
288
292
|
deps?: SessionRouterDeps;
|
|
289
293
|
/** Runtime-specific identity validation; Router supplies a conservative fallback. */
|
|
290
294
|
correlateFrame?: SessionRouterFrameCorrelator;
|
|
@@ -611,6 +615,7 @@ type AdoptedSession = {
|
|
|
611
615
|
export class SessionRouter {
|
|
612
616
|
readonly #agentDir: string;
|
|
613
617
|
readonly #sessionIds: ReadonlySet<string> | undefined;
|
|
618
|
+
readonly #observer: boolean;
|
|
614
619
|
readonly #deps: SessionRouterDeps;
|
|
615
620
|
readonly #correlateFrame: SessionRouterFrameCorrelator;
|
|
616
621
|
readonly #index: SessionIndex;
|
|
@@ -627,6 +632,8 @@ export class SessionRouter {
|
|
|
627
632
|
>();
|
|
628
633
|
readonly #reviving = new Set<string>();
|
|
629
634
|
readonly #notificationReceipts = new Map<string, NotificationCleanupReceipt>();
|
|
635
|
+
/** Recent retention-gap coordinates already reported at warning level. */
|
|
636
|
+
readonly #concededReplayGaps = new Map<string, number>();
|
|
630
637
|
#stopTimer: (() => void) | undefined;
|
|
631
638
|
#reconcileTail: Promise<void> = Promise.resolve();
|
|
632
639
|
#reconcilePending: { readonly runEpoch: number; force: boolean } | undefined;
|
|
@@ -650,6 +657,7 @@ export class SessionRouter {
|
|
|
650
657
|
constructor(options: SessionRouterOptions) {
|
|
651
658
|
this.#agentDir = options.agentDir;
|
|
652
659
|
this.#sessionIds = options.sessionIds === undefined ? undefined : new Set(options.sessionIds);
|
|
660
|
+
this.#observer = options.observer === true;
|
|
653
661
|
this.#deps = options.deps ?? {};
|
|
654
662
|
this.#correlateFrame = options.correlateFrame ?? fallbackCorrelation;
|
|
655
663
|
this.#index = this.#deps.createIndex?.(options.agentDir) ?? new DefaultSessionIndex(options.agentDir);
|
|
@@ -1516,7 +1524,10 @@ export class SessionRouter {
|
|
|
1516
1524
|
endpointMtimeMs,
|
|
1517
1525
|
});
|
|
1518
1526
|
} else {
|
|
1519
|
-
const defaultClient = new SdkClient(endpoint.url, endpoint.token, {
|
|
1527
|
+
const defaultClient = new SdkClient(endpoint.url, endpoint.token, {
|
|
1528
|
+
...ACP_SESSION_RECONNECT,
|
|
1529
|
+
...(this.#observer ? { capabilities: [SESSION_HOST_OBSERVER_CAPABILITY, TURN_STREAM_CAPABILITY] } : {}),
|
|
1530
|
+
});
|
|
1520
1531
|
transport = defaultClient;
|
|
1521
1532
|
connection = defaultClient.connect().then(() => defaultClient);
|
|
1522
1533
|
}
|
|
@@ -2203,6 +2214,24 @@ export class SessionRouter {
|
|
|
2203
2214
|
`chat daemon replay barrier failed (${reason}); rebuilding session ${attached.sessionId} at generation ${attached.generation} from seq ${attached.cursor.seq}.`,
|
|
2204
2215
|
);
|
|
2205
2216
|
}
|
|
2217
|
+
|
|
2218
|
+
#logReplayRetentionGap(
|
|
2219
|
+
attached: AttachedSession,
|
|
2220
|
+
gap: Readonly<{ fromSeq: number; toSeq: number }>,
|
|
2221
|
+
recoveredNote: string,
|
|
2222
|
+
): void {
|
|
2223
|
+
const key = JSON.stringify([attached.sessionId, attached.generation, gap.fromSeq, gap.toSeq]);
|
|
2224
|
+
const repeat = rememberReplayRetentionGap(this.#concededReplayGaps, key);
|
|
2225
|
+
if (repeat !== undefined) {
|
|
2226
|
+
logger.debug(
|
|
2227
|
+
`chat daemon replay retention gap repeated (sequences ${gap.fromSeq}-${gap.toSeq}); suppressed warning ${repeat} for session ${attached.sessionId} generation ${attached.generation}.`,
|
|
2228
|
+
);
|
|
2229
|
+
return;
|
|
2230
|
+
}
|
|
2231
|
+
logger.warn(
|
|
2232
|
+
`chat daemon replay conceded a retention gap (sequences ${gap.fromSeq}-${gap.toSeq} are gone from the host${recoveredNote}); session ${attached.sessionId} generation ${attached.generation} resumes at seq ${gap.toSeq + 1}.`,
|
|
2233
|
+
);
|
|
2234
|
+
}
|
|
2206
2235
|
#failDelivery(attached: AttachedSession, seq: number, error: unknown): void {
|
|
2207
2236
|
const previous = this.#undelivered.get(attached.sessionId);
|
|
2208
2237
|
const attempts = previous?.generation === attached.generation && previous.seq === seq ? previous.attempts + 1 : 1;
|
|
@@ -2503,9 +2532,7 @@ export class SessionRouter {
|
|
|
2503
2532
|
held.splice(0, held.length, ...carried);
|
|
2504
2533
|
const recoveredNote =
|
|
2505
2534
|
recovered.length > 0 ? `, ${recovered.length} of them recovered from live delivery` : "";
|
|
2506
|
-
|
|
2507
|
-
`chat daemon replay conceded a retention gap (sequences ${gap.fromSeq}-${gap.toSeq} are gone from the host${recoveredNote}); session ${attached.sessionId} generation ${attached.generation} resumes at seq ${gap.toSeq + 1}.`,
|
|
2508
|
-
);
|
|
2535
|
+
this.#logReplayRetentionGap(attached, gap, recoveredNote);
|
|
2509
2536
|
for (const entry of recovered) this.#rememberRecoveredFrame(attached, entry.seq, entry.frame);
|
|
2510
2537
|
if (!(await this.#deliverRecoveredFrames(attached))) return;
|
|
2511
2538
|
if (gap.toSeq > attached.cursor.seq) attached.cursor.seq = gap.toSeq;
|