yepanywhere 0.5.2 → 0.6.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/README.md +21 -5
- package/bundled/@yep-anywhere/shared/dist/agent-context.d.ts +9 -0
- package/bundled/@yep-anywhere/shared/dist/agent-context.d.ts.map +1 -0
- package/bundled/@yep-anywhere/shared/dist/agent-context.js +18 -0
- package/bundled/@yep-anywhere/shared/dist/agent-context.js.map +1 -0
- package/bundled/@yep-anywhere/shared/dist/app-types.d.ts +104 -1
- package/bundled/@yep-anywhere/shared/dist/app-types.d.ts.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/app-types.js +4 -0
- package/bundled/@yep-anywhere/shared/dist/app-types.js.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/binary-framing.d.ts +4 -1
- package/bundled/@yep-anywhere/shared/dist/binary-framing.d.ts.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/binary-framing.js +8 -3
- package/bundled/@yep-anywhere/shared/dist/binary-framing.js.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/entry/AssistantEntrySchema.d.ts +4 -0
- package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/entry/AssistantEntrySchema.d.ts.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/entry/BaseEntrySchema.d.ts +4 -0
- package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/entry/BaseEntrySchema.d.ts.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/entry/BaseEntrySchema.js +7 -0
- package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/entry/BaseEntrySchema.js.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/entry/ProgressEntrySchema.d.ts +4 -0
- package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/entry/ProgressEntrySchema.d.ts.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/entry/SystemEntrySchema.d.ts +64 -1
- package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/entry/SystemEntrySchema.d.ts.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/entry/SystemEntrySchema.js +9 -0
- package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/entry/SystemEntrySchema.js.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/entry/UserEntrySchema.d.ts +4 -0
- package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/entry/UserEntrySchema.d.ts.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/guards.d.ts.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/guards.js +45 -1
- package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/guards.js.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/index.d.ts +144 -2
- package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/index.d.ts.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/tool/ToolResultSchemas.d.ts +6 -4
- package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/tool/ToolResultSchemas.d.ts.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/tool/ToolResultSchemas.js +8 -1
- package/bundled/@yep-anywhere/shared/dist/claude-sdk-schema/tool/ToolResultSchemas.js.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/codex-schema/index.d.ts +3 -2
- package/bundled/@yep-anywhere/shared/dist/codex-schema/index.d.ts.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/codex-schema/index.js +3 -2
- package/bundled/@yep-anywhere/shared/dist/codex-schema/index.js.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/codex-schema/session.d.ts +87 -3
- package/bundled/@yep-anywhere/shared/dist/codex-schema/session.d.ts.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/codex-schema/session.js +39 -1
- package/bundled/@yep-anywhere/shared/dist/codex-schema/session.js.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/dag.d.ts +31 -11
- package/bundled/@yep-anywhere/shared/dist/dag.d.ts.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/dag.js +77 -33
- package/bundled/@yep-anywhere/shared/dist/dag.js.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/git-status.d.ts +70 -1
- package/bundled/@yep-anywhere/shared/dist/git-status.d.ts.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/git-status.js +6 -1
- package/bundled/@yep-anywhere/shared/dist/git-status.js.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/ideMetadata.js +1 -1
- package/bundled/@yep-anywhere/shared/dist/ideMetadata.js.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/index.d.ts +20 -11
- package/bundled/@yep-anywhere/shared/dist/index.d.ts.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/index.js +8 -3
- package/bundled/@yep-anywhere/shared/dist/index.js.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/local-resource.d.ts +1 -0
- package/bundled/@yep-anywhere/shared/dist/local-resource.d.ts.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/local-resource.js +4 -0
- package/bundled/@yep-anywhere/shared/dist/local-resource.js.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/opencode-schema/events.d.ts +136 -0
- package/bundled/@yep-anywhere/shared/dist/opencode-schema/events.d.ts.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/opencode-schema/events.js +65 -3
- package/bundled/@yep-anywhere/shared/dist/opencode-schema/events.js.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/opencode-schema/types.d.ts +1 -1
- package/bundled/@yep-anywhere/shared/dist/opencode-schema/types.d.ts.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/project-queue.d.ts +153 -0
- package/bundled/@yep-anywhere/shared/dist/project-queue.d.ts.map +1 -0
- package/bundled/@yep-anywhere/shared/dist/project-queue.js +8 -0
- package/bundled/@yep-anywhere/shared/dist/project-queue.js.map +1 -0
- package/bundled/@yep-anywhere/shared/dist/relay-protocol.d.ts +26 -2
- package/bundled/@yep-anywhere/shared/dist/relay-protocol.d.ts.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/relay-protocol.js +33 -0
- package/bundled/@yep-anywhere/shared/dist/relay-protocol.js.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/relay.d.ts +45 -5
- package/bundled/@yep-anywhere/shared/dist/relay.d.ts.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/relay.js.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/safe-restart.d.ts +25 -0
- package/bundled/@yep-anywhere/shared/dist/safe-restart.d.ts.map +1 -0
- package/bundled/@yep-anywhere/shared/dist/safe-restart.js +2 -0
- package/bundled/@yep-anywhere/shared/dist/safe-restart.js.map +1 -0
- package/bundled/@yep-anywhere/shared/dist/session/SessionView.d.ts +2 -2
- package/bundled/@yep-anywhere/shared/dist/session/SessionView.js +3 -3
- package/bundled/@yep-anywhere/shared/dist/session/SessionView.js.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/session/UnifiedSession.d.ts +10 -0
- package/bundled/@yep-anywhere/shared/dist/session/UnifiedSession.d.ts.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/session-liveness.d.ts +18 -0
- package/bundled/@yep-anywhere/shared/dist/session-liveness.d.ts.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/types.d.ts +253 -8
- package/bundled/@yep-anywhere/shared/dist/types.d.ts.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/types.js +48 -5
- package/bundled/@yep-anywhere/shared/dist/types.js.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/upload.d.ts +34 -2
- package/bundled/@yep-anywhere/shared/dist/upload.d.ts.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/user-message-metadata.d.ts +47 -0
- package/bundled/@yep-anywhere/shared/dist/user-message-metadata.d.ts.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/user-message-metadata.js +59 -1
- package/bundled/@yep-anywhere/shared/dist/user-message-metadata.js.map +1 -1
- package/bundled/@yep-anywhere/shared/dist/workstreams.d.ts +54 -0
- package/bundled/@yep-anywhere/shared/dist/workstreams.d.ts.map +1 -0
- package/bundled/@yep-anywhere/shared/dist/workstreams.js +8 -0
- package/bundled/@yep-anywhere/shared/dist/workstreams.js.map +1 -0
- package/bundled/@yep-anywhere/shared/package.json +1 -1
- package/client-dist/assets/alegreya-sans-latin-400-italic-BQIUBrX-.woff2 +0 -0
- package/client-dist/assets/alegreya-sans-latin-400-normal-BxeZdXas.woff2 +0 -0
- package/client-dist/assets/alegreya-sans-latin-500-normal-uodOEoAl.woff2 +0 -0
- package/client-dist/assets/alegreya-sans-latin-700-normal-DFYOGfC8.woff2 +0 -0
- package/client-dist/assets/de-CHMDbVD5.js +6 -0
- package/client-dist/assets/es-CK8MPF_C.js +6 -0
- package/client-dist/assets/fira-mono-latin-400-normal-DVTTRLHv.woff2 +0 -0
- package/client-dist/assets/fira-mono-latin-ext-400-normal-B2gPvaNr.woff2 +0 -0
- package/client-dist/assets/fira-mono-symbols2-400-normal-C6JptOil.woff2 +0 -0
- package/client-dist/assets/fr-49PXQiUL.js +6 -0
- package/client-dist/assets/index-B-09fVut.js +557 -0
- package/client-dist/assets/index-uJnfvD1f.css +1 -0
- package/client-dist/assets/inter-latin-400-italic-D1l0FflY.woff2 +0 -0
- package/client-dist/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
- package/client-dist/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
- package/client-dist/assets/inter-latin-700-normal-Yt3aPRUw.woff2 +0 -0
- package/client-dist/assets/ja-CrCGPmoH.js +6 -0
- package/client-dist/assets/zh-CN-AFJxv5ke.js +6 -0
- package/client-dist/index.html +3 -3
- package/client-dist/sw.js +96 -9
- package/dist/app.d.ts +25 -0
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +350 -35
- package/dist/app.js.map +1 -1
- package/dist/augments/augment-generator.d.ts +1 -1
- package/dist/augments/augment-generator.d.ts.map +1 -1
- package/dist/augments/augment-generator.js +2 -2
- package/dist/augments/augment-generator.js.map +1 -1
- package/dist/augments/markdown-augments.d.ts +1 -1
- package/dist/augments/markdown-augments.d.ts.map +1 -1
- package/dist/augments/markdown-augments.js +5 -5
- package/dist/augments/markdown-augments.js.map +1 -1
- package/dist/augments/safe-markdown.d.ts +10 -0
- package/dist/augments/safe-markdown.d.ts.map +1 -1
- package/dist/augments/safe-markdown.js +146 -3
- package/dist/augments/safe-markdown.js.map +1 -1
- package/dist/augments/stream-augmenter.d.ts +3 -0
- package/dist/augments/stream-augmenter.d.ts.map +1 -1
- package/dist/augments/stream-augmenter.js +6 -3
- package/dist/augments/stream-augmenter.js.map +1 -1
- package/dist/augments/stream-coordinator.d.ts +5 -1
- package/dist/augments/stream-coordinator.d.ts.map +1 -1
- package/dist/augments/stream-coordinator.js +6 -4
- package/dist/augments/stream-coordinator.js.map +1 -1
- package/dist/augments/task-list-augments.d.ts +27 -0
- package/dist/augments/task-list-augments.d.ts.map +1 -0
- package/dist/augments/task-list-augments.js +360 -0
- package/dist/augments/task-list-augments.js.map +1 -0
- package/dist/cli.d.ts +1 -17
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +22 -8
- package/dist/cli.js.map +1 -1
- package/dist/codex/correlationDebugLogger.d.ts.map +1 -1
- package/dist/codex/correlationDebugLogger.js +36 -8
- package/dist/codex/correlationDebugLogger.js.map +1 -1
- package/dist/codex/normalization.d.ts +1 -0
- package/dist/codex/normalization.d.ts.map +1 -1
- package/dist/codex/normalization.js +262 -7
- package/dist/codex/normalization.js.map +1 -1
- package/dist/config.d.ts +49 -6
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +55 -14
- package/dist/config.js.map +1 -1
- package/dist/defaults.d.ts +3 -0
- package/dist/defaults.d.ts.map +1 -0
- package/dist/defaults.js +3 -0
- package/dist/defaults.js.map +1 -0
- package/dist/device/DeviceBridgeService.js +1 -1
- package/dist/device/DeviceBridgeService.js.map +1 -1
- package/dist/envSettings.d.ts +64 -0
- package/dist/envSettings.d.ts.map +1 -0
- package/dist/envSettings.js +553 -0
- package/dist/envSettings.js.map +1 -0
- package/dist/frontend/static.d.ts.map +1 -1
- package/dist/frontend/static.js +3 -1
- package/dist/frontend/static.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +190 -14
- package/dist/index.js.map +1 -1
- package/dist/indexes/SessionDiscoveryIndex.d.ts +78 -0
- package/dist/indexes/SessionDiscoveryIndex.d.ts.map +1 -0
- package/dist/indexes/SessionDiscoveryIndex.js +223 -0
- package/dist/indexes/SessionDiscoveryIndex.js.map +1 -0
- package/dist/indexes/SessionIndexService.d.ts +114 -1
- package/dist/indexes/SessionIndexService.d.ts.map +1 -1
- package/dist/indexes/SessionIndexService.js +875 -105
- package/dist/indexes/SessionIndexService.js.map +1 -1
- package/dist/indexes/index.d.ts +2 -1
- package/dist/indexes/index.d.ts.map +1 -1
- package/dist/indexes/index.js +1 -0
- package/dist/indexes/index.js.map +1 -1
- package/dist/indexes/types.d.ts +26 -0
- package/dist/indexes/types.d.ts.map +1 -1
- package/dist/logging/logger.d.ts.map +1 -1
- package/dist/logging/logger.js +2 -3
- package/dist/logging/logger.js.map +1 -1
- package/dist/maintenance/server.d.ts.map +1 -1
- package/dist/maintenance/server.js +8 -11
- package/dist/maintenance/server.js.map +1 -1
- package/dist/metadata/ProjectMetadataService.d.ts +7 -0
- package/dist/metadata/ProjectMetadataService.d.ts.map +1 -1
- package/dist/metadata/ProjectMetadataService.js +63 -19
- package/dist/metadata/ProjectMetadataService.js.map +1 -1
- package/dist/metadata/SessionMetadataService.d.ts +82 -3
- package/dist/metadata/SessionMetadataService.d.ts.map +1 -1
- package/dist/metadata/SessionMetadataService.js +233 -17
- package/dist/metadata/SessionMetadataService.js.map +1 -1
- package/dist/middleware/file-access.d.ts +66 -0
- package/dist/middleware/file-access.d.ts.map +1 -0
- package/dist/middleware/file-access.js +112 -0
- package/dist/middleware/file-access.js.map +1 -0
- package/dist/projects/codex-scanner.d.ts +28 -1
- package/dist/projects/codex-scanner.d.ts.map +1 -1
- package/dist/projects/codex-scanner.js +149 -39
- package/dist/projects/codex-scanner.js.map +1 -1
- package/dist/projects/gemini-scanner.d.ts.map +1 -1
- package/dist/projects/gemini-scanner.js +59 -6
- package/dist/projects/gemini-scanner.js.map +1 -1
- package/dist/projects/paths.d.ts +15 -1
- package/dist/projects/paths.d.ts.map +1 -1
- package/dist/projects/paths.js +69 -23
- package/dist/projects/paths.js.map +1 -1
- package/dist/projects/scanner.d.ts +5 -0
- package/dist/projects/scanner.d.ts.map +1 -1
- package/dist/projects/scanner.js +136 -28
- package/dist/projects/scanner.js.map +1 -1
- package/dist/push/InactivityPushNotifier.d.ts +61 -0
- package/dist/push/InactivityPushNotifier.d.ts.map +1 -0
- package/dist/push/InactivityPushNotifier.js +305 -0
- package/dist/push/InactivityPushNotifier.js.map +1 -0
- package/dist/push/PushNotifier.d.ts.map +1 -1
- package/dist/push/PushNotifier.js.map +1 -1
- package/dist/push/PushService.d.ts +7 -4
- package/dist/push/PushService.d.ts.map +1 -1
- package/dist/push/PushService.js +27 -7
- package/dist/push/PushService.js.map +1 -1
- package/dist/push/index.d.ts +2 -1
- package/dist/push/index.d.ts.map +1 -1
- package/dist/push/index.js +1 -0
- package/dist/push/index.js.map +1 -1
- package/dist/push/routes.d.ts.map +1 -1
- package/dist/push/routes.js +28 -1
- package/dist/push/routes.js.map +1 -1
- package/dist/push/types.d.ts +21 -3
- package/dist/push/types.d.ts.map +1 -1
- package/dist/push/types.js +2 -0
- package/dist/push/types.js.map +1 -1
- package/dist/routes/dev.d.ts +2 -0
- package/dist/routes/dev.d.ts.map +1 -1
- package/dist/routes/dev.js +25 -0
- package/dist/routes/dev.js.map +1 -1
- package/dist/routes/env-settings.d.ts +20 -0
- package/dist/routes/env-settings.d.ts.map +1 -0
- package/dist/routes/env-settings.js +25 -0
- package/dist/routes/env-settings.js.map +1 -0
- package/dist/routes/files.d.ts +9 -0
- package/dist/routes/files.d.ts.map +1 -1
- package/dist/routes/files.js +98 -10
- package/dist/routes/files.js.map +1 -1
- package/dist/routes/git-status.d.ts.map +1 -1
- package/dist/routes/git-status.js +621 -23
- package/dist/routes/git-status.js.map +1 -1
- package/dist/routes/global-sessions.d.ts +11 -1
- package/dist/routes/global-sessions.d.ts.map +1 -1
- package/dist/routes/global-sessions.js +53 -33
- package/dist/routes/global-sessions.js.map +1 -1
- package/dist/routes/inbox.d.ts +10 -1
- package/dist/routes/inbox.d.ts.map +1 -1
- package/dist/routes/inbox.js +30 -3
- package/dist/routes/inbox.js.map +1 -1
- package/dist/routes/local-file.d.ts +6 -2
- package/dist/routes/local-file.d.ts.map +1 -1
- package/dist/routes/local-file.js +13 -4
- package/dist/routes/local-file.js.map +1 -1
- package/dist/routes/local-image.d.ts +2 -1
- package/dist/routes/local-image.d.ts.map +1 -1
- package/dist/routes/local-image.js.map +1 -1
- package/dist/routes/local-resource-policy.d.ts +7 -1
- package/dist/routes/local-resource-policy.d.ts.map +1 -1
- package/dist/routes/local-resource-policy.js +0 -0
- package/dist/routes/local-resource-policy.js.map +1 -1
- package/dist/routes/processes.d.ts.map +1 -1
- package/dist/routes/processes.js +49 -11
- package/dist/routes/processes.js.map +1 -1
- package/dist/routes/project-queue-response.d.ts +26 -0
- package/dist/routes/project-queue-response.d.ts.map +1 -0
- package/dist/routes/project-queue-response.js +188 -0
- package/dist/routes/project-queue-response.js.map +1 -0
- package/dist/routes/project-queue.d.ts +5 -0
- package/dist/routes/project-queue.d.ts.map +1 -0
- package/dist/routes/project-queue.js +219 -0
- package/dist/routes/project-queue.js.map +1 -0
- package/dist/routes/projects.d.ts +6 -0
- package/dist/routes/projects.d.ts.map +1 -1
- package/dist/routes/projects.js +116 -28
- package/dist/routes/projects.js.map +1 -1
- package/dist/routes/providers.d.ts +5 -0
- package/dist/routes/providers.d.ts.map +1 -1
- package/dist/routes/providers.js +52 -33
- package/dist/routes/providers.js.map +1 -1
- package/dist/routes/public-shares.d.ts.map +1 -1
- package/dist/routes/public-shares.js +46 -17
- package/dist/routes/public-shares.js.map +1 -1
- package/dist/routes/recents.d.ts +3 -0
- package/dist/routes/recents.d.ts.map +1 -1
- package/dist/routes/recents.js +3 -1
- package/dist/routes/recents.js.map +1 -1
- package/dist/routes/server-admin.d.ts +9 -0
- package/dist/routes/server-admin.d.ts.map +1 -1
- package/dist/routes/server-admin.js +45 -7
- package/dist/routes/server-admin.js.map +1 -1
- package/dist/routes/session-claude-resume-guard.d.ts +16 -0
- package/dist/routes/session-claude-resume-guard.d.ts.map +1 -0
- package/dist/routes/session-claude-resume-guard.js +50 -0
- package/dist/routes/session-claude-resume-guard.js.map +1 -0
- package/dist/routes/session-compact-thresholds.d.ts +22 -0
- package/dist/routes/session-compact-thresholds.d.ts.map +1 -0
- package/dist/routes/session-compact-thresholds.js +35 -0
- package/dist/routes/session-compact-thresholds.js.map +1 -0
- package/dist/routes/session-index.d.ts +7 -0
- package/dist/routes/session-index.d.ts.map +1 -0
- package/dist/routes/session-index.js +9 -0
- package/dist/routes/session-index.js.map +1 -0
- package/dist/routes/session-list-options.d.ts +1 -1
- package/dist/routes/session-list-options.d.ts.map +1 -1
- package/dist/routes/session-list-options.js +1 -1
- package/dist/routes/session-list-options.js.map +1 -1
- package/dist/routes/session-request-helpers.d.ts +31 -0
- package/dist/routes/session-request-helpers.d.ts.map +1 -0
- package/dist/routes/session-request-helpers.js +212 -0
- package/dist/routes/session-request-helpers.js.map +1 -0
- package/dist/routes/sessions.d.ts +14 -1
- package/dist/routes/sessions.d.ts.map +1 -1
- package/dist/routes/sessions.js +2141 -551
- package/dist/routes/sessions.js.map +1 -1
- package/dist/routes/settings.d.ts +7 -1
- package/dist/routes/settings.d.ts.map +1 -1
- package/dist/routes/settings.js +771 -25
- package/dist/routes/settings.js.map +1 -1
- package/dist/routes/speech.d.ts +24 -2
- package/dist/routes/speech.d.ts.map +1 -1
- package/dist/routes/speech.js +539 -10
- package/dist/routes/speech.js.map +1 -1
- package/dist/routes/supervisor-queue.d.ts +6 -0
- package/dist/routes/supervisor-queue.d.ts.map +1 -0
- package/dist/routes/supervisor-queue.js +35 -0
- package/dist/routes/supervisor-queue.js.map +1 -0
- package/dist/routes/upload.d.ts +2 -0
- package/dist/routes/upload.d.ts.map +1 -1
- package/dist/routes/upload.js +190 -38
- package/dist/routes/upload.js.map +1 -1
- package/dist/routes/version.d.ts +18 -1
- package/dist/routes/version.d.ts.map +1 -1
- package/dist/routes/version.js +22 -1
- package/dist/routes/version.js.map +1 -1
- package/dist/routes/workstreams.d.ts +11 -0
- package/dist/routes/workstreams.d.ts.map +1 -0
- package/dist/routes/workstreams.js +144 -0
- package/dist/routes/workstreams.js.map +1 -0
- package/dist/routes/ws-message-router.d.ts +10 -1
- package/dist/routes/ws-message-router.d.ts.map +1 -1
- package/dist/routes/ws-message-router.js +43 -4
- package/dist/routes/ws-message-router.js.map +1 -1
- package/dist/routes/ws-relay-handlers.d.ts +27 -5
- package/dist/routes/ws-relay-handlers.d.ts.map +1 -1
- package/dist/routes/ws-relay-handlers.js +177 -19
- package/dist/routes/ws-relay-handlers.js.map +1 -1
- package/dist/routes/ws-relay.d.ts +19 -0
- package/dist/routes/ws-relay.d.ts.map +1 -1
- package/dist/routes/ws-relay.js +21 -7
- package/dist/routes/ws-relay.js.map +1 -1
- package/dist/sdk/cli-detection.d.ts +1 -1
- package/dist/sdk/cli-detection.d.ts.map +1 -1
- package/dist/sdk/cli-detection.js +47 -7
- package/dist/sdk/cli-detection.js.map +1 -1
- package/dist/sdk/messageLogger.d.ts.map +1 -1
- package/dist/sdk/messageLogger.js +38 -10
- package/dist/sdk/messageLogger.js.map +1 -1
- package/dist/sdk/messageQueue.d.ts.map +1 -1
- package/dist/sdk/messageQueue.js +26 -0
- package/dist/sdk/messageQueue.js.map +1 -1
- package/dist/sdk/providers/__mocks__/grok.d.ts +1 -1
- package/dist/sdk/providers/__mocks__/grok.d.ts.map +1 -1
- package/dist/sdk/providers/__mocks__/grok.js +1 -1
- package/dist/sdk/providers/__mocks__/grok.js.map +1 -1
- package/dist/sdk/providers/agentctl-session-env.d.ts +8 -0
- package/dist/sdk/providers/agentctl-session-env.d.ts.map +1 -0
- package/dist/sdk/providers/agentctl-session-env.js +52 -0
- package/dist/sdk/providers/agentctl-session-env.js.map +1 -0
- package/dist/sdk/providers/claude-ollama.d.ts +2 -1
- package/dist/sdk/providers/claude-ollama.d.ts.map +1 -1
- package/dist/sdk/providers/claude-ollama.js +1 -0
- package/dist/sdk/providers/claude-ollama.js.map +1 -1
- package/dist/sdk/providers/claude-retention.d.ts +19 -0
- package/dist/sdk/providers/claude-retention.d.ts.map +1 -0
- package/dist/sdk/providers/claude-retention.js +169 -0
- package/dist/sdk/providers/claude-retention.js.map +1 -0
- package/dist/sdk/providers/claude.d.ts +52 -5
- package/dist/sdk/providers/claude.d.ts.map +1 -1
- package/dist/sdk/providers/claude.js +593 -71
- package/dist/sdk/providers/claude.js.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/AgentMessageInputContent.d.ts +8 -0
- package/dist/sdk/providers/codex-protocol/generated/AgentMessageInputContent.d.ts.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/AgentMessageInputContent.js +3 -0
- package/dist/sdk/providers/codex-protocol/generated/AgentMessageInputContent.js.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/InternalChatMessageMetadataPassthrough.d.ts +10 -0
- package/dist/sdk/providers/codex-protocol/generated/InternalChatMessageMetadataPassthrough.d.ts.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/InternalChatMessageMetadataPassthrough.js +3 -0
- package/dist/sdk/providers/codex-protocol/generated/InternalChatMessageMetadataPassthrough.js.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/LegacyAppPathString.d.ts +23 -0
- package/dist/sdk/providers/codex-protocol/generated/LegacyAppPathString.d.ts.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/LegacyAppPathString.js +3 -0
- package/dist/sdk/providers/codex-protocol/generated/LegacyAppPathString.js.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/MultiAgentMode.d.ts +8 -0
- package/dist/sdk/providers/codex-protocol/generated/MultiAgentMode.d.ts.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/MultiAgentMode.js +3 -0
- package/dist/sdk/providers/codex-protocol/generated/MultiAgentMode.js.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/ReasoningEffort.d.ts +1 -1
- package/dist/sdk/providers/codex-protocol/generated/ReasoningEffort.d.ts.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/ResponseItem.d.ts +38 -1
- package/dist/sdk/providers/codex-protocol/generated/ResponseItem.d.ts.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/AdditionalFileSystemPermissions.d.ts +3 -3
- package/dist/sdk/providers/codex-protocol/generated/v2/AdditionalFileSystemPermissions.d.ts.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/CapabilityRootLocation.d.ts +9 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/CapabilityRootLocation.d.ts.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/CapabilityRootLocation.js +3 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/CapabilityRootLocation.js.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/CommandExecutionRequestApprovalParams.d.ts +6 -2
- package/dist/sdk/providers/codex-protocol/generated/v2/CommandExecutionRequestApprovalParams.d.ts.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/DynamicToolFunctionSpec.d.ts +8 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/DynamicToolFunctionSpec.d.ts.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/DynamicToolFunctionSpec.js +3 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/DynamicToolFunctionSpec.js.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/DynamicToolNamespaceSpec.d.ts +7 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/DynamicToolNamespaceSpec.d.ts.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/DynamicToolNamespaceSpec.js +3 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/DynamicToolNamespaceSpec.js.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/DynamicToolNamespaceTool.d.ts +5 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/DynamicToolNamespaceTool.d.ts.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/DynamicToolNamespaceTool.js +3 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/DynamicToolNamespaceTool.js.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/DynamicToolSpec.d.ts +6 -7
- package/dist/sdk/providers/codex-protocol/generated/v2/DynamicToolSpec.d.ts.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/FileSystemPath.d.ts +2 -2
- package/dist/sdk/providers/codex-protocol/generated/v2/FileSystemPath.d.ts.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/McpToolCallAppContext.d.ts +6 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/McpToolCallAppContext.d.ts.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/McpToolCallAppContext.js +3 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/McpToolCallAppContext.js.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/PermissionsRequestApprovalParams.d.ts +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/PermissionsRequestApprovalParams.d.ts.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/SelectedCapabilityRoot.d.ts +15 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/SelectedCapabilityRoot.d.ts.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/SelectedCapabilityRoot.js +3 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/SelectedCapabilityRoot.js.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/SortDirection.d.ts +2 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/SortDirection.d.ts.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/SortDirection.js +3 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/SortDirection.js.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/SubAgentActivityKind.d.ts +2 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/SubAgentActivityKind.d.ts.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/SubAgentActivityKind.js +3 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/SubAgentActivityKind.js.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/Thread.d.ts +8 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/Thread.d.ts.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadCompactStartParams.d.ts +4 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadCompactStartParams.d.ts.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadCompactStartParams.js +3 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadCompactStartParams.js.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadCompactStartResponse.d.ts +2 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadCompactStartResponse.d.ts.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadCompactStartResponse.js +3 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadCompactStartResponse.js.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadForkParams.d.ts +64 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadForkParams.d.ts.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadForkParams.js +3 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadForkParams.js.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadForkResponse.d.ts +46 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadForkResponse.d.ts.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadForkResponse.js +3 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadForkResponse.js.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadItem.d.ts +19 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadItem.d.ts.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadReadResponse.d.ts +5 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadReadResponse.d.ts.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadReadResponse.js +3 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadReadResponse.js.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadResumeInitialTurnsPageParams.d.ts +17 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadResumeInitialTurnsPageParams.d.ts.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadResumeInitialTurnsPageParams.js +3 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadResumeInitialTurnsPageParams.js.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadResumeParams.d.ts +7 -7
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadResumeParams.d.ts.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadResumeResponse.d.ts +13 -2
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadResumeResponse.d.ts.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadRollbackParams.d.ts +11 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadRollbackParams.d.ts.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadRollbackParams.js +3 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadRollbackParams.js.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadRollbackResponse.d.ts +12 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadRollbackResponse.d.ts.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadRollbackResponse.js +3 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadRollbackResponse.js.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadSource.d.ts +1 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadSource.d.ts.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadStartParams.d.ts +13 -9
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadStartParams.d.ts.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadStartResponse.d.ts +8 -2
- package/dist/sdk/providers/codex-protocol/generated/v2/ThreadStartResponse.d.ts.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/ToolRequestUserInputParams.d.ts +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/ToolRequestUserInputParams.d.ts.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/TurnEnvironmentParams.d.ts +2 -2
- package/dist/sdk/providers/codex-protocol/generated/v2/TurnEnvironmentParams.d.ts.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/TurnStartParams.d.ts +17 -5
- package/dist/sdk/providers/codex-protocol/generated/v2/TurnStartParams.d.ts.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/TurnSteerParams.d.ts +8 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/TurnSteerParams.d.ts.map +1 -1
- package/dist/sdk/providers/codex-protocol/generated/v2/TurnsPage.d.ts +7 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/TurnsPage.d.ts.map +1 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/TurnsPage.js +3 -0
- package/dist/sdk/providers/codex-protocol/generated/v2/TurnsPage.js.map +1 -0
- package/dist/sdk/providers/codex-protocol/index.d.ts +7 -0
- package/dist/sdk/providers/codex-protocol/index.d.ts.map +1 -1
- package/dist/sdk/providers/codex.d.ts +26 -4
- package/dist/sdk/providers/codex.d.ts.map +1 -1
- package/dist/sdk/providers/codex.js +457 -37
- package/dist/sdk/providers/codex.js.map +1 -1
- package/dist/sdk/providers/env-filter.d.ts.map +1 -1
- package/dist/sdk/providers/env-filter.js +19 -1
- package/dist/sdk/providers/env-filter.js.map +1 -1
- package/dist/sdk/providers/gemini-tools.d.ts +28 -0
- package/dist/sdk/providers/gemini-tools.d.ts.map +1 -0
- package/dist/sdk/providers/gemini-tools.js +57 -0
- package/dist/sdk/providers/gemini-tools.js.map +1 -0
- package/dist/sdk/providers/gemini.d.ts.map +1 -1
- package/dist/sdk/providers/gemini.js +4 -2
- package/dist/sdk/providers/gemini.js.map +1 -1
- package/dist/sdk/providers/grok-acp.d.ts +1 -1
- package/dist/sdk/providers/grok-acp.d.ts.map +1 -1
- package/dist/sdk/providers/grok-acp.js +1 -1
- package/dist/sdk/providers/grok-acp.js.map +1 -1
- package/dist/sdk/providers/index.d.ts +1 -0
- package/dist/sdk/providers/index.d.ts.map +1 -1
- package/dist/sdk/providers/index.js +6 -0
- package/dist/sdk/providers/index.js.map +1 -1
- package/dist/sdk/providers/opencode-tools.d.ts +36 -0
- package/dist/sdk/providers/opencode-tools.d.ts.map +1 -0
- package/dist/sdk/providers/opencode-tools.js +78 -0
- package/dist/sdk/providers/opencode-tools.js.map +1 -0
- package/dist/sdk/providers/opencode.d.ts +53 -5
- package/dist/sdk/providers/opencode.d.ts.map +1 -1
- package/dist/sdk/providers/opencode.js +379 -71
- package/dist/sdk/providers/opencode.js.map +1 -1
- package/dist/sdk/providers/pi-rpc-client.d.ts +90 -0
- package/dist/sdk/providers/pi-rpc-client.d.ts.map +1 -0
- package/dist/sdk/providers/pi-rpc-client.js +168 -0
- package/dist/sdk/providers/pi-rpc-client.js.map +1 -0
- package/dist/sdk/providers/pi-tools.d.ts +38 -0
- package/dist/sdk/providers/pi-tools.d.ts.map +1 -0
- package/dist/sdk/providers/pi-tools.js +214 -0
- package/dist/sdk/providers/pi-tools.js.map +1 -0
- package/dist/sdk/providers/pi.d.ts +84 -0
- package/dist/sdk/providers/pi.d.ts.map +1 -0
- package/dist/sdk/providers/pi.js +686 -0
- package/dist/sdk/providers/pi.js.map +1 -0
- package/dist/sdk/providers/staticSlashCommands.d.ts +4 -0
- package/dist/sdk/providers/staticSlashCommands.d.ts.map +1 -0
- package/dist/sdk/providers/staticSlashCommands.js +14 -0
- package/dist/sdk/providers/staticSlashCommands.js.map +1 -0
- package/dist/sdk/providers/types.d.ts +144 -17
- package/dist/sdk/providers/types.d.ts.map +1 -1
- package/dist/sdk/remote-spawn.d.ts.map +1 -1
- package/dist/sdk/remote-spawn.js.map +1 -1
- package/dist/sdk/slashCommandEmulation.d.ts +9 -0
- package/dist/sdk/slashCommandEmulation.d.ts.map +1 -1
- package/dist/sdk/slashCommandEmulation.js +15 -0
- package/dist/sdk/slashCommandEmulation.js.map +1 -1
- package/dist/sdk/types.d.ts +40 -0
- package/dist/sdk/types.d.ts.map +1 -1
- package/dist/security/approvalAuditLog.d.ts +3 -2
- package/dist/security/approvalAuditLog.d.ts.map +1 -1
- package/dist/security/approvalAuditLog.js +62 -2
- package/dist/security/approvalAuditLog.js.map +1 -1
- package/dist/services/BrowserProfileService.d.ts +21 -0
- package/dist/services/BrowserProfileService.d.ts.map +1 -1
- package/dist/services/BrowserProfileService.js +74 -1
- package/dist/services/BrowserProfileService.js.map +1 -1
- package/dist/services/CacheMissBillingMonitor.d.ts +25 -0
- package/dist/services/CacheMissBillingMonitor.d.ts.map +1 -0
- package/dist/services/CacheMissBillingMonitor.js +179 -0
- package/dist/services/CacheMissBillingMonitor.js.map +1 -0
- package/dist/services/CodexUpdateChecker.d.ts.map +1 -1
- package/dist/services/CodexUpdateChecker.js +3 -2
- package/dist/services/CodexUpdateChecker.js.map +1 -1
- package/dist/services/ModelInfoService.d.ts +58 -9
- package/dist/services/ModelInfoService.d.ts.map +1 -1
- package/dist/services/ModelInfoService.js +127 -14
- package/dist/services/ModelInfoService.js.map +1 -1
- package/dist/services/ProjectQueueScheduler.d.ts +91 -0
- package/dist/services/ProjectQueueScheduler.d.ts.map +1 -0
- package/dist/services/ProjectQueueScheduler.js +404 -0
- package/dist/services/ProjectQueueScheduler.js.map +1 -0
- package/dist/services/ProjectQueueService.d.ts +60 -0
- package/dist/services/ProjectQueueService.d.ts.map +1 -0
- package/dist/services/ProjectQueueService.js +804 -0
- package/dist/services/ProjectQueueService.js.map +1 -0
- package/dist/services/RelayClientService.d.ts +5 -0
- package/dist/services/RelayClientService.d.ts.map +1 -1
- package/dist/services/RelayClientService.js +26 -12
- package/dist/services/RelayClientService.js.map +1 -1
- package/dist/services/SafeRestartService.d.ts +48 -0
- package/dist/services/SafeRestartService.d.ts.map +1 -0
- package/dist/services/SafeRestartService.js +173 -0
- package/dist/services/SafeRestartService.js.map +1 -0
- package/dist/services/ServerSettingsService.d.ts +41 -1
- package/dist/services/ServerSettingsService.d.ts.map +1 -1
- package/dist/services/ServerSettingsService.js +110 -1
- package/dist/services/ServerSettingsService.js.map +1 -1
- package/dist/services/SessionQueuePersistenceService.d.ts +55 -0
- package/dist/services/SessionQueuePersistenceService.d.ts.map +1 -0
- package/dist/services/SessionQueuePersistenceService.js +264 -0
- package/dist/services/SessionQueuePersistenceService.js.map +1 -0
- package/dist/services/WorkstreamService.d.ts +92 -0
- package/dist/services/WorkstreamService.d.ts.map +1 -0
- package/dist/services/WorkstreamService.js +627 -0
- package/dist/services/WorkstreamService.js.map +1 -0
- package/dist/services/index.d.ts +4 -0
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +4 -0
- package/dist/services/index.js.map +1 -1
- package/dist/services/projectWorkIdle.d.ts +42 -0
- package/dist/services/projectWorkIdle.d.ts.map +1 -0
- package/dist/services/projectWorkIdle.js +50 -0
- package/dist/services/projectWorkIdle.js.map +1 -0
- package/dist/services/voice/SpeechBackend.d.ts +18 -1
- package/dist/services/voice/SpeechBackend.d.ts.map +1 -1
- package/dist/services/voice/SpeechBackend.js +3 -0
- package/dist/services/voice/SpeechBackend.js.map +1 -1
- package/dist/services/voice/audioRetention.d.ts +20 -0
- package/dist/services/voice/audioRetention.d.ts.map +1 -1
- package/dist/services/voice/audioRetention.js +2 -0
- package/dist/services/voice/audioRetention.js.map +1 -1
- package/dist/services/voice/deepgramBackend.d.ts.map +1 -1
- package/dist/services/voice/deepgramBackend.js +4 -1
- package/dist/services/voice/deepgramBackend.js.map +1 -1
- package/dist/services/voice/localNemoBackend.d.ts +31 -0
- package/dist/services/voice/localNemoBackend.d.ts.map +1 -0
- package/dist/services/voice/localNemoBackend.js +181 -0
- package/dist/services/voice/localNemoBackend.js.map +1 -0
- package/dist/services/voice/localParakeetBackend.d.ts +31 -0
- package/dist/services/voice/localParakeetBackend.d.ts.map +1 -0
- package/dist/services/voice/localParakeetBackend.js +180 -0
- package/dist/services/voice/localParakeetBackend.js.map +1 -0
- package/dist/services/voice/localSttRuntime.d.ts +21 -0
- package/dist/services/voice/localSttRuntime.d.ts.map +1 -0
- package/dist/services/voice/localSttRuntime.js +87 -0
- package/dist/services/voice/localSttRuntime.js.map +1 -0
- package/dist/services/voice/localWhisperBackend.d.ts +2 -1
- package/dist/services/voice/localWhisperBackend.d.ts.map +1 -1
- package/dist/services/voice/localWhisperBackend.js +47 -34
- package/dist/services/voice/localWhisperBackend.js.map +1 -1
- package/dist/services/voice/nemo_worker.py +232 -0
- package/dist/services/voice/parakeet_worker.py +151 -0
- package/dist/services/voice/registry.d.ts +19 -4
- package/dist/services/voice/registry.d.ts.map +1 -1
- package/dist/services/voice/registry.js +72 -22
- package/dist/services/voice/registry.js.map +1 -1
- package/dist/services/voice/serialQueue.d.ts +17 -0
- package/dist/services/voice/serialQueue.d.ts.map +1 -0
- package/dist/services/voice/serialQueue.js +24 -0
- package/dist/services/voice/serialQueue.js.map +1 -0
- package/dist/services/voice/whisper_worker.py +94 -0
- package/dist/services/voice/xaiSttBackend.d.ts +1 -1
- package/dist/services/voice/xaiSttBackend.d.ts.map +1 -1
- package/dist/services/voice/xaiSttBackend.js +15 -3
- package/dist/services/voice/xaiSttBackend.js.map +1 -1
- package/dist/sessions/agent-excerpt.d.ts +29 -0
- package/dist/sessions/agent-excerpt.d.ts.map +1 -0
- package/dist/sessions/agent-excerpt.js +128 -0
- package/dist/sessions/agent-excerpt.js.map +1 -0
- package/dist/sessions/claude-messages.d.ts.map +1 -1
- package/dist/sessions/claude-messages.js +75 -4
- package/dist/sessions/claude-messages.js.map +1 -1
- package/dist/sessions/claude-summary.d.ts +33 -0
- package/dist/sessions/claude-summary.d.ts.map +1 -0
- package/dist/sessions/claude-summary.js +461 -0
- package/dist/sessions/claude-summary.js.map +1 -0
- package/dist/sessions/codex-discovery.d.ts +46 -0
- package/dist/sessions/codex-discovery.d.ts.map +1 -0
- package/dist/sessions/codex-discovery.js +269 -0
- package/dist/sessions/codex-discovery.js.map +1 -0
- package/dist/sessions/codex-reader.d.ts +96 -13
- package/dist/sessions/codex-reader.d.ts.map +1 -1
- package/dist/sessions/codex-reader.js +1069 -141
- package/dist/sessions/codex-reader.js.map +1 -1
- package/dist/sessions/dag.d.ts +25 -4
- package/dist/sessions/dag.d.ts.map +1 -1
- package/dist/sessions/dag.js +37 -4
- package/dist/sessions/dag.js.map +1 -1
- package/dist/sessions/gemini-reader.d.ts +3 -1
- package/dist/sessions/gemini-reader.d.ts.map +1 -1
- package/dist/sessions/gemini-reader.js +17 -8
- package/dist/sessions/gemini-reader.js.map +1 -1
- package/dist/sessions/grok-reader.d.ts +1 -0
- package/dist/sessions/grok-reader.d.ts.map +1 -1
- package/dist/sessions/grok-reader.js +11 -5
- package/dist/sessions/grok-reader.js.map +1 -1
- package/dist/sessions/normalization.d.ts +3 -1
- package/dist/sessions/normalization.d.ts.map +1 -1
- package/dist/sessions/normalization.js +72 -16
- package/dist/sessions/normalization.js.map +1 -1
- package/dist/sessions/null-reader.d.ts +31 -0
- package/dist/sessions/null-reader.d.ts.map +1 -0
- package/dist/sessions/null-reader.js +30 -0
- package/dist/sessions/null-reader.js.map +1 -0
- package/dist/sessions/opencode-db-reader.d.ts +66 -0
- package/dist/sessions/opencode-db-reader.d.ts.map +1 -0
- package/dist/sessions/opencode-db-reader.js +333 -0
- package/dist/sessions/opencode-db-reader.js.map +1 -0
- package/dist/sessions/opencode-reader.d.ts +50 -0
- package/dist/sessions/opencode-reader.d.ts.map +1 -1
- package/dist/sessions/opencode-reader.js +375 -71
- package/dist/sessions/opencode-reader.js.map +1 -1
- package/dist/sessions/pagination.d.ts.map +1 -1
- package/dist/sessions/pagination.js +119 -3
- package/dist/sessions/pagination.js.map +1 -1
- package/dist/sessions/persisted-augments.d.ts +2 -1
- package/dist/sessions/persisted-augments.d.ts.map +1 -1
- package/dist/sessions/persisted-augments.js +2 -2
- package/dist/sessions/persisted-augments.js.map +1 -1
- package/dist/sessions/pi-fork.d.ts +12 -0
- package/dist/sessions/pi-fork.d.ts.map +1 -0
- package/dist/sessions/pi-fork.js +125 -0
- package/dist/sessions/pi-fork.js.map +1 -0
- package/dist/sessions/pi-reader.d.ts +81 -0
- package/dist/sessions/pi-reader.d.ts.map +1 -0
- package/dist/sessions/pi-reader.js +413 -0
- package/dist/sessions/pi-reader.js.map +1 -0
- package/dist/sessions/provider-resolution.d.ts +10 -3
- package/dist/sessions/provider-resolution.d.ts.map +1 -1
- package/dist/sessions/provider-resolution.js +62 -6
- package/dist/sessions/provider-resolution.js.map +1 -1
- package/dist/sessions/reader.d.ts +17 -24
- package/dist/sessions/reader.d.ts.map +1 -1
- package/dist/sessions/reader.js +86 -157
- package/dist/sessions/reader.js.map +1 -1
- package/dist/sessions/recap-overlays.d.ts +38 -0
- package/dist/sessions/recap-overlays.d.ts.map +1 -0
- package/dist/sessions/recap-overlays.js +176 -0
- package/dist/sessions/recap-overlays.js.map +1 -0
- package/dist/sessions/summary-parser-worker-client.d.ts +80 -0
- package/dist/sessions/summary-parser-worker-client.d.ts.map +1 -0
- package/dist/sessions/summary-parser-worker-client.js +539 -0
- package/dist/sessions/summary-parser-worker-client.js.map +1 -0
- package/dist/sessions/summary-parser-worker-entry.d.ts +2 -0
- package/dist/sessions/summary-parser-worker-entry.d.ts.map +1 -0
- package/dist/sessions/summary-parser-worker-entry.js +29 -0
- package/dist/sessions/summary-parser-worker-entry.js.map +1 -0
- package/dist/sessions/summary-parser-worker-protocol.d.ts +105 -0
- package/dist/sessions/summary-parser-worker-protocol.d.ts.map +1 -0
- package/dist/sessions/summary-parser-worker-protocol.js +35 -0
- package/dist/sessions/summary-parser-worker-protocol.js.map +1 -0
- package/dist/sessions/summary-parser-worker-runner.d.ts +3 -0
- package/dist/sessions/summary-parser-worker-runner.d.ts.map +1 -0
- package/dist/sessions/summary-parser-worker-runner.js +158 -0
- package/dist/sessions/summary-parser-worker-runner.js.map +1 -0
- package/dist/sessions/types.d.ts +30 -1
- package/dist/sessions/types.d.ts.map +1 -1
- package/dist/startupEnv.d.ts +2 -0
- package/dist/startupEnv.d.ts.map +1 -0
- package/dist/startupEnv.js +97 -0
- package/dist/startupEnv.js.map +1 -0
- package/dist/subscriptions.d.ts.map +1 -1
- package/dist/subscriptions.js +28 -18
- package/dist/subscriptions.js.map +1 -1
- package/dist/supervisor/ExternalSessionTracker.d.ts +5 -1
- package/dist/supervisor/ExternalSessionTracker.d.ts.map +1 -1
- package/dist/supervisor/ExternalSessionTracker.js +98 -6
- package/dist/supervisor/ExternalSessionTracker.js.map +1 -1
- package/dist/supervisor/Process.d.ts +252 -32
- package/dist/supervisor/Process.d.ts.map +1 -1
- package/dist/supervisor/Process.js +1233 -219
- package/dist/supervisor/Process.js.map +1 -1
- package/dist/supervisor/Supervisor.d.ts +201 -5
- package/dist/supervisor/Supervisor.d.ts.map +1 -1
- package/dist/supervisor/Supervisor.js +1074 -55
- package/dist/supervisor/Supervisor.js.map +1 -1
- package/dist/supervisor/WorkerQueue.d.ts +3 -1
- package/dist/supervisor/WorkerQueue.d.ts.map +1 -1
- package/dist/supervisor/WorkerQueue.js +1 -0
- package/dist/supervisor/WorkerQueue.js.map +1 -1
- package/dist/supervisor/composeTimeAnchor.d.ts +36 -0
- package/dist/supervisor/composeTimeAnchor.d.ts.map +1 -0
- package/dist/supervisor/composeTimeAnchor.js +51 -0
- package/dist/supervisor/composeTimeAnchor.js.map +1 -0
- package/dist/supervisor/deferredDeliverySettings.d.ts +23 -0
- package/dist/supervisor/deferredDeliverySettings.d.ts.map +1 -0
- package/dist/supervisor/deferredDeliverySettings.js +40 -0
- package/dist/supervisor/deferredDeliverySettings.js.map +1 -0
- package/dist/supervisor/liveness.d.ts +5 -2
- package/dist/supervisor/liveness.d.ts.map +1 -1
- package/dist/supervisor/liveness.js +40 -2
- package/dist/supervisor/liveness.js.map +1 -1
- package/dist/supervisor/types.d.ts +56 -5
- package/dist/supervisor/types.d.ts.map +1 -1
- package/dist/supervisor/types.js +0 -2
- package/dist/supervisor/types.js.map +1 -1
- package/dist/uploads/AttachmentStagingService.d.ts +94 -0
- package/dist/uploads/AttachmentStagingService.d.ts.map +1 -0
- package/dist/uploads/AttachmentStagingService.js +673 -0
- package/dist/uploads/AttachmentStagingService.js.map +1 -0
- package/dist/uploads/index.d.ts +2 -0
- package/dist/uploads/index.d.ts.map +1 -1
- package/dist/uploads/index.js +1 -0
- package/dist/uploads/index.js.map +1 -1
- package/dist/uploads/manager.d.ts +1 -0
- package/dist/uploads/manager.d.ts.map +1 -1
- package/dist/uploads/manager.js +72 -12
- package/dist/uploads/manager.js.map +1 -1
- package/dist/utils/codexRolloutFiles.d.ts +16 -0
- package/dist/utils/codexRolloutFiles.d.ts.map +1 -0
- package/dist/utils/codexRolloutFiles.js +45 -0
- package/dist/utils/codexRolloutFiles.js.map +1 -0
- package/dist/utils/jsonl.d.ts +8 -0
- package/dist/utils/jsonl.d.ts.map +1 -1
- package/dist/utils/jsonl.js +158 -5
- package/dist/utils/jsonl.js.map +1 -1
- package/dist/utils/publicShareViewerUrl.d.ts.map +1 -1
- package/dist/utils/publicShareViewerUrl.js +2 -15
- package/dist/utils/publicShareViewerUrl.js.map +1 -1
- package/dist/watcher/EventBus.d.ts +42 -4
- package/dist/watcher/EventBus.d.ts.map +1 -1
- package/dist/watcher/EventBus.js.map +1 -1
- package/dist/watcher/FileWatcher.d.ts +47 -0
- package/dist/watcher/FileWatcher.d.ts.map +1 -1
- package/dist/watcher/FileWatcher.js +185 -14
- package/dist/watcher/FileWatcher.js.map +1 -1
- package/dist/watcher/index.d.ts +2 -2
- package/dist/watcher/index.d.ts.map +1 -1
- package/dist/watcher/index.js.map +1 -1
- package/dist/yaModuleEnv.d.ts +6 -6
- package/dist/yaModuleEnv.d.ts.map +1 -1
- package/dist/yaModuleEnv.js +12 -12
- package/dist/yaModuleEnv.js.map +1 -1
- package/package.json +5 -6
- package/client-dist/assets/de-BuEb60Yc.js +0 -6
- package/client-dist/assets/es-CRlmPKnE.js +0 -6
- package/client-dist/assets/fr-Cglgjc2X.js +0 -6
- package/client-dist/assets/index-BNj7ibmq.js +0 -524
- package/client-dist/assets/index-CAmsUazi.css +0 -1
- package/client-dist/assets/ja-DMb9mFPv.js +0 -6
- package/client-dist/assets/zh-CN-D1tbfamz.js +0 -6
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { truncateSessionTitle, } from "../../bundled/@yep-anywhere/shared/dist/index.js";
|
|
2
|
+
import { DEFAULT_PROMPT_CACHE_KEEPALIVE_INACTIVITY_MINUTES, truncateSessionTitle, } from "../../bundled/@yep-anywhere/shared/dist/index.js";
|
|
3
3
|
import { getLogger } from "../logging/logger.js";
|
|
4
|
+
import { getProjectName } from "../projects/paths.js";
|
|
4
5
|
import { getProvider } from "../sdk/providers/index.js";
|
|
5
|
-
import {
|
|
6
|
+
import { CacheMissBillingMonitor } from "../services/CacheMissBillingMonitor.js";
|
|
7
|
+
import { formatAgentRecapExcerpt } from "../sessions/agent-excerpt.js";
|
|
8
|
+
import { isAwaySummaryMessage, latestRecapMessage, messageTimestampMs, toDurableRecapMessage, } from "../sessions/recap-overlays.js";
|
|
9
|
+
import { normalizeSlashCommandName } from "../sdk/slashCommandEmulation.js";
|
|
10
|
+
import { NATIVE_RECAP_FALLBACK_GRACE_MS, Process, } from "./Process.js";
|
|
6
11
|
import { WorkerQueue, isQueueFullError, } from "./WorkerQueue.js";
|
|
7
12
|
import { DEFAULT_IDLE_PREEMPT_THRESHOLD_MS, encodeProjectId, } from "./types.js";
|
|
8
13
|
/** Maximum number of terminated processes to retain */
|
|
@@ -20,6 +25,32 @@ const LIVENESS_PROBE_CHECK_INTERVAL_MS = 30 * 1000;
|
|
|
20
25
|
const LIVENESS_PROBE_REFRESH_MS = 60 * 1000;
|
|
21
26
|
const DEFAULT_HEARTBEAT_TURN_TEXT = "continue";
|
|
22
27
|
const DEFAULT_HEARTBEAT_TURNS_AFTER_MINUTES = 5;
|
|
28
|
+
function thinkingConfigsEqual(current, next) {
|
|
29
|
+
if (current?.type !== next?.type)
|
|
30
|
+
return false;
|
|
31
|
+
if (!current || !next)
|
|
32
|
+
return true;
|
|
33
|
+
if (current.type === "adaptive" && next.type === "adaptive") {
|
|
34
|
+
return current.display === next.display;
|
|
35
|
+
}
|
|
36
|
+
if (current.type === "enabled" && next.type === "enabled") {
|
|
37
|
+
return (current.budgetTokens === next.budgetTokens &&
|
|
38
|
+
current.display === next.display);
|
|
39
|
+
}
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
function isDynamicThinkingModeConfig(thinking) {
|
|
43
|
+
return (!thinking ||
|
|
44
|
+
thinking.type === "disabled" ||
|
|
45
|
+
(thinking.type === "adaptive" && thinking.display === undefined));
|
|
46
|
+
}
|
|
47
|
+
function canApplyThinkingConfigDynamically(current, next) {
|
|
48
|
+
if (!isDynamicThinkingModeConfig(current))
|
|
49
|
+
return false;
|
|
50
|
+
if (!isDynamicThinkingModeConfig(next))
|
|
51
|
+
return false;
|
|
52
|
+
return current?.type !== next?.type;
|
|
53
|
+
}
|
|
23
54
|
const DEFAULT_INTERRUPT_TIMEOUT_MS = 2000;
|
|
24
55
|
const FORCED_HEARTBEAT_INTERRUPT_PREAMBLE = "interrupted for heartbeat; resume interrupted command after responding:";
|
|
25
56
|
const HEARTBEAT_RESET_PROBE_STATUSES = new Set(["active", "idle", "waiting-input"]);
|
|
@@ -28,6 +59,73 @@ const ACTIVE_HEARTBEAT_DOUBT_STATUSES = new Set([
|
|
|
28
59
|
"recently-active-unverified",
|
|
29
60
|
"long-silent-unverified",
|
|
30
61
|
]);
|
|
62
|
+
const RESUME_COMPACT_WAIT_MS = 3 * 60 * 1000;
|
|
63
|
+
export class ResumeCompactionError extends Error {
|
|
64
|
+
sessionId;
|
|
65
|
+
provider;
|
|
66
|
+
attempt;
|
|
67
|
+
recovery = "full-resume";
|
|
68
|
+
constructor(params) {
|
|
69
|
+
super(describeResumeCompactionAttempt(params.attempt));
|
|
70
|
+
this.name = "ResumeCompactionError";
|
|
71
|
+
this.sessionId = params.sessionId;
|
|
72
|
+
this.provider = params.provider;
|
|
73
|
+
this.attempt = params.attempt;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function describeResumeCompactionAttempt(attempt) {
|
|
77
|
+
switch (attempt.status) {
|
|
78
|
+
case "completed":
|
|
79
|
+
return `Compact-first resume completed with /${attempt.command}`;
|
|
80
|
+
case "timed-out":
|
|
81
|
+
return `Compact-first resume timed out after ${attempt.timeoutMs}ms waiting for /${attempt.command}`;
|
|
82
|
+
case "failed":
|
|
83
|
+
return attempt.command
|
|
84
|
+
? `Compact-first resume failed after /${attempt.command}: ${attempt.reason}`
|
|
85
|
+
: `Compact-first resume failed: ${attempt.reason}`;
|
|
86
|
+
case "unavailable":
|
|
87
|
+
return `Compact-first resume unavailable: ${attempt.reason}`;
|
|
88
|
+
case "skipped":
|
|
89
|
+
return `Compact-first resume skipped: ${attempt.reason}`;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function isCompactBoundaryMessage(message) {
|
|
93
|
+
return message.type === "system" && message.subtype === "compact_boundary";
|
|
94
|
+
}
|
|
95
|
+
function compactFailureReason(message) {
|
|
96
|
+
if (message.type !== "system" ||
|
|
97
|
+
message.subtype !== "status" ||
|
|
98
|
+
message.compact_result !== "failed") {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
return typeof message.compact_error === "string" && message.compact_error
|
|
102
|
+
? message.compact_error
|
|
103
|
+
: "provider reported compaction failure";
|
|
104
|
+
}
|
|
105
|
+
function isCompactSuccessStatus(message) {
|
|
106
|
+
return (message.type === "system" &&
|
|
107
|
+
message.subtype === "status" &&
|
|
108
|
+
message.compact_result === "success");
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Pure gate for the per-model compact-early threshold (task 029): true when a
|
|
112
|
+
* valid percent (1–99) and a known context window put live usage at or over
|
|
113
|
+
* the token threshold (percent% × window). Anything unknown or out of range
|
|
114
|
+
* yields false — the trigger never fires on missing usage. Semantics are
|
|
115
|
+
* "current usage already crosses the threshold", not a prediction of the next
|
|
116
|
+
* turn's size.
|
|
117
|
+
*/
|
|
118
|
+
export function crossesCompactThreshold(percent, contextWindow, inputTokens) {
|
|
119
|
+
if (typeof percent !== "number" || percent <= 0 || percent >= 100) {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
if (typeof contextWindow !== "number" || contextWindow <= 0)
|
|
123
|
+
return false;
|
|
124
|
+
if (typeof inputTokens !== "number" || !Number.isFinite(inputTokens)) {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
return inputTokens >= (percent / 100) * contextWindow;
|
|
128
|
+
}
|
|
31
129
|
function getStaleInTurnThresholdMs(provider) {
|
|
32
130
|
return provider === "codex" || provider === "codex-oss"
|
|
33
131
|
? CODEX_STALE_IN_TURN_THRESHOLD_MS
|
|
@@ -100,6 +198,7 @@ const INITIAL_RECONCILE_DELAYS_MS = [1000, 3000];
|
|
|
100
198
|
export class Supervisor {
|
|
101
199
|
processes = new Map();
|
|
102
200
|
sessionToProcess = new Map(); // sessionId -> processId
|
|
201
|
+
sessionActivationInFlight = new Map();
|
|
103
202
|
observedProcessIds = new Set();
|
|
104
203
|
everOwnedSessions = new Set(); // Sessions we've ever owned (for orphan detection)
|
|
105
204
|
terminatedProcesses = []; // Recently terminated processes
|
|
@@ -113,14 +212,30 @@ export class Supervisor {
|
|
|
113
212
|
idlePreemptThresholdMs;
|
|
114
213
|
workerQueue;
|
|
115
214
|
onSessionExecutor;
|
|
215
|
+
onContextWindowObserved;
|
|
116
216
|
onSessionSummary;
|
|
117
217
|
staleCheckTimer;
|
|
118
218
|
getHeartbeatTurnSettings;
|
|
119
219
|
getHeartbeatTurnCandidates;
|
|
220
|
+
getPromptCacheKeepaliveSettings;
|
|
221
|
+
cacheMissBillingMonitor;
|
|
120
222
|
heartbeatTurnInFlight = false;
|
|
121
223
|
heartbeatTurnTimer;
|
|
122
224
|
livenessProbeTimer;
|
|
225
|
+
/**
|
|
226
|
+
* One-shot patient-queue re-checks keyed by process id. Bounded: armed only
|
|
227
|
+
* while a process holds patient deferred entries; cleared on unregister.
|
|
228
|
+
*/
|
|
229
|
+
patientCheckTimers = new Map();
|
|
123
230
|
interruptTimeoutMs;
|
|
231
|
+
sessionMetadataService;
|
|
232
|
+
sessionQueuePersistenceService;
|
|
233
|
+
// In-flight forked recaps, keyed by process id. The AbortController cancels
|
|
234
|
+
// the generator-fork helper turn when the parent becomes active again, so a
|
|
235
|
+
// returning user's new turn is never shadowed by a stale recap. See
|
|
236
|
+
// topics/recaps.md.
|
|
237
|
+
forkedRecapInFlight = new Map();
|
|
238
|
+
pendingForkedRecapRequests = new Map();
|
|
124
239
|
constructor(options) {
|
|
125
240
|
this.provider = options.provider ?? null;
|
|
126
241
|
this.sdk = options.sdk ?? null;
|
|
@@ -136,11 +251,22 @@ export class Supervisor {
|
|
|
136
251
|
maxQueueSize: options.maxQueueSize,
|
|
137
252
|
});
|
|
138
253
|
this.onSessionExecutor = options.onSessionExecutor;
|
|
254
|
+
this.onContextWindowObserved = options.onContextWindowObserved;
|
|
139
255
|
this.onSessionSummary = options.onSessionSummary;
|
|
140
256
|
this.getHeartbeatTurnSettings = options.getHeartbeatTurnSettings;
|
|
141
257
|
this.getHeartbeatTurnCandidates = options.getHeartbeatTurnCandidates;
|
|
258
|
+
this.getPromptCacheKeepaliveSettings =
|
|
259
|
+
options.getPromptCacheKeepaliveSettings;
|
|
260
|
+
this.cacheMissBillingMonitor = new CacheMissBillingMonitor({
|
|
261
|
+
eventBus: options.eventBus,
|
|
262
|
+
sessionMetadataService: options.sessionMetadataService,
|
|
263
|
+
getSettings: options.getCacheMissBillingSettings,
|
|
264
|
+
});
|
|
142
265
|
this.interruptTimeoutMs =
|
|
143
266
|
options.interruptTimeoutMs ?? DEFAULT_INTERRUPT_TIMEOUT_MS;
|
|
267
|
+
this.sessionMetadataService = options.sessionMetadataService;
|
|
268
|
+
this.sessionQueuePersistenceService =
|
|
269
|
+
options.sessionQueuePersistenceService;
|
|
144
270
|
this.staleCheckTimer = setInterval(() => this.terminateStaleProcesses(), STALE_CHECK_INTERVAL_MS);
|
|
145
271
|
this.staleCheckTimer.unref(); // Don't keep process alive for cleanup
|
|
146
272
|
this.heartbeatTurnTimer = setInterval(() => {
|
|
@@ -176,8 +302,52 @@ export class Supervisor {
|
|
|
176
302
|
}
|
|
177
303
|
return "off";
|
|
178
304
|
}
|
|
179
|
-
async
|
|
180
|
-
const
|
|
305
|
+
async waitForSessionActivation(sessionId) {
|
|
306
|
+
const activation = this.sessionActivationInFlight.get(sessionId);
|
|
307
|
+
if (!activation) {
|
|
308
|
+
return false;
|
|
309
|
+
}
|
|
310
|
+
try {
|
|
311
|
+
await activation;
|
|
312
|
+
}
|
|
313
|
+
catch {
|
|
314
|
+
// The caller will retry the ordinary resume path, which can surface the
|
|
315
|
+
// fresh failure or recover if the transient activation failed.
|
|
316
|
+
}
|
|
317
|
+
return true;
|
|
318
|
+
}
|
|
319
|
+
async startSessionActivation(sessionId, activate) {
|
|
320
|
+
const activation = Promise.resolve().then(activate);
|
|
321
|
+
this.sessionActivationInFlight.set(sessionId, activation);
|
|
322
|
+
try {
|
|
323
|
+
return (await activation);
|
|
324
|
+
}
|
|
325
|
+
finally {
|
|
326
|
+
if (this.sessionActivationInFlight.get(sessionId) === activation) {
|
|
327
|
+
this.sessionActivationInFlight.delete(sessionId);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
registerPromptCacheKeepaliveViewer(process) {
|
|
332
|
+
if (!process.supportsPromptCacheKeepalive()) {
|
|
333
|
+
return () => { };
|
|
334
|
+
}
|
|
335
|
+
return process.registerPromptCacheKeepaliveLease({
|
|
336
|
+
getInactivityMs: () => {
|
|
337
|
+
const setting = this.getPromptCacheKeepaliveSettings?.(process.provider);
|
|
338
|
+
if (!setting?.enabled) {
|
|
339
|
+
return null;
|
|
340
|
+
}
|
|
341
|
+
const inactivityMinutes = Number.isFinite(setting.inactivityMinutes) &&
|
|
342
|
+
setting.inactivityMinutes > 0
|
|
343
|
+
? setting.inactivityMinutes
|
|
344
|
+
: DEFAULT_PROMPT_CACHE_KEEPALIVE_INACTIVITY_MINUTES;
|
|
345
|
+
return inactivityMinutes * 60_000;
|
|
346
|
+
},
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
async startSession(projectPath, message, permissionMode, modelSettings, launchOptions) {
|
|
350
|
+
const projectId = launchOptions?.projectId ?? encodeProjectId(projectPath);
|
|
181
351
|
// Check if at capacity
|
|
182
352
|
if (this.isAtCapacity()) {
|
|
183
353
|
// Try to preempt an idle worker
|
|
@@ -192,6 +362,7 @@ export class Supervisor {
|
|
|
192
362
|
type: "new-session",
|
|
193
363
|
projectPath,
|
|
194
364
|
projectId,
|
|
365
|
+
workstreamId: launchOptions?.workstreamId,
|
|
195
366
|
message,
|
|
196
367
|
permissionMode,
|
|
197
368
|
modelSettings,
|
|
@@ -223,8 +394,8 @@ export class Supervisor {
|
|
|
223
394
|
* Used for two-phase flow: create session first, upload files, then send message.
|
|
224
395
|
* The agent will wait for a message to be pushed to the queue.
|
|
225
396
|
*/
|
|
226
|
-
async createSession(projectPath, permissionMode, modelSettings) {
|
|
227
|
-
const projectId = encodeProjectId(projectPath);
|
|
397
|
+
async createSession(projectPath, permissionMode, modelSettings, launchOptions) {
|
|
398
|
+
const projectId = launchOptions?.projectId ?? encodeProjectId(projectPath);
|
|
228
399
|
// Check if at capacity
|
|
229
400
|
if (this.isAtCapacity()) {
|
|
230
401
|
// Try to preempt an idle worker
|
|
@@ -239,6 +410,7 @@ export class Supervisor {
|
|
|
239
410
|
type: "new-session",
|
|
240
411
|
projectPath,
|
|
241
412
|
projectId,
|
|
413
|
+
workstreamId: launchOptions?.workstreamId,
|
|
242
414
|
message: { text: "" }, // Placeholder, will be replaced when first message sent
|
|
243
415
|
permissionMode,
|
|
244
416
|
modelSettings,
|
|
@@ -265,6 +437,60 @@ export class Supervisor {
|
|
|
265
437
|
// Fall back to legacy mock SDK - not supported for create-only
|
|
266
438
|
throw new Error("createSession requires provider or real SDK - legacy mock SDK not supported");
|
|
267
439
|
}
|
|
440
|
+
/**
|
|
441
|
+
* Reactivate an existing session: spawn a live harness process bound to the
|
|
442
|
+
* session id WITHOUT delivering a user turn. The process resumes the session
|
|
443
|
+
* and idles on the queue (the same state it occupies after a completed turn),
|
|
444
|
+
* so the client can read live process state (model options, config) before
|
|
445
|
+
* any message is sent. Idempotent: returns the existing live process if the
|
|
446
|
+
* session is already owned.
|
|
447
|
+
*
|
|
448
|
+
* Provider-agnostic: rides the existing message-less resume path
|
|
449
|
+
* (`createProviderSession`/`createRealSession` with `resumeSessionId`), so
|
|
450
|
+
* Claude and Codex reactivate with no synthetic turn.
|
|
451
|
+
*/
|
|
452
|
+
async reactivateSession(projectPath, resumeSessionId, permissionMode, modelSettings, options) {
|
|
453
|
+
const existing = this.getProcessForSession(resumeSessionId);
|
|
454
|
+
if (existing) {
|
|
455
|
+
if (!existing.isTerminated) {
|
|
456
|
+
return existing;
|
|
457
|
+
}
|
|
458
|
+
this.unregisterProcess(existing);
|
|
459
|
+
}
|
|
460
|
+
const activeActivation = this.sessionActivationInFlight.get(resumeSessionId);
|
|
461
|
+
if (activeActivation) {
|
|
462
|
+
return activeActivation;
|
|
463
|
+
}
|
|
464
|
+
return this.startSessionActivation(resumeSessionId, async () => {
|
|
465
|
+
const activated = this.getProcessForSession(resumeSessionId);
|
|
466
|
+
if (activated) {
|
|
467
|
+
if (!activated.isTerminated) {
|
|
468
|
+
return activated;
|
|
469
|
+
}
|
|
470
|
+
this.unregisterProcess(activated);
|
|
471
|
+
}
|
|
472
|
+
if (this.isAtCapacity()) {
|
|
473
|
+
const preemptable = options?.preempt === false ? undefined : this.findPreemptableWorker();
|
|
474
|
+
if (preemptable) {
|
|
475
|
+
await this.preemptWorker(preemptable);
|
|
476
|
+
}
|
|
477
|
+
else {
|
|
478
|
+
// A background away-recap passes preempt:false: it should never evict
|
|
479
|
+
// a live worker just to revive a different session for a recap.
|
|
480
|
+
throw new Error("Cannot reactivate: server is at worker capacity and no idle process can be preempted");
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
const projectId = encodeProjectId(projectPath);
|
|
484
|
+
const provider = this.resolveProvider(modelSettings);
|
|
485
|
+
if (provider) {
|
|
486
|
+
return this.createProviderSession(projectPath, projectId, permissionMode, modelSettings, provider, resumeSessionId);
|
|
487
|
+
}
|
|
488
|
+
if (this.realSdk) {
|
|
489
|
+
return this.createRealSession(projectPath, projectId, permissionMode, modelSettings, resumeSessionId);
|
|
490
|
+
}
|
|
491
|
+
throw new Error("reactivateSession requires provider or real SDK - legacy mock SDK not supported");
|
|
492
|
+
});
|
|
493
|
+
}
|
|
268
494
|
/**
|
|
269
495
|
* Create a session using the real SDK without an initial message.
|
|
270
496
|
* The session is created and waits for a message to be queued.
|
|
@@ -288,6 +514,7 @@ export class Supervisor {
|
|
|
288
514
|
clientName: modelSettings?.clientName,
|
|
289
515
|
globalInstructions: modelSettings?.globalInstructions,
|
|
290
516
|
promptSuggestions: promptSuggestionMode === "native",
|
|
517
|
+
onProviderRetentionChange: () => this.handleProviderRetentionChanged(processHolder),
|
|
291
518
|
onToolApproval: async (toolName, input, opts) => {
|
|
292
519
|
if (!processHolder.process) {
|
|
293
520
|
return { behavior: "deny", message: "Process not ready" };
|
|
@@ -295,7 +522,7 @@ export class Supervisor {
|
|
|
295
522
|
return processHolder.process.handleToolApproval(toolName, input, opts);
|
|
296
523
|
},
|
|
297
524
|
});
|
|
298
|
-
const { iterator, queue, abort, isProcessAlive, probeLiveness, getProviderActivity, setMaxThinkingTokens, interrupt, supportedModels, supportedCommands, setModel, } = result;
|
|
525
|
+
const { iterator, queue, abort, isProcessAlive, probeLiveness, getProviderActivity, getProviderRetention, setMaxThinkingTokens, interrupt, supportedModels, supportedCommands, setModel, publishAgentctlSessionId, } = result;
|
|
299
526
|
const tempSessionId = resumeSessionId ?? randomUUID();
|
|
300
527
|
const options = {
|
|
301
528
|
projectPath,
|
|
@@ -303,11 +530,13 @@ export class Supervisor {
|
|
|
303
530
|
sessionId: tempSessionId,
|
|
304
531
|
idleTimeoutMs: this.idleTimeoutMs,
|
|
305
532
|
queue,
|
|
533
|
+
sessionQueuePersistenceService: this.sessionQueuePersistenceService,
|
|
306
534
|
abortFn: abort,
|
|
307
535
|
isProcessAlive,
|
|
308
536
|
shouldRetainIdleProcess: (sessionId) => this.shouldRetainIdleProcess(sessionId),
|
|
309
537
|
probeLivenessFn: probeLiveness,
|
|
310
538
|
getProviderActivityFn: getProviderActivity,
|
|
539
|
+
getProviderRetentionFn: getProviderRetention,
|
|
311
540
|
pid: () => {
|
|
312
541
|
const p = result.pid;
|
|
313
542
|
return typeof p === "function" ? p() : p;
|
|
@@ -317,6 +546,7 @@ export class Supervisor {
|
|
|
317
546
|
supportedModelsFn: supportedModels,
|
|
318
547
|
supportedCommandsFn: supportedCommands,
|
|
319
548
|
setModelFn: setModel,
|
|
549
|
+
publishAgentctlSessionIdFn: publishAgentctlSessionId,
|
|
320
550
|
permissionMode: effectiveMode,
|
|
321
551
|
provider: "claude", // Real SDK is always Claude
|
|
322
552
|
model: modelSettings?.model,
|
|
@@ -326,6 +556,7 @@ export class Supervisor {
|
|
|
326
556
|
executor: modelSettings?.executor,
|
|
327
557
|
permissions: modelSettings?.permissions,
|
|
328
558
|
recapMode: modelSettings?.recapMode,
|
|
559
|
+
recapAfterSeconds: modelSettings?.recapAfterSeconds,
|
|
329
560
|
promptSuggestionMode,
|
|
330
561
|
helperSideModel: modelSettings?.helperSideModel,
|
|
331
562
|
};
|
|
@@ -344,6 +575,254 @@ export class Supervisor {
|
|
|
344
575
|
await process.primeSupportedCommandsForMessage(message);
|
|
345
576
|
return process.queueMessage(message, options);
|
|
346
577
|
}
|
|
578
|
+
watchResumeCompaction(process, command, timeoutMs = RESUME_COMPACT_WAIT_MS) {
|
|
579
|
+
let finished = false;
|
|
580
|
+
let timeout;
|
|
581
|
+
let unsubscribe;
|
|
582
|
+
const finish = (attempt) => {
|
|
583
|
+
if (finished) {
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
finished = true;
|
|
587
|
+
if (timeout) {
|
|
588
|
+
clearTimeout(timeout);
|
|
589
|
+
}
|
|
590
|
+
unsubscribe?.();
|
|
591
|
+
resolve(attempt);
|
|
592
|
+
};
|
|
593
|
+
let resolve;
|
|
594
|
+
const promise = new Promise((innerResolve) => {
|
|
595
|
+
resolve = innerResolve;
|
|
596
|
+
});
|
|
597
|
+
timeout = setTimeout(() => finish({ status: "timed-out", command, timeoutMs }), timeoutMs);
|
|
598
|
+
timeout.unref?.();
|
|
599
|
+
unsubscribe = process.subscribe((event) => {
|
|
600
|
+
if (event.type === "message") {
|
|
601
|
+
const failedReason = compactFailureReason(event.message);
|
|
602
|
+
if (failedReason) {
|
|
603
|
+
finish({ status: "failed", command, reason: failedReason });
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
if (isCompactBoundaryMessage(event.message) ||
|
|
607
|
+
isCompactSuccessStatus(event.message)) {
|
|
608
|
+
finish({ status: "completed", command });
|
|
609
|
+
}
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
if (event.type === "error") {
|
|
613
|
+
finish({
|
|
614
|
+
status: "failed",
|
|
615
|
+
command,
|
|
616
|
+
reason: event.error.message,
|
|
617
|
+
});
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
if (event.type === "terminated") {
|
|
621
|
+
finish({
|
|
622
|
+
status: "failed",
|
|
623
|
+
command,
|
|
624
|
+
reason: event.reason,
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
});
|
|
628
|
+
return {
|
|
629
|
+
promise,
|
|
630
|
+
cancel: () => finish({
|
|
631
|
+
status: "failed",
|
|
632
|
+
command,
|
|
633
|
+
reason: "compact command was not queued",
|
|
634
|
+
}),
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
async findResumeCompactCommand(process) {
|
|
638
|
+
if (!process.supportsDynamicCommands) {
|
|
639
|
+
return {
|
|
640
|
+
ok: false,
|
|
641
|
+
attempt: {
|
|
642
|
+
status: "unavailable",
|
|
643
|
+
reason: "provider process does not advertise slash commands",
|
|
644
|
+
},
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
let commands;
|
|
648
|
+
try {
|
|
649
|
+
commands = await process.supportedCommands();
|
|
650
|
+
}
|
|
651
|
+
catch (error) {
|
|
652
|
+
return {
|
|
653
|
+
ok: false,
|
|
654
|
+
attempt: {
|
|
655
|
+
status: "failed",
|
|
656
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
657
|
+
},
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
const command = commands
|
|
661
|
+
?.map((candidate) => normalizeSlashCommandName(candidate.name))
|
|
662
|
+
.find((name) => name === "compact" || name === "compress");
|
|
663
|
+
if (!command) {
|
|
664
|
+
return {
|
|
665
|
+
ok: false,
|
|
666
|
+
attempt: {
|
|
667
|
+
status: "unavailable",
|
|
668
|
+
reason: "no compact/compress slash command advertised",
|
|
669
|
+
},
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
return { ok: true, command };
|
|
673
|
+
}
|
|
674
|
+
async tryResumeCompaction(process, options) {
|
|
675
|
+
if (process.provider !== "claude" && process.provider !== "claude-ollama") {
|
|
676
|
+
return {
|
|
677
|
+
status: "unavailable",
|
|
678
|
+
reason: `${process.provider} does not support compact-first resume`,
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
if (!options?.allowNonIdleStart && process.state.type !== "idle") {
|
|
682
|
+
return {
|
|
683
|
+
status: "skipped",
|
|
684
|
+
reason: `process was ${process.state.type}`,
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
const command = await this.findResumeCompactCommand(process);
|
|
688
|
+
if (!command.ok) {
|
|
689
|
+
return command.attempt;
|
|
690
|
+
}
|
|
691
|
+
const watcher = this.watchResumeCompaction(process, command.command);
|
|
692
|
+
const queued = process.queueMessage(
|
|
693
|
+
// Hidden: native compaction shows no `/compact` user turn, so neither
|
|
694
|
+
// should YA-initiated compaction (resume-time or threshold-triggered).
|
|
695
|
+
{ text: `/${command.command}`, metadata: { hidden: true } }, { allowSteer: false });
|
|
696
|
+
if (!queued.success) {
|
|
697
|
+
watcher.cancel();
|
|
698
|
+
return {
|
|
699
|
+
status: "failed",
|
|
700
|
+
command: command.command,
|
|
701
|
+
reason: queued.error ?? "compact command was not accepted",
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
return watcher.promise;
|
|
705
|
+
}
|
|
706
|
+
/**
|
|
707
|
+
* Threshold-triggered preemptive compaction (task 029). When the per-model
|
|
708
|
+
* compact-at-% is set and live context already sits at/over that fraction of
|
|
709
|
+
* the model's window, run a `/compact` before delivering the next turn — the
|
|
710
|
+
* same native compaction the harness would eventually auto-fire, just
|
|
711
|
+
* earlier. Conservative per task 002: claude only, idle process only, only
|
|
712
|
+
* when usage is known. Best-effort — the turn is delivered regardless of the
|
|
713
|
+
* compaction outcome, and there is no retry loop. Reuses
|
|
714
|
+
* `tryResumeCompaction`, so the boundary the client renders is the native
|
|
715
|
+
* `compact_boundary` and the `/compact` carries no visible user echo.
|
|
716
|
+
*
|
|
717
|
+
* No double compaction: live usage is re-read and re-tested immediately
|
|
718
|
+
* before executing (there is no deferral gap between decide and run), so a
|
|
719
|
+
* prior compaction — the harness's enforced one or a previous voluntary one —
|
|
720
|
+
* that dropped usage below the threshold makes the next evaluation a no-op.
|
|
721
|
+
* The voluntary threshold also sits well below the harness's enforced point,
|
|
722
|
+
* so in steady state the two never fire together.
|
|
723
|
+
*/
|
|
724
|
+
async maybeCompactBeforeDelivery(process, sessionId, modelSettings) {
|
|
725
|
+
const percent = modelSettings?.compactAtContextPercent;
|
|
726
|
+
if (typeof percent !== "number" || percent <= 0 || percent >= 100)
|
|
727
|
+
return;
|
|
728
|
+
// Only an idle claude process can be safely compacted before delivery;
|
|
729
|
+
// tryResumeCompaction also self-guards, but skip the usage read otherwise.
|
|
730
|
+
if (process.state.type !== "idle")
|
|
731
|
+
return;
|
|
732
|
+
if (process.provider !== "claude" && process.provider !== "claude-ollama") {
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
// Prefer the route-resolved window; process.contextWindow is often
|
|
736
|
+
// undefined and ignores always-1M for opus/sonnet.
|
|
737
|
+
const contextWindow = modelSettings?.compactAtContextWindow ?? process.contextWindow;
|
|
738
|
+
if (!contextWindow || contextWindow <= 0)
|
|
739
|
+
return;
|
|
740
|
+
let inputTokens;
|
|
741
|
+
try {
|
|
742
|
+
const summary = await this.onSessionSummary?.(sessionId, process.projectId);
|
|
743
|
+
inputTokens = summary?.contextUsage?.inputTokens;
|
|
744
|
+
}
|
|
745
|
+
catch {
|
|
746
|
+
// Usage unavailable → never block the turn.
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
749
|
+
if (!crossesCompactThreshold(percent, contextWindow, inputTokens))
|
|
750
|
+
return;
|
|
751
|
+
try {
|
|
752
|
+
const attempt = await this.tryResumeCompaction(process);
|
|
753
|
+
if (attempt.status !== "completed") {
|
|
754
|
+
getLogger().info({
|
|
755
|
+
event: "threshold_compaction_skipped",
|
|
756
|
+
sessionId,
|
|
757
|
+
processId: process.id,
|
|
758
|
+
status: attempt.status,
|
|
759
|
+
percent,
|
|
760
|
+
inputTokens,
|
|
761
|
+
thresholdTokens: Math.round((percent / 100) * contextWindow),
|
|
762
|
+
}, "Threshold compaction did not complete; delivering turn as-is");
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
catch (error) {
|
|
766
|
+
getLogger().warn({
|
|
767
|
+
event: "threshold_compaction_failed",
|
|
768
|
+
sessionId,
|
|
769
|
+
processId: process.id,
|
|
770
|
+
error: error instanceof Error ? error.message : String(error),
|
|
771
|
+
}, "Threshold compaction errored; delivering turn as-is");
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
async queueAfterResumeCompaction(params) {
|
|
775
|
+
const attempt = await this.tryResumeCompaction(params.process, {
|
|
776
|
+
allowNonIdleStart: params.allowNonIdleStart,
|
|
777
|
+
});
|
|
778
|
+
if (attempt.status !== "completed") {
|
|
779
|
+
throw new ResumeCompactionError({
|
|
780
|
+
sessionId: params.sessionId,
|
|
781
|
+
provider: params.process.provider,
|
|
782
|
+
attempt,
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
const queued = await this.queueProcessMessage(params.process, params.message, {
|
|
786
|
+
allowSteer: false,
|
|
787
|
+
});
|
|
788
|
+
if (!queued.success) {
|
|
789
|
+
throw new Error(queued.error ?? "Failed to queue message after compact");
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
async startCompactFirstProviderResume(projectPath, projectId, message, resumeSessionId, permissionMode, modelSettings, provider) {
|
|
793
|
+
const process = await this.createProviderSession(projectPath, projectId, permissionMode, modelSettings, provider, resumeSessionId);
|
|
794
|
+
try {
|
|
795
|
+
await this.queueAfterResumeCompaction({
|
|
796
|
+
process,
|
|
797
|
+
sessionId: resumeSessionId,
|
|
798
|
+
message,
|
|
799
|
+
allowNonIdleStart: true,
|
|
800
|
+
});
|
|
801
|
+
return process;
|
|
802
|
+
}
|
|
803
|
+
catch (error) {
|
|
804
|
+
await process.abort();
|
|
805
|
+
this.unregisterProcess(process);
|
|
806
|
+
throw error;
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
async startCompactFirstRealResume(projectPath, projectId, message, resumeSessionId, permissionMode, modelSettings) {
|
|
810
|
+
const process = await this.createRealSession(projectPath, projectId, permissionMode, modelSettings, resumeSessionId);
|
|
811
|
+
try {
|
|
812
|
+
await this.queueAfterResumeCompaction({
|
|
813
|
+
process,
|
|
814
|
+
sessionId: resumeSessionId,
|
|
815
|
+
message,
|
|
816
|
+
allowNonIdleStart: true,
|
|
817
|
+
});
|
|
818
|
+
return process;
|
|
819
|
+
}
|
|
820
|
+
catch (error) {
|
|
821
|
+
await process.abort();
|
|
822
|
+
this.unregisterProcess(process);
|
|
823
|
+
throw error;
|
|
824
|
+
}
|
|
825
|
+
}
|
|
347
826
|
/**
|
|
348
827
|
* Start a session using the real SDK with full features.
|
|
349
828
|
*/
|
|
@@ -371,6 +850,7 @@ export class Supervisor {
|
|
|
371
850
|
remoteEnv: modelSettings?.remoteEnv,
|
|
372
851
|
globalInstructions: modelSettings?.globalInstructions,
|
|
373
852
|
promptSuggestions: promptSuggestionMode === "native",
|
|
853
|
+
onProviderRetentionChange: () => this.handleProviderRetentionChanged(processHolder),
|
|
374
854
|
onToolApproval: async (toolName, input, opts) => {
|
|
375
855
|
// Delegate to the process's handleToolApproval
|
|
376
856
|
if (!processHolder.process) {
|
|
@@ -379,18 +859,20 @@ export class Supervisor {
|
|
|
379
859
|
return processHolder.process.handleToolApproval(toolName, input, opts);
|
|
380
860
|
},
|
|
381
861
|
});
|
|
382
|
-
const { iterator, queue, abort, isProcessAlive, probeLiveness, getProviderActivity, setMaxThinkingTokens, interrupt, supportedModels, supportedCommands, setModel, } = result;
|
|
862
|
+
const { iterator, queue, abort, isProcessAlive, probeLiveness, getProviderActivity, getProviderRetention, setMaxThinkingTokens, interrupt, supportedModels, supportedCommands, setModel, publishAgentctlSessionId, } = result;
|
|
383
863
|
const options = {
|
|
384
864
|
projectPath,
|
|
385
865
|
projectId,
|
|
386
866
|
sessionId: tempSessionId,
|
|
387
867
|
idleTimeoutMs: this.idleTimeoutMs,
|
|
388
868
|
queue,
|
|
869
|
+
sessionQueuePersistenceService: this.sessionQueuePersistenceService,
|
|
389
870
|
abortFn: abort,
|
|
390
871
|
isProcessAlive,
|
|
391
872
|
shouldRetainIdleProcess: (sessionId) => this.shouldRetainIdleProcess(sessionId),
|
|
392
873
|
probeLivenessFn: probeLiveness,
|
|
393
874
|
getProviderActivityFn: getProviderActivity,
|
|
875
|
+
getProviderRetentionFn: getProviderRetention,
|
|
394
876
|
pid: () => {
|
|
395
877
|
const p = result.pid;
|
|
396
878
|
return typeof p === "function" ? p() : p;
|
|
@@ -400,6 +882,7 @@ export class Supervisor {
|
|
|
400
882
|
supportedModelsFn: supportedModels,
|
|
401
883
|
supportedCommandsFn: supportedCommands,
|
|
402
884
|
setModelFn: setModel,
|
|
885
|
+
publishAgentctlSessionIdFn: publishAgentctlSessionId,
|
|
403
886
|
permissionMode: effectiveMode,
|
|
404
887
|
provider: "claude", // Real SDK is always Claude
|
|
405
888
|
model: modelSettings?.model,
|
|
@@ -409,6 +892,7 @@ export class Supervisor {
|
|
|
409
892
|
executor: modelSettings?.executor,
|
|
410
893
|
permissions: modelSettings?.permissions,
|
|
411
894
|
recapMode: modelSettings?.recapMode,
|
|
895
|
+
recapAfterSeconds: modelSettings?.recapAfterSeconds,
|
|
412
896
|
promptSuggestionMode,
|
|
413
897
|
helperSideModel: modelSettings?.helperSideModel,
|
|
414
898
|
};
|
|
@@ -458,6 +942,7 @@ export class Supervisor {
|
|
|
458
942
|
globalInstructions: modelSettings?.globalInstructions,
|
|
459
943
|
promptSuggestions: promptSuggestionMode === "native",
|
|
460
944
|
shouldEmitLiveDeltas: () => processHolder.process?.hasLiveDeltaSubscribers() ?? false,
|
|
945
|
+
onProviderRetentionChange: () => this.handleProviderRetentionChanged(processHolder),
|
|
461
946
|
onToolApproval: async (toolName, input, opts) => {
|
|
462
947
|
if (!processHolder.process) {
|
|
463
948
|
return { behavior: "deny", message: "Process not ready" };
|
|
@@ -465,7 +950,7 @@ export class Supervisor {
|
|
|
465
950
|
return processHolder.process.handleToolApproval(toolName, input, opts);
|
|
466
951
|
},
|
|
467
952
|
});
|
|
468
|
-
const { iterator, queue, abort, isProcessAlive, probeLiveness, getProviderActivity, setMaxThinkingTokens, interrupt, steer, supportedModels, supportedCommands, setModel, } = result;
|
|
953
|
+
const { iterator, queue, abort, isProcessAlive, probeLiveness, getProviderActivity, getProviderRetention, setMaxThinkingTokens, interrupt, steer, supportedModels, supportedCommands, setModel, runProviderCommand, publishAgentctlSessionId, } = result;
|
|
469
954
|
const tempSessionId = resumeSessionId ?? randomUUID();
|
|
470
955
|
const options = {
|
|
471
956
|
projectPath,
|
|
@@ -473,11 +958,14 @@ export class Supervisor {
|
|
|
473
958
|
sessionId: tempSessionId,
|
|
474
959
|
idleTimeoutMs: this.idleTimeoutMs,
|
|
475
960
|
queue,
|
|
961
|
+
sessionQueuePersistenceService: this.sessionQueuePersistenceService,
|
|
476
962
|
abortFn: abort,
|
|
477
963
|
isProcessAlive,
|
|
478
964
|
shouldRetainIdleProcess: (sessionId) => this.shouldRetainIdleProcess(sessionId),
|
|
479
965
|
probeLivenessFn: probeLiveness,
|
|
480
966
|
getProviderActivityFn: getProviderActivity,
|
|
967
|
+
getProviderRetentionFn: getProviderRetention,
|
|
968
|
+
refreshPromptCacheFn: result.refreshPromptCache,
|
|
481
969
|
pid: () => {
|
|
482
970
|
const p = result.pid;
|
|
483
971
|
return typeof p === "function" ? p() : p;
|
|
@@ -488,6 +976,8 @@ export class Supervisor {
|
|
|
488
976
|
supportedModelsFn: supportedModels,
|
|
489
977
|
supportedCommandsFn: supportedCommands,
|
|
490
978
|
setModelFn: setModel,
|
|
979
|
+
runProviderCommandFn: runProviderCommand,
|
|
980
|
+
publishAgentctlSessionIdFn: publishAgentctlSessionId,
|
|
491
981
|
permissionMode: effectiveMode,
|
|
492
982
|
provider: activeProvider.name,
|
|
493
983
|
model: modelSettings?.model,
|
|
@@ -497,6 +987,7 @@ export class Supervisor {
|
|
|
497
987
|
executor: modelSettings?.executor,
|
|
498
988
|
permissions: modelSettings?.permissions,
|
|
499
989
|
recapMode: modelSettings?.recapMode,
|
|
990
|
+
recapAfterSeconds: modelSettings?.recapAfterSeconds,
|
|
500
991
|
promptSuggestionMode,
|
|
501
992
|
helperSideModel: modelSettings?.helperSideModel,
|
|
502
993
|
};
|
|
@@ -527,6 +1018,9 @@ export class Supervisor {
|
|
|
527
1018
|
const result = await activeProvider.startSession({
|
|
528
1019
|
cwd: projectPath,
|
|
529
1020
|
resumeSessionId,
|
|
1021
|
+
resumeSessionAt: resumeSessionId
|
|
1022
|
+
? modelSettings?.resumeSessionAt
|
|
1023
|
+
: undefined,
|
|
530
1024
|
permissionMode: effectiveMode,
|
|
531
1025
|
model: modelSettings?.model,
|
|
532
1026
|
serviceTier: modelSettings?.serviceTier,
|
|
@@ -537,6 +1031,7 @@ export class Supervisor {
|
|
|
537
1031
|
globalInstructions: modelSettings?.globalInstructions,
|
|
538
1032
|
promptSuggestions: promptSuggestionMode === "native",
|
|
539
1033
|
shouldEmitLiveDeltas: () => processHolder.process?.hasLiveDeltaSubscribers() ?? false,
|
|
1034
|
+
onProviderRetentionChange: () => this.handleProviderRetentionChanged(processHolder),
|
|
540
1035
|
onToolApproval: async (toolName, input, opts) => {
|
|
541
1036
|
if (!processHolder.process) {
|
|
542
1037
|
return { behavior: "deny", message: "Process not ready" };
|
|
@@ -544,7 +1039,7 @@ export class Supervisor {
|
|
|
544
1039
|
return processHolder.process.handleToolApproval(toolName, input, opts);
|
|
545
1040
|
},
|
|
546
1041
|
});
|
|
547
|
-
const { iterator, queue, abort, isProcessAlive, probeLiveness, getProviderActivity, setMaxThinkingTokens, interrupt, steer, supportedModels, supportedCommands, setModel, } = result;
|
|
1042
|
+
const { iterator, queue, abort, isProcessAlive, probeLiveness, getProviderActivity, getProviderRetention, setMaxThinkingTokens, interrupt, steer, supportedModels, supportedCommands, setModel, runProviderCommand, publishAgentctlSessionId, } = result;
|
|
548
1043
|
const tempSessionId = resumeSessionId ?? randomUUID();
|
|
549
1044
|
const options = {
|
|
550
1045
|
projectPath,
|
|
@@ -552,11 +1047,14 @@ export class Supervisor {
|
|
|
552
1047
|
sessionId: tempSessionId,
|
|
553
1048
|
idleTimeoutMs: this.idleTimeoutMs,
|
|
554
1049
|
queue,
|
|
1050
|
+
sessionQueuePersistenceService: this.sessionQueuePersistenceService,
|
|
555
1051
|
abortFn: abort,
|
|
556
1052
|
isProcessAlive,
|
|
557
1053
|
shouldRetainIdleProcess: (sessionId) => this.shouldRetainIdleProcess(sessionId),
|
|
558
1054
|
probeLivenessFn: probeLiveness,
|
|
559
1055
|
getProviderActivityFn: getProviderActivity,
|
|
1056
|
+
getProviderRetentionFn: getProviderRetention,
|
|
1057
|
+
refreshPromptCacheFn: result.refreshPromptCache,
|
|
560
1058
|
pid: () => {
|
|
561
1059
|
const p = result.pid;
|
|
562
1060
|
return typeof p === "function" ? p() : p;
|
|
@@ -567,6 +1065,8 @@ export class Supervisor {
|
|
|
567
1065
|
supportedModelsFn: supportedModels,
|
|
568
1066
|
supportedCommandsFn: supportedCommands,
|
|
569
1067
|
setModelFn: setModel,
|
|
1068
|
+
runProviderCommandFn: runProviderCommand,
|
|
1069
|
+
publishAgentctlSessionIdFn: publishAgentctlSessionId,
|
|
570
1070
|
permissionMode: effectiveMode,
|
|
571
1071
|
provider: activeProvider.name,
|
|
572
1072
|
model: modelSettings?.model,
|
|
@@ -576,6 +1076,7 @@ export class Supervisor {
|
|
|
576
1076
|
executor: modelSettings?.executor,
|
|
577
1077
|
permissions: modelSettings?.permissions,
|
|
578
1078
|
recapMode: modelSettings?.recapMode,
|
|
1079
|
+
recapAfterSeconds: modelSettings?.recapAfterSeconds,
|
|
579
1080
|
promptSuggestionMode,
|
|
580
1081
|
helperSideModel: modelSettings?.helperSideModel,
|
|
581
1082
|
};
|
|
@@ -626,6 +1127,7 @@ export class Supervisor {
|
|
|
626
1127
|
return process;
|
|
627
1128
|
}
|
|
628
1129
|
async resumeSession(sessionId, projectPath, message, permissionMode, modelSettings) {
|
|
1130
|
+
await this.waitForSessionActivation(sessionId);
|
|
629
1131
|
// Check if already have a process for this session
|
|
630
1132
|
const existingProcessId = this.sessionToProcess.get(sessionId);
|
|
631
1133
|
if (existingProcessId) {
|
|
@@ -636,13 +1138,14 @@ export class Supervisor {
|
|
|
636
1138
|
this.unregisterProcess(existingProcess);
|
|
637
1139
|
}
|
|
638
1140
|
else {
|
|
1141
|
+
let restartExistingProcess = false;
|
|
639
1142
|
// Check if thinking/effort settings changed
|
|
640
|
-
const thinkingChanged = existingProcess.thinking?.
|
|
641
|
-
(modelSettings?.thinking?.type ?? undefined);
|
|
1143
|
+
const thinkingChanged = !thinkingConfigsEqual(existingProcess.thinking, modelSettings?.thinking);
|
|
642
1144
|
const effortChanged = existingProcess.effort !== modelSettings?.effort;
|
|
643
1145
|
if (thinkingChanged || effortChanged) {
|
|
644
1146
|
if (thinkingChanged &&
|
|
645
1147
|
!effortChanged &&
|
|
1148
|
+
canApplyThinkingConfigDynamically(existingProcess.thinking, modelSettings?.thinking) &&
|
|
646
1149
|
existingProcess.supportsThinkingModeChange) {
|
|
647
1150
|
// Toggle adaptive/disabled dynamically via deprecated API
|
|
648
1151
|
const tokens = modelSettings?.thinking?.type === "disabled" ? 0 : 1;
|
|
@@ -667,21 +1170,38 @@ export class Supervisor {
|
|
|
667
1170
|
sessionId,
|
|
668
1171
|
processId: existingProcess.id,
|
|
669
1172
|
oldThinking: existingProcess.thinking?.type,
|
|
1173
|
+
oldThinkingDisplay: existingProcess.thinking?.type === "adaptive" ||
|
|
1174
|
+
existingProcess.thinking?.type === "enabled"
|
|
1175
|
+
? existingProcess.thinking.display
|
|
1176
|
+
: undefined,
|
|
670
1177
|
oldEffort: existingProcess.effort,
|
|
671
1178
|
newThinking: modelSettings?.thinking?.type,
|
|
1179
|
+
newThinkingDisplay: modelSettings?.thinking?.type === "adaptive" ||
|
|
1180
|
+
modelSettings?.thinking?.type === "enabled"
|
|
1181
|
+
? modelSettings.thinking.display
|
|
1182
|
+
: undefined,
|
|
672
1183
|
newEffort: modelSettings?.effort,
|
|
673
1184
|
}, "Thinking/effort changed, restarting process");
|
|
674
1185
|
await existingProcess.abort();
|
|
675
1186
|
this.unregisterProcess(existingProcess);
|
|
1187
|
+
restartExistingProcess = true;
|
|
676
1188
|
// Fall through to start a new session with the updated settings
|
|
677
1189
|
}
|
|
678
1190
|
}
|
|
679
1191
|
// Update permission mode if specified
|
|
680
|
-
if (permissionMode) {
|
|
1192
|
+
if (!restartExistingProcess && permissionMode) {
|
|
681
1193
|
existingProcess.setPermissionMode(permissionMode);
|
|
682
1194
|
}
|
|
683
1195
|
// Queue message to existing process (if we didn't fall through to restart)
|
|
684
|
-
if (!existingProcess.isTerminated) {
|
|
1196
|
+
if (!restartExistingProcess && !existingProcess.isTerminated) {
|
|
1197
|
+
if (modelSettings?.resumeMode === "compact-first") {
|
|
1198
|
+
await this.queueAfterResumeCompaction({
|
|
1199
|
+
process: existingProcess,
|
|
1200
|
+
sessionId,
|
|
1201
|
+
message,
|
|
1202
|
+
});
|
|
1203
|
+
return existingProcess;
|
|
1204
|
+
}
|
|
685
1205
|
const result = await this.queueProcessMessage(existingProcess, message);
|
|
686
1206
|
if (result.success) {
|
|
687
1207
|
return existingProcess;
|
|
@@ -704,46 +1224,322 @@ export class Supervisor {
|
|
|
704
1224
|
};
|
|
705
1225
|
}
|
|
706
1226
|
const projectId = encodeProjectId(projectPath);
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
1227
|
+
if (this.isAtCapacity() && !this.findPreemptableWorker()) {
|
|
1228
|
+
const result = this.workerQueue.enqueue({
|
|
1229
|
+
type: "resume-session",
|
|
1230
|
+
projectPath,
|
|
1231
|
+
projectId,
|
|
1232
|
+
sessionId,
|
|
1233
|
+
message,
|
|
1234
|
+
permissionMode,
|
|
1235
|
+
modelSettings,
|
|
1236
|
+
});
|
|
1237
|
+
if (isQueueFullError(result)) {
|
|
1238
|
+
return result;
|
|
714
1239
|
}
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
1240
|
+
return {
|
|
1241
|
+
queued: true,
|
|
1242
|
+
queueId: result.queueId,
|
|
1243
|
+
position: result.position,
|
|
1244
|
+
};
|
|
1245
|
+
}
|
|
1246
|
+
if (await this.waitForSessionActivation(sessionId)) {
|
|
1247
|
+
return this.resumeSession(sessionId, projectPath, message, permissionMode, modelSettings);
|
|
1248
|
+
}
|
|
1249
|
+
return this.startSessionActivation(sessionId, async () => {
|
|
1250
|
+
if (this.isAtCapacity()) {
|
|
1251
|
+
const preemptable = this.findPreemptableWorker();
|
|
1252
|
+
if (preemptable) {
|
|
1253
|
+
await this.preemptWorker(preemptable);
|
|
1254
|
+
}
|
|
1255
|
+
else {
|
|
1256
|
+
throw new Error("Cannot resume: server is at worker capacity and no idle process can be preempted");
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
const provider = this.resolveProvider(modelSettings);
|
|
1260
|
+
const resumeMode = modelSettings?.resumeMode ?? "full";
|
|
1261
|
+
// Use provider if available (preferred)
|
|
1262
|
+
if (provider) {
|
|
1263
|
+
if (resumeMode === "compact-first") {
|
|
1264
|
+
return this.startCompactFirstProviderResume(projectPath, projectId, message, sessionId, permissionMode, modelSettings, provider);
|
|
1265
|
+
}
|
|
1266
|
+
return this.startProviderSession(projectPath, projectId, message, sessionId, permissionMode, modelSettings, provider);
|
|
1267
|
+
}
|
|
1268
|
+
// Use real SDK if available
|
|
1269
|
+
if (this.realSdk) {
|
|
1270
|
+
if (resumeMode === "compact-first") {
|
|
1271
|
+
return this.startCompactFirstRealResume(projectPath, projectId, message, sessionId, permissionMode, modelSettings);
|
|
1272
|
+
}
|
|
1273
|
+
return this.startRealSession(projectPath, projectId, message, sessionId, permissionMode, modelSettings);
|
|
1274
|
+
}
|
|
1275
|
+
// Fall back to legacy mock SDK
|
|
1276
|
+
if (resumeMode === "compact-first") {
|
|
1277
|
+
throw new ResumeCompactionError({
|
|
721
1278
|
sessionId,
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
1279
|
+
provider: "claude",
|
|
1280
|
+
attempt: {
|
|
1281
|
+
status: "unavailable",
|
|
1282
|
+
reason: "legacy mock SDK does not support compact-first resume",
|
|
1283
|
+
},
|
|
725
1284
|
});
|
|
726
|
-
|
|
727
|
-
|
|
1285
|
+
}
|
|
1286
|
+
return this.startLegacySession(projectPath, projectId, message, sessionId, permissionMode);
|
|
1287
|
+
});
|
|
1288
|
+
}
|
|
1289
|
+
/** Whether the resolved provider has a real transcript-fork primitive. */
|
|
1290
|
+
supportsForkSession(providerName) {
|
|
1291
|
+
const provider = this.resolveProvider(providerName ? { providerName } : undefined);
|
|
1292
|
+
return typeof provider?.forkSession === "function";
|
|
1293
|
+
}
|
|
1294
|
+
/**
|
|
1295
|
+
* Fork a session's transcript into a new resumable session, optionally
|
|
1296
|
+
* sliced at a message UUID. Throws when the provider has no fork
|
|
1297
|
+
* primitive — fork must not be emulated (see
|
|
1298
|
+
* topics/session-context-actions.md).
|
|
1299
|
+
*/
|
|
1300
|
+
async forkSession(options) {
|
|
1301
|
+
const provider = this.resolveProvider(options.providerName ? { providerName: options.providerName } : undefined);
|
|
1302
|
+
if (!provider) {
|
|
1303
|
+
throw new Error("provider is not available");
|
|
1304
|
+
}
|
|
1305
|
+
if (typeof provider.forkSession !== "function") {
|
|
1306
|
+
throw new Error(`${provider.name} does not support transcript fork`);
|
|
1307
|
+
}
|
|
1308
|
+
return provider.forkSession({
|
|
1309
|
+
sessionId: options.sessionId,
|
|
1310
|
+
cwd: options.projectPath,
|
|
1311
|
+
upToMessageId: options.upToMessageId,
|
|
1312
|
+
title: options.title,
|
|
1313
|
+
});
|
|
1314
|
+
}
|
|
1315
|
+
async generateSummary(providerName, request) {
|
|
1316
|
+
const provider = this.resolveProvider(providerName ? { providerName } : undefined);
|
|
1317
|
+
if (!provider) {
|
|
1318
|
+
throw new Error("provider is not available");
|
|
1319
|
+
}
|
|
1320
|
+
if (typeof provider.generateSummary !== "function") {
|
|
1321
|
+
throw new Error(`${provider.name} does not support summary generation`);
|
|
1322
|
+
}
|
|
1323
|
+
return provider.generateSummary(request);
|
|
1324
|
+
}
|
|
1325
|
+
async archiveHelperFork(childSessionId, parentSessionId, title, providerName, process) {
|
|
1326
|
+
if (!this.sessionMetadataService) {
|
|
1327
|
+
return;
|
|
1328
|
+
}
|
|
1329
|
+
await this.sessionMetadataService.updateMetadata(childSessionId, {
|
|
1330
|
+
title,
|
|
1331
|
+
archived: true,
|
|
1332
|
+
parentSessionId,
|
|
1333
|
+
});
|
|
1334
|
+
await this.sessionMetadataService.setProvider(childSessionId, providerName);
|
|
1335
|
+
await this.sessionMetadataService.setExecutor(childSessionId, process.executor);
|
|
1336
|
+
await this.sessionMetadataService.setRequestedModel(childSessionId, process.requestedModel);
|
|
1337
|
+
}
|
|
1338
|
+
publishRecapListUpdate(process, text, timestamp = new Date().toISOString()) {
|
|
1339
|
+
if (!this.eventBus) {
|
|
1340
|
+
return;
|
|
1341
|
+
}
|
|
1342
|
+
const lastAgentText = formatAgentRecapExcerpt(text);
|
|
1343
|
+
if (!lastAgentText) {
|
|
1344
|
+
return;
|
|
1345
|
+
}
|
|
1346
|
+
const event = {
|
|
1347
|
+
type: "session-updated",
|
|
1348
|
+
sessionId: process.sessionId,
|
|
1349
|
+
projectId: process.projectId,
|
|
1350
|
+
updatedAt: timestamp,
|
|
1351
|
+
lastAgentText,
|
|
1352
|
+
timestamp: new Date().toISOString(),
|
|
1353
|
+
};
|
|
1354
|
+
this.eventBus.emit(event);
|
|
1355
|
+
}
|
|
1356
|
+
async persistRecapOverlay(process, message) {
|
|
1357
|
+
if (!this.sessionMetadataService) {
|
|
1358
|
+
return;
|
|
1359
|
+
}
|
|
1360
|
+
try {
|
|
1361
|
+
await this.sessionMetadataService.addRecapMessage(process.sessionId, message);
|
|
1362
|
+
}
|
|
1363
|
+
catch (error) {
|
|
1364
|
+
getLogger().warn({
|
|
1365
|
+
event: "session_recap_overlay_persist_failed",
|
|
1366
|
+
sessionId: process.sessionId,
|
|
1367
|
+
processId: process.id,
|
|
1368
|
+
projectId: process.projectId,
|
|
1369
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1370
|
+
}, `Failed to persist recap overlay: ${process.sessionId}`);
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
async handleRecapResult(process, result) {
|
|
1374
|
+
if (result.syntheticMessage) {
|
|
1375
|
+
await this.persistRecapOverlay(process, result.syntheticMessage);
|
|
1376
|
+
}
|
|
1377
|
+
if (result.emitted && result.text) {
|
|
1378
|
+
this.publishRecapListUpdate(process, result.text, result.syntheticMessage?.timestamp);
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
/**
|
|
1382
|
+
* Raise a recap's "summarize since" floor to the latest already-emitted
|
|
1383
|
+
* recap for the session. A recap covers the transcript through (about) its
|
|
1384
|
+
* own timestamp, so a second return event with no assistant output after
|
|
1385
|
+
* the last recap has nothing new to say — regenerating the same summary
|
|
1386
|
+
* from the same context is wasted work and stacks duplicate recap rows.
|
|
1387
|
+
*/
|
|
1388
|
+
recapFloorMs(sessionId, sinceMs) {
|
|
1389
|
+
const recaps = this.sessionMetadataService?.getRecapMessages(sessionId);
|
|
1390
|
+
const latest = recaps ? latestRecapMessage(recaps) : undefined;
|
|
1391
|
+
const lastRecapMs = latest ? messageTimestampMs(latest) : null;
|
|
1392
|
+
if (lastRecapMs === null) {
|
|
1393
|
+
return sinceMs;
|
|
1394
|
+
}
|
|
1395
|
+
return sinceMs === null ? lastRecapMs : Math.max(sinceMs, lastRecapMs);
|
|
1396
|
+
}
|
|
1397
|
+
async requestForkedRecap(process, provider, sinceMs, options) {
|
|
1398
|
+
if (!provider.supportsRecaps || !provider.generateSummary) {
|
|
1399
|
+
return {
|
|
1400
|
+
supported: false,
|
|
1401
|
+
emitted: false,
|
|
1402
|
+
reason: "provider does not support recaps",
|
|
1403
|
+
};
|
|
1404
|
+
}
|
|
1405
|
+
sinceMs = this.recapFloorMs(process.sessionId, sinceMs);
|
|
1406
|
+
if (typeof provider.forkSession !== "function") {
|
|
1407
|
+
return process.requestTailedRecapFallback(provider, { sinceMs });
|
|
1408
|
+
}
|
|
1409
|
+
if (this.forkedRecapInFlight.has(process.id)) {
|
|
1410
|
+
return {
|
|
1411
|
+
supported: true,
|
|
1412
|
+
emitted: false,
|
|
1413
|
+
reason: "recap already in flight",
|
|
1414
|
+
};
|
|
1415
|
+
}
|
|
1416
|
+
if (process.state.type === "in-turn") {
|
|
1417
|
+
this.pendingForkedRecapRequests.set(process.id, sinceMs);
|
|
1418
|
+
return {
|
|
1419
|
+
supported: true,
|
|
1420
|
+
emitted: false,
|
|
1421
|
+
reason: "recap deferred until turn completes",
|
|
1422
|
+
};
|
|
1423
|
+
}
|
|
1424
|
+
// A process freshly revived for this recap has an empty in-memory recap
|
|
1425
|
+
// buffer (it never streamed) and will not emit a native away_summary on its
|
|
1426
|
+
// own, so the native wait and the recent-text emptiness gate below would
|
|
1427
|
+
// both wrongly suppress. Skip them: the fork reads the transcript from disk,
|
|
1428
|
+
// and its own empty-text fallback handles a genuinely empty transcript.
|
|
1429
|
+
if (options?.revived !== true) {
|
|
1430
|
+
const nativeRecap = await process.waitForNativeRecapSince(sinceMs, provider.supportsNativeRecaps ? NATIVE_RECAP_FALLBACK_GRACE_MS : 0);
|
|
1431
|
+
if (nativeRecap) {
|
|
1432
|
+
return {
|
|
1433
|
+
supported: true,
|
|
1434
|
+
emitted: true,
|
|
1435
|
+
reason: "native recap emitted",
|
|
1436
|
+
text: nativeRecap.text,
|
|
1437
|
+
};
|
|
1438
|
+
}
|
|
1439
|
+
const recent = process.getRecentAssistantText(sinceMs);
|
|
1440
|
+
if (recent.length === 0) {
|
|
1441
|
+
return {
|
|
1442
|
+
supported: true,
|
|
1443
|
+
emitted: false,
|
|
1444
|
+
reason: "no recent assistant activity to summarize",
|
|
1445
|
+
};
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
const abortController = new AbortController();
|
|
1449
|
+
this.forkedRecapInFlight.set(process.id, abortController);
|
|
1450
|
+
let generatorSessionId;
|
|
1451
|
+
try {
|
|
1452
|
+
const generator = await this.forkSession({
|
|
1453
|
+
sessionId: process.sessionId,
|
|
1454
|
+
projectPath: process.projectPath,
|
|
1455
|
+
providerName: process.provider,
|
|
1456
|
+
title: "Recap generator",
|
|
1457
|
+
});
|
|
1458
|
+
generatorSessionId = generator.sessionId;
|
|
1459
|
+
await this.archiveHelperFork(generator.sessionId, process.sessionId, "Recap generator", process.provider, process);
|
|
1460
|
+
const text = (await provider.generateSummary({
|
|
1461
|
+
purpose: "recap",
|
|
1462
|
+
strategy: "fork",
|
|
1463
|
+
generatorSessionId: generator.sessionId,
|
|
1464
|
+
cwd: process.projectPath,
|
|
1465
|
+
signal: abortController.signal,
|
|
1466
|
+
})).text.trim();
|
|
1467
|
+
if (!text) {
|
|
1468
|
+
return process.requestTailedRecapFallback(provider, { sinceMs });
|
|
1469
|
+
}
|
|
1470
|
+
const lateNativeRecap = process.getNativeRecapSince(sinceMs);
|
|
1471
|
+
if (lateNativeRecap) {
|
|
1472
|
+
return {
|
|
1473
|
+
supported: true,
|
|
1474
|
+
emitted: true,
|
|
1475
|
+
reason: "native recap emitted",
|
|
1476
|
+
text: lateNativeRecap.text,
|
|
1477
|
+
};
|
|
1478
|
+
}
|
|
1479
|
+
const syntheticMessage = process.emitSyntheticSystemMessage("away_summary", text);
|
|
1480
|
+
return { supported: true, emitted: true, text, syntheticMessage };
|
|
1481
|
+
}
|
|
1482
|
+
catch (error) {
|
|
1483
|
+
// Cancellation on parent activity is expected, not a failure.
|
|
1484
|
+
if (abortController.signal.aborted) {
|
|
1485
|
+
const nativeRecap = process.getNativeRecapSince(sinceMs);
|
|
1486
|
+
if (nativeRecap) {
|
|
1487
|
+
return {
|
|
1488
|
+
supported: true,
|
|
1489
|
+
emitted: true,
|
|
1490
|
+
reason: "native recap emitted",
|
|
1491
|
+
text: nativeRecap.text,
|
|
1492
|
+
};
|
|
728
1493
|
}
|
|
729
1494
|
return {
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
1495
|
+
supported: true,
|
|
1496
|
+
emitted: false,
|
|
1497
|
+
reason: "recap cancelled by new activity",
|
|
733
1498
|
};
|
|
734
1499
|
}
|
|
1500
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
1501
|
+
getLogger().warn({
|
|
1502
|
+
event: "session_forked_recap_failed",
|
|
1503
|
+
sessionId: process.sessionId,
|
|
1504
|
+
processId: process.id,
|
|
1505
|
+
projectId: process.projectId,
|
|
1506
|
+
providerName: process.provider,
|
|
1507
|
+
generatorSessionId,
|
|
1508
|
+
error: reason,
|
|
1509
|
+
}, `Forked recap generation failed: ${reason}`);
|
|
1510
|
+
return process.requestTailedRecapFallback(provider, { sinceMs });
|
|
735
1511
|
}
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
if (provider) {
|
|
739
|
-
return this.startProviderSession(projectPath, projectId, message, sessionId, permissionMode, modelSettings, provider);
|
|
1512
|
+
finally {
|
|
1513
|
+
this.forkedRecapInFlight.delete(process.id);
|
|
740
1514
|
}
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
1515
|
+
}
|
|
1516
|
+
/**
|
|
1517
|
+
* Parent became active again: abort any in-flight forked recap (cancelling
|
|
1518
|
+
* the generator-fork helper turn) and drop a not-yet-started deferred
|
|
1519
|
+
* request, so a returning user's new turn is never shadowed by a stale
|
|
1520
|
+
* recap. See topics/fork-recap.md.
|
|
1521
|
+
*/
|
|
1522
|
+
cancelInFlightForkedRecap(process) {
|
|
1523
|
+
const abortController = this.forkedRecapInFlight.get(process.id);
|
|
1524
|
+
if (abortController && !abortController.signal.aborted) {
|
|
1525
|
+
abortController.abort();
|
|
744
1526
|
}
|
|
745
|
-
|
|
746
|
-
|
|
1527
|
+
this.pendingForkedRecapRequests.delete(process.id);
|
|
1528
|
+
}
|
|
1529
|
+
flushPendingForkedRecapRequest(process) {
|
|
1530
|
+
if (process.recapMode !== "fork" ||
|
|
1531
|
+
process.state.type !== "idle" ||
|
|
1532
|
+
this.forkedRecapInFlight.has(process.id) ||
|
|
1533
|
+
!this.pendingForkedRecapRequests.has(process.id)) {
|
|
1534
|
+
return;
|
|
1535
|
+
}
|
|
1536
|
+
const sinceMs = this.pendingForkedRecapRequests.get(process.id) ?? null;
|
|
1537
|
+
this.pendingForkedRecapRequests.delete(process.id);
|
|
1538
|
+
const provider = getProvider(process.provider);
|
|
1539
|
+
if (!provider) {
|
|
1540
|
+
return;
|
|
1541
|
+
}
|
|
1542
|
+
void this.requestForkedRecap(process, provider, sinceMs).then((result) => this.handleRecapResult(process, result));
|
|
747
1543
|
}
|
|
748
1544
|
getProcess(processId) {
|
|
749
1545
|
return this.processes.get(processId);
|
|
@@ -767,7 +1563,7 @@ export class Supervisor {
|
|
|
767
1563
|
const nextEffort = hasEffortUpdate ? updates.effort : process.effort;
|
|
768
1564
|
const modelChanged = nextModel !== process.resolvedModel;
|
|
769
1565
|
const serviceTierChanged = nextServiceTier !== process.serviceTier;
|
|
770
|
-
const thinkingChanged =
|
|
1566
|
+
const thinkingChanged = !thinkingConfigsEqual(process.thinking, nextThinking);
|
|
771
1567
|
const effortChanged = nextEffort !== process.effort;
|
|
772
1568
|
if (!modelChanged &&
|
|
773
1569
|
!serviceTierChanged &&
|
|
@@ -796,6 +1592,7 @@ export class Supervisor {
|
|
|
796
1592
|
providerName: process.provider,
|
|
797
1593
|
executor: process.executor,
|
|
798
1594
|
recapMode: process.recapMode,
|
|
1595
|
+
recapAfterSeconds: process.recapAfterSeconds,
|
|
799
1596
|
promptSuggestionMode: process.promptSuggestionMode,
|
|
800
1597
|
helperSideModel: process.helperSideModel,
|
|
801
1598
|
};
|
|
@@ -809,6 +1606,13 @@ export class Supervisor {
|
|
|
809
1606
|
return null;
|
|
810
1607
|
}
|
|
811
1608
|
process.setRecapConfig(config);
|
|
1609
|
+
this.emitOwnershipChange(process.sessionId, process.projectId, {
|
|
1610
|
+
owner: "self",
|
|
1611
|
+
processId: process.id,
|
|
1612
|
+
permissionMode: process.permissionMode,
|
|
1613
|
+
modeVersion: process.modeVersion,
|
|
1614
|
+
recapAfterSeconds: process.recapAfterSeconds,
|
|
1615
|
+
});
|
|
812
1616
|
return process;
|
|
813
1617
|
}
|
|
814
1618
|
getProcessForSession(sessionId) {
|
|
@@ -836,12 +1640,18 @@ export class Supervisor {
|
|
|
836
1640
|
}
|
|
837
1641
|
const isActiveSteeringMessage = message.metadata?.deliveryIntent === "steer" &&
|
|
838
1642
|
process.state.type === "in-turn";
|
|
1643
|
+
const hasExplicitThinkingSettings = modelSettings?.thinking !== undefined ||
|
|
1644
|
+
modelSettings?.effort !== undefined;
|
|
839
1645
|
const requestedThinking = isActiveSteeringMessage
|
|
840
1646
|
? process.thinking
|
|
841
|
-
:
|
|
1647
|
+
: hasExplicitThinkingSettings
|
|
1648
|
+
? modelSettings?.thinking
|
|
1649
|
+
: process.thinking;
|
|
842
1650
|
const requestedEffort = isActiveSteeringMessage
|
|
843
1651
|
? process.effort
|
|
844
|
-
:
|
|
1652
|
+
: hasExplicitThinkingSettings
|
|
1653
|
+
? modelSettings?.effort
|
|
1654
|
+
: process.effort;
|
|
845
1655
|
const requestedServiceTier = isActiveSteeringMessage
|
|
846
1656
|
? process.serviceTier
|
|
847
1657
|
: (modelSettings?.serviceTier ?? process.serviceTier);
|
|
@@ -849,12 +1659,13 @@ export class Supervisor {
|
|
|
849
1659
|
// Service tier is cost-affecting, so changes require an explicit restart
|
|
850
1660
|
// rather than being inferred from a normal prompt.
|
|
851
1661
|
const serviceTierChanged = process.serviceTier !== requestedServiceTier;
|
|
852
|
-
const thinkingChanged = process.thinking
|
|
1662
|
+
const thinkingChanged = !thinkingConfigsEqual(process.thinking, requestedThinking);
|
|
853
1663
|
const effortChanged = process.effort !== requestedEffort;
|
|
854
1664
|
if (serviceTierChanged || thinkingChanged || effortChanged) {
|
|
855
1665
|
if (!serviceTierChanged &&
|
|
856
1666
|
thinkingChanged &&
|
|
857
1667
|
!effortChanged &&
|
|
1668
|
+
canApplyThinkingConfigDynamically(process.thinking, requestedThinking) &&
|
|
858
1669
|
process.supportsThinkingModeChange) {
|
|
859
1670
|
// Toggle thinking dynamically via deprecated API (works for auto↔off)
|
|
860
1671
|
const tokens = requestedThinking?.type === "disabled" ? 0 : 1;
|
|
@@ -891,6 +1702,7 @@ export class Supervisor {
|
|
|
891
1702
|
...modelSettings,
|
|
892
1703
|
serviceTier: requestedServiceTier,
|
|
893
1704
|
recapMode: modelSettings?.recapMode ?? process.recapMode,
|
|
1705
|
+
recapAfterSeconds: modelSettings?.recapAfterSeconds ?? process.recapAfterSeconds,
|
|
894
1706
|
promptSuggestionMode: modelSettings?.promptSuggestionMode ?? process.promptSuggestionMode,
|
|
895
1707
|
helperSideModel: modelSettings?.helperSideModel ?? process.helperSideModel,
|
|
896
1708
|
};
|
|
@@ -905,6 +1717,10 @@ export class Supervisor {
|
|
|
905
1717
|
if (permissionMode) {
|
|
906
1718
|
process.setPermissionMode(permissionMode);
|
|
907
1719
|
}
|
|
1720
|
+
// Preemptively compact when this turn would push an already-near-threshold
|
|
1721
|
+
// session over its per-model compact-early limit (task 029). No-op unless
|
|
1722
|
+
// the threshold is set and the idle process is over it.
|
|
1723
|
+
await this.maybeCompactBeforeDelivery(process, sessionId, modelSettings);
|
|
908
1724
|
const result = await this.queueProcessMessage(process, message);
|
|
909
1725
|
if (result.success) {
|
|
910
1726
|
return { success: true, process, restarted: false };
|
|
@@ -923,6 +1739,9 @@ export class Supervisor {
|
|
|
923
1739
|
const log = getLogger();
|
|
924
1740
|
try {
|
|
925
1741
|
for (const process of this.processes.values()) {
|
|
1742
|
+
if (this.queuePatientDeferredMessagesForProcess(process, now, log)) {
|
|
1743
|
+
continue;
|
|
1744
|
+
}
|
|
926
1745
|
await this.queueHeartbeatTurnForProcess(process, now, log);
|
|
927
1746
|
}
|
|
928
1747
|
if (!this.getHeartbeatTurnCandidates) {
|
|
@@ -938,7 +1757,68 @@ export class Supervisor {
|
|
|
938
1757
|
}
|
|
939
1758
|
}
|
|
940
1759
|
shouldRetainIdleProcess(sessionId) {
|
|
941
|
-
|
|
1760
|
+
const process = this.getProcessForSession(sessionId);
|
|
1761
|
+
return (process?.hasPatientDeferredMessages() === true ||
|
|
1762
|
+
this.getHeartbeatTurnSettings?.(sessionId)?.enabled === true);
|
|
1763
|
+
}
|
|
1764
|
+
queuePatientDeferredMessagesForProcess(process, now, log) {
|
|
1765
|
+
if (!process.hasPatientDeferredMessages() ||
|
|
1766
|
+
process.isTerminated ||
|
|
1767
|
+
process.state.type !== "idle" ||
|
|
1768
|
+
process.queueDepth > 0 ||
|
|
1769
|
+
process.isProcessAlive === false) {
|
|
1770
|
+
return false;
|
|
1771
|
+
}
|
|
1772
|
+
const liveness = process.getLivenessSnapshot(new Date(now));
|
|
1773
|
+
if (liveness.derivedStatus !== "verified-idle") {
|
|
1774
|
+
return false;
|
|
1775
|
+
}
|
|
1776
|
+
const fallbackMs = process.state.since.getTime();
|
|
1777
|
+
const quietSinceMs = getHeartbeatResetAtMs(liveness, fallbackMs);
|
|
1778
|
+
if (!Number.isFinite(quietSinceMs)) {
|
|
1779
|
+
return false;
|
|
1780
|
+
}
|
|
1781
|
+
// Each patient entry carries its own patience window (seconds of
|
|
1782
|
+
// verified quiet); promote the elapsed ones and schedule a precise
|
|
1783
|
+
// re-check for the shortest remaining wait.
|
|
1784
|
+
const { promoted, nextPatienceMsRemaining } = process.promoteEligiblePatientDeferredMessages({ quietSinceMs, now });
|
|
1785
|
+
if (nextPatienceMsRemaining !== null) {
|
|
1786
|
+
this.schedulePatientDeferredCheck(process, nextPatienceMsRemaining);
|
|
1787
|
+
}
|
|
1788
|
+
if (!promoted) {
|
|
1789
|
+
return false;
|
|
1790
|
+
}
|
|
1791
|
+
log.info({
|
|
1792
|
+
event: "patient_deferred_messages_promoted",
|
|
1793
|
+
sessionId: process.sessionId,
|
|
1794
|
+
processId: process.id,
|
|
1795
|
+
projectId: process.projectId,
|
|
1796
|
+
quietMs: Math.max(0, now - quietSinceMs),
|
|
1797
|
+
quietSince: new Date(quietSinceMs).toISOString(),
|
|
1798
|
+
livenessStatus: liveness.derivedStatus,
|
|
1799
|
+
}, `Promoted patient deferred messages for session: ${process.sessionId}`);
|
|
1800
|
+
return true;
|
|
1801
|
+
}
|
|
1802
|
+
/**
|
|
1803
|
+
* Arm (or re-arm) the one-shot patient-queue re-check for a process. The
|
|
1804
|
+
* check itself re-derives eligibility and re-arms only while patient
|
|
1805
|
+
* entries remain, so the timer cannot become a standing poll.
|
|
1806
|
+
*/
|
|
1807
|
+
schedulePatientDeferredCheck(process, delayMs) {
|
|
1808
|
+
const existing = this.patientCheckTimers.get(process.id);
|
|
1809
|
+
if (existing) {
|
|
1810
|
+
clearTimeout(existing);
|
|
1811
|
+
}
|
|
1812
|
+
const delay = Math.max(250, Math.min(delayMs, 60 * 60 * 1000));
|
|
1813
|
+
const timer = setTimeout(() => {
|
|
1814
|
+
this.patientCheckTimers.delete(process.id);
|
|
1815
|
+
if (!this.processes.has(process.id)) {
|
|
1816
|
+
return;
|
|
1817
|
+
}
|
|
1818
|
+
this.queuePatientDeferredMessagesForProcess(process, Date.now(), getLogger());
|
|
1819
|
+
}, delay);
|
|
1820
|
+
timer.unref();
|
|
1821
|
+
this.patientCheckTimers.set(process.id, timer);
|
|
942
1822
|
}
|
|
943
1823
|
async queueHeartbeatTurnForProcess(process, now, log) {
|
|
944
1824
|
const settings = this.getHeartbeatTurnSettings?.(process.sessionId);
|
|
@@ -1304,7 +2184,15 @@ export class Supervisor {
|
|
|
1304
2184
|
reason: "provider not found",
|
|
1305
2185
|
};
|
|
1306
2186
|
}
|
|
1307
|
-
|
|
2187
|
+
const result = process.recapMode === "fork"
|
|
2188
|
+
? await this.requestForkedRecap(process, provider, options?.sinceMs ?? null, { revived: options?.revived === true })
|
|
2189
|
+
: await process.requestRecap(provider, {
|
|
2190
|
+
...options,
|
|
2191
|
+
sinceMs: this.recapFloorMs(process.sessionId, options?.sinceMs ?? null),
|
|
2192
|
+
});
|
|
2193
|
+
await this.handleRecapResult(process, result);
|
|
2194
|
+
const { syntheticMessage: _syntheticMessage, ...publicResult } = result;
|
|
2195
|
+
return publicResult;
|
|
1308
2196
|
}
|
|
1309
2197
|
async interruptProcessWithTimeout(process, options) {
|
|
1310
2198
|
const log = getLogger();
|
|
@@ -1371,6 +2259,7 @@ export class Supervisor {
|
|
|
1371
2259
|
providerName,
|
|
1372
2260
|
executor: sourceProcess.executor,
|
|
1373
2261
|
permissions: sourceProcess.permissions,
|
|
2262
|
+
recapAfterSeconds: sourceProcess.recapAfterSeconds,
|
|
1374
2263
|
});
|
|
1375
2264
|
const log = getLogger();
|
|
1376
2265
|
if (!("id" in result)) {
|
|
@@ -1424,6 +2313,24 @@ export class Supervisor {
|
|
|
1424
2313
|
else if (event.type === "complete") {
|
|
1425
2314
|
this.unregisterProcess(process);
|
|
1426
2315
|
}
|
|
2316
|
+
else if (event.type === "message") {
|
|
2317
|
+
this.cacheMissBillingMonitor.observeMessage(process, event.message);
|
|
2318
|
+
if (isAwaySummaryMessage(event.message) &&
|
|
2319
|
+
event.message.isSynthetic !== true) {
|
|
2320
|
+
const durable = toDurableRecapMessage(event.message, "provider-native");
|
|
2321
|
+
if (durable) {
|
|
2322
|
+
void this.persistRecapOverlay(process, durable);
|
|
2323
|
+
this.publishRecapListUpdate(process, durable.content, durable.timestamp);
|
|
2324
|
+
this.cancelInFlightForkedRecap(process);
|
|
2325
|
+
}
|
|
2326
|
+
}
|
|
2327
|
+
}
|
|
2328
|
+
else if (event.type === "recap-result") {
|
|
2329
|
+
void this.handleRecapResult(process, event.result);
|
|
2330
|
+
}
|
|
2331
|
+
else if (event.type === "context-window-observed") {
|
|
2332
|
+
this.onContextWindowObserved?.(event.model, event.contextWindow, event.provider);
|
|
2333
|
+
}
|
|
1427
2334
|
else if (event.type === "session-id-changed") {
|
|
1428
2335
|
// Update session→process mapping when temp ID is replaced by real ID from SDK
|
|
1429
2336
|
// This is critical for ExternalSessionTracker to correctly identify owned sessions
|
|
@@ -1459,6 +2366,7 @@ export class Supervisor {
|
|
|
1459
2366
|
processId: process.id,
|
|
1460
2367
|
permissionMode: process.permissionMode,
|
|
1461
2368
|
modeVersion: process.modeVersion,
|
|
2369
|
+
recapAfterSeconds: process.recapAfterSeconds,
|
|
1462
2370
|
};
|
|
1463
2371
|
this.emitOwnershipChange(event.newSessionId, process.projectId, ownership);
|
|
1464
2372
|
// Retry early metadata reconciliation with authoritative session ID.
|
|
@@ -1480,14 +2388,45 @@ export class Supervisor {
|
|
|
1480
2388
|
? "tool-approval"
|
|
1481
2389
|
: "user-question";
|
|
1482
2390
|
}
|
|
1483
|
-
|
|
2391
|
+
// A turn that settles to idle while the provider still has background
|
|
2392
|
+
// work retained should report as active, not idle.
|
|
2393
|
+
const activity = event.state.type === "idle" && process.isRetainingProviderWork()
|
|
2394
|
+
? "in-turn"
|
|
2395
|
+
: event.state.type;
|
|
2396
|
+
this.emitAgentActivityChange(process.sessionId, process.projectId, activity, pendingInputType);
|
|
1484
2397
|
}
|
|
1485
2398
|
// Emit worker activity on any state change (affects hasActiveWork)
|
|
1486
2399
|
this.emitWorkerActivity();
|
|
2400
|
+
// A fresh idle boundary starts the patient-queue quiet clock; arm a
|
|
2401
|
+
// prompt re-check so seconds-scale patience does not wait for the
|
|
2402
|
+
// 30s heartbeat tick.
|
|
2403
|
+
if (event.state.type === "idle" &&
|
|
2404
|
+
process.hasPatientDeferredMessages()) {
|
|
2405
|
+
this.schedulePatientDeferredCheck(process, 250);
|
|
2406
|
+
}
|
|
2407
|
+
if (event.state.type === "idle") {
|
|
2408
|
+
this.flushPendingForkedRecapRequest(process);
|
|
2409
|
+
}
|
|
2410
|
+
// Parent started a new turn: cancel any in-flight/deferred forked recap
|
|
2411
|
+
// so a returning user's live turn is not shadowed by a stale recap.
|
|
2412
|
+
if (event.state.type === "in-turn") {
|
|
2413
|
+
this.cancelInFlightForkedRecap(process);
|
|
2414
|
+
}
|
|
2415
|
+
}
|
|
2416
|
+
else if (event.type === "deferred-queue") {
|
|
2417
|
+
if (event.reason === "queued" &&
|
|
2418
|
+
process.state.type === "idle" &&
|
|
2419
|
+
process.hasPatientDeferredMessages()) {
|
|
2420
|
+
this.schedulePatientDeferredCheck(process, 250);
|
|
2421
|
+
}
|
|
2422
|
+
this.emitWorkerActivity();
|
|
1487
2423
|
}
|
|
1488
2424
|
else if (event.type === "terminated") {
|
|
1489
2425
|
this.emitProcessTerminated(process.sessionId, process.projectId, process.id, process.provider, event.reason);
|
|
1490
2426
|
}
|
|
2427
|
+
else if (event.type === "provider-runtime-status-change") {
|
|
2428
|
+
this.emitProviderRuntimeStatusChange(process.sessionId, process.projectId, event.status);
|
|
2429
|
+
}
|
|
1491
2430
|
});
|
|
1492
2431
|
}
|
|
1493
2432
|
registerProcess(process, isNewSession) {
|
|
@@ -1510,6 +2449,7 @@ export class Supervisor {
|
|
|
1510
2449
|
processId: process.id,
|
|
1511
2450
|
permissionMode: process.permissionMode,
|
|
1512
2451
|
modeVersion: process.modeVersion,
|
|
2452
|
+
recapAfterSeconds: process.recapAfterSeconds,
|
|
1513
2453
|
};
|
|
1514
2454
|
// Emit session created event for new sessions
|
|
1515
2455
|
if (isNewSession) {
|
|
@@ -1536,6 +2476,15 @@ export class Supervisor {
|
|
|
1536
2476
|
}
|
|
1537
2477
|
unregisterProcess(process) {
|
|
1538
2478
|
this.observedProcessIds.delete(process.id);
|
|
2479
|
+
this.cacheMissBillingMonitor.forgetProcess(process.id);
|
|
2480
|
+
this.pendingForkedRecapRequests.delete(process.id);
|
|
2481
|
+
this.forkedRecapInFlight.get(process.id)?.abort();
|
|
2482
|
+
this.forkedRecapInFlight.delete(process.id);
|
|
2483
|
+
const patientTimer = this.patientCheckTimers.get(process.id);
|
|
2484
|
+
if (patientTimer) {
|
|
2485
|
+
clearTimeout(patientTimer);
|
|
2486
|
+
this.patientCheckTimers.delete(process.id);
|
|
2487
|
+
}
|
|
1539
2488
|
if (!this.processes.has(process.id)) {
|
|
1540
2489
|
return;
|
|
1541
2490
|
}
|
|
@@ -1624,6 +2573,7 @@ export class Supervisor {
|
|
|
1624
2573
|
const session = {
|
|
1625
2574
|
id: process.sessionId,
|
|
1626
2575
|
projectId: process.projectId,
|
|
2576
|
+
projectName: getProjectName(process.projectPath),
|
|
1627
2577
|
title: optimistic.title,
|
|
1628
2578
|
fullTitle: optimistic.fullTitle,
|
|
1629
2579
|
createdAt: now,
|
|
@@ -1676,6 +2626,7 @@ export class Supervisor {
|
|
|
1676
2626
|
updatedAt: summary.updatedAt,
|
|
1677
2627
|
contextUsage: summary.contextUsage,
|
|
1678
2628
|
model: summary.model,
|
|
2629
|
+
lastAgentText: summary.lastAgentText,
|
|
1679
2630
|
timestamp: new Date().toISOString(),
|
|
1680
2631
|
};
|
|
1681
2632
|
this.eventBus.emit(event);
|
|
@@ -1707,6 +2658,37 @@ export class Supervisor {
|
|
|
1707
2658
|
};
|
|
1708
2659
|
this.eventBus.emit(event);
|
|
1709
2660
|
}
|
|
2661
|
+
emitProviderRuntimeStatusChange(sessionId, projectId, providerRuntimeStatus) {
|
|
2662
|
+
if (!this.eventBus)
|
|
2663
|
+
return;
|
|
2664
|
+
const event = {
|
|
2665
|
+
type: "provider-runtime-status-changed",
|
|
2666
|
+
sessionId,
|
|
2667
|
+
projectId,
|
|
2668
|
+
providerRuntimeStatus,
|
|
2669
|
+
timestamp: new Date().toISOString(),
|
|
2670
|
+
};
|
|
2671
|
+
this.eventBus.emit(event);
|
|
2672
|
+
}
|
|
2673
|
+
handleProviderRetentionChanged(processHolder) {
|
|
2674
|
+
const process = processHolder.process;
|
|
2675
|
+
process?.handleProviderRetentionChanged();
|
|
2676
|
+
this.emitWorkerActivity();
|
|
2677
|
+
// Background work starting/finishing flips an idle session between active
|
|
2678
|
+
// and truly idle without a state-change event. Surface that so inbox/sidebar
|
|
2679
|
+
// activity indicators update live rather than only on the next refresh.
|
|
2680
|
+
if (process && process.state.type === "idle") {
|
|
2681
|
+
this.emitAgentActivityChange(process.sessionId, process.projectId, process.isRetainingProviderWork() ? "in-turn" : "idle");
|
|
2682
|
+
}
|
|
2683
|
+
}
|
|
2684
|
+
processHasActiveWork(process) {
|
|
2685
|
+
if (process.state.type === "in-turn" ||
|
|
2686
|
+
process.state.type === "waiting-input") {
|
|
2687
|
+
return true;
|
|
2688
|
+
}
|
|
2689
|
+
return (process.getLivenessSnapshot().derivedStatus ===
|
|
2690
|
+
"verified-waiting-provider");
|
|
2691
|
+
}
|
|
1710
2692
|
/**
|
|
1711
2693
|
* Emit worker activity event for safe restart indicator.
|
|
1712
2694
|
* Called when workers are added, removed, or change state.
|
|
@@ -1714,16 +2696,48 @@ export class Supervisor {
|
|
|
1714
2696
|
emitWorkerActivity() {
|
|
1715
2697
|
if (!this.eventBus)
|
|
1716
2698
|
return;
|
|
1717
|
-
const
|
|
2699
|
+
const interruptibleSessionCount = Array.from(this.processes.values()).filter((p) => this.processHasActiveWork(p)).length;
|
|
2700
|
+
const queuedSessionMessageCount = this.getQueuedSessionMessageCount();
|
|
1718
2701
|
const event = {
|
|
1719
2702
|
type: "worker-activity-changed",
|
|
1720
2703
|
activeWorkers: this.processes.size,
|
|
2704
|
+
interruptibleSessionCount,
|
|
1721
2705
|
queueLength: this.workerQueue.length,
|
|
1722
|
-
|
|
2706
|
+
queuedSessionMessageCount,
|
|
2707
|
+
hasActiveWork: interruptibleSessionCount > 0,
|
|
1723
2708
|
timestamp: new Date().toISOString(),
|
|
1724
2709
|
};
|
|
1725
2710
|
this.eventBus.emit(event);
|
|
1726
2711
|
}
|
|
2712
|
+
getQueuedSessionMessageCount() {
|
|
2713
|
+
let count = this.workerQueue.length;
|
|
2714
|
+
for (const process of this.processes.values()) {
|
|
2715
|
+
count += process.queueDepth;
|
|
2716
|
+
count += process.getDeferredQueueSummary().length;
|
|
2717
|
+
}
|
|
2718
|
+
return count;
|
|
2719
|
+
}
|
|
2720
|
+
async preserveRestartablePatientQueuesForRestart() {
|
|
2721
|
+
if (!this.sessionQueuePersistenceService || this.workerQueue.length > 0) {
|
|
2722
|
+
return 0;
|
|
2723
|
+
}
|
|
2724
|
+
const processes = Array.from(this.processes.values()).filter((process) => !process.isTerminated);
|
|
2725
|
+
if (processes.some((process) => this.processHasActiveWork(process))) {
|
|
2726
|
+
return 0;
|
|
2727
|
+
}
|
|
2728
|
+
if (processes.some((process) => process.queueDepth > 0 || process.hasVolatileDeferredMessages())) {
|
|
2729
|
+
return 0;
|
|
2730
|
+
}
|
|
2731
|
+
let preservedCount = 0;
|
|
2732
|
+
for (const process of processes) {
|
|
2733
|
+
preservedCount +=
|
|
2734
|
+
await process.preservePatientDeferredMessagesForRestart();
|
|
2735
|
+
}
|
|
2736
|
+
if (preservedCount > 0) {
|
|
2737
|
+
this.emitWorkerActivity();
|
|
2738
|
+
}
|
|
2739
|
+
return preservedCount;
|
|
2740
|
+
}
|
|
1727
2741
|
// ============ Staleness Detection ============
|
|
1728
2742
|
/**
|
|
1729
2743
|
* Terminate processes stuck in "in-turn" with no SDK messages for too long.
|
|
@@ -1838,6 +2852,9 @@ export class Supervisor {
|
|
|
1838
2852
|
const result = await this.startSessionInternal(request.projectPath, request.projectId, request.message, request.sessionId, request.permissionMode, request.modelSettings);
|
|
1839
2853
|
process = result;
|
|
1840
2854
|
}
|
|
2855
|
+
if (request.workstreamId) {
|
|
2856
|
+
await this.sessionMetadataService?.setWorkstream(process.sessionId, request.workstreamId);
|
|
2857
|
+
}
|
|
1841
2858
|
// Emit queue removed event
|
|
1842
2859
|
this.eventBus?.emit({
|
|
1843
2860
|
type: "queue-request-removed",
|
|
@@ -1909,11 +2926,13 @@ export class Supervisor {
|
|
|
1909
2926
|
* Returns whether any workers are actively processing or waiting for input.
|
|
1910
2927
|
*/
|
|
1911
2928
|
getWorkerActivity() {
|
|
1912
|
-
const
|
|
2929
|
+
const interruptibleSessionCount = Array.from(this.processes.values()).filter((p) => this.processHasActiveWork(p)).length;
|
|
1913
2930
|
return {
|
|
1914
2931
|
activeWorkers: this.processes.size,
|
|
2932
|
+
interruptibleSessionCount,
|
|
1915
2933
|
queueLength: this.workerQueue.length,
|
|
1916
|
-
|
|
2934
|
+
queuedSessionMessageCount: this.getQueuedSessionMessageCount(),
|
|
2935
|
+
hasActiveWork: interruptibleSessionCount > 0,
|
|
1917
2936
|
};
|
|
1918
2937
|
}
|
|
1919
2938
|
}
|