@ours.network/fleet 1.2.0-nightly.7 → 1.2.0-nightly.70
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/README.md +279 -68
- package/dist/account-origin.d.ts +2 -0
- package/dist/account-origin.js +6 -0
- package/dist/agent-ours/bridge.js +26 -9
- package/dist/agent-ours/correspondence.d.ts +10 -0
- package/dist/agent-ours/correspondence.js +1 -0
- package/dist/agent-ours/file-rpc.d.ts +12 -0
- package/dist/agent-ours/file-rpc.js +18 -4
- package/dist/agent-ours/harness.js +9 -1
- package/dist/agent-ours/mcp-endpoint.d.ts +19 -0
- package/dist/agent-ours/mcp-endpoint.js +98 -25
- package/dist/agent-ours/runtime.d.ts +9 -1
- package/dist/agent-ours/runtime.js +50 -2
- package/dist/agent-ours/service.d.ts +24 -1
- package/dist/agent-ours/service.js +97 -13
- package/dist/application/codex-models.d.ts +15 -0
- package/dist/application/codex-models.js +56 -0
- package/dist/application/conversation-history.d.ts +27 -0
- package/dist/application/conversation-history.js +215 -0
- package/dist/application/conversation-role-observer.d.ts +62 -0
- package/dist/application/conversation-role-observer.js +206 -0
- package/dist/application/fleet-query-service.d.ts +1 -1
- package/dist/application/fleet-query-service.js +2 -2
- package/dist/application/log-service.js +8 -8
- package/dist/application/model-catalog.d.ts +1 -1
- package/dist/application/model-catalog.js +5 -2
- package/dist/application/preset-provenance.d.ts +19 -0
- package/dist/application/preset-provenance.js +59 -0
- package/dist/application/role-creation-service.js +3 -2
- package/dist/application/role-removal-service.js +17 -3
- package/dist/application/role-repository.js +19 -2
- package/dist/application/room-layout-definitions.d.ts +45 -0
- package/dist/application/room-layout-definitions.js +130 -0
- package/dist/application/session-control.d.ts +61 -17
- package/dist/application/session-control.js +207 -23
- package/dist/application/supervisor-ours-tools.js +5 -11
- package/dist/application/task-layouts.d.ts +91 -0
- package/dist/application/task-layouts.js +259 -0
- package/dist/application/task-room-service.d.ts +99 -3
- package/dist/application/task-room-service.js +285 -32
- package/dist/application/types.d.ts +2 -0
- package/dist/atomic-file.d.ts +34 -1
- package/dist/atomic-file.js +161 -18
- package/dist/briefing.d.ts +3 -1
- package/dist/briefing.js +97 -31
- package/dist/build-info.json +9 -4
- package/dist/capabilities.d.ts +9 -1
- package/dist/capabilities.js +13 -0
- package/dist/cli.js +400 -37
- package/dist/client-profile.d.ts +5 -17
- package/dist/client-profile.js +4 -127
- package/dist/config.d.ts +45 -0
- package/dist/config.js +57 -6
- package/dist/creation.d.ts +1 -1
- package/dist/creation.js +4 -4
- package/dist/daemon-recovery.d.ts +1 -8
- package/dist/daemon-recovery.js +8 -113
- package/dist/docs.d.ts +1 -1
- package/dist/docs.js +207 -19
- package/dist/doctor.d.ts +4 -1
- package/dist/doctor.js +75 -60
- package/dist/erased-resources.d.ts +9 -0
- package/dist/erased-resources.js +87 -0
- package/dist/file-delivery/reader.d.ts +15 -0
- package/dist/file-delivery/reader.js +63 -0
- package/dist/file-delivery/store.d.ts +15 -0
- package/dist/file-delivery/store.js +124 -0
- package/dist/file-delivery/types.d.ts +19 -0
- package/dist/file-delivery/types.js +1 -0
- package/dist/fleet-command-audit.d.ts +7 -0
- package/dist/fleet-command-audit.js +24 -8
- package/dist/harness/agent-session.d.ts +4 -0
- package/dist/harness/claude-code-session.js +1 -1
- package/dist/harness/claude-code.js +21 -11
- package/dist/harness/claude-runtime.d.ts +12 -0
- package/dist/harness/claude-runtime.js +43 -0
- package/dist/harness/codex-app-server-proxy.d.ts +4 -1
- package/dist/harness/codex-app-server-proxy.js +41 -5
- package/dist/harness/codex-reasoning.d.ts +5 -0
- package/dist/harness/codex-reasoning.js +12 -0
- package/dist/harness/codex-runtime.d.ts +11 -1
- package/dist/harness/codex-runtime.js +31 -4
- package/dist/harness/codex-session.js +2 -2
- package/dist/harness/codex.js +24 -12
- package/dist/init-wizard.d.ts +2 -0
- package/dist/init-wizard.js +38 -19
- package/dist/isolation/policy.js +6 -1
- package/dist/isolation/types.d.ts +5 -0
- package/dist/managed-cli.d.ts +253 -0
- package/dist/managed-cli.js +923 -0
- package/dist/managed-recovery.d.ts +13 -0
- package/dist/managed-recovery.js +31 -0
- package/dist/minimal-setup.d.ts +2 -0
- package/dist/minimal-setup.js +44 -0
- package/dist/monitor.d.ts +8 -34
- package/dist/monitor.js +89 -152
- package/dist/notifications/fleet-producer.d.ts +19 -0
- package/dist/notifications/fleet-producer.js +208 -0
- package/dist/notifications/outbox.d.ts +46 -0
- package/dist/notifications/outbox.js +158 -0
- package/dist/notifications/target-cleanup.d.ts +10 -0
- package/dist/notifications/target-cleanup.js +63 -0
- package/dist/notifications/task-producer.d.ts +18 -0
- package/dist/notifications/task-producer.js +67 -0
- package/dist/ops.d.ts +2 -0
- package/dist/ops.js +20 -3
- package/dist/owner-channel/channel.js +17 -6
- package/dist/owner-channel/commands.d.ts +4 -0
- package/dist/owner-channel/commands.js +8 -0
- package/dist/owner-channel/lifecycle-outbox.js +4 -3
- package/dist/owner-channel/ours-client.js +2 -17
- package/dist/paths.d.ts +2 -0
- package/dist/paths.js +2 -0
- package/dist/preset-migration.js +43 -0
- package/dist/process-incarnation.d.ts +23 -0
- package/dist/process-incarnation.js +42 -0
- package/dist/reminders/manager.d.ts +75 -0
- package/dist/reminders/manager.js +278 -0
- package/dist/reminders/runtime.d.ts +27 -0
- package/dist/reminders/runtime.js +32 -0
- package/dist/reminders/schedule.d.ts +37 -0
- package/dist/reminders/schedule.js +104 -0
- package/dist/reminders/store.d.ts +341 -0
- package/dist/reminders/store.js +762 -0
- package/dist/reminders/tools.d.ts +20 -0
- package/dist/reminders/tools.js +114 -0
- package/dist/resolved-plan.js +1 -0
- package/dist/rooms-tasks/add-member.d.ts +48 -0
- package/dist/rooms-tasks/add-member.js +83 -0
- package/dist/rooms-tasks/archived-absence.d.ts +8 -0
- package/dist/rooms-tasks/archived-absence.js +48 -0
- package/dist/rooms-tasks/cli.js +65 -5
- package/dist/rooms-tasks/close.d.ts +6 -2
- package/dist/rooms-tasks/close.js +246 -37
- package/dist/rooms-tasks/config.d.ts +1 -1
- package/dist/rooms-tasks/config.js +11 -4
- package/dist/rooms-tasks/cowork-adapter.d.ts +12 -5
- package/dist/rooms-tasks/cowork-adapter.js +15 -121
- package/dist/rooms-tasks/cowork-http.js +56 -6
- package/dist/rooms-tasks/deletion.d.ts +1 -1
- package/dist/rooms-tasks/deletion.js +84 -5
- package/dist/rooms-tasks/erasure.d.ts +6 -0
- package/dist/rooms-tasks/erasure.js +173 -0
- package/dist/rooms-tasks/external-worker.d.ts +1 -1
- package/dist/rooms-tasks/external-worker.js +3 -4
- package/dist/rooms-tasks/layout-binding-client.d.ts +11 -0
- package/dist/rooms-tasks/layout-binding-client.js +56 -0
- package/dist/rooms-tasks/layout-binding-grants.d.ts +21 -0
- package/dist/rooms-tasks/layout-binding-grants.js +128 -0
- package/dist/rooms-tasks/layout-cli.d.ts +4 -0
- package/dist/rooms-tasks/layout-cli.js +107 -0
- package/dist/rooms-tasks/layout-config.d.ts +11 -0
- package/dist/rooms-tasks/layout-config.js +89 -0
- package/dist/rooms-tasks/layout-control.d.ts +21 -0
- package/dist/rooms-tasks/layout-control.js +52 -0
- package/dist/rooms-tasks/layout-member-retirement.d.ts +10 -0
- package/dist/rooms-tasks/layout-member-retirement.js +90 -0
- package/dist/rooms-tasks/layout-service.d.ts +43 -0
- package/dist/rooms-tasks/layout-service.js +203 -0
- package/dist/rooms-tasks/layout.d.ts +121 -0
- package/dist/rooms-tasks/layout.js +285 -0
- package/dist/rooms-tasks/legacy-task-member.d.ts +19 -0
- package/dist/rooms-tasks/legacy-task-member.js +116 -0
- package/dist/rooms-tasks/live-readiness.d.ts +18 -0
- package/dist/rooms-tasks/live-readiness.js +85 -0
- package/dist/rooms-tasks/member-ownership.d.ts +5 -0
- package/dist/rooms-tasks/member-ownership.js +40 -0
- package/dist/rooms-tasks/member-startup.d.ts +1 -0
- package/dist/rooms-tasks/member-startup.js +2 -0
- package/dist/rooms-tasks/provision.d.ts +3 -0
- package/dist/rooms-tasks/provision.js +101 -49
- package/dist/rooms-tasks/recovery.d.ts +19 -0
- package/dist/rooms-tasks/recovery.js +110 -0
- package/dist/rooms-tasks/room-state.d.ts +4 -2
- package/dist/rooms-tasks/room-state.js +47 -8
- package/dist/rooms-tasks/task-service-retirement.d.ts +11 -0
- package/dist/rooms-tasks/task-service-retirement.js +21 -0
- package/dist/rooms-tasks/task-state.d.ts +51 -8
- package/dist/rooms-tasks/task-state.js +245 -25
- package/dist/rooms-tasks/types.d.ts +40 -0
- package/dist/rooms-tasks/workspace-artifacts.d.ts +6 -0
- package/dist/rooms-tasks/workspace-artifacts.js +93 -0
- package/dist/rooms-tasks/workspace.d.ts +35 -0
- package/dist/rooms-tasks/workspace.js +325 -0
- package/dist/runner.d.ts +33 -4
- package/dist/runner.js +389 -56
- package/dist/session/acp.d.ts +75 -2
- package/dist/session/acp.js +345 -82
- package/dist/session/arbiter.d.ts +98 -0
- package/dist/session/arbiter.js +272 -3
- package/dist/session/codex-app-server.d.ts +45 -1
- package/dist/session/codex-app-server.js +225 -32
- package/dist/session/control.d.ts +17 -3
- package/dist/session/control.js +213 -23
- package/dist/session/conversation-normalizer.d.ts +2 -1
- package/dist/session/conversation-normalizer.js +1 -1
- package/dist/session/conversation-observation.d.ts +25 -0
- package/dist/session/conversation-observation.js +100 -0
- package/dist/session/conversation-replay.d.ts +50 -0
- package/dist/session/conversation-replay.js +203 -0
- package/dist/session/conversation-store.d.ts +15 -1
- package/dist/session/conversation-store.js +206 -26
- package/dist/session/conversation-types.d.ts +57 -4
- package/dist/session/prompt-batch.d.ts +79 -0
- package/dist/session/prompt-batch.js +120 -0
- package/dist/session/task-notice.d.ts +14 -0
- package/dist/session/task-notice.js +13 -0
- package/dist/session/types.d.ts +42 -1
- package/dist/setup-tunnel-preflight.d.ts +34 -0
- package/dist/setup-tunnel-preflight.js +62 -0
- package/dist/socket-path.d.ts +2 -0
- package/dist/socket-path.js +22 -0
- package/dist/spawn.d.ts +5 -1
- package/dist/spawn.js +40 -4
- package/dist/startup-prompt.d.ts +15 -0
- package/dist/startup-prompt.js +71 -0
- package/dist/startup-readiness.d.ts +32 -0
- package/dist/startup-readiness.js +101 -0
- package/dist/startup-telemetry.d.ts +16 -0
- package/dist/startup-telemetry.js +46 -0
- package/dist/subscriptions/cli.d.ts +91 -0
- package/dist/subscriptions/cli.js +223 -0
- package/dist/subscriptions/launch.d.ts +37 -0
- package/dist/subscriptions/launch.js +93 -0
- package/dist/subscriptions/login.d.ts +76 -0
- package/dist/subscriptions/login.js +207 -0
- package/dist/subscriptions/observed.d.ts +7 -0
- package/dist/subscriptions/observed.js +44 -0
- package/dist/subscriptions/probe.d.ts +10 -0
- package/dist/subscriptions/probe.js +73 -0
- package/dist/subscriptions/service.d.ts +102 -0
- package/dist/subscriptions/service.js +364 -0
- package/dist/subscriptions/store.d.ts +71 -0
- package/dist/subscriptions/store.js +140 -0
- package/dist/supervisor/adoption.d.ts +8 -0
- package/dist/supervisor/adoption.js +78 -0
- package/dist/supervisor/catalog.d.ts +62 -0
- package/dist/supervisor/catalog.js +254 -0
- package/dist/supervisor/fleet.d.ts +8 -0
- package/dist/supervisor/fleet.js +89 -0
- package/dist/supervisor/index.js +3 -6
- package/dist/supervisor/launchd.d.ts +1 -1
- package/dist/supervisor/launchd.js +26 -13
- package/dist/supervisor/legacy.d.ts +35 -0
- package/dist/supervisor/legacy.js +524 -0
- package/dist/supervisor/manager.d.ts +15 -0
- package/dist/supervisor/manager.js +270 -0
- package/dist/supervisor/registration-refresh.d.ts +45 -0
- package/dist/supervisor/registration-refresh.js +266 -0
- package/dist/supervisor/scope.d.ts +4 -0
- package/dist/supervisor/scope.js +10 -0
- package/dist/supervisor/systemd.d.ts +2 -2
- package/dist/supervisor/systemd.js +19 -33
- package/dist/task-supervision.d.ts +9 -0
- package/dist/task-supervision.js +145 -0
- package/dist/temp-idle.d.ts +17 -0
- package/dist/temp-idle.js +42 -0
- package/dist/temp-lifecycle.d.ts +23 -8
- package/dist/temp-lifecycle.js +123 -66
- package/dist/temp-supervisor-recovery.d.ts +1 -1
- package/dist/temp-supervisor-recovery.js +2 -2
- package/dist/tunnel-setup-completion.d.ts +7 -0
- package/dist/tunnel-setup-completion.js +13 -0
- package/dist/tunnel-setup-input.d.ts +19 -0
- package/dist/tunnel-setup-input.js +124 -0
- package/dist/web/agent-attachments.d.ts +29 -0
- package/dist/web/agent-attachments.js +162 -0
- package/dist/web/auth.d.ts +65 -2
- package/dist/web/auth.js +201 -11
- package/dist/web/available-port.d.ts +2 -0
- package/dist/web/available-port.js +23 -0
- package/dist/web/control.d.ts +3 -3
- package/dist/web/control.js +10 -8
- package/dist/web/conversation-stream-codec.d.ts +23 -0
- package/dist/web/conversation-stream-codec.js +110 -0
- package/dist/web/conversation-stream.d.ts +25 -0
- package/dist/web/conversation-stream.js +231 -0
- package/dist/web/fleet-config-service.d.ts +4 -1
- package/dist/web/fleet-config-service.js +46 -15
- package/dist/web/prefix-gateway.d.ts +32 -0
- package/dist/web/prefix-gateway.js +238 -0
- package/dist/web/runtime.d.ts +3 -1
- package/dist/web/runtime.js +128 -33
- package/dist/web/server.d.ts +16 -0
- package/dist/web/server.js +639 -55
- package/dist/web/service.d.ts +11 -2
- package/dist/web/service.js +30 -4
- package/dist/web/workspace-devices.d.ts +107 -0
- package/dist/web/workspace-devices.js +277 -0
- package/dist/web/workspace-tunnel.d.ts +1 -0
- package/dist/web/workspace-tunnel.js +34 -0
- package/dist/workspace-enrollment.d.ts +83 -0
- package/dist/workspace-enrollment.js +580 -0
- package/dist/workspace-replacement.d.ts +66 -0
- package/dist/workspace-replacement.js +220 -0
- package/docs/acp-files.md +146 -0
- package/docs/conversation-stream.md +190 -0
- package/docs/fleet-migration.md +54 -0
- package/docs/live-voice.md +13 -0
- package/docs/room-layouts.md +227 -0
- package/docs/self-reminders.md +374 -0
- package/docs/task-workspaces.md +225 -0
- package/docs/validation/managed-cli-permissions.md +421 -0
- package/examples/room-layouts/fresh.yaml +27 -0
- package/examples/room-layouts/scoped.yaml +21 -0
- package/examples/room-layouts/shared.yaml +19 -0
- package/package.json +24 -20
- package/presets/README.md +78 -0
- package/presets/brain-catalog.json +8 -2
- package/presets/fleet/agent_templates/Critic.yaml +1 -1
- package/presets/fleet/agent_templates/Developer.yaml +1 -1
- package/presets/fleet/agent_templates/Engineer.yaml +5 -0
- package/presets/fleet/agent_templates/LocalCoordinator.yaml +4 -2
- package/presets/fleet/agents/FleetCoordinator.yaml +1 -1
- package/presets/fleet/brains/claude-fable-5-1-high.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-1-low.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-1-max.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-1-medium.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-1-xhigh.yaml +5 -0
- package/presets/fleet/brains/claude-fable-5-high.yaml +1 -1
- package/presets/fleet/brains/claude-fable-5-low.yaml +1 -1
- package/presets/fleet/brains/claude-fable-5-max.yaml +1 -1
- package/presets/fleet/brains/claude-fable-5-medium.yaml +1 -1
- package/presets/fleet/brains/claude-fable-5-xhigh.yaml +1 -1
- package/presets/fleet/brains/claude-haiku-4-5-20251001-default.yaml +4 -0
- package/presets/fleet/brains/claude-opus-5-5-high.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-5-low.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-5-max.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-5-medium.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-5-xhigh.yaml +5 -0
- package/presets/fleet/brains/claude-opus-5-high.yaml +1 -1
- package/presets/fleet/brains/claude-opus-5-low.yaml +1 -1
- package/presets/fleet/brains/claude-opus-5-max.yaml +1 -1
- package/presets/fleet/brains/claude-opus-5-medium.yaml +1 -1
- package/presets/fleet/brains/claude-opus-5-xhigh.yaml +1 -1
- package/presets/fleet/brains/claude-sonnet-5-high.yaml +1 -1
- package/presets/fleet/brains/claude-sonnet-5-low.yaml +1 -1
- package/presets/fleet/brains/claude-sonnet-5-max.yaml +1 -1
- package/presets/fleet/brains/claude-sonnet-5-medium.yaml +1 -1
- package/presets/fleet/brains/claude-sonnet-5-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-3-codex-spark-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-mini-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-mini-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-mini-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-mini-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-4-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-5-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-5-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-5-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-5-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-luna-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-luna-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-luna-max.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-luna-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-luna-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-sol-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-sol-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-sol-max.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-sol-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-sol-ultra.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-sol-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-terra-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-terra-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-terra-max.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-terra-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-terra-ultra.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-5-6-terra-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-6-1-sol-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-1-sol-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-1-sol-max.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-1-sol-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-1-sol-ultra.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-1-sol-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-astra-high.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-6-astra-low.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-6-astra-max.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-6-astra-medium.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-6-astra-ultra.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-6-astra-xhigh.yaml +1 -1
- package/presets/fleet/brains/codex-gpt-6-luna-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-luna-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-luna-max.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-luna-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-luna-xhigh.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-sol-high.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-sol-low.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-sol-max.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-sol-medium.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-sol-ultra.yaml +5 -0
- package/presets/fleet/brains/codex-gpt-6-sol-xhigh.yaml +5 -0
- package/presets/fleet/roles/Coordinator.yaml +12 -11
- package/presets/fleet/roles/Critic.yaml +13 -0
- package/presets/fleet/roles/Developer.yaml +13 -0
- package/presets/fleet/roles/Engineer.yaml +53 -0
- package/presets/fleet/room_layouts/engineering.yaml +25 -0
- package/presets/fleet/room_layouts/pair.yaml +24 -0
- package/presets/fleet/room_layouts/single.yaml +17 -0
- package/presets/fleet/room_layouts/team.yaml +30 -0
- package/presets/fleet/room_templates/engineering.yaml +19 -0
- package/presets/manifest.json +2 -2
- package/dist/web-app/assets/index-59GF-gsZ.css +0 -1
- package/dist/web-app/assets/index-C0h3ALvs.js +0 -10
- package/dist/web-app/icons/ours-fleet-maskable.svg +0 -4
- package/dist/web-app/icons/ours-fleet.svg +0 -4
- package/dist/web-app/index.html +0 -17
- package/dist/web-app/manifest.webmanifest +0 -15
- package/dist/web-app/offline.html +0 -18
- package/dist/web-app/sw.js +0 -51
|
@@ -1,5 +1,53 @@
|
|
|
1
1
|
import type { ConversationHandlePage, ExitRecord, InterruptOutcome, PromptOrigin, QueuedPrompt, SessionEvent, AgentSession, SessionSnapshot, SubmitPromptOptions, TurnCancellationSource, TurnResult } from './types.js';
|
|
2
2
|
import type { ConversationEventV1, ConversationSnapshot, PromptReceipt, SubmitPromptCommand } from './conversation-types.js';
|
|
3
|
+
export type ReminderAttempt =
|
|
4
|
+
/** Admitted; `queued.completion` settles when the turn (or its refusal) ends. */
|
|
5
|
+
{
|
|
6
|
+
state: 'admitted';
|
|
7
|
+
queued: QueuedPrompt;
|
|
8
|
+
} | {
|
|
9
|
+
state: 'busy';
|
|
10
|
+
} | {
|
|
11
|
+
state: 'unavailable';
|
|
12
|
+
error: string;
|
|
13
|
+
admitted: false;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* The single interruption an urgent reminder may request, as the arbiter saw
|
|
17
|
+
* it. `target` names the exact checked turn; `outcome` is what the session
|
|
18
|
+
* and the target's own terminal result actually reported.
|
|
19
|
+
*/
|
|
20
|
+
export interface UrgentInterruptReport {
|
|
21
|
+
target: UrgentInterruptTarget;
|
|
22
|
+
outcome: 'cancelled' | 'ended' | 'forced' | 'failed';
|
|
23
|
+
reason?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface UrgentInterruptTarget {
|
|
26
|
+
source: NonNullable<SessionSnapshot['activePromptSource']>;
|
|
27
|
+
sessionId?: string;
|
|
28
|
+
generation: string;
|
|
29
|
+
promptId: string;
|
|
30
|
+
}
|
|
31
|
+
/** The urgent path's durable seams; every one is synchronous and owned by the reminder store. */
|
|
32
|
+
export interface UrgentReminderHooks {
|
|
33
|
+
/** The durable `admitting` claim (as for `tryReminder`). False: nothing is queued. */
|
|
34
|
+
beforeQueue(): boolean;
|
|
35
|
+
/** Release fence; the only way the prompt reaches the model. */
|
|
36
|
+
releaseGuard(): boolean;
|
|
37
|
+
/** Whether this event may still request its one interruption. */
|
|
38
|
+
mayInterrupt(): boolean;
|
|
39
|
+
/** Durable mark written BEFORE the session is asked to cancel. False: do not cancel. */
|
|
40
|
+
markRequested(target: UrgentInterruptTarget): boolean;
|
|
41
|
+
/** How the requested interruption ended. */
|
|
42
|
+
recordOutcome(report: UrgentInterruptReport): void;
|
|
43
|
+
/** The busy turn was not interruptible this time, and why. */
|
|
44
|
+
deferred(reason: UrgentDeferral): void;
|
|
45
|
+
/** Still this caller's current, undispatched claim? Re-checked after every await. */
|
|
46
|
+
stillAdmitting(): boolean;
|
|
47
|
+
/** The wake text, built once the interruption (if any) is known. */
|
|
48
|
+
text(report?: UrgentInterruptReport): string;
|
|
49
|
+
}
|
|
50
|
+
export type UrgentDeferral = 'protected_turn' | 'untracked_turn' | 'permission_pending' | 'queued_work' | 'session_starting' | 'interrupt_unsupported' | 'uncorrelatable' | 'interrupt_already_used';
|
|
3
51
|
export type ScheduledAttempt = {
|
|
4
52
|
state: 'started';
|
|
5
53
|
queued: QueuedPrompt;
|
|
@@ -22,7 +70,12 @@ export declare class RoleTurnArbiter implements AgentSession {
|
|
|
22
70
|
readonly capabilities: import("./types.js").AgentSessionCapabilities | undefined;
|
|
23
71
|
private tail;
|
|
24
72
|
private unsettled;
|
|
73
|
+
/** Admissions waiting for the boundary; an urgent interruption yields to them. */
|
|
74
|
+
private waiting;
|
|
75
|
+
/** Terminal results of prompts this arbiter admitted and that have not settled yet. */
|
|
76
|
+
private readonly live;
|
|
25
77
|
private stopping;
|
|
78
|
+
private retiring;
|
|
26
79
|
/** Bumped by `retireStalledAdmission`; every claim carries the one it was made under. */
|
|
27
80
|
private generation;
|
|
28
81
|
/** Resolves the instant the CURRENT generation is retired. */
|
|
@@ -53,6 +106,11 @@ export declare class RoleTurnArbiter implements AgentSession {
|
|
|
53
106
|
*/
|
|
54
107
|
retireStalledAdmission(): void;
|
|
55
108
|
queuePrompt(text: string, options?: SubmitPromptOptions): Promise<QueuedPrompt>;
|
|
109
|
+
/** Inbox traffic must not cancel or steer an active human console/voice turn.
|
|
110
|
+
* Queue it once; the monitor commits its cursor after that turn succeeds.
|
|
111
|
+
* Other origins retain their configured monitor policy.
|
|
112
|
+
*/
|
|
113
|
+
private monitorAdmissionOptions;
|
|
56
114
|
submitPrompt(text: string, options?: SubmitPromptOptions): Promise<TurnResult>;
|
|
57
115
|
/**
|
|
58
116
|
* Do not hold `exclusive` while ACP waits for a tool boundary: permission
|
|
@@ -62,6 +120,40 @@ export declare class RoleTurnArbiter implements AgentSession {
|
|
|
62
120
|
tryScheduled(text: string, origin: Extract<PromptOrigin, {
|
|
63
121
|
kind: 'scheduled-loop';
|
|
64
122
|
}>, beforeQueue?: () => void | Promise<void>): Promise<ScheduledAttempt>;
|
|
123
|
+
/**
|
|
124
|
+
* Admit a self-reminder wake only into an idle role, at the same boundary
|
|
125
|
+
* every producer uses. It never interrupts or steers, and never joins a
|
|
126
|
+
* queue behind other work: a busy role answers `busy` and the caller tries
|
|
127
|
+
* again later. `beforeQueue` makes the caller's durable claim; if it
|
|
128
|
+
* declines, nothing is queued. `releaseGuard` is the session's last-moment
|
|
129
|
+
* fence and is the only way the prompt can reach the model.
|
|
130
|
+
*/
|
|
131
|
+
tryReminder(text: string, origin: Extract<PromptOrigin, {
|
|
132
|
+
kind: 'self-reminder';
|
|
133
|
+
}>, beforeQueue: () => boolean, releaseGuard: () => boolean): Promise<ReminderAttempt>;
|
|
134
|
+
/**
|
|
135
|
+
* Admit an URGENT self-reminder wake. Idle: exactly `tryReminder`. Busy: the
|
|
136
|
+
* reminder may ask the exact checked turn to stop — once per event — and is
|
|
137
|
+
* then admitted at the next boundary like any other reminder.
|
|
138
|
+
*
|
|
139
|
+
* The check and the cancel request happen in one synchronous step inside the
|
|
140
|
+
* admission boundary, so the turn asked to stop is the turn that was checked.
|
|
141
|
+
* Only a running, correlatable, interruptible turn with nothing queued behind
|
|
142
|
+
* it and no admission waiting is ever asked to stop; anything else is a
|
|
143
|
+
* reported deferral (`busy`). After the cancellation the boundary is given up
|
|
144
|
+
* before the wake is queued, so an owner prompt (or any producer) that
|
|
145
|
+
* arrived meanwhile is admitted first and the wake simply finds the role
|
|
146
|
+
* busy. A forced, failed or uncertain cancellation never queues the wake.
|
|
147
|
+
*/
|
|
148
|
+
tryUrgentReminder(origin: Extract<PromptOrigin, {
|
|
149
|
+
kind: 'self-reminder';
|
|
150
|
+
}>, hooks: UrgentReminderHooks): Promise<ReminderAttempt>;
|
|
151
|
+
/** The exact interruptible turn, or why there is none. Synchronous by design. */
|
|
152
|
+
private urgentTarget;
|
|
153
|
+
private queueReminder;
|
|
154
|
+
/** Retire only at the same admission boundary used by all prompt producers. */
|
|
155
|
+
retireIfIdle(expired: (snapshot: SessionSnapshot, queueDepth: number) => boolean): Promise<boolean>;
|
|
156
|
+
sharedTurnId(promptId: string): string | undefined;
|
|
65
157
|
stopScheduledAdmission(): void;
|
|
66
158
|
isAlive(): boolean;
|
|
67
159
|
snapshot(): SessionSnapshot;
|
|
@@ -70,8 +162,14 @@ export declare class RoleTurnArbiter implements AgentSession {
|
|
|
70
162
|
limit?: number;
|
|
71
163
|
}): ConversationHandlePage;
|
|
72
164
|
conversationSnapshot(): ConversationSnapshot;
|
|
165
|
+
subscribeConversationFailure(listener: (generation: string) => void): () => void;
|
|
166
|
+
conversationReplayAvailable(expectedGeneration: string): boolean;
|
|
167
|
+
replayConversation(request: import('./conversation-replay.js').ConversationReplayRequest): AsyncIterable<import("./conversation-replay.js").ConversationReplayPage>;
|
|
168
|
+
observeConversation(listener: (state: import('./conversation-types.js').ConversationObservationState) => void): import('./conversation-types.js').ConversationObservation;
|
|
73
169
|
subscribeConversation(listener: (event: ConversationEventV1) => void): () => void;
|
|
74
170
|
submitPromptBrowser(command: SubmitPromptCommand): Promise<PromptReceipt>;
|
|
171
|
+
get liveVoiceSupported(): boolean;
|
|
172
|
+
interruptPrompt(generation: string, promptId: string): Promise<InterruptOutcome>;
|
|
75
173
|
interrupt(source?: TurnCancellationSource): Promise<InterruptOutcome>;
|
|
76
174
|
respondPermission(permissionId: string, optionId: string): boolean;
|
|
77
175
|
respondPermissionV2(permissionId: string, optionId: string, sessionGeneration: string): 'accepted' | 'stale';
|
package/dist/session/arbiter.js
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
import { ACP_CANCEL_DEADLINE_EXCEEDED, SessionControlError, interruptOutcome, } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Turn sources an urgent reminder may cancel. Owner-channel requests and the
|
|
4
|
+
* owner console are owner commands: cancelling one finalizes the request and
|
|
5
|
+
* its reply route (owner-channel/channel.ts), which is an owner-visible
|
|
6
|
+
* effect. Startup is the readiness gate, stall-watchdog is mid-recovery, and
|
|
7
|
+
* another self-reminder's turn must not be cancelled by a sibling.
|
|
8
|
+
*/
|
|
9
|
+
const URGENT_INTERRUPTIBLE = new Set(['fleet-monitor', 'scheduled-loop', 'local-console']);
|
|
10
|
+
/** How long a settled cancellation may take to surface the target's own terminal result. */
|
|
11
|
+
const URGENT_CORRELATION_MS = 2_000;
|
|
2
12
|
/**
|
|
3
13
|
* Raised for admissions that were still waiting on a generation which had to be
|
|
4
14
|
* retired. It carries `ACP_CANCEL_DEADLINE_EXCEEDED` because that is the only
|
|
@@ -28,7 +38,12 @@ export class RoleTurnArbiter {
|
|
|
28
38
|
capabilities;
|
|
29
39
|
tail = Promise.resolve();
|
|
30
40
|
unsettled = 0;
|
|
41
|
+
/** Admissions waiting for the boundary; an urgent interruption yields to them. */
|
|
42
|
+
waiting = 0;
|
|
43
|
+
/** Terminal results of prompts this arbiter admitted and that have not settled yet. */
|
|
44
|
+
live = new Map();
|
|
31
45
|
stopping = false;
|
|
46
|
+
retiring = false;
|
|
32
47
|
/** Bumped by `retireStalledAdmission`; every claim carries the one it was made under. */
|
|
33
48
|
generation = 0;
|
|
34
49
|
/** Resolves the instant the CURRENT generation is retired. */
|
|
@@ -48,11 +63,18 @@ export class RoleTurnArbiter {
|
|
|
48
63
|
*/
|
|
49
64
|
exclusive(operation) {
|
|
50
65
|
const generation = this.generation;
|
|
66
|
+
this.waiting++;
|
|
67
|
+
let counted = true;
|
|
68
|
+
const uncount = () => { if (counted) {
|
|
69
|
+
counted = false;
|
|
70
|
+
this.waiting = Math.max(0, this.waiting - 1);
|
|
71
|
+
} };
|
|
51
72
|
const run = Promise.race([this.tail, this.retirement.promise]).then(() => {
|
|
73
|
+
uncount();
|
|
52
74
|
if (generation !== this.generation)
|
|
53
75
|
throw new AdmissionRetiredError();
|
|
54
76
|
return operation();
|
|
55
|
-
});
|
|
77
|
+
}, error => { uncount(); throw error; });
|
|
56
78
|
this.tail = run.then(() => undefined, () => undefined);
|
|
57
79
|
return run;
|
|
58
80
|
}
|
|
@@ -60,10 +82,12 @@ export class RoleTurnArbiter {
|
|
|
60
82
|
const generation = this.generation;
|
|
61
83
|
this.unsettled++;
|
|
62
84
|
const completion = queued.completion.finally(() => {
|
|
85
|
+
this.live.delete(queued.promptId);
|
|
63
86
|
// A retired generation's claims were released in one step already.
|
|
64
87
|
if (generation === this.generation)
|
|
65
88
|
this.unsettled = Math.max(0, this.unsettled - 1);
|
|
66
89
|
});
|
|
90
|
+
this.live.set(queued.promptId, completion);
|
|
67
91
|
return { ...queued, completion };
|
|
68
92
|
}
|
|
69
93
|
/**
|
|
@@ -86,10 +110,29 @@ export class RoleTurnArbiter {
|
|
|
86
110
|
this.retirement = retirementSignal();
|
|
87
111
|
this.tail = Promise.resolve();
|
|
88
112
|
this.unsettled = 0;
|
|
113
|
+
this.waiting = 0;
|
|
89
114
|
retired.retire();
|
|
90
115
|
}
|
|
91
116
|
queuePrompt(text, options = {}) {
|
|
92
|
-
return this.exclusive(async () =>
|
|
117
|
+
return this.exclusive(async () => {
|
|
118
|
+
if (this.retiring)
|
|
119
|
+
throw new Error('Chat is closing');
|
|
120
|
+
return this.track(await this.session.queuePrompt(text, this.monitorAdmissionOptions(options)));
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
/** Inbox traffic must not cancel or steer an active human console/voice turn.
|
|
124
|
+
* Queue it once; the monitor commits its cursor after that turn succeeds.
|
|
125
|
+
* Other origins retain their configured monitor policy.
|
|
126
|
+
*/
|
|
127
|
+
monitorAdmissionOptions(options) {
|
|
128
|
+
if (options.origin?.kind !== 'fleet-monitor')
|
|
129
|
+
return options;
|
|
130
|
+
const active = this.session.snapshot().activePromptSource;
|
|
131
|
+
// A self-reminder turn is protected the same way: a retried wake (say the
|
|
132
|
+
// one an urgent reminder just interrupted) queues behind it instead of
|
|
133
|
+
// cancelling it before the agent could inspect and acknowledge.
|
|
134
|
+
return active === 'owner-admin-console' || active === 'self-reminder'
|
|
135
|
+
? { ...options, interrupt: false, steer: false } : options;
|
|
93
136
|
}
|
|
94
137
|
async submitPrompt(text, options = {}) {
|
|
95
138
|
return (await this.queuePrompt(text, options)).completion;
|
|
@@ -99,6 +142,10 @@ export class RoleTurnArbiter {
|
|
|
99
142
|
* answers and explicit interrupts must remain able to pass immediately.
|
|
100
143
|
*/
|
|
101
144
|
submitPromptAfterTool(text, options = {}) {
|
|
145
|
+
if (this.retiring)
|
|
146
|
+
return Promise.reject(new Error('Chat is closing'));
|
|
147
|
+
if (this.monitorAdmissionOptions(options) !== options)
|
|
148
|
+
return this.submitPrompt(text, options);
|
|
102
149
|
return this.session.submitPromptAfterTool?.(text, options)
|
|
103
150
|
?? this.session.submitPrompt(text, { ...options, interrupt: false, steer: false });
|
|
104
151
|
}
|
|
@@ -136,6 +183,179 @@ export class RoleTurnArbiter {
|
|
|
136
183
|
throw error;
|
|
137
184
|
});
|
|
138
185
|
}
|
|
186
|
+
/**
|
|
187
|
+
* Admit a self-reminder wake only into an idle role, at the same boundary
|
|
188
|
+
* every producer uses. It never interrupts or steers, and never joins a
|
|
189
|
+
* queue behind other work: a busy role answers `busy` and the caller tries
|
|
190
|
+
* again later. `beforeQueue` makes the caller's durable claim; if it
|
|
191
|
+
* declines, nothing is queued. `releaseGuard` is the session's last-moment
|
|
192
|
+
* fence and is the only way the prompt can reach the model.
|
|
193
|
+
*/
|
|
194
|
+
async tryReminder(text, origin, beforeQueue, releaseGuard) {
|
|
195
|
+
await new Promise(resolve => setImmediate(resolve));
|
|
196
|
+
return this.exclusive(async () => {
|
|
197
|
+
const snapshot = this.session.snapshot();
|
|
198
|
+
if (this.stopping || this.retiring || !snapshot.alive || snapshot.readiness === 'failed')
|
|
199
|
+
return { state: 'unavailable', error: this.stopping ? 'role is stopping' : 'session is unavailable', admitted: false };
|
|
200
|
+
if (snapshot.readiness !== 'idle' || this.unsettled > 0)
|
|
201
|
+
return { state: 'busy' };
|
|
202
|
+
if (!beforeQueue())
|
|
203
|
+
return { state: 'unavailable', error: 'claim declined', admitted: false };
|
|
204
|
+
try {
|
|
205
|
+
const queued = await this.session.queuePrompt(text, {
|
|
206
|
+
interrupt: false, steer: false, origin, releaseGuard,
|
|
207
|
+
});
|
|
208
|
+
return { state: 'admitted', queued: this.track(queued) };
|
|
209
|
+
}
|
|
210
|
+
catch (error) {
|
|
211
|
+
return { state: 'unavailable', error: error?.message ?? String(error), admitted: false };
|
|
212
|
+
}
|
|
213
|
+
}).catch(error => {
|
|
214
|
+
if (error instanceof AdmissionRetiredError)
|
|
215
|
+
return { state: 'unavailable', error: error.message, admitted: false };
|
|
216
|
+
throw error;
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Admit an URGENT self-reminder wake. Idle: exactly `tryReminder`. Busy: the
|
|
221
|
+
* reminder may ask the exact checked turn to stop — once per event — and is
|
|
222
|
+
* then admitted at the next boundary like any other reminder.
|
|
223
|
+
*
|
|
224
|
+
* The check and the cancel request happen in one synchronous step inside the
|
|
225
|
+
* admission boundary, so the turn asked to stop is the turn that was checked.
|
|
226
|
+
* Only a running, correlatable, interruptible turn with nothing queued behind
|
|
227
|
+
* it and no admission waiting is ever asked to stop; anything else is a
|
|
228
|
+
* reported deferral (`busy`). After the cancellation the boundary is given up
|
|
229
|
+
* before the wake is queued, so an owner prompt (or any producer) that
|
|
230
|
+
* arrived meanwhile is admitted first and the wake simply finds the role
|
|
231
|
+
* busy. A forced, failed or uncertain cancellation never queues the wake.
|
|
232
|
+
*/
|
|
233
|
+
async tryUrgentReminder(origin, hooks) {
|
|
234
|
+
await new Promise(resolve => setImmediate(resolve));
|
|
235
|
+
const unavailable = (error) => ({ state: 'unavailable', error, admitted: false });
|
|
236
|
+
const first = await this.exclusive(async () => {
|
|
237
|
+
const snapshot = this.session.snapshot();
|
|
238
|
+
if (this.stopping || this.retiring || !snapshot.alive || snapshot.readiness === 'failed')
|
|
239
|
+
return unavailable(this.stopping ? 'role is stopping' : 'session is unavailable');
|
|
240
|
+
if (snapshot.readiness === 'idle' && this.unsettled === 0)
|
|
241
|
+
return this.queueReminder(hooks, origin);
|
|
242
|
+
const deferral = this.urgentTarget(snapshot);
|
|
243
|
+
if (typeof deferral === 'string' || !hooks.mayInterrupt()) {
|
|
244
|
+
hooks.deferred(typeof deferral === 'string' ? deferral : 'interrupt_already_used');
|
|
245
|
+
return { state: 'busy' };
|
|
246
|
+
}
|
|
247
|
+
if (!hooks.beforeQueue())
|
|
248
|
+
return unavailable('claim declined');
|
|
249
|
+
if (!hooks.markRequested(deferral))
|
|
250
|
+
return unavailable('interrupt request not recorded');
|
|
251
|
+
const terminal = this.live.get(deferral.promptId);
|
|
252
|
+
// No await between the check above and this call: the session cancels
|
|
253
|
+
// the turn that was checked, never a successor.
|
|
254
|
+
let report;
|
|
255
|
+
try {
|
|
256
|
+
const outcome = interruptOutcome(await this.session.interrupt('self-reminder'));
|
|
257
|
+
report = outcome.state === 'forced'
|
|
258
|
+
? { target: deferral, outcome: 'forced', ...(outcome.reasonCode ? { reason: outcome.reasonCode } : {}) }
|
|
259
|
+
: { target: deferral, outcome: await correlate(terminal) };
|
|
260
|
+
}
|
|
261
|
+
catch (error) {
|
|
262
|
+
report = { target: deferral, outcome: 'failed', reason: controlReason(error) };
|
|
263
|
+
}
|
|
264
|
+
hooks.recordOutcome(report);
|
|
265
|
+
return report;
|
|
266
|
+
}).catch(error => {
|
|
267
|
+
if (error instanceof AdmissionRetiredError)
|
|
268
|
+
return unavailable(error.message);
|
|
269
|
+
throw error;
|
|
270
|
+
});
|
|
271
|
+
if ('state' in first)
|
|
272
|
+
return first;
|
|
273
|
+
if (first.outcome === 'forced' || first.outcome === 'failed')
|
|
274
|
+
return unavailable(`interruption ${first.outcome}; the wake was not queued`);
|
|
275
|
+
// Give up the boundary: anything that queued during the cancellation —
|
|
276
|
+
// owner input first among them — is admitted before the wake.
|
|
277
|
+
await new Promise(resolve => setImmediate(resolve));
|
|
278
|
+
return this.exclusive(async () => {
|
|
279
|
+
const snapshot = this.session.snapshot();
|
|
280
|
+
if (this.stopping || this.retiring || !snapshot.alive || snapshot.readiness === 'failed')
|
|
281
|
+
return unavailable(this.stopping ? 'role is stopping' : 'session is unavailable');
|
|
282
|
+
if (!hooks.stillAdmitting())
|
|
283
|
+
return unavailable('reminder changed during the interruption');
|
|
284
|
+
if (snapshot.readiness !== 'idle' || this.unsettled > 0 || this.waiting > 0)
|
|
285
|
+
return { state: 'busy' };
|
|
286
|
+
return this.queueReminder(hooks, origin, first, false);
|
|
287
|
+
}).catch(error => {
|
|
288
|
+
if (error instanceof AdmissionRetiredError)
|
|
289
|
+
return unavailable(error.message);
|
|
290
|
+
throw error;
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
/** The exact interruptible turn, or why there is none. Synchronous by design. */
|
|
294
|
+
urgentTarget(snapshot) {
|
|
295
|
+
if (snapshot.readiness === 'starting')
|
|
296
|
+
return 'session_starting';
|
|
297
|
+
if (snapshot.readiness === 'awaiting_permission' || snapshot.pendingPermissionId)
|
|
298
|
+
return 'permission_pending';
|
|
299
|
+
if (snapshot.readiness !== 'running')
|
|
300
|
+
return 'untracked_turn';
|
|
301
|
+
const source = snapshot.activePromptSource;
|
|
302
|
+
if (!source)
|
|
303
|
+
return 'untracked_turn';
|
|
304
|
+
if (!URGENT_INTERRUPTIBLE.has(source))
|
|
305
|
+
return 'protected_turn';
|
|
306
|
+
if (!this.session.capabilities?.interrupt)
|
|
307
|
+
return 'interrupt_unsupported';
|
|
308
|
+
if (this.waiting > 0 || this.unsettled > 1)
|
|
309
|
+
return 'queued_work';
|
|
310
|
+
if (!this.session.observeConversation)
|
|
311
|
+
return 'uncorrelatable';
|
|
312
|
+
let state;
|
|
313
|
+
try {
|
|
314
|
+
const observation = this.session.observeConversation(() => { });
|
|
315
|
+
state = observation.snapshot;
|
|
316
|
+
observation.unsubscribe();
|
|
317
|
+
}
|
|
318
|
+
catch {
|
|
319
|
+
return 'uncorrelatable';
|
|
320
|
+
}
|
|
321
|
+
if (state.pendingPermissions.length || state.pendingPermissionIds.length)
|
|
322
|
+
return 'permission_pending';
|
|
323
|
+
if (state.pendingPromptCount > 0 || state.queueDepth > 1)
|
|
324
|
+
return 'queued_work';
|
|
325
|
+
if (state.activePromptIds.length < 1)
|
|
326
|
+
return 'untracked_turn';
|
|
327
|
+
return {
|
|
328
|
+
source, generation: state.sessionGeneration, promptId: state.activePromptIds[0],
|
|
329
|
+
...(snapshot.sessionId ? { sessionId: snapshot.sessionId } : {}),
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
async queueReminder(hooks, origin, report, claim = true) {
|
|
333
|
+
if (claim && !hooks.beforeQueue())
|
|
334
|
+
return { state: 'unavailable', error: 'claim declined', admitted: false };
|
|
335
|
+
try {
|
|
336
|
+
const queued = await this.session.queuePrompt(hooks.text(report), {
|
|
337
|
+
interrupt: false, steer: false, origin, releaseGuard: () => hooks.releaseGuard(),
|
|
338
|
+
});
|
|
339
|
+
return { state: 'admitted', queued: this.track(queued) };
|
|
340
|
+
}
|
|
341
|
+
catch (error) {
|
|
342
|
+
return { state: 'unavailable', error: error?.message ?? String(error), admitted: false };
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
/** Retire only at the same admission boundary used by all prompt producers. */
|
|
346
|
+
retireIfIdle(expired) {
|
|
347
|
+
return this.exclusive(async () => {
|
|
348
|
+
const snapshot = this.session.snapshot();
|
|
349
|
+
const queue = this.session.conversationSnapshot?.().queueDepth ?? -1;
|
|
350
|
+
if (this.retiring || this.unsettled > 0 || snapshot.readiness !== 'idle' || !expired(snapshot, queue))
|
|
351
|
+
return false;
|
|
352
|
+
this.retiring = true;
|
|
353
|
+
this.stopping = true;
|
|
354
|
+
await this.session.close();
|
|
355
|
+
return true;
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
sharedTurnId(promptId) { return this.session.sharedTurnId?.(promptId); }
|
|
139
359
|
stopScheduledAdmission() { this.stopping = true; }
|
|
140
360
|
isAlive() { return this.session.isAlive(); }
|
|
141
361
|
snapshot() { return this.session.snapshot(); }
|
|
@@ -149,6 +369,24 @@ export class RoleTurnArbiter {
|
|
|
149
369
|
throw new Error('conversation snapshot is unavailable');
|
|
150
370
|
return this.session.conversationSnapshot();
|
|
151
371
|
}
|
|
372
|
+
subscribeConversationFailure(listener) {
|
|
373
|
+
if (!this.session.subscribeConversationFailure)
|
|
374
|
+
throw new Error('conversation durability observation is unavailable');
|
|
375
|
+
return this.session.subscribeConversationFailure(listener);
|
|
376
|
+
}
|
|
377
|
+
conversationReplayAvailable(expectedGeneration) {
|
|
378
|
+
return this.session.conversationReplayAvailable?.(expectedGeneration) ?? false;
|
|
379
|
+
}
|
|
380
|
+
replayConversation(request) {
|
|
381
|
+
if (!this.session.replayConversation)
|
|
382
|
+
throw new Error('conversation replay is unavailable');
|
|
383
|
+
return this.session.replayConversation(request);
|
|
384
|
+
}
|
|
385
|
+
observeConversation(listener) {
|
|
386
|
+
if (!this.session.observeConversation)
|
|
387
|
+
throw new Error('conversation observation is unavailable');
|
|
388
|
+
return this.session.observeConversation(listener);
|
|
389
|
+
}
|
|
152
390
|
subscribeConversation(listener) {
|
|
153
391
|
if (!this.session.subscribeConversation)
|
|
154
392
|
throw new Error('conversation subscription is unavailable');
|
|
@@ -157,7 +395,16 @@ export class RoleTurnArbiter {
|
|
|
157
395
|
submitPromptBrowser(command) {
|
|
158
396
|
if (!this.session.submitPromptBrowser)
|
|
159
397
|
return Promise.reject(new Error('browser prompt admission is unavailable'));
|
|
160
|
-
return this.exclusive(() => this.
|
|
398
|
+
return this.exclusive(() => { if (this.retiring)
|
|
399
|
+
throw new Error('Chat is closing'); return this.session.submitPromptBrowser(command); });
|
|
400
|
+
}
|
|
401
|
+
get liveVoiceSupported() { return this.session.liveVoiceSupported === true; }
|
|
402
|
+
interruptPrompt(generation, promptId) {
|
|
403
|
+
return this.exclusive(async () => {
|
|
404
|
+
if (!this.session.interruptPrompt)
|
|
405
|
+
throw new Error('targeted voice interrupt is unavailable');
|
|
406
|
+
return interruptOutcome(await this.session.interruptPrompt(generation, promptId));
|
|
407
|
+
});
|
|
161
408
|
}
|
|
162
409
|
interrupt(source = 'local-console') {
|
|
163
410
|
return this.exclusive(async () => interruptOutcome(await this.session.interrupt(source)));
|
|
@@ -175,3 +422,25 @@ export class RoleTurnArbiter {
|
|
|
175
422
|
exitResult() { return this.session.exitResult(); }
|
|
176
423
|
close() { return this.session.close(); }
|
|
177
424
|
}
|
|
425
|
+
/**
|
|
426
|
+
* Whether the target's own terminal result proves this request cancelled it.
|
|
427
|
+
* A settled interrupt says only that the turn (or nothing) ended; without the
|
|
428
|
+
* target's correlated result the honest answer is `ended`.
|
|
429
|
+
*/
|
|
430
|
+
async function correlate(terminal) {
|
|
431
|
+
if (!terminal)
|
|
432
|
+
return 'ended';
|
|
433
|
+
let timer;
|
|
434
|
+
const result = await Promise.race([
|
|
435
|
+
terminal,
|
|
436
|
+
new Promise(resolve => { timer = setTimeout(() => resolve(undefined), URGENT_CORRELATION_MS); timer.unref?.(); }),
|
|
437
|
+
]);
|
|
438
|
+
if (timer)
|
|
439
|
+
clearTimeout(timer);
|
|
440
|
+
return result?.outcome === 'cancelled' && result.cancellationSource === 'self-reminder' ? 'cancelled' : 'ended';
|
|
441
|
+
}
|
|
442
|
+
function controlReason(error) {
|
|
443
|
+
if (error instanceof SessionControlError)
|
|
444
|
+
return error.reasonCode ?? error.kind;
|
|
445
|
+
return 'control_error';
|
|
446
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { type TaskNoticeBinding, type TaskCreatedNotice } from './task-notice.js';
|
|
1
2
|
import type { CommonPermissions } from '../config.js';
|
|
2
|
-
import type { ConversationEventV1, ConversationSnapshot, PromptOrigin, PromptReceipt, SubmitPromptCommand } from './conversation-types.js';
|
|
3
|
+
import type { ConversationEventV1, ConversationObservationState, ConversationSnapshot, PromptOrigin, PromptReceipt, SubmitPromptCommand } from './conversation-types.js';
|
|
4
|
+
import { type PendingPrompt } from './prompt-batch.js';
|
|
3
5
|
import type { CodexAppServerTransportFactory } from './codex-app-server-transport.js';
|
|
4
6
|
import type { AgentSession, ConversationHandlePage, ExitRecord, InterruptOutcome, QueuedPrompt, SessionEvent, SessionSnapshot, SubmitPromptOptions, TurnCancellationSource, TurnResult } from './types.js';
|
|
5
7
|
type JsonObject = Record<string, unknown>;
|
|
@@ -10,6 +12,9 @@ export interface CodexAppServerSessionOptions {
|
|
|
10
12
|
env: Record<string, string>;
|
|
11
13
|
stateDir: string;
|
|
12
14
|
mode: 'fresh' | 'resume';
|
|
15
|
+
requireResume?: boolean;
|
|
16
|
+
/** Hold recovered never-started prompts until activateRecoveredPrompts(). */
|
|
17
|
+
deferRecoveredPrompts?: boolean;
|
|
13
18
|
permissions: CommonPermissions;
|
|
14
19
|
permissionMode: NonNullable<SessionSnapshot['permissionMode']>;
|
|
15
20
|
model?: string | null;
|
|
@@ -28,6 +33,16 @@ export interface CodexAppServerSessionOptions {
|
|
|
28
33
|
}
|
|
29
34
|
/** Server-generated application provenance for authenticated browser prompts only. */
|
|
30
35
|
export declare function nativePromptAdditionalContext(origin: PromptOrigin | undefined): JsonObject | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Application context for a turn that carries several admitted prompts.
|
|
38
|
+
*
|
|
39
|
+
* The single-prompt context says "the accompanying user text", which would
|
|
40
|
+
* cover every member. A shared turn therefore carries this one entry instead:
|
|
41
|
+
* each member is its own user text item, in order, and its route and exact
|
|
42
|
+
* bytes are stated here by the server. Text imitating this wording is still
|
|
43
|
+
* only user text; it cannot add an application-context entry.
|
|
44
|
+
*/
|
|
45
|
+
export declare function nativeBatchAdditionalContext(members: ReadonlyArray<Pick<PendingPrompt, 'text' | 'origin'>>): JsonObject | undefined;
|
|
31
46
|
/** Native Codex session implementing Fleet's provider-neutral live-session contract. */
|
|
32
47
|
export declare class CodexAppServerSession implements AgentSession {
|
|
33
48
|
private readonly options;
|
|
@@ -53,7 +68,13 @@ export declare class CodexAppServerSession implements AgentSession {
|
|
|
53
68
|
private lastError?;
|
|
54
69
|
private exit;
|
|
55
70
|
private queueDepth;
|
|
71
|
+
private readonly deferredRecovered;
|
|
72
|
+
private readonly observation;
|
|
56
73
|
private promptTail;
|
|
74
|
+
/** Admitted prompts not yet handed to the app-server, in admission order. */
|
|
75
|
+
private readonly pendingPrompts;
|
|
76
|
+
/** Admitted prompt → the turn that carries it, while that turn is open. */
|
|
77
|
+
private readonly sharedTurns;
|
|
57
78
|
private activeTurn?;
|
|
58
79
|
private controllerCount;
|
|
59
80
|
private controllerGrace?;
|
|
@@ -67,7 +88,20 @@ export declare class CodexAppServerSession implements AgentSession {
|
|
|
67
88
|
isAlive(): boolean;
|
|
68
89
|
snapshot(): SessionSnapshot;
|
|
69
90
|
queuePrompt(text: string, options?: SubmitPromptOptions): Promise<QueuedPrompt>;
|
|
91
|
+
/** The turn whose events and result answer this admitted prompt; itself unless a release shared it. */
|
|
92
|
+
sharedTurnId(promptId: string): string | undefined;
|
|
93
|
+
/** Each prompt keeps its own step in the chain; the step it reaches releases a whole snapshot. */
|
|
94
|
+
private enqueue;
|
|
95
|
+
/**
|
|
96
|
+
* The turn boundary: the first waiting prompt to get here synchronously
|
|
97
|
+
* takes every pending prompt delivered with it into one turn. A prompt
|
|
98
|
+
* admitted afterwards stays pending for the next boundary, and a step whose
|
|
99
|
+
* prompt was already taken reports that turn's result.
|
|
100
|
+
*/
|
|
101
|
+
private release;
|
|
70
102
|
submitPrompt(text: string, options?: SubmitPromptOptions): Promise<TurnResult>;
|
|
103
|
+
readonly liveVoiceSupported = true;
|
|
104
|
+
interruptPrompt(generation: string, promptId: string): Promise<InterruptOutcome>;
|
|
71
105
|
interrupt(source?: TurnCancellationSource): Promise<InterruptOutcome>;
|
|
72
106
|
respondPermission(permissionId: string, optionId: string): boolean;
|
|
73
107
|
respondPermissionV2(permissionId: string, optionId: string, sessionGeneration: string): 'accepted' | 'stale';
|
|
@@ -76,15 +110,25 @@ export declare class CodexAppServerSession implements AgentSession {
|
|
|
76
110
|
setControllerAttached(attached: boolean): void;
|
|
77
111
|
exitResult(): ExitRecord | null;
|
|
78
112
|
close(): Promise<void>;
|
|
113
|
+
taskNoticeBinding(): TaskNoticeBinding | undefined;
|
|
114
|
+
recordTaskCreated(binding: TaskNoticeBinding, notice: TaskCreatedNotice): void;
|
|
79
115
|
conversationPage(request?: {
|
|
80
116
|
after?: string;
|
|
81
117
|
limit?: number;
|
|
82
118
|
}): ConversationHandlePage;
|
|
119
|
+
subscribeConversationFailure(listener: (generation: string) => void): () => void;
|
|
120
|
+
conversationReplayAvailable(expectedGeneration: string): boolean;
|
|
121
|
+
replayConversation(request: import('./conversation-replay.js').ConversationReplayRequest): AsyncGenerator<import("./conversation-replay.js").ConversationReplayPage, any, any>;
|
|
122
|
+
observeConversation(listener: (state: ConversationObservationState) => void): import("./conversation-types.js").ConversationObservation;
|
|
123
|
+
private captureObservation;
|
|
83
124
|
conversationSnapshot(): ConversationSnapshot;
|
|
84
125
|
subscribeConversation(listener: (event: ConversationEventV1) => void): () => void;
|
|
85
126
|
submitPromptBrowser(command: SubmitPromptCommand): Promise<PromptReceipt>;
|
|
86
127
|
private initialize;
|
|
87
128
|
private recoverOpenPrompts;
|
|
129
|
+
/** Dispatch recovered prompts once the caller's control plane is listening. */
|
|
130
|
+
activateRecoveredPrompts(): void;
|
|
131
|
+
private dispatchRecovered;
|
|
88
132
|
private admit;
|
|
89
133
|
private runPrompt;
|
|
90
134
|
private steer;
|