@namzu/sdk 49.0.0 → 50.0.0
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 +507 -0
- package/README.md +137 -125
- package/dist/agents/QueryAgent.d.ts.map +1 -1
- package/dist/agents/QueryAgent.js +1 -0
- package/dist/agents/QueryAgent.js.map +1 -1
- package/dist/agents/examples/SupervisorAgent.d.ts.map +1 -1
- package/dist/agents/examples/SupervisorAgent.js +1 -0
- package/dist/agents/examples/SupervisorAgent.js.map +1 -1
- package/dist/agents/runAgent.d.ts +2 -0
- package/dist/agents/runAgent.d.ts.map +1 -1
- package/dist/agents/runAgent.js +1 -0
- package/dist/agents/runAgent.js.map +1 -1
- package/dist/authorization/shell-lexer.d.ts.map +1 -1
- package/dist/authorization/shell-lexer.js +16 -1
- package/dist/authorization/shell-lexer.js.map +1 -1
- package/dist/bridge/acp/permission.d.ts +8 -2
- package/dist/bridge/acp/permission.d.ts.map +1 -1
- package/dist/bridge/acp/permission.js +1 -0
- package/dist/bridge/acp/permission.js.map +1 -1
- package/dist/bridge/acp/server.d.ts +25 -1
- package/dist/bridge/acp/server.d.ts.map +1 -1
- package/dist/bridge/acp/server.js +205 -21
- package/dist/bridge/acp/server.js.map +1 -1
- package/dist/bridge/acp/tasks.d.ts +5 -0
- package/dist/bridge/acp/tasks.d.ts.map +1 -0
- package/dist/bridge/acp/tasks.js +19 -0
- package/dist/bridge/acp/tasks.js.map +1 -0
- package/dist/bridge/acp/update.d.ts.map +1 -1
- package/dist/bridge/acp/update.js +148 -13
- package/dist/bridge/acp/update.js.map +1 -1
- package/dist/config/runtime.d.ts +31 -31
- package/dist/connector/mcp/adapter.d.ts.map +1 -1
- package/dist/connector/mcp/adapter.js +11 -4
- package/dist/connector/mcp/adapter.js.map +1 -1
- package/dist/connector/mcp/client.d.ts.map +1 -1
- package/dist/connector/mcp/client.js +6 -3
- package/dist/connector/mcp/client.js.map +1 -1
- package/dist/constants/acp/index.d.ts +3 -0
- package/dist/constants/acp/index.d.ts.map +1 -1
- package/dist/constants/acp/index.js +3 -0
- package/dist/constants/acp/index.js.map +1 -1
- package/dist/contracts/a2a.d.ts +80 -80
- package/dist/contracts/schemas.d.ts +2 -2
- package/dist/contracts/session/schemas.d.ts +10 -10
- package/dist/manager/agent/lifecycle.d.ts +11 -0
- package/dist/manager/agent/lifecycle.d.ts.map +1 -1
- package/dist/manager/agent/lifecycle.js +178 -3
- package/dist/manager/agent/lifecycle.js.map +1 -1
- package/dist/manager/plan/lifecycle.d.ts +7 -8
- package/dist/manager/plan/lifecycle.d.ts.map +1 -1
- package/dist/manager/plan/lifecycle.js +7 -8
- package/dist/manager/plan/lifecycle.js.map +1 -1
- package/dist/manager/resident/consumption.d.ts +8 -8
- package/dist/manager/resident/learning-cycle.d.ts +2 -2
- package/dist/manager/resident/learning-observation.d.ts +12 -12
- package/dist/manager/resident/learning.d.ts +82 -82
- package/dist/manager/resident/outbox.d.ts +8 -8
- package/dist/manager/resident/proposal.d.ts +2 -2
- package/dist/manager/resident/store.d.ts +10 -10
- package/dist/manager/session/attribution.d.ts +1 -0
- package/dist/manager/session/attribution.d.ts.map +1 -1
- package/dist/manager/session/attribution.js +9 -1
- package/dist/manager/session/attribution.js.map +1 -1
- package/dist/manager/session/streamed-message-identity.d.ts +6 -0
- package/dist/manager/session/streamed-message-identity.d.ts.map +1 -0
- package/dist/manager/session/streamed-message-identity.js +14 -0
- package/dist/manager/session/streamed-message-identity.js.map +1 -0
- package/dist/manager/session/turn-recorder.d.ts.map +1 -1
- package/dist/manager/session/turn-recorder.js +4 -3
- package/dist/manager/session/turn-recorder.js.map +1 -1
- package/dist/pals/activity/causality.d.ts +23 -0
- package/dist/pals/activity/causality.d.ts.map +1 -0
- package/dist/pals/activity/causality.js +205 -0
- package/dist/pals/activity/causality.js.map +1 -0
- package/dist/pals/activity/projection.d.ts +5 -0
- package/dist/pals/activity/projection.d.ts.map +1 -0
- package/dist/pals/activity/projection.js +79 -0
- package/dist/pals/activity/projection.js.map +1 -0
- package/dist/pals/activity/source.d.ts +16 -0
- package/dist/pals/activity/source.d.ts.map +1 -0
- package/dist/pals/activity/source.js +235 -0
- package/dist/pals/activity/source.js.map +1 -0
- package/dist/pals/activity/subscription-policy.d.ts +38 -0
- package/dist/pals/activity/subscription-policy.d.ts.map +1 -0
- package/dist/pals/activity/subscription-policy.js +183 -0
- package/dist/pals/activity/subscription-policy.js.map +1 -0
- package/dist/pals/activity/subscription-schema.d.ts +353 -0
- package/dist/pals/activity/subscription-schema.d.ts.map +1 -0
- package/dist/pals/activity/subscription-schema.js +24 -0
- package/dist/pals/activity/subscription-schema.js.map +1 -0
- package/dist/pals/activity/subscription-store.d.ts +25 -0
- package/dist/pals/activity/subscription-store.d.ts.map +1 -0
- package/dist/pals/activity/subscription-store.js +152 -0
- package/dist/pals/activity/subscription-store.js.map +1 -0
- package/dist/pals/activity/subscription-types.d.ts +42 -0
- package/dist/pals/activity/subscription-types.d.ts.map +1 -0
- package/dist/pals/activity/subscription-types.js +2 -0
- package/dist/pals/activity/subscription-types.js.map +1 -0
- package/dist/pals/activity/subscriptions.d.ts +32 -0
- package/dist/pals/activity/subscriptions.d.ts.map +1 -0
- package/dist/pals/activity/subscriptions.js +151 -0
- package/dist/pals/activity/subscriptions.js.map +1 -0
- package/dist/pals/activity/types.d.ts +77 -0
- package/dist/pals/activity/types.d.ts.map +1 -0
- package/dist/pals/activity/types.js +2 -0
- package/dist/pals/activity/types.js.map +1 -0
- package/dist/pals/channels/ingress.d.ts +9 -0
- package/dist/pals/channels/ingress.d.ts.map +1 -0
- package/dist/pals/channels/ingress.js +131 -0
- package/dist/pals/channels/ingress.js.map +1 -0
- package/dist/pals/channels/routes.d.ts +20 -0
- package/dist/pals/channels/routes.d.ts.map +1 -0
- package/dist/pals/channels/routes.js +111 -0
- package/dist/pals/channels/routes.js.map +1 -0
- package/dist/pals/channels/routing.d.ts +37 -0
- package/dist/pals/channels/routing.d.ts.map +1 -0
- package/dist/pals/channels/routing.js +150 -0
- package/dist/pals/channels/routing.js.map +1 -0
- package/dist/pals/channels/schema.d.ts +234 -0
- package/dist/pals/channels/schema.d.ts.map +1 -0
- package/dist/pals/channels/schema.js +94 -0
- package/dist/pals/channels/schema.js.map +1 -0
- package/dist/pals/channels/types.d.ts +115 -0
- package/dist/pals/channels/types.d.ts.map +1 -0
- package/dist/pals/channels/types.js +2 -0
- package/dist/pals/channels/types.js.map +1 -0
- package/dist/pals/communication/broker.d.ts +8 -0
- package/dist/pals/communication/broker.d.ts.map +1 -0
- package/dist/pals/communication/broker.js +121 -0
- package/dist/pals/communication/broker.js.map +1 -0
- package/dist/pals/communication/dispatch.d.ts +4 -0
- package/dist/pals/communication/dispatch.d.ts.map +1 -0
- package/dist/pals/communication/dispatch.js +57 -0
- package/dist/pals/communication/dispatch.js.map +1 -0
- package/dist/pals/communication/inbound.d.ts +9 -0
- package/dist/pals/communication/inbound.d.ts.map +1 -0
- package/dist/pals/communication/inbound.js +155 -0
- package/dist/pals/communication/inbound.js.map +1 -0
- package/dist/pals/communication/ingress-dispatch.d.ts +5 -0
- package/dist/pals/communication/ingress-dispatch.d.ts.map +1 -0
- package/dist/pals/communication/ingress-dispatch.js +51 -0
- package/dist/pals/communication/ingress-dispatch.js.map +1 -0
- package/dist/pals/communication/ingress-inbound.d.ts +9 -0
- package/dist/pals/communication/ingress-inbound.d.ts.map +1 -0
- package/dist/pals/communication/ingress-inbound.js +222 -0
- package/dist/pals/communication/ingress-inbound.js.map +1 -0
- package/dist/pals/communication/ingress-schema.d.ts +7829 -0
- package/dist/pals/communication/ingress-schema.d.ts.map +1 -0
- package/dist/pals/communication/ingress-schema.js +479 -0
- package/dist/pals/communication/ingress-schema.js.map +1 -0
- package/dist/pals/communication/ingress-types.d.ts +187 -0
- package/dist/pals/communication/ingress-types.d.ts.map +1 -0
- package/dist/pals/communication/ingress-types.js +73 -0
- package/dist/pals/communication/ingress-types.js.map +1 -0
- package/dist/pals/communication/operator.d.ts +75 -0
- package/dist/pals/communication/operator.d.ts.map +1 -0
- package/dist/pals/communication/operator.js +217 -0
- package/dist/pals/communication/operator.js.map +1 -0
- package/dist/pals/communication/policy.d.ts +41 -0
- package/dist/pals/communication/policy.d.ts.map +1 -0
- package/dist/pals/communication/policy.js +138 -0
- package/dist/pals/communication/policy.js.map +1 -0
- package/dist/pals/communication/schema.d.ts +2000 -0
- package/dist/pals/communication/schema.d.ts.map +1 -0
- package/dist/pals/communication/schema.js +170 -0
- package/dist/pals/communication/schema.js.map +1 -0
- package/dist/pals/communication/store.d.ts +61 -0
- package/dist/pals/communication/store.d.ts.map +1 -0
- package/dist/pals/communication/store.js +450 -0
- package/dist/pals/communication/store.js.map +1 -0
- package/dist/pals/communication/tools.d.ts +23 -0
- package/dist/pals/communication/tools.d.ts.map +1 -0
- package/dist/pals/communication/tools.js +107 -0
- package/dist/pals/communication/tools.js.map +1 -0
- package/dist/pals/communication/types.d.ts +168 -0
- package/dist/pals/communication/types.d.ts.map +1 -0
- package/dist/pals/communication/types.js +24 -0
- package/dist/pals/communication/types.js.map +1 -0
- package/dist/pals/communication/verify.d.ts +22 -0
- package/dist/pals/communication/verify.d.ts.map +1 -0
- package/dist/pals/communication/verify.js +142 -0
- package/dist/pals/communication/verify.js.map +1 -0
- package/dist/pals/lifecycle.d.ts +37 -0
- package/dist/pals/lifecycle.d.ts.map +1 -0
- package/dist/pals/lifecycle.js +22 -0
- package/dist/pals/lifecycle.js.map +1 -0
- package/dist/pals/prompt.d.ts +30 -0
- package/dist/pals/prompt.d.ts.map +1 -0
- package/dist/pals/prompt.js +65 -0
- package/dist/pals/prompt.js.map +1 -0
- package/dist/pals/reference-images.d.ts +44 -0
- package/dist/pals/reference-images.d.ts.map +1 -0
- package/dist/pals/reference-images.js +248 -0
- package/dist/pals/reference-images.js.map +1 -0
- package/dist/pals/runtime.d.ts +46 -0
- package/dist/pals/runtime.d.ts.map +1 -0
- package/dist/pals/runtime.js +624 -0
- package/dist/pals/runtime.js.map +1 -0
- package/dist/pals/store.d.ts +26 -0
- package/dist/pals/store.d.ts.map +1 -0
- package/dist/pals/store.js +334 -0
- package/dist/pals/store.js.map +1 -0
- package/dist/pals/types.d.ts +145 -0
- package/dist/pals/types.d.ts.map +1 -0
- package/dist/pals/types.js +2 -0
- package/dist/pals/types.js.map +1 -0
- package/dist/peers/envelope.js +1 -1
- package/dist/peers/envelope.js.map +1 -1
- package/dist/peers/protocol.d.ts +83 -83
- package/dist/peers/record.d.ts +10 -10
- package/dist/plugin/shell-hook.d.ts.map +1 -1
- package/dist/plugin/shell-hook.js +7 -2
- package/dist/plugin/shell-hook.js.map +1 -1
- package/dist/process/kill-tree.d.ts.map +1 -1
- package/dist/process/kill-tree.js +9 -1
- package/dist/process/kill-tree.js.map +1 -1
- package/dist/provider/errors.d.ts +19 -0
- package/dist/provider/errors.d.ts.map +1 -1
- package/dist/provider/errors.js +123 -2
- package/dist/provider/errors.js.map +1 -1
- package/dist/public-runtime.d.ts +41 -13
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +35 -7
- package/dist/public-runtime.js.map +1 -1
- package/dist/public-tools.d.ts +8 -3
- package/dist/public-tools.d.ts.map +1 -1
- package/dist/public-tools.js +8 -3
- package/dist/public-tools.js.map +1 -1
- package/dist/public-types.d.ts +27 -7
- package/dist/public-types.d.ts.map +1 -1
- package/dist/registry/tool/presentation.d.ts +1 -0
- package/dist/registry/tool/presentation.d.ts.map +1 -1
- package/dist/registry/tool/presentation.js +9 -7
- package/dist/registry/tool/presentation.js.map +1 -1
- package/dist/runtime/harness-session/index.d.ts +5 -0
- package/dist/runtime/harness-session/index.d.ts.map +1 -0
- package/dist/runtime/harness-session/index.js +928 -0
- package/dist/runtime/harness-session/index.js.map +1 -0
- package/dist/runtime/harness-session/journal.d.ts +37 -0
- package/dist/runtime/harness-session/journal.d.ts.map +1 -0
- package/dist/runtime/harness-session/journal.js +177 -0
- package/dist/runtime/harness-session/journal.js.map +1 -0
- package/dist/runtime/harness-session/saved-view.d.ts +8 -0
- package/dist/runtime/harness-session/saved-view.d.ts.map +1 -0
- package/dist/runtime/harness-session/saved-view.js +112 -0
- package/dist/runtime/harness-session/saved-view.js.map +1 -0
- package/dist/runtime/jobs/awaited-jobs.d.ts +2 -1
- package/dist/runtime/jobs/awaited-jobs.d.ts.map +1 -1
- package/dist/runtime/jobs/awaited-jobs.js +2 -1
- package/dist/runtime/jobs/awaited-jobs.js.map +1 -1
- package/dist/runtime/jobs/registry.d.ts +56 -1
- package/dist/runtime/jobs/registry.d.ts.map +1 -1
- package/dist/runtime/jobs/registry.js +351 -34
- package/dist/runtime/jobs/registry.js.map +1 -1
- package/dist/runtime/query/abandon-turn.d.ts +12 -1
- package/dist/runtime/query/abandon-turn.d.ts.map +1 -1
- package/dist/runtime/query/abandon-turn.js +3 -1
- package/dist/runtime/query/abandon-turn.js.map +1 -1
- package/dist/runtime/query/checkpoint.d.ts +4 -0
- package/dist/runtime/query/checkpoint.d.ts.map +1 -1
- package/dist/runtime/query/checkpoint.js +10 -0
- package/dist/runtime/query/checkpoint.js.map +1 -1
- package/dist/runtime/query/durable-inbound.d.ts +5 -0
- package/dist/runtime/query/durable-inbound.d.ts.map +1 -0
- package/dist/runtime/query/durable-inbound.js +89 -0
- package/dist/runtime/query/durable-inbound.js.map +1 -0
- package/dist/runtime/query/events.d.ts +4 -0
- package/dist/runtime/query/events.d.ts.map +1 -1
- package/dist/runtime/query/events.js +22 -5
- package/dist/runtime/query/events.js.map +1 -1
- package/dist/runtime/query/executor/tool-call-admission.d.ts +5 -1
- package/dist/runtime/query/executor/tool-call-admission.d.ts.map +1 -1
- package/dist/runtime/query/executor/tool-call-admission.js +85 -13
- package/dist/runtime/query/executor/tool-call-admission.js.map +1 -1
- package/dist/runtime/query/executor.d.ts +41 -18
- package/dist/runtime/query/executor.d.ts.map +1 -1
- package/dist/runtime/query/executor.js +227 -114
- package/dist/runtime/query/executor.js.map +1 -1
- package/dist/runtime/query/index.d.ts +3 -0
- package/dist/runtime/query/index.d.ts.map +1 -1
- package/dist/runtime/query/index.js +21 -4
- package/dist/runtime/query/index.js.map +1 -1
- package/dist/runtime/query/iteration/index.d.ts +18 -6
- package/dist/runtime/query/iteration/index.d.ts.map +1 -1
- package/dist/runtime/query/iteration/index.js +144 -67
- package/dist/runtime/query/iteration/index.js.map +1 -1
- package/dist/runtime/query/iteration/outstanding-work.d.ts +9 -5
- package/dist/runtime/query/iteration/outstanding-work.d.ts.map +1 -1
- package/dist/runtime/query/iteration/outstanding-work.js +61 -6
- package/dist/runtime/query/iteration/outstanding-work.js.map +1 -1
- package/dist/runtime/query/iteration/phases/context.d.ts +4 -0
- package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/context.js.map +1 -1
- package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/tool-review.js +99 -16
- package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
- package/dist/runtime/query/observation-context.d.ts +2 -2
- package/dist/runtime/query/observation-context.d.ts.map +1 -1
- package/dist/runtime/query/observation-context.js +20 -13
- package/dist/runtime/query/observation-context.js.map +1 -1
- package/dist/runtime/query/prepare-turn.js +2 -2
- package/dist/runtime/query/prepare-turn.js.map +1 -1
- package/dist/runtime/query/prompt-cache.d.ts +1 -0
- package/dist/runtime/query/prompt-cache.d.ts.map +1 -1
- package/dist/runtime/query/prompt-cache.js +2 -0
- package/dist/runtime/query/prompt-cache.js.map +1 -1
- package/dist/runtime/query/prompt.d.ts +2 -0
- package/dist/runtime/query/prompt.d.ts.map +1 -1
- package/dist/runtime/query/prompt.js +23 -1
- package/dist/runtime/query/prompt.js.map +1 -1
- package/dist/runtime/query/repeat-call.d.ts +12 -3
- package/dist/runtime/query/repeat-call.d.ts.map +1 -1
- package/dist/runtime/query/repeat-call.js +33 -10
- package/dist/runtime/query/repeat-call.js.map +1 -1
- package/dist/runtime/query/resume-pending.d.ts +5 -6
- package/dist/runtime/query/resume-pending.d.ts.map +1 -1
- package/dist/runtime/query/resume-pending.js +30 -3
- package/dist/runtime/query/resume-pending.js.map +1 -1
- package/dist/runtime/query/resume-session.js +1 -1
- package/dist/runtime/query/resume-session.js.map +1 -1
- package/dist/runtime/query/review-policy.d.ts +8 -1
- package/dist/runtime/query/review-policy.d.ts.map +1 -1
- package/dist/runtime/query/review-policy.js +6 -0
- package/dist/runtime/query/review-policy.js.map +1 -1
- package/dist/runtime/query/saved-presentation.d.ts +13 -0
- package/dist/runtime/query/saved-presentation.d.ts.map +1 -0
- package/dist/runtime/query/saved-presentation.js +63 -0
- package/dist/runtime/query/saved-presentation.js.map +1 -0
- package/dist/runtime/query/steering.d.ts +6 -9
- package/dist/runtime/query/steering.d.ts.map +1 -1
- package/dist/runtime/query/steering.js.map +1 -1
- package/dist/runtime/query/tool-executions.d.ts +7 -3
- package/dist/runtime/query/tool-executions.d.ts.map +1 -1
- package/dist/runtime/query/tool-executions.js +89 -9
- package/dist/runtime/query/tool-executions.js.map +1 -1
- package/dist/runtime/query/tooling.d.ts +3 -1
- package/dist/runtime/query/tooling.d.ts.map +1 -1
- package/dist/runtime/query/tooling.js +3 -0
- package/dist/runtime/query/tooling.js.map +1 -1
- package/dist/scheduler/completion-inbox.d.ts +25 -1
- package/dist/scheduler/completion-inbox.d.ts.map +1 -1
- package/dist/scheduler/completion-inbox.js +102 -8
- package/dist/scheduler/completion-inbox.js.map +1 -1
- package/dist/scheduler/delegating.d.ts.map +1 -1
- package/dist/scheduler/delegating.js +5 -0
- package/dist/scheduler/delegating.js.map +1 -1
- package/dist/scheduler/local.d.ts.map +1 -1
- package/dist/scheduler/local.js +2 -0
- package/dist/scheduler/local.js.map +1 -1
- package/dist/session/summary/materialize.d.ts +10 -6
- package/dist/session/summary/materialize.d.ts.map +1 -1
- package/dist/session/summary/materialize.js +41 -8
- package/dist/session/summary/materialize.js.map +1 -1
- package/dist/store/budget/ledger.d.ts +9 -0
- package/dist/store/budget/ledger.d.ts.map +1 -1
- package/dist/store/budget/ledger.js +58 -6
- package/dist/store/budget/ledger.js.map +1 -1
- package/dist/store/evidence/index-page.d.ts +12 -12
- package/dist/store/evidence/source-text.d.ts +4 -4
- package/dist/store/session/disk.d.ts +9 -4
- package/dist/store/session/disk.d.ts.map +1 -1
- package/dist/store/session/disk.js +57 -11
- package/dist/store/session/disk.js.map +1 -1
- package/dist/store/session/memory.d.ts +5 -3
- package/dist/store/session/memory.d.ts.map +1 -1
- package/dist/store/session/memory.js +24 -7
- package/dist/store/session/memory.js.map +1 -1
- package/dist/store/session-log/core.d.ts +26 -6
- package/dist/store/session-log/core.d.ts.map +1 -1
- package/dist/store/session-log/core.js +61 -8
- package/dist/store/session-log/core.js.map +1 -1
- package/dist/store/session-log/disk.d.ts +2 -2
- package/dist/store/session-log/disk.d.ts.map +1 -1
- package/dist/store/session-log/disk.js +1 -0
- package/dist/store/session-log/disk.js.map +1 -1
- package/dist/store/session-log/fold.d.ts +7 -0
- package/dist/store/session-log/fold.d.ts.map +1 -1
- package/dist/store/session-log/fold.js +21 -0
- package/dist/store/session-log/fold.js.map +1 -1
- package/dist/store/session-log/index.d.ts +5 -3
- package/dist/store/session-log/index.d.ts.map +1 -1
- package/dist/store/session-log/index.js +3 -1
- package/dist/store/session-log/index.js.map +1 -1
- package/dist/store/session-log/memory.d.ts +1 -1
- package/dist/store/session-log/memory.d.ts.map +1 -1
- package/dist/store/session-log/memory.js +1 -0
- package/dist/store/session-log/memory.js.map +1 -1
- package/dist/store/session-log/spill.d.ts +10 -3
- package/dist/store/session-log/spill.d.ts.map +1 -1
- package/dist/store/session-log/spill.js +70 -5
- package/dist/store/session-log/spill.js.map +1 -1
- package/dist/store/session-log/structured-result.d.ts +21 -0
- package/dist/store/session-log/structured-result.d.ts.map +1 -0
- package/dist/store/session-log/structured-result.js +67 -0
- package/dist/store/session-log/structured-result.js.map +1 -0
- package/dist/store/task/disk.d.ts +11 -0
- package/dist/store/task/disk.d.ts.map +1 -1
- package/dist/store/task/disk.js +41 -2
- package/dist/store/task/disk.js.map +1 -1
- package/dist/store/task/memory.d.ts.map +1 -1
- package/dist/store/task/memory.js +15 -3
- package/dist/store/task/memory.js.map +1 -1
- package/dist/tools/admit-facts.d.ts +13 -0
- package/dist/tools/admit-facts.d.ts.map +1 -0
- package/dist/tools/admit-facts.js +142 -0
- package/dist/tools/admit-facts.js.map +1 -0
- package/dist/tools/builtins/bash.d.ts +4 -1
- package/dist/tools/builtins/bash.d.ts.map +1 -1
- package/dist/tools/builtins/bash.js +108 -22
- package/dist/tools/builtins/bash.js.map +1 -1
- package/dist/tools/builtins/browser.d.ts +10 -10
- package/dist/tools/builtins/computer-use.d.ts +90 -90
- package/dist/tools/builtins/edit.d.ts +17 -0
- package/dist/tools/builtins/edit.d.ts.map +1 -1
- package/dist/tools/builtins/edit.js +34 -0
- package/dist/tools/builtins/edit.js.map +1 -1
- package/dist/tools/builtins/file-write-result.d.ts.map +1 -1
- package/dist/tools/builtins/file-write-result.js +13 -0
- package/dist/tools/builtins/file-write-result.js.map +1 -1
- package/dist/tools/builtins/glob.d.ts.map +1 -1
- package/dist/tools/builtins/glob.js +12 -0
- package/dist/tools/builtins/glob.js.map +1 -1
- package/dist/tools/builtins/grep.d.ts.map +1 -1
- package/dist/tools/builtins/grep.js +14 -0
- package/dist/tools/builtins/grep.js.map +1 -1
- package/dist/tools/builtins/index.d.ts +2 -0
- package/dist/tools/builtins/index.d.ts.map +1 -1
- package/dist/tools/builtins/index.js +1 -0
- package/dist/tools/builtins/index.js.map +1 -1
- package/dist/tools/builtins/job.d.ts.map +1 -1
- package/dist/tools/builtins/job.js +4 -1
- package/dist/tools/builtins/job.js.map +1 -1
- package/dist/tools/builtins/lsp.d.ts +2 -2
- package/dist/tools/builtins/read-file.d.ts.map +1 -1
- package/dist/tools/builtins/read-file.js +49 -0
- package/dist/tools/builtins/read-file.js.map +1 -1
- package/dist/tools/builtins/view-image.d.ts +24 -0
- package/dist/tools/builtins/view-image.d.ts.map +1 -0
- package/dist/tools/builtins/view-image.js +385 -0
- package/dist/tools/builtins/view-image.js.map +1 -0
- package/dist/tools/builtins/wait-for-job-bounds.d.ts +2 -0
- package/dist/tools/builtins/wait-for-job-bounds.d.ts.map +1 -1
- package/dist/tools/builtins/wait-for-job-bounds.js +1 -0
- package/dist/tools/builtins/wait-for-job-bounds.js.map +1 -1
- package/dist/tools/builtins/wait-for-job.d.ts +2 -0
- package/dist/tools/builtins/wait-for-job.d.ts.map +1 -1
- package/dist/tools/builtins/wait-for-job.js +104 -6
- package/dist/tools/builtins/wait-for-job.js.map +1 -1
- package/dist/tools/builtins/write-file.d.ts.map +1 -1
- package/dist/tools/builtins/write-file.js +1 -0
- package/dist/tools/builtins/write-file.js.map +1 -1
- package/dist/tools/command-shell.d.ts +37 -2
- package/dist/tools/command-shell.d.ts.map +1 -1
- package/dist/tools/command-shell.js +100 -3
- package/dist/tools/command-shell.js.map +1 -1
- package/dist/tools/coordinator/agent.d.ts +9 -19
- package/dist/tools/coordinator/agent.d.ts.map +1 -1
- package/dist/tools/coordinator/agent.js.map +1 -1
- package/dist/tools/coordinator/index.d.ts.map +1 -1
- package/dist/tools/coordinator/index.js +127 -67
- package/dist/tools/coordinator/index.js.map +1 -1
- package/dist/tools/coordinator/wait-with-idle-bound.d.ts +2 -0
- package/dist/tools/coordinator/wait-with-idle-bound.d.ts.map +1 -1
- package/dist/tools/coordinator/wait-with-idle-bound.js +1 -1
- package/dist/tools/coordinator/wait-with-idle-bound.js.map +1 -1
- package/dist/tools/defineTool.d.ts.map +1 -1
- package/dist/tools/defineTool.js +4 -0
- package/dist/tools/defineTool.js.map +1 -1
- package/dist/tools/failure-facts.d.ts +8 -0
- package/dist/tools/failure-facts.d.ts.map +1 -0
- package/dist/tools/failure-facts.js +24 -0
- package/dist/tools/failure-facts.js.map +1 -0
- package/dist/tools/host-output.d.ts +24 -0
- package/dist/tools/host-output.d.ts.map +1 -0
- package/dist/tools/host-output.js +117 -0
- package/dist/tools/host-output.js.map +1 -0
- package/dist/tools/oem-code-pages.d.ts +8 -0
- package/dist/tools/oem-code-pages.d.ts.map +1 -0
- package/dist/tools/oem-code-pages.js +23 -0
- package/dist/tools/oem-code-pages.js.map +1 -0
- package/dist/tools/schedules/schedule-tool.d.ts.map +1 -1
- package/dist/tools/schedules/schedule-tool.js +35 -6
- package/dist/tools/schedules/schedule-tool.js.map +1 -1
- package/dist/tools/schedules/types.d.ts +23 -3
- package/dist/tools/schedules/types.d.ts.map +1 -1
- package/dist/tools/task/list.d.ts.map +1 -1
- package/dist/tools/task/list.js +14 -6
- package/dist/tools/task/list.js.map +1 -1
- package/dist/tools/task/present.d.ts.map +1 -1
- package/dist/tools/task/present.js +26 -6
- package/dist/tools/task/present.js.map +1 -1
- package/dist/tools/task/update.d.ts.map +1 -1
- package/dist/tools/task/update.js +12 -5
- package/dist/tools/task/update.js.map +1 -1
- package/dist/tools/text-window.d.ts +19 -0
- package/dist/tools/text-window.d.ts.map +1 -0
- package/dist/tools/text-window.js +83 -0
- package/dist/tools/text-window.js.map +1 -0
- package/dist/toolsets/manager.d.ts +11 -0
- package/dist/toolsets/manager.d.ts.map +1 -1
- package/dist/toolsets/manager.js +45 -1
- package/dist/toolsets/manager.js.map +1 -1
- package/dist/types/acp/index.d.ts +137 -1
- package/dist/types/acp/index.d.ts.map +1 -1
- package/dist/types/agent/base.d.ts +3 -0
- package/dist/types/agent/base.d.ts.map +1 -1
- package/dist/types/agent/manager.d.ts +8 -23
- package/dist/types/agent/manager.d.ts.map +1 -1
- package/dist/types/agent/scheduler.d.ts +10 -1
- package/dist/types/agent/scheduler.d.ts.map +1 -1
- package/dist/types/agent/task.d.ts +4 -0
- package/dist/types/agent/task.d.ts.map +1 -1
- package/dist/types/authorization/index.d.ts +30 -30
- package/dist/types/connector/mcp.d.ts +7 -0
- package/dist/types/connector/mcp.d.ts.map +1 -1
- package/dist/types/errors/catalog.d.ts.map +1 -1
- package/dist/types/errors/catalog.js +4 -2
- package/dist/types/errors/catalog.js.map +1 -1
- package/dist/types/harness/schema.d.ts +354 -0
- package/dist/types/harness/schema.d.ts.map +1 -0
- package/dist/types/harness/schema.js +203 -0
- package/dist/types/harness/schema.js.map +1 -0
- package/dist/types/harness/session.d.ts +278 -0
- package/dist/types/harness/session.d.ts.map +1 -0
- package/dist/types/harness/session.js +2 -0
- package/dist/types/harness/session.js.map +1 -0
- package/dist/types/hitl/index.d.ts +12 -0
- package/dist/types/hitl/index.d.ts.map +1 -1
- package/dist/types/hitl/index.js.map +1 -1
- package/dist/types/job/index.d.ts +47 -0
- package/dist/types/job/index.d.ts.map +1 -0
- package/dist/types/job/index.js +2 -0
- package/dist/types/job/index.js.map +1 -0
- package/dist/types/message/inbound-delivery.d.ts +44 -0
- package/dist/types/message/inbound-delivery.d.ts.map +1 -0
- package/dist/types/message/inbound-delivery.js +14 -0
- package/dist/types/message/inbound-delivery.js.map +1 -0
- package/dist/types/message/index.d.ts +4 -1
- package/dist/types/message/index.d.ts.map +1 -1
- package/dist/types/message/index.js +5 -1
- package/dist/types/message/index.js.map +1 -1
- package/dist/types/plugin/index.d.ts +6 -6
- package/dist/types/sandbox/index.d.ts +39 -2
- package/dist/types/sandbox/index.d.ts.map +1 -1
- package/dist/types/sandbox/index.js.map +1 -1
- package/dist/types/session/checkpoint.d.ts +24 -17
- package/dist/types/session/checkpoint.d.ts.map +1 -1
- package/dist/types/session/checkpoint.js +1 -0
- package/dist/types/session/checkpoint.js.map +1 -1
- package/dist/types/session/events.d.ts +23 -1
- package/dist/types/session/events.d.ts.map +1 -1
- package/dist/types/session/events.js.map +1 -1
- package/dist/types/session/records.d.ts +1514 -565
- package/dist/types/session/records.d.ts.map +1 -1
- package/dist/types/session/records.js +89 -1
- package/dist/types/session/records.js.map +1 -1
- package/dist/types/session/step.d.ts +2 -0
- package/dist/types/session/step.d.ts.map +1 -1
- package/dist/types/session/step.js.map +1 -1
- package/dist/types/session/store.d.ts +19 -10
- package/dist/types/session/store.d.ts.map +1 -1
- package/dist/types/session/tool-execution.d.ts +6 -0
- package/dist/types/session/tool-execution.d.ts.map +1 -1
- package/dist/types/structured-output/index.d.ts +12 -2
- package/dist/types/structured-output/index.d.ts.map +1 -1
- package/dist/types/summary/ref.d.ts +3 -1
- package/dist/types/summary/ref.d.ts.map +1 -1
- package/dist/types/tool/index.d.ts +32 -4
- package/dist/types/tool/index.d.ts.map +1 -1
- package/dist/types/tool/index.js.map +1 -1
- package/dist/types/tool/presentation.d.ts +106 -0
- package/dist/types/tool/presentation.d.ts.map +1 -1
- package/dist/utils/json-snapshot.d.ts +6 -2
- package/dist/utils/json-snapshot.d.ts.map +1 -1
- package/dist/utils/json-snapshot.js +19 -9
- package/dist/utils/json-snapshot.js.map +1 -1
- package/dist/utils/structured-result-json.d.ts +5 -0
- package/dist/utils/structured-result-json.d.ts.map +1 -0
- package/dist/utils/structured-result-json.js +10 -0
- package/dist/utils/structured-result-json.js.map +1 -0
- package/package.json +1 -1
- package/src/agents/QueryAgent.ts +1 -0
- package/src/agents/examples/SupervisorAgent.ts +1 -0
- package/src/agents/runAgent.ts +3 -0
- package/src/authorization/shell-lexer.ts +16 -1
- package/src/bridge/acp/permission.ts +17 -3
- package/src/bridge/acp/server.ts +271 -25
- package/src/bridge/acp/tasks.ts +23 -0
- package/src/bridge/acp/update.ts +167 -13
- package/src/connector/mcp/adapter.ts +16 -4
- package/src/connector/mcp/client.ts +6 -2
- package/src/constants/acp/index.ts +4 -0
- package/src/manager/agent/lifecycle.ts +230 -3
- package/src/manager/plan/lifecycle.ts +11 -9
- package/src/manager/session/attribution.ts +12 -2
- package/src/manager/session/streamed-message-identity.ts +21 -0
- package/src/manager/session/turn-recorder.ts +4 -3
- package/src/pals/activity/causality.ts +261 -0
- package/src/pals/activity/projection.ts +89 -0
- package/src/pals/activity/source.ts +240 -0
- package/src/pals/activity/subscription-policy.ts +230 -0
- package/src/pals/activity/subscription-schema.ts +27 -0
- package/src/pals/activity/subscription-store.ts +172 -0
- package/src/pals/activity/subscription-types.ts +48 -0
- package/src/pals/activity/subscriptions.ts +209 -0
- package/src/pals/activity/types.ts +108 -0
- package/src/pals/channels/ingress.ts +153 -0
- package/src/pals/channels/routes.ts +118 -0
- package/src/pals/channels/routing.ts +197 -0
- package/src/pals/channels/schema.ts +108 -0
- package/src/pals/channels/types.ts +156 -0
- package/src/pals/communication/broker.ts +131 -0
- package/src/pals/communication/dispatch.ts +66 -0
- package/src/pals/communication/inbound.ts +193 -0
- package/src/pals/communication/ingress-dispatch.ts +63 -0
- package/src/pals/communication/ingress-inbound.ts +269 -0
- package/src/pals/communication/ingress-schema.ts +526 -0
- package/src/pals/communication/ingress-types.ts +336 -0
- package/src/pals/communication/operator.ts +315 -0
- package/src/pals/communication/policy.ts +174 -0
- package/src/pals/communication/schema.ts +173 -0
- package/src/pals/communication/store.ts +577 -0
- package/src/pals/communication/tools.ts +139 -0
- package/src/pals/communication/types.ts +227 -0
- package/src/pals/communication/verify.ts +220 -0
- package/src/pals/lifecycle.ts +54 -0
- package/src/pals/prompt.ts +101 -0
- package/src/pals/reference-images.ts +322 -0
- package/src/pals/runtime.ts +670 -0
- package/src/pals/store.ts +369 -0
- package/src/pals/types.ts +157 -0
- package/src/peers/envelope.ts +1 -1
- package/src/plugin/shell-hook.ts +8 -2
- package/src/process/kill-tree.ts +10 -1
- package/src/provider/errors.ts +135 -2
- package/src/public-runtime.ts +117 -12
- package/src/public-tools.ts +13 -1
- package/src/public-types.ts +69 -7
- package/src/registry/tool/presentation.ts +9 -4
- package/src/runtime/harness-session/index.ts +1125 -0
- package/src/runtime/harness-session/journal.ts +209 -0
- package/src/runtime/harness-session/saved-view.ts +122 -0
- package/src/runtime/jobs/awaited-jobs.ts +2 -1
- package/src/runtime/jobs/registry.ts +397 -41
- package/src/runtime/query/abandon-turn.ts +18 -2
- package/src/runtime/query/checkpoint.ts +11 -0
- package/src/runtime/query/durable-inbound.ts +101 -0
- package/src/runtime/query/events.ts +22 -5
- package/src/runtime/query/executor/tool-call-admission.ts +125 -32
- package/src/runtime/query/executor.ts +316 -130
- package/src/runtime/query/index.ts +24 -4
- package/src/runtime/query/iteration/index.ts +218 -104
- package/src/runtime/query/iteration/outstanding-work.ts +55 -7
- package/src/runtime/query/iteration/phases/context.ts +4 -0
- package/src/runtime/query/iteration/phases/tool-review.ts +118 -21
- package/src/runtime/query/observation-context.ts +22 -16
- package/src/runtime/query/prepare-turn.ts +2 -2
- package/src/runtime/query/prompt-cache.ts +3 -0
- package/src/runtime/query/prompt.ts +32 -1
- package/src/runtime/query/repeat-call.ts +40 -10
- package/src/runtime/query/resume-pending.ts +60 -7
- package/src/runtime/query/resume-session.ts +1 -1
- package/src/runtime/query/review-policy.ts +23 -2
- package/src/runtime/query/saved-presentation.ts +70 -0
- package/src/runtime/query/steering.ts +6 -9
- package/src/runtime/query/tool-executions.ts +108 -9
- package/src/runtime/query/tooling.ts +6 -1
- package/src/scheduler/completion-inbox.ts +108 -7
- package/src/scheduler/delegating.ts +5 -0
- package/src/scheduler/local.ts +2 -0
- package/src/session/summary/materialize.ts +51 -9
- package/src/store/budget/ledger.ts +60 -5
- package/src/store/session/disk.ts +77 -10
- package/src/store/session/memory.ts +32 -7
- package/src/store/session-log/core.ts +118 -11
- package/src/store/session-log/disk.ts +9 -2
- package/src/store/session-log/fold.ts +22 -0
- package/src/store/session-log/index.ts +5 -0
- package/src/store/session-log/memory.ts +2 -1
- package/src/store/session-log/spill.ts +89 -6
- package/src/store/session-log/structured-result.ts +96 -0
- package/src/store/task/disk.ts +46 -2
- package/src/store/task/memory.ts +13 -3
- package/src/tools/admit-facts.ts +145 -0
- package/src/tools/builtins/bash.ts +132 -24
- package/src/tools/builtins/edit.ts +42 -0
- package/src/tools/builtins/file-write-result.ts +14 -0
- package/src/tools/builtins/glob.ts +12 -0
- package/src/tools/builtins/grep.ts +14 -0
- package/src/tools/builtins/index.ts +2 -0
- package/src/tools/builtins/job.ts +4 -1
- package/src/tools/builtins/read-file.ts +57 -0
- package/src/tools/builtins/view-image.ts +409 -0
- package/src/tools/builtins/wait-for-job-bounds.ts +3 -0
- package/src/tools/builtins/wait-for-job.ts +141 -32
- package/src/tools/builtins/write-file.ts +4 -2
- package/src/tools/command-shell.ts +132 -5
- package/src/tools/coordinator/agent.ts +9 -19
- package/src/tools/coordinator/index.ts +150 -75
- package/src/tools/coordinator/wait-with-idle-bound.ts +3 -1
- package/src/tools/defineTool.ts +4 -0
- package/src/tools/failure-facts.ts +24 -0
- package/src/tools/host-output.ts +136 -0
- package/src/tools/oem-code-pages.ts +22 -0
- package/src/tools/schedules/schedule-tool.ts +38 -5
- package/src/tools/schedules/types.ts +23 -3
- package/src/tools/task/list.ts +15 -7
- package/src/tools/task/present.ts +37 -7
- package/src/tools/task/update.ts +12 -5
- package/src/tools/text-window.ts +87 -0
- package/src/toolsets/manager.ts +58 -1
- package/src/types/acp/index.ts +150 -4
- package/src/types/agent/base.ts +3 -0
- package/src/types/agent/manager.ts +8 -23
- package/src/types/agent/scheduler.ts +10 -1
- package/src/types/agent/task.ts +4 -0
- package/src/types/connector/mcp.ts +7 -0
- package/src/types/errors/catalog.ts +4 -2
- package/src/types/harness/schema.ts +203 -0
- package/src/types/harness/session.ts +306 -0
- package/src/types/hitl/index.ts +17 -1
- package/src/types/job/index.ts +42 -0
- package/src/types/message/inbound-delivery.ts +63 -0
- package/src/types/message/index.ts +8 -1
- package/src/types/sandbox/index.ts +46 -0
- package/src/types/session/checkpoint.ts +4 -1
- package/src/types/session/events.ts +23 -1
- package/src/types/session/records.ts +114 -2
- package/src/types/session/step.ts +2 -0
- package/src/types/session/store.ts +23 -9
- package/src/types/session/tool-execution.ts +6 -0
- package/src/types/structured-output/index.ts +13 -2
- package/src/types/summary/ref.ts +3 -1
- package/src/types/tool/index.ts +39 -5
- package/src/types/tool/presentation.ts +121 -0
- package/src/utils/json-snapshot.ts +26 -9
- package/src/utils/structured-result-json.ts +10 -0
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
import { spawn } from 'node:child_process'
|
|
1
|
+
import type { spawn } from 'node:child_process'
|
|
2
2
|
|
|
3
3
|
import { SANDBOX_KILL_GRACE_MS } from '../../constants/sandbox/index.js'
|
|
4
4
|
import { killTree } from '../../process/kill-tree.js'
|
|
5
|
-
import {
|
|
5
|
+
import { describeSpawnFailure, spawnHostShell } from '../../tools/command-shell.js'
|
|
6
6
|
import { scrubInheritedEnv } from '../../tools/env-scrub.js'
|
|
7
|
+
import { createHostOutputDecoder } from '../../tools/host-output.js'
|
|
8
|
+
import type {
|
|
9
|
+
BackgroundJobOutputWaitOptions,
|
|
10
|
+
BackgroundJobOutputWaitResult,
|
|
11
|
+
} from '../../types/job/index.js'
|
|
7
12
|
import { subscribeToAbort } from '../../utils/abort.js'
|
|
8
13
|
|
|
9
14
|
/**
|
|
@@ -40,6 +45,17 @@ export interface BackgroundJob {
|
|
|
40
45
|
readonly exitedAt?: number
|
|
41
46
|
readonly exitCode?: number
|
|
42
47
|
readonly signal?: string
|
|
48
|
+
/**
|
|
49
|
+
* Why the command never started, in words for the model: set when the
|
|
50
|
+
* process could not be spawned at all (missing shell, bad working
|
|
51
|
+
* directory). Such a job has no `exitCode`; it is not a command that
|
|
52
|
+
* ran and returned a status.
|
|
53
|
+
*/
|
|
54
|
+
readonly error?: string
|
|
55
|
+
/** Stopping the owned tree failed; the job remains owned and counted as live. */
|
|
56
|
+
readonly recoveryRequired?: boolean
|
|
57
|
+
/** Safe registry diagnostic for an unconfirmed stop; excludes transport secrets. */
|
|
58
|
+
readonly stopError?: string
|
|
43
59
|
}
|
|
44
60
|
|
|
45
61
|
export interface BackgroundJobOutput {
|
|
@@ -57,6 +73,8 @@ export interface BackgroundJobOutput {
|
|
|
57
73
|
readonly droppedBytes: number
|
|
58
74
|
readonly status: BackgroundJobStatus
|
|
59
75
|
readonly exitCode?: number
|
|
76
|
+
/** Set when the command could not be started; see {@link BackgroundJob.error}. */
|
|
77
|
+
readonly error?: string
|
|
60
78
|
}
|
|
61
79
|
|
|
62
80
|
/** A job's process, when something other than the registry starts it. */
|
|
@@ -64,6 +82,8 @@ export interface JobProcess {
|
|
|
64
82
|
readonly child: ReturnType<typeof spawn>
|
|
65
83
|
/** How to stop it, when the registry's process-group kill would not reach everything. */
|
|
66
84
|
kill?(signal: NodeJS.Signals): void
|
|
85
|
+
/** Confirm the owned tree stopped; reject instead of claiming an unconfirmed exit. */
|
|
86
|
+
terminate?(signal?: NodeJS.Signals): Promise<void>
|
|
67
87
|
}
|
|
68
88
|
|
|
69
89
|
export interface StartJobParams {
|
|
@@ -90,10 +110,47 @@ export interface BackgroundJobRegistryConfig {
|
|
|
90
110
|
readonly maxJobsPerOwner?: number
|
|
91
111
|
/** Retained output per job. Oldest bytes go first, and are counted. */
|
|
92
112
|
readonly maxOutputBytesPerJob?: number
|
|
113
|
+
/** Concurrent output observers per owner; default 32. Refused rather than queued. */
|
|
114
|
+
readonly maxOutputWaitersPerOwner?: number
|
|
115
|
+
/** Concurrent output observers across the registry; default 256. */
|
|
116
|
+
readonly maxOutputWaiters?: number
|
|
93
117
|
}
|
|
94
118
|
|
|
95
119
|
const DEFAULT_MAX_JOBS_PER_OWNER = 8
|
|
96
120
|
const DEFAULT_MAX_OUTPUT_BYTES = 1024 * 1024
|
|
121
|
+
const MAX_CHANNEL_CHUNKS = 4096
|
|
122
|
+
const MAX_WAIT_RESULT_BYTES = 32 * 1024
|
|
123
|
+
const MAX_OUTPUT_WAIT_MS = 60 * 60 * 1000
|
|
124
|
+
|
|
125
|
+
/** Starting another observer would exceed its owner's or registry's bound. */
|
|
126
|
+
export class BackgroundJobOutputWaitLimitError extends Error {
|
|
127
|
+
constructor(readonly details: { owner: string; limit: number; scope: 'owner' | 'registry' }) {
|
|
128
|
+
super(
|
|
129
|
+
`Background output wait limit ${details.limit} reached for ${details.scope}; finish or cancel an existing wait first.`,
|
|
130
|
+
)
|
|
131
|
+
this.name = 'BackgroundJobOutputWaitLimitError'
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
interface OutputChunk {
|
|
136
|
+
readonly stream: 'stdout' | 'stderr'
|
|
137
|
+
readonly offset: number
|
|
138
|
+
readonly bytes: Buffer
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Start at a complete UTF-8 code point when a byte cap or cursor bisects one. */
|
|
142
|
+
function utf8Start(bytes: Buffer, start: number): number {
|
|
143
|
+
let at = start
|
|
144
|
+
while (at < bytes.length && ((bytes[at] ?? 0) & 0xc0) === 0x80) at++
|
|
145
|
+
return at
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function outputTail(text: string, maxBytes: number): { text: string; omitted: number } {
|
|
149
|
+
const bytes = Buffer.from(text)
|
|
150
|
+
if (bytes.length <= maxBytes) return { text, omitted: 0 }
|
|
151
|
+
const start = utf8Start(bytes, bytes.length - maxBytes)
|
|
152
|
+
return { text: bytes.subarray(start).toString('utf8'), omitted: start }
|
|
153
|
+
}
|
|
97
154
|
|
|
98
155
|
/** A start that would exceed a declared bound. */
|
|
99
156
|
export class BackgroundJobLimitError extends Error {
|
|
@@ -124,11 +181,21 @@ interface JobEntry {
|
|
|
124
181
|
child: ReturnType<typeof spawn>
|
|
125
182
|
/** The spawner's own kill, when it gave one. */
|
|
126
183
|
killProcess?: (signal: NodeJS.Signals) => void
|
|
184
|
+
terminateProcess?: (signal?: NodeJS.Signals) => Promise<void>
|
|
185
|
+
terminationAttempt?: Promise<void>
|
|
186
|
+
killRequested?: boolean
|
|
187
|
+
closedResult?: { code: number | null; signal: NodeJS.Signals | null }
|
|
188
|
+
finalize?: (code: number | null, signal: NodeJS.Signals | null) => void
|
|
127
189
|
/** Retained tail. */
|
|
128
190
|
buffer: string
|
|
129
191
|
/** Bytes produced in total, including the ones the cap dropped. */
|
|
130
192
|
produced: number
|
|
193
|
+
/** Channel identity is retained separately, under the same byte cap and a chunk cap. */
|
|
194
|
+
outputChunks: OutputChunk[]
|
|
195
|
+
outputObservers: Set<(chunk?: OutputChunk) => void>
|
|
131
196
|
exit: Promise<void>
|
|
197
|
+
/** Settles once the process exists or failed to; `error` says which. */
|
|
198
|
+
started: Promise<{ readonly error?: string }>
|
|
132
199
|
}
|
|
133
200
|
|
|
134
201
|
/** Whether any process of the group led by `pid` is still alive. */
|
|
@@ -148,6 +215,8 @@ export class BackgroundJobRegistry {
|
|
|
148
215
|
private readonly jobs = new Map<string, JobEntry>()
|
|
149
216
|
private counter = 0
|
|
150
217
|
private readonly exitListeners = new Set<(job: BackgroundJob) => void>()
|
|
218
|
+
private outputWaiters = 0
|
|
219
|
+
private readonly outputWaitersByOwner = new Map<string, number>()
|
|
151
220
|
|
|
152
221
|
/**
|
|
153
222
|
* Be told when a job ends, whoever owns it. A job outlives the call that
|
|
@@ -172,7 +241,43 @@ export class BackgroundJobRegistry {
|
|
|
172
241
|
}
|
|
173
242
|
}
|
|
174
243
|
|
|
175
|
-
|
|
244
|
+
/** A failed remote stop never releases ownership or announces a terminal job. */
|
|
245
|
+
private confirmTermination(entry: JobEntry): Promise<void> {
|
|
246
|
+
if (entry.terminationAttempt) return entry.terminationAttempt
|
|
247
|
+
const terminate = entry.terminateProcess
|
|
248
|
+
if (!terminate) return Promise.reject(new Error('The process has no confirmed termination API'))
|
|
249
|
+
const attempt = Promise.resolve()
|
|
250
|
+
.then(() => terminate('SIGTERM'))
|
|
251
|
+
.then(() => {
|
|
252
|
+
const { recoveryRequired: _recovery, stopError: _error, ...record } = entry.record
|
|
253
|
+
entry.record = record
|
|
254
|
+
if (entry.closedResult) entry.finalize?.(entry.closedResult.code, entry.closedResult.signal)
|
|
255
|
+
})
|
|
256
|
+
.catch((error: unknown) => {
|
|
257
|
+
entry.record = {
|
|
258
|
+
...entry.record,
|
|
259
|
+
recoveryRequired: true,
|
|
260
|
+
stopError:
|
|
261
|
+
'The process provider could not confirm the owned job stopped; retry termination or recover its environment.',
|
|
262
|
+
}
|
|
263
|
+
for (const observer of entry.outputObservers) observer()
|
|
264
|
+
throw error
|
|
265
|
+
})
|
|
266
|
+
.finally(() => {
|
|
267
|
+
entry.terminationAttempt = undefined
|
|
268
|
+
})
|
|
269
|
+
entry.terminationAttempt = attempt
|
|
270
|
+
return attempt
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
constructor(private readonly config: BackgroundJobRegistryConfig = {}) {
|
|
274
|
+
for (const key of ['maxOutputWaiters', 'maxOutputWaitersPerOwner'] as const) {
|
|
275
|
+
const value = config[key]
|
|
276
|
+
if (value !== undefined && (!Number.isSafeInteger(value) || value < 1)) {
|
|
277
|
+
throw new RangeError(`${key} must be a positive safe integer.`)
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
176
281
|
|
|
177
282
|
private get maxJobs(): number {
|
|
178
283
|
return this.config.maxJobsPerOwner ?? DEFAULT_MAX_JOBS_PER_OWNER
|
|
@@ -206,33 +311,42 @@ export class BackgroundJobRegistry {
|
|
|
206
311
|
// started it, which makes the leak longer-lived, not smaller.
|
|
207
312
|
const inherited = scrubInheritedEnv()
|
|
208
313
|
|
|
209
|
-
// The same
|
|
210
|
-
// rules' reading of the line holds for the job too
|
|
211
|
-
|
|
314
|
+
// The same spawn as a foreground `bash` call, so the permission
|
|
315
|
+
// rules' reading of the line holds for the job too, and so the two
|
|
316
|
+
// cannot disagree about how a shell is started on a given platform.
|
|
212
317
|
const started = params.spawn
|
|
213
318
|
? params.spawn()
|
|
214
319
|
: {
|
|
215
|
-
child:
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
detached: process.platform !== 'win32',
|
|
225
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
226
|
-
},
|
|
227
|
-
),
|
|
320
|
+
child: spawnHostShell(params.command, {
|
|
321
|
+
cwd: params.workingDirectory,
|
|
322
|
+
env: { ...inherited.env, ...params.env },
|
|
323
|
+
// `detached` makes the child the leader of its own process group
|
|
324
|
+
// off Windows, which is what `killTree` needs to reach the command
|
|
325
|
+
// and everything it forks rather than only the wrapping shell. See
|
|
326
|
+
// `process/kill-tree.ts`.
|
|
327
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
328
|
+
}),
|
|
228
329
|
}
|
|
229
330
|
const child = started.child
|
|
230
331
|
// Started, not adopted: this process stays the parent for the job's
|
|
231
332
|
// whole life. `unref` would let Node exit with the job still running,
|
|
232
333
|
// which is the orphan this registry exists to prevent.
|
|
233
|
-
|
|
234
|
-
|
|
334
|
+
// Raw bytes, decoded here: a Windows console writes its OEM code page.
|
|
335
|
+
// A process a sandbox started runs a Linux guest, so it is UTF-8.
|
|
336
|
+
const decoders = {
|
|
337
|
+
stdout: createHostOutputDecoder(params.spawn ? { platform: 'linux' } : {}),
|
|
338
|
+
stderr: createHostOutputDecoder(params.spawn ? { platform: 'linux' } : {}),
|
|
339
|
+
}
|
|
340
|
+
let startError: string | undefined
|
|
341
|
+
let settleStarted!: () => void
|
|
342
|
+
const startedPromise = new Promise<{ readonly error?: string }>((resolve) => {
|
|
343
|
+
settleStarted = () => resolve(startError === undefined ? {} : { error: startError })
|
|
344
|
+
})
|
|
345
|
+
// A process the host's own spawner started is the host's to vouch for:
|
|
346
|
+
// it may be remote, and need not emit `spawn` at all.
|
|
347
|
+
if (params.spawn || child.pid !== undefined) settleStarted()
|
|
235
348
|
|
|
349
|
+
let finalizeEntry!: (code: number | null, signal: NodeJS.Signals | null) => void
|
|
236
350
|
const entry: JobEntry = {
|
|
237
351
|
record: {
|
|
238
352
|
id,
|
|
@@ -243,35 +357,58 @@ export class BackgroundJobRegistry {
|
|
|
243
357
|
},
|
|
244
358
|
child,
|
|
245
359
|
...(started.kill ? { killProcess: started.kill.bind(started) } : {}),
|
|
360
|
+
...(started.terminate ? { terminateProcess: started.terminate.bind(started) } : {}),
|
|
246
361
|
buffer: '',
|
|
247
362
|
produced: 0,
|
|
363
|
+
outputChunks: [],
|
|
364
|
+
outputObservers: new Set(),
|
|
365
|
+
started: startedPromise,
|
|
248
366
|
exit: new Promise<void>((resolve) => {
|
|
249
367
|
let spawned = child.pid !== undefined
|
|
250
368
|
let failedToSpawn = false
|
|
369
|
+
let finalized = false
|
|
251
370
|
const finalize = (code: number | null, signal: NodeJS.Signals | null): void => {
|
|
371
|
+
if (finalized) return
|
|
372
|
+
finalized = true
|
|
252
373
|
entry.record = {
|
|
253
374
|
...entry.record,
|
|
254
375
|
// A job killed by this registry says `killed`, not
|
|
255
376
|
// `exited` with a signal a reader has to interpret. The
|
|
256
377
|
// two are different answers to "why did my job stop".
|
|
257
|
-
status: entry.record.status === 'killed' ? 'killed' : 'exited',
|
|
378
|
+
status: entry.killRequested || entry.record.status === 'killed' ? 'killed' : 'exited',
|
|
258
379
|
exitedAt: Date.now(),
|
|
259
380
|
...(code === null ? {} : { exitCode: code }),
|
|
260
381
|
...(signal ? { signal } : {}),
|
|
261
382
|
}
|
|
262
383
|
resolve()
|
|
384
|
+
for (const observer of entry.outputObservers) observer()
|
|
263
385
|
this.announceExit(entry.record)
|
|
264
386
|
}
|
|
387
|
+
finalizeEntry = finalize
|
|
265
388
|
child.once('spawn', () => {
|
|
266
389
|
spawned = true
|
|
390
|
+
settleStarted()
|
|
267
391
|
})
|
|
268
|
-
child.on('error', () => {
|
|
392
|
+
child.on('error', (error) => {
|
|
269
393
|
// A failed spawn emits both `error` and `close`. Waiting for
|
|
270
394
|
// `close` also covers errors on an already-running process
|
|
271
395
|
// (such as a failed kill) without announcing a false exit.
|
|
272
|
-
if (
|
|
396
|
+
if (spawned) return
|
|
397
|
+
failedToSpawn = true
|
|
398
|
+
startError ??= describeSpawnFailure(error, params.workingDirectory)
|
|
399
|
+
settleStarted()
|
|
273
400
|
})
|
|
274
401
|
child.once('close', (code, signal) => {
|
|
402
|
+
for (const stream of ['stdout', 'stderr'] as const) {
|
|
403
|
+
const rest = decoders[stream].end()
|
|
404
|
+
if (rest) append(rest, stream)
|
|
405
|
+
}
|
|
406
|
+
if (failedToSpawn && startError !== undefined) {
|
|
407
|
+
// In the output too, so a caller that only reads output (or
|
|
408
|
+
// redirects it, as a model does) still learns why it is empty.
|
|
409
|
+
append(`${startError}\n`, 'stderr')
|
|
410
|
+
entry.record = { ...entry.record, error: startError }
|
|
411
|
+
}
|
|
275
412
|
// The job is the process GROUP, not the shell. A command that
|
|
276
413
|
// backgrounds its real work (`server &`) exits the shell at
|
|
277
414
|
// once and leaves the server as the group's survivor; calling
|
|
@@ -282,6 +419,14 @@ export class BackgroundJobRegistry {
|
|
|
282
419
|
// alive, and ends — with the shell's exit code — when the
|
|
283
420
|
// group is empty.
|
|
284
421
|
const exitCode = failedToSpawn ? null : code
|
|
422
|
+
if (entry.terminateProcess) {
|
|
423
|
+
entry.closedResult = { code: exitCode, signal }
|
|
424
|
+
void this.confirmTermination(entry).catch(() => {
|
|
425
|
+
// The retained running record exposes recoveryRequired. A
|
|
426
|
+
// later kill retries instead of forgetting the guest tree.
|
|
427
|
+
})
|
|
428
|
+
return
|
|
429
|
+
}
|
|
285
430
|
if (entry.record.status !== 'killed' && groupAlive(child.pid)) {
|
|
286
431
|
const poll = setInterval(() => {
|
|
287
432
|
if (groupAlive(child.pid)) return
|
|
@@ -295,30 +440,58 @@ export class BackgroundJobRegistry {
|
|
|
295
440
|
})
|
|
296
441
|
}),
|
|
297
442
|
}
|
|
443
|
+
entry.finalize = finalizeEntry
|
|
298
444
|
|
|
299
|
-
const append = (text: string): void => {
|
|
300
|
-
entry.produced
|
|
445
|
+
const append = (text: string, stream: 'stdout' | 'stderr'): void => {
|
|
446
|
+
const chunk: OutputChunk = { stream, offset: entry.produced, bytes: Buffer.from(text) }
|
|
447
|
+
if (chunk.bytes.length === 0) return
|
|
448
|
+
entry.produced += chunk.bytes.length
|
|
301
449
|
entry.buffer += text
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
450
|
+
entry.buffer = outputTail(entry.buffer, this.maxBytes).text
|
|
451
|
+
entry.outputChunks.push(chunk)
|
|
452
|
+
const retainedStart = entry.produced - Buffer.byteLength(entry.buffer)
|
|
453
|
+
while (
|
|
454
|
+
entry.outputChunks.length > MAX_CHANNEL_CHUNKS ||
|
|
455
|
+
(entry.outputChunks[0] &&
|
|
456
|
+
entry.outputChunks[0].offset + entry.outputChunks[0].bytes.length <= retainedStart)
|
|
457
|
+
) {
|
|
458
|
+
entry.outputChunks.shift()
|
|
459
|
+
}
|
|
460
|
+
const first = entry.outputChunks[0]
|
|
461
|
+
if (first && first.offset < retainedStart) {
|
|
462
|
+
const skip = utf8Start(first.bytes, retainedStart - first.offset)
|
|
463
|
+
entry.outputChunks[0] = {
|
|
464
|
+
...first,
|
|
465
|
+
offset: first.offset + skip,
|
|
466
|
+
bytes: Buffer.from(first.bytes.subarray(skip)),
|
|
467
|
+
}
|
|
313
468
|
}
|
|
469
|
+
// Deliver the actual chunk even when its beginning has already fallen
|
|
470
|
+
// outside retention: an active observer must not miss a fast producer.
|
|
471
|
+
for (const observer of entry.outputObservers) observer(chunk)
|
|
472
|
+
}
|
|
473
|
+
const onData = (stream: 'stdout' | 'stderr') => (data: Buffer | string) => {
|
|
474
|
+
const text = typeof data === 'string' ? data : decoders[stream].write(data)
|
|
475
|
+
if (text) append(text, stream)
|
|
314
476
|
}
|
|
315
|
-
child.stdout?.on('data', (
|
|
316
|
-
child.stderr?.on('data', (
|
|
477
|
+
child.stdout?.on('data', onData('stdout'))
|
|
478
|
+
child.stderr?.on('data', onData('stderr'))
|
|
317
479
|
|
|
318
480
|
this.jobs.set(id, entry)
|
|
319
481
|
return entry.record
|
|
320
482
|
}
|
|
321
483
|
|
|
484
|
+
/**
|
|
485
|
+
* Resolves once the job's process exists, or once it could not be
|
|
486
|
+
* created (`error` then says why). Lets a caller report a start that
|
|
487
|
+
* failed in the same reply that would otherwise say "started".
|
|
488
|
+
*/
|
|
489
|
+
awaitStarted(id: string): Promise<{ readonly error?: string }> {
|
|
490
|
+
const entry = this.jobs.get(id)
|
|
491
|
+
if (!entry) throw new UnknownBackgroundJobError({ id })
|
|
492
|
+
return entry.started
|
|
493
|
+
}
|
|
494
|
+
|
|
322
495
|
/** The record, or throw for an id this registry does not know. */
|
|
323
496
|
get(id: string): BackgroundJob {
|
|
324
497
|
const entry = this.jobs.get(id)
|
|
@@ -369,6 +542,171 @@ export class BackgroundJobRegistry {
|
|
|
369
542
|
})
|
|
370
543
|
}
|
|
371
544
|
|
|
545
|
+
/**
|
|
546
|
+
* Observe a literal in one pipe, including retained output after the cursor.
|
|
547
|
+
* A marker is evidence of output, not exit intent or service health. Every
|
|
548
|
+
* observer is independent and bounded; cancellation never stops the job.
|
|
549
|
+
*/
|
|
550
|
+
waitForOutput(
|
|
551
|
+
id: string,
|
|
552
|
+
opts: BackgroundJobOutputWaitOptions,
|
|
553
|
+
): Promise<BackgroundJobOutputWaitResult> {
|
|
554
|
+
const entry = this.jobs.get(id)
|
|
555
|
+
if (!entry) throw new UnknownBackgroundJobError({ id })
|
|
556
|
+
// Capture the admitted condition and clocks once; a caller retaining its
|
|
557
|
+
// mutable options object cannot alter a bound after validation.
|
|
558
|
+
const {
|
|
559
|
+
literal: literalText,
|
|
560
|
+
stream: requestedStream,
|
|
561
|
+
fromOffset,
|
|
562
|
+
timeoutMs,
|
|
563
|
+
idleTimeoutMs,
|
|
564
|
+
signal,
|
|
565
|
+
} = opts
|
|
566
|
+
if (
|
|
567
|
+
typeof literalText !== 'string' ||
|
|
568
|
+
literalText.length === 0 ||
|
|
569
|
+
Buffer.byteLength(literalText) > 4096 ||
|
|
570
|
+
Buffer.from(literalText).toString('utf8') !== literalText
|
|
571
|
+
) {
|
|
572
|
+
throw new RangeError('Output literal must be non-empty valid UTF-8, at most 4096 bytes.')
|
|
573
|
+
}
|
|
574
|
+
const stream = requestedStream ?? 'either'
|
|
575
|
+
if (!['stdout', 'stderr', 'either'].includes(stream))
|
|
576
|
+
throw new RangeError('Unknown output stream.')
|
|
577
|
+
for (const [name, value] of [
|
|
578
|
+
['timeoutMs', timeoutMs],
|
|
579
|
+
['idleTimeoutMs', idleTimeoutMs],
|
|
580
|
+
] as const) {
|
|
581
|
+
if (
|
|
582
|
+
(name === 'timeoutMs' || value !== undefined) &&
|
|
583
|
+
(value === undefined ||
|
|
584
|
+
!Number.isSafeInteger(value) ||
|
|
585
|
+
value < 1 ||
|
|
586
|
+
value > MAX_OUTPUT_WAIT_MS)
|
|
587
|
+
) {
|
|
588
|
+
throw new RangeError(`${name} must be an integer from 1 through ${MAX_OUTPUT_WAIT_MS}.`)
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
const from = fromOffset ?? 0
|
|
592
|
+
if (!Number.isSafeInteger(from) || from < 0 || from > entry.produced) {
|
|
593
|
+
throw new RangeError('fromOffset must be an observed, nonnegative output byte cursor.')
|
|
594
|
+
}
|
|
595
|
+
const literal = Buffer.from(literalText)
|
|
596
|
+
const suffix = { stdout: Buffer.alloc(0), stderr: Buffer.alloc(0) }
|
|
597
|
+
const match = (chunk: OutputChunk): 'stdout' | 'stderr' | undefined => {
|
|
598
|
+
if (
|
|
599
|
+
(stream !== 'either' && stream !== chunk.stream) ||
|
|
600
|
+
chunk.offset + chunk.bytes.length <= from
|
|
601
|
+
)
|
|
602
|
+
return
|
|
603
|
+
const skip = utf8Start(chunk.bytes, Math.max(0, from - chunk.offset))
|
|
604
|
+
const bytes = Buffer.concat([suffix[chunk.stream], chunk.bytes.subarray(skip)])
|
|
605
|
+
const found = bytes.indexOf(literal) !== -1
|
|
606
|
+
// Only the bytes that can prefix a future match survive each chunk.
|
|
607
|
+
// Copy so a tiny suffix never retains a large producer buffer.
|
|
608
|
+
suffix[chunk.stream] = Buffer.from(
|
|
609
|
+
bytes.subarray(Math.max(0, bytes.length - literal.length + 1)),
|
|
610
|
+
)
|
|
611
|
+
return found ? chunk.stream : undefined
|
|
612
|
+
}
|
|
613
|
+
let output = ''
|
|
614
|
+
let cursor = from
|
|
615
|
+
let droppedBytes = 0
|
|
616
|
+
let omittedOutputBytes = 0
|
|
617
|
+
const read = (): void => {
|
|
618
|
+
const observed = this.read(id, { fromOffset: cursor })
|
|
619
|
+
cursor = observed.nextOffset
|
|
620
|
+
droppedBytes += observed.droppedBytes
|
|
621
|
+
const tail = outputTail(output + observed.chunk, MAX_WAIT_RESULT_BYTES)
|
|
622
|
+
output = tail.text
|
|
623
|
+
omittedOutputBytes += tail.omitted
|
|
624
|
+
}
|
|
625
|
+
read()
|
|
626
|
+
const retainedStart = entry.produced - Buffer.byteLength(entry.buffer)
|
|
627
|
+
const searchableStart = entry.outputChunks[0]?.offset ?? entry.produced
|
|
628
|
+
const unsearchedBytes = Math.max(0, searchableStart - Math.max(from, retainedStart))
|
|
629
|
+
const progress = () => ({
|
|
630
|
+
status: entry.record.status,
|
|
631
|
+
...(entry.record.exitCode === undefined ? {} : { exitCode: entry.record.exitCode }),
|
|
632
|
+
...(entry.record.error === undefined ? {} : { error: entry.record.error }),
|
|
633
|
+
output,
|
|
634
|
+
nextOffset: cursor,
|
|
635
|
+
droppedBytes,
|
|
636
|
+
unsearchedBytes,
|
|
637
|
+
omittedOutputBytes,
|
|
638
|
+
})
|
|
639
|
+
if (signal?.aborted) return Promise.resolve({ ...progress(), kind: 'aborted' })
|
|
640
|
+
// Check synchronously before subscribing. No process event can intervene
|
|
641
|
+
// in this call stack, so even a marker printed before activation is seen.
|
|
642
|
+
for (const chunk of entry.outputChunks) {
|
|
643
|
+
const matchedStream = match(chunk)
|
|
644
|
+
if (matchedStream) return Promise.resolve({ ...progress(), kind: 'matched', matchedStream })
|
|
645
|
+
}
|
|
646
|
+
if (entry.record.status !== 'running') {
|
|
647
|
+
return Promise.resolve({
|
|
648
|
+
...progress(),
|
|
649
|
+
kind: entry.record.status === 'killed' ? 'stopped' : 'exited',
|
|
650
|
+
})
|
|
651
|
+
}
|
|
652
|
+
const owner = entry.record.owner
|
|
653
|
+
const ownerCount = this.outputWaitersByOwner.get(owner) ?? 0
|
|
654
|
+
const ownerLimit = this.config.maxOutputWaitersPerOwner ?? 32
|
|
655
|
+
const globalLimit = this.config.maxOutputWaiters ?? 256
|
|
656
|
+
if (ownerCount >= ownerLimit)
|
|
657
|
+
throw new BackgroundJobOutputWaitLimitError({ owner, limit: ownerLimit, scope: 'owner' })
|
|
658
|
+
if (this.outputWaiters >= globalLimit)
|
|
659
|
+
throw new BackgroundJobOutputWaitLimitError({ owner, limit: globalLimit, scope: 'registry' })
|
|
660
|
+
this.outputWaiters++
|
|
661
|
+
this.outputWaitersByOwner.set(owner, ownerCount + 1)
|
|
662
|
+
return new Promise((resolve) => {
|
|
663
|
+
const startedAt = Date.now()
|
|
664
|
+
let settled = false
|
|
665
|
+
let disposeAbort = () => {}
|
|
666
|
+
let idleTimer: ReturnType<typeof setTimeout> | undefined
|
|
667
|
+
const finish = (result: BackgroundJobOutputWaitResult): void => {
|
|
668
|
+
if (settled) return
|
|
669
|
+
settled = true
|
|
670
|
+
entry.outputObservers.delete(observe)
|
|
671
|
+
clearTimeout(wallTimer)
|
|
672
|
+
clearTimeout(idleTimer)
|
|
673
|
+
disposeAbort()
|
|
674
|
+
this.outputWaiters--
|
|
675
|
+
const remaining = (this.outputWaitersByOwner.get(owner) ?? 1) - 1
|
|
676
|
+
if (remaining === 0) this.outputWaitersByOwner.delete(owner)
|
|
677
|
+
else this.outputWaitersByOwner.set(owner, remaining)
|
|
678
|
+
resolve(result)
|
|
679
|
+
}
|
|
680
|
+
const timeout = (cause: 'wall' | 'idle'): void => {
|
|
681
|
+
read()
|
|
682
|
+
finish({ ...progress(), kind: 'timeout', cause, elapsedMs: Date.now() - startedAt })
|
|
683
|
+
}
|
|
684
|
+
const resetIdle = (): void => {
|
|
685
|
+
if (idleTimeoutMs === undefined) return
|
|
686
|
+
clearTimeout(idleTimer)
|
|
687
|
+
idleTimer = setTimeout(() => timeout('idle'), idleTimeoutMs)
|
|
688
|
+
idleTimer.unref?.()
|
|
689
|
+
}
|
|
690
|
+
const observe = (chunk?: OutputChunk): void => {
|
|
691
|
+
read()
|
|
692
|
+
const matchedStream = chunk ? match(chunk) : undefined
|
|
693
|
+
if (matchedStream) finish({ ...progress(), kind: 'matched', matchedStream })
|
|
694
|
+
else if (entry.record.status !== 'running') {
|
|
695
|
+
finish({ ...progress(), kind: entry.record.status === 'killed' ? 'stopped' : 'exited' })
|
|
696
|
+
} else if (chunk) resetIdle()
|
|
697
|
+
}
|
|
698
|
+
entry.outputObservers.add(observe)
|
|
699
|
+
const wallTimer = setTimeout(() => timeout('wall'), timeoutMs)
|
|
700
|
+
wallTimer.unref?.()
|
|
701
|
+
resetIdle()
|
|
702
|
+
if (signal)
|
|
703
|
+
disposeAbort = subscribeToAbort(signal, () => {
|
|
704
|
+
read()
|
|
705
|
+
finish({ ...progress(), kind: 'aborted' })
|
|
706
|
+
})
|
|
707
|
+
})
|
|
708
|
+
}
|
|
709
|
+
|
|
372
710
|
/**
|
|
373
711
|
* Output since `fromOffset`, with what the cap dropped stated.
|
|
374
712
|
*
|
|
@@ -386,14 +724,17 @@ export class BackgroundJobRegistry {
|
|
|
386
724
|
// the gap is reported rather than closed over.
|
|
387
725
|
const effective = Math.max(from, bufferStart)
|
|
388
726
|
const skip = Math.max(0, effective - bufferStart)
|
|
389
|
-
const
|
|
727
|
+
const bytes = Buffer.from(entry.buffer)
|
|
728
|
+
const aligned = utf8Start(bytes, skip)
|
|
729
|
+
const chunk = bytes.subarray(aligned).toString('utf8')
|
|
390
730
|
|
|
391
731
|
return {
|
|
392
732
|
chunk,
|
|
393
733
|
nextOffset: entry.produced,
|
|
394
|
-
droppedBytes: Math.max(0, effective - from),
|
|
734
|
+
droppedBytes: Math.max(0, effective - from) + Math.max(0, aligned - skip),
|
|
395
735
|
status: entry.record.status,
|
|
396
736
|
...(entry.record.exitCode === undefined ? {} : { exitCode: entry.record.exitCode }),
|
|
737
|
+
...(entry.record.error === undefined ? {} : { error: entry.record.error }),
|
|
397
738
|
}
|
|
398
739
|
}
|
|
399
740
|
|
|
@@ -402,11 +743,18 @@ export class BackgroundJobRegistry {
|
|
|
402
743
|
const entry = this.jobs.get(id)
|
|
403
744
|
if (!entry) throw new UnknownBackgroundJobError({ id })
|
|
404
745
|
if (entry.record.status !== 'running') return entry.record
|
|
746
|
+
if (entry.terminateProcess) {
|
|
747
|
+
entry.killRequested = true
|
|
748
|
+
await this.confirmTermination(entry)
|
|
749
|
+
await entry.exit
|
|
750
|
+
return entry.record
|
|
751
|
+
}
|
|
405
752
|
|
|
406
753
|
// Marked before the signal, so the `close` handler that follows can
|
|
407
754
|
// tell a kill from an ordinary exit. Set it after and the race decides
|
|
408
755
|
// which of two different answers a reader gets.
|
|
409
756
|
entry.record = { ...entry.record, status: 'killed' }
|
|
757
|
+
for (const observer of entry.outputObservers) observer()
|
|
410
758
|
const signal = (sig: NodeJS.Signals) =>
|
|
411
759
|
entry.killProcess ? entry.killProcess(sig) : killTree(entry.child, sig)
|
|
412
760
|
signal('SIGTERM')
|
|
@@ -509,6 +857,10 @@ export function bindOwner(
|
|
|
509
857
|
})
|
|
510
858
|
},
|
|
511
859
|
get: (id: string) => mine(id),
|
|
860
|
+
awaitStarted: (id: string) => {
|
|
861
|
+
mine(id)
|
|
862
|
+
return registry.awaitStarted(id)
|
|
863
|
+
},
|
|
512
864
|
read: (id: string, opts?: { fromOffset?: number }) => {
|
|
513
865
|
mine(id)
|
|
514
866
|
return registry.read(id, opts ?? {})
|
|
@@ -517,6 +869,10 @@ export function bindOwner(
|
|
|
517
869
|
mine(id)
|
|
518
870
|
return registry.waitForExit(id, opts ?? {})
|
|
519
871
|
},
|
|
872
|
+
waitForOutput: (id: string, opts: BackgroundJobOutputWaitOptions) => {
|
|
873
|
+
mine(id)
|
|
874
|
+
return registry.waitForOutput(id, opts)
|
|
875
|
+
},
|
|
520
876
|
...(defaults.onAwaited
|
|
521
877
|
? {
|
|
522
878
|
markAwaited: (id: string) => {
|
|
@@ -20,6 +20,18 @@ export interface SessionLocatorOptions {
|
|
|
20
20
|
readonly lease?: SessionLease
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
/** Options for {@link abandonTurn}. */
|
|
24
|
+
export interface AbandonTurnOptions extends SessionLocatorOptions {
|
|
25
|
+
/**
|
|
26
|
+
* The caller gives the turn's messages back to the person, for instance by
|
|
27
|
+
* putting the prompt back in a message box to send again. The abandoned
|
|
28
|
+
* turn then contributes no message to the next turn's context, so the
|
|
29
|
+
* provider does not see that prompt twice. The records stay in the log.
|
|
30
|
+
* Absent (the default): the turn's messages stay in the context.
|
|
31
|
+
*/
|
|
32
|
+
readonly withdrawMessages?: boolean
|
|
33
|
+
}
|
|
34
|
+
|
|
23
35
|
/** Lease time-to-live for a lease a session-level operation claims for one append. */
|
|
24
36
|
const OPERATION_LEASE_TTL_MS = 30_000
|
|
25
37
|
|
|
@@ -103,8 +115,12 @@ export async function abandonTurn(
|
|
|
103
115
|
sessionId: SessionId,
|
|
104
116
|
turnId: TurnId,
|
|
105
117
|
reason: string,
|
|
106
|
-
options:
|
|
118
|
+
options: AbandonTurnOptions = {},
|
|
107
119
|
): Promise<void> {
|
|
108
120
|
const log = await locateSessionLog(sessionId, options)
|
|
109
|
-
await withSessionLease(log, options.lease, (lease) =>
|
|
121
|
+
await withSessionLease(log, options.lease, (lease) =>
|
|
122
|
+
log.abandonTurn(lease, turnId, reason, {
|
|
123
|
+
...(options.withdrawMessages ? { withdrawMessages: true } : {}),
|
|
124
|
+
}),
|
|
125
|
+
)
|
|
110
126
|
}
|
|
@@ -268,6 +268,8 @@ export class CheckpointManager {
|
|
|
268
268
|
private restoredReviewAttempts = 0
|
|
269
269
|
private nativeStructuredAttemptsSource?: () => number
|
|
270
270
|
private restoredNativeAttempts = 0
|
|
271
|
+
private toolStructuredAttemptsSource?: () => number
|
|
272
|
+
private restoredToolAttempts = 0
|
|
271
273
|
private lastCreatedId?: CheckpointId
|
|
272
274
|
private traceSource?: () => SerializedSpanContext | undefined
|
|
273
275
|
private parkTtlMs?: number
|
|
@@ -314,6 +316,13 @@ export class CheckpointManager {
|
|
|
314
316
|
return this.restoredNativeAttempts
|
|
315
317
|
}
|
|
316
318
|
|
|
319
|
+
setToolStructuredAttemptsSource(source: () => number): void {
|
|
320
|
+
this.toolStructuredAttemptsSource = source
|
|
321
|
+
}
|
|
322
|
+
get restoredToolStructuredAttempts(): number {
|
|
323
|
+
return this.restoredToolAttempts
|
|
324
|
+
}
|
|
325
|
+
|
|
317
326
|
setStructuredReviewAttemptsSource(source: () => number): void {
|
|
318
327
|
this.structuredReviewAttemptsSource = source
|
|
319
328
|
}
|
|
@@ -398,6 +407,7 @@ export class CheckpointManager {
|
|
|
398
407
|
answerAttempts: this.answerReviewAttemptsSource?.() ?? this.restoredAnswerAttempts,
|
|
399
408
|
nativeStructuredAttempts:
|
|
400
409
|
this.nativeStructuredAttemptsSource?.() ?? this.restoredNativeAttempts,
|
|
410
|
+
toolStructuredAttempts: this.toolStructuredAttemptsSource?.() ?? this.restoredToolAttempts,
|
|
401
411
|
},
|
|
402
412
|
...(latestUserMessageId ? { latestUserMessageId } : {}),
|
|
403
413
|
...withDefined('workingState', this.workingStateSource?.()),
|
|
@@ -597,6 +607,7 @@ export class CheckpointManager {
|
|
|
597
607
|
this.turnCreatedAt ??= document.turnCreatedAt
|
|
598
608
|
this.restoredAnswerAttempts = document.review.answerAttempts
|
|
599
609
|
this.restoredNativeAttempts = document.review.nativeStructuredAttempts
|
|
610
|
+
this.restoredToolAttempts = document.review.toolStructuredAttempts ?? 0
|
|
600
611
|
this.restoredReviewAttempts = document.review.structuredAttempts
|
|
601
612
|
this.restoredUserMessage = restored.latestUserMessage
|
|
602
613
|
this.restoredUserMessageId = restored.latestUserMessage
|