@maudecode/talaria-web 1.17.2 → 1.19.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/_release.json +8 -8
- package/dist/api/auth-raw.d.ts +1 -1
- package/dist/api/auth-raw.js +20 -20
- package/dist/api/auth-raw.js.map +1 -1
- package/dist/api/automation-raw.d.ts +7 -1
- package/dist/api/automation-raw.js +74 -27
- package/dist/api/automation-raw.js.map +1 -1
- package/dist/api/automation-router.d.ts +128 -23
- package/dist/api/automation-router.js +29 -13
- package/dist/api/automation-router.js.map +1 -1
- package/dist/api/chat-router.d.ts +1845 -40
- package/dist/api/chat-router.js +196 -114
- package/dist/api/chat-router.js.map +1 -1
- package/dist/api/git-router.d.ts +37 -3
- package/dist/api/git-router.js +47 -48
- package/dist/api/git-router.js.map +1 -1
- package/dist/api/raw-routes.d.ts +9 -1
- package/dist/api/raw-routes.js +286 -73
- package/dist/api/raw-routes.js.map +1 -1
- package/dist/api/router.d.ts +16 -6
- package/dist/api/router.js +28 -26
- package/dist/api/router.js.map +1 -1
- package/dist/api/session-visibility.d.ts +4 -4
- package/dist/api/session-visibility.js +26 -16
- package/dist/api/session-visibility.js.map +1 -1
- package/dist/api/sessions-router.d.ts +3312 -131
- package/dist/api/sessions-router.js +287 -157
- package/dist/api/sessions-router.js.map +1 -1
- package/dist/api/settings-router.d.ts +457 -8
- package/dist/api/settings-router.js +54 -33
- package/dist/api/settings-router.js.map +1 -1
- package/dist/api/sse-routes.d.ts +7 -2
- package/dist/api/sse-routes.js +109 -62
- package/dist/api/sse-routes.js.map +1 -1
- package/dist/api/tools-raw.d.ts +5 -0
- package/dist/api/tools-raw.js +63 -55
- package/dist/api/tools-raw.js.map +1 -1
- package/dist/api/tools-router.d.ts +998 -85
- package/dist/api/tools-router.js +447 -61
- package/dist/api/tools-router.js.map +1 -1
- package/dist/api/transcribe-stream.d.ts +16 -0
- package/dist/api/transcribe-stream.js +172 -0
- package/dist/api/transcribe-stream.js.map +1 -0
- package/dist/app.d.ts +4 -1
- package/dist/app.js +98 -59
- package/dist/app.js.map +1 -1
- package/dist/auth/gate.js +15 -11
- package/dist/auth/gate.js.map +1 -1
- package/dist/auth/oidc.d.ts +5 -2
- package/dist/auth/oidc.js +8 -7
- package/dist/auth/oidc.js.map +1 -1
- package/dist/auth/passkeys.d.ts +15 -14
- package/dist/auth/passkeys.js +89 -91
- package/dist/auth/passkeys.js.map +1 -1
- package/dist/auth/store.d.ts +17 -7
- package/dist/auth/store.js +93 -52
- package/dist/auth/store.js.map +1 -1
- package/dist/bin/talaria-web.js +12 -81
- package/dist/bin/talaria-web.js.map +1 -1
- package/dist/cli/ctl.js +2 -1
- package/dist/cli/ctl.js.map +1 -1
- package/dist/cli/dotenv.d.ts +5 -0
- package/dist/cli/dotenv.js +15 -2
- package/dist/cli/dotenv.js.map +1 -1
- package/dist/cli/launcher.js +5 -5
- package/dist/cli/launcher.js.map +1 -1
- package/dist/cli/main.d.ts +1 -0
- package/dist/cli/main.js +85 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/supervise.d.ts +2 -0
- package/dist/cli/supervise.js +67 -4
- package/dist/cli/supervise.js.map +1 -1
- package/dist/config/agent-config.d.ts +34 -11
- package/dist/config/agent-config.js +116 -60
- package/dist/config/agent-config.js.map +1 -1
- package/dist/config.d.ts +4 -0
- package/dist/config.js +19 -6
- package/dist/config.js.map +1 -1
- package/dist/fs/atomic.d.ts +1 -0
- package/dist/fs/atomic.js +4 -1
- package/dist/fs/atomic.js.map +1 -1
- package/dist/fs/stat.d.ts +1 -0
- package/dist/fs/stat.js +11 -0
- package/dist/fs/stat.js.map +1 -0
- package/dist/http/context.d.ts +31 -12
- package/dist/http/context.js +60 -24
- package/dist/http/context.js.map +1 -1
- package/dist/http/csp.d.ts +2 -1
- package/dist/http/csp.js +3 -2
- package/dist/http/csp.js.map +1 -1
- package/dist/onboarding.d.ts +2 -2
- package/dist/onboarding.js +10 -8
- package/dist/onboarding.js.map +1 -1
- package/dist/profiles/profiles.d.ts +20 -4
- package/dist/profiles/profiles.js +115 -30
- package/dist/profiles/profiles.js.map +1 -1
- package/dist/projects.d.ts +15 -6
- package/dist/projects.js +55 -47
- package/dist/projects.js.map +1 -1
- package/dist/providers/catalog.d.ts +84 -14
- package/dist/providers/catalog.js +474 -151
- package/dist/providers/catalog.js.map +1 -1
- package/dist/providers/env-file.d.ts +10 -3
- package/dist/providers/env-file.js +24 -75
- package/dist/providers/env-file.js.map +1 -1
- package/dist/providers/runtime-env.d.ts +4 -2
- package/dist/providers/runtime-env.js +9 -6
- package/dist/providers/runtime-env.js.map +1 -1
- package/dist/providers/tables.d.ts +3 -1
- package/dist/providers/tables.js +4 -2
- package/dist/providers/tables.js.map +1 -1
- package/dist/raster-image.d.ts +7 -0
- package/dist/raster-image.js +267 -0
- package/dist/raster-image.js.map +1 -0
- package/dist/redact.js +342 -46
- package/dist/redact.js.map +1 -1
- package/dist/release.d.ts +7 -0
- package/dist/release.js +14 -0
- package/dist/release.js.map +1 -1
- package/dist/runtime.d.ts +5 -1
- package/dist/runtime.js +305 -96
- package/dist/runtime.js.map +1 -1
- package/dist/server.js +15 -0
- package/dist/server.js.map +1 -1
- package/dist/sessions/anchor.d.ts +9 -3
- package/dist/sessions/anchor.js +28 -36
- package/dist/sessions/anchor.js.map +1 -1
- package/dist/sessions/background-events.d.ts +2 -0
- package/dist/sessions/background-events.js +10 -0
- package/dist/sessions/background-events.js.map +1 -0
- package/dist/sessions/background-tasks.d.ts +26 -27
- package/dist/sessions/background-tasks.js +89 -97
- package/dist/sessions/background-tasks.js.map +1 -1
- package/dist/sessions/background-updates.d.ts +15 -8
- package/dist/sessions/background-updates.js +101 -25
- package/dist/sessions/background-updates.js.map +1 -1
- package/dist/sessions/cli-sessions.d.ts +27 -6
- package/dist/sessions/cli-sessions.js +152 -42
- package/dist/sessions/cli-sessions.js.map +1 -1
- package/dist/sessions/completions.d.ts +77 -9
- package/dist/sessions/completions.js +482 -45
- package/dist/sessions/completions.js.map +1 -1
- package/dist/sessions/compress.d.ts +8 -0
- package/dist/sessions/compress.js +2 -2
- package/dist/sessions/compress.js.map +1 -1
- package/dist/sessions/drafts.d.ts +14 -10
- package/dist/sessions/drafts.js +38 -43
- package/dist/sessions/drafts.js.map +1 -1
- package/dist/sessions/export.d.ts +5 -0
- package/dist/sessions/export.js +30 -0
- package/dist/sessions/export.js.map +1 -1
- package/dist/sessions/gateway-sessions.d.ts +46 -0
- package/dist/sessions/gateway-sessions.js +378 -0
- package/dist/sessions/gateway-sessions.js.map +1 -0
- package/dist/sessions/gateway-watcher.d.ts +7 -3
- package/dist/sessions/gateway-watcher.js +31 -19
- package/dist/sessions/gateway-watcher.js.map +1 -1
- package/dist/sessions/goals.d.ts +31 -0
- package/dist/sessions/goals.js +75 -0
- package/dist/sessions/goals.js.map +1 -0
- package/dist/sessions/handoff.d.ts +32 -0
- package/dist/sessions/handoff.js +114 -0
- package/dist/sessions/handoff.js.map +1 -0
- package/dist/sessions/journal.d.ts +5 -79
- package/dist/sessions/journal.js +15 -606
- package/dist/sessions/journal.js.map +1 -1
- package/dist/sessions/list.d.ts +31 -16
- package/dist/sessions/list.js +139 -129
- package/dist/sessions/list.js.map +1 -1
- package/dist/sessions/merge.d.ts +69 -13
- package/dist/sessions/merge.js +265 -64
- package/dist/sessions/merge.js.map +1 -1
- package/dist/sessions/notices.d.ts +22 -0
- package/dist/sessions/notices.js +72 -0
- package/dist/sessions/notices.js.map +1 -0
- package/dist/sessions/pending.d.ts +10 -4
- package/dist/sessions/pending.js +83 -7
- package/dist/sessions/pending.js.map +1 -1
- package/dist/sessions/prefix-index.d.ts +82 -0
- package/dist/sessions/prefix-index.js +232 -0
- package/dist/sessions/prefix-index.js.map +1 -0
- package/dist/sessions/recovery.d.ts +19 -0
- package/dist/sessions/recovery.js +322 -0
- package/dist/sessions/recovery.js.map +1 -0
- package/dist/sessions/relay.d.ts +38 -19
- package/dist/sessions/relay.js +302 -79
- package/dist/sessions/relay.js.map +1 -1
- package/dist/sessions/service.d.ts +260 -55
- package/dist/sessions/service.js +1448 -462
- package/dist/sessions/service.js.map +1 -1
- package/dist/sessions/session.d.ts +24 -2
- package/dist/sessions/session.js +69 -7
- package/dist/sessions/session.js.map +1 -1
- package/dist/sessions/shares.d.ts +7 -6
- package/dist/sessions/shares.js +22 -45
- package/dist/sessions/shares.js.map +1 -1
- package/dist/sessions/source-kind.js +1 -0
- package/dist/sessions/source-kind.js.map +1 -1
- package/dist/sessions/state-db-identity.d.ts +18 -0
- package/dist/sessions/state-db-identity.js +67 -0
- package/dist/sessions/state-db-identity.js.map +1 -0
- package/dist/sessions/state-db-worker.d.ts +1 -0
- package/dist/sessions/state-db-worker.js +35 -0
- package/dist/sessions/state-db-worker.js.map +1 -0
- package/dist/sessions/state-db.d.ts +113 -7
- package/dist/sessions/state-db.js +861 -44
- package/dist/sessions/state-db.js.map +1 -1
- package/dist/sessions/storage/backend.d.ts +162 -0
- package/dist/sessions/storage/backend.js +19 -0
- package/dist/sessions/storage/backend.js.map +1 -0
- package/dist/sessions/storage/conformance.d.ts +20 -0
- package/dist/sessions/storage/conformance.js +237 -0
- package/dist/sessions/storage/conformance.js.map +1 -0
- package/dist/sessions/storage/document.d.ts +16 -0
- package/dist/sessions/storage/document.js +44 -0
- package/dist/sessions/storage/document.js.map +1 -0
- package/dist/sessions/storage/json-documents.d.ts +23 -0
- package/dist/sessions/storage/json-documents.js +233 -0
- package/dist/sessions/storage/json-documents.js.map +1 -0
- package/dist/sessions/storage/json-files.d.ts +12 -0
- package/dist/sessions/storage/json-files.js +124 -0
- package/dist/sessions/storage/json-files.js.map +1 -0
- package/dist/sessions/storage/json-installation.d.ts +3 -0
- package/dist/sessions/storage/json-installation.js +31 -0
- package/dist/sessions/storage/json-installation.js.map +1 -0
- package/dist/sessions/storage/json-journal.d.ts +114 -0
- package/dist/sessions/storage/json-journal.js +686 -0
- package/dist/sessions/storage/json-journal.js.map +1 -0
- package/dist/sessions/storage/json-recovery.d.ts +4 -0
- package/dist/sessions/storage/json-recovery.js +195 -0
- package/dist/sessions/storage/json-recovery.js.map +1 -0
- package/dist/sessions/storage/json.d.ts +68 -0
- package/dist/sessions/storage/json.js +258 -0
- package/dist/sessions/storage/json.js.map +1 -0
- package/dist/sessions/storage/row.d.ts +6 -0
- package/dist/sessions/storage/row.js +49 -0
- package/dist/sessions/storage/row.js.map +1 -0
- package/dist/sessions/storage/search-text.d.ts +4 -0
- package/dist/sessions/storage/search-text.js +16 -0
- package/dist/sessions/storage/search-text.js.map +1 -0
- package/dist/sessions/store.d.ts +65 -68
- package/dist/sessions/store.js +305 -602
- package/dist/sessions/store.js.map +1 -1
- package/dist/sessions/streams.d.ts +4 -0
- package/dist/sessions/streams.js +9 -1
- package/dist/sessions/streams.js.map +1 -1
- package/dist/sessions/titles.d.ts +2 -0
- package/dist/sessions/titles.js +5 -1
- package/dist/sessions/titles.js.map +1 -1
- package/dist/sessions/todo.d.ts +5 -0
- package/dist/sessions/todo.js +28 -21
- package/dist/sessions/todo.js.map +1 -1
- package/dist/sessions/tool-display.d.ts +5 -4
- package/dist/sessions/tool-display.js +30 -50
- package/dist/sessions/tool-display.js.map +1 -1
- package/dist/sessions/turn-context.d.ts +11 -2
- package/dist/sessions/turn-context.js +18 -11
- package/dist/sessions/turn-context.js.map +1 -1
- package/dist/sessions/turn.d.ts +122 -17
- package/dist/sessions/turn.js +939 -358
- package/dist/sessions/turn.js.map +1 -1
- package/dist/sessions/wakeup-pause.d.ts +54 -0
- package/dist/sessions/wakeup-pause.js +163 -0
- package/dist/sessions/wakeup-pause.js.map +1 -0
- package/dist/sessions/window.js +13 -12
- package/dist/sessions/window.js.map +1 -1
- package/dist/settings.d.ts +19 -7
- package/dist/settings.js +178 -184
- package/dist/settings.js.map +1 -1
- package/dist/sidecar/client.d.ts +17 -3
- package/dist/sidecar/client.js +78 -8
- package/dist/sidecar/client.js.map +1 -1
- package/dist/sidecar/discover.d.ts +2 -1
- package/dist/sidecar/discover.js +93 -10
- package/dist/sidecar/discover.js.map +1 -1
- package/dist/sidecar/env.d.ts +4 -0
- package/dist/sidecar/env.js +3 -0
- package/dist/sidecar/env.js.map +1 -0
- package/dist/sidecar/fake.d.ts +2 -2
- package/dist/sidecar/fake.js +19 -2
- package/dist/sidecar/fake.js.map +1 -1
- package/dist/startup.d.ts +13 -5
- package/dist/startup.js +48 -0
- package/dist/startup.js.map +1 -1
- package/dist/test/env-file.d.ts +5 -0
- package/dist/test/env-file.js +88 -0
- package/dist/test/env-file.js.map +1 -0
- package/dist/test/harness.d.ts +1 -0
- package/dist/test/harness.js +1 -1
- package/dist/test/harness.js.map +1 -1
- package/dist/test/passkeys.d.ts +22 -0
- package/dist/test/passkeys.js +62 -0
- package/dist/test/passkeys.js.map +1 -0
- package/dist/test/storage.d.ts +15 -0
- package/dist/test/storage.js +26 -0
- package/dist/test/storage.js.map +1 -0
- package/dist/test/ts-worker-hooks.d.ts +1 -0
- package/dist/test/ts-worker-hooks.js +24 -0
- package/dist/test/ts-worker-hooks.js.map +1 -0
- package/dist/text/diff.d.ts +9 -14
- package/dist/text/diff.js +74 -108
- package/dist/text/diff.js.map +1 -1
- package/dist/tools/commands.d.ts +6 -1
- package/dist/tools/commands.js +8 -2
- package/dist/tools/commands.js.map +1 -1
- package/dist/tools/connectors.d.ts +33 -0
- package/dist/tools/connectors.js +121 -0
- package/dist/tools/connectors.js.map +1 -0
- package/dist/tools/crons.d.ts +38 -1
- package/dist/tools/crons.js +122 -18
- package/dist/tools/crons.js.map +1 -1
- package/dist/tools/dashboard-plugins.d.ts +53 -0
- package/dist/tools/dashboard-plugins.js +188 -0
- package/dist/tools/dashboard-plugins.js.map +1 -0
- package/dist/tools/extensions.d.ts +18 -5
- package/dist/tools/extensions.js +344 -266
- package/dist/tools/extensions.js.map +1 -1
- package/dist/tools/gateway-restart.d.ts +62 -0
- package/dist/tools/gateway-restart.js +142 -0
- package/dist/tools/gateway-restart.js.map +1 -0
- package/dist/tools/health.d.ts +44 -0
- package/dist/tools/health.js +201 -46
- package/dist/tools/health.js.map +1 -1
- package/dist/tools/hygiene.d.ts +4 -3
- package/dist/tools/hygiene.js +23 -9
- package/dist/tools/hygiene.js.map +1 -1
- package/dist/tools/kanban.d.ts +4 -2
- package/dist/tools/kanban.js +28 -19
- package/dist/tools/kanban.js.map +1 -1
- package/dist/tools/mcp.d.ts +13 -0
- package/dist/tools/mcp.js +88 -0
- package/dist/tools/mcp.js.map +1 -1
- package/dist/tools/memory-masks.d.ts +5 -0
- package/dist/tools/memory-masks.js +256 -0
- package/dist/tools/memory-masks.js.map +1 -0
- package/dist/tools/memory.d.ts +29 -3
- package/dist/tools/memory.js +69 -27
- package/dist/tools/memory.js.map +1 -1
- package/dist/tools/plugin-settings.d.ts +15 -0
- package/dist/tools/plugin-settings.js +90 -0
- package/dist/tools/plugin-settings.js.map +1 -0
- package/dist/tools/project-os.d.ts +11 -0
- package/dist/tools/project-os.js +267 -0
- package/dist/tools/project-os.js.map +1 -0
- package/dist/tools/skills.d.ts +14 -5
- package/dist/tools/skills.js +49 -16
- package/dist/tools/skills.js.map +1 -1
- package/dist/tools/update-notifications.d.ts +34 -15
- package/dist/tools/update-notifications.js +141 -57
- package/dist/tools/update-notifications.js.map +1 -1
- package/dist/tools/update-rollback.d.ts +11 -0
- package/dist/tools/update-rollback.js +28 -0
- package/dist/tools/update-rollback.js.map +1 -0
- package/dist/tools/updates.d.ts +110 -32
- package/dist/tools/updates.js +1112 -294
- package/dist/tools/updates.js.map +1 -1
- package/dist/tools/wiki.d.ts +68 -0
- package/dist/tools/wiki.js +413 -0
- package/dist/tools/wiki.js.map +1 -0
- package/dist/util.d.ts +2 -0
- package/dist/util.js +5 -0
- package/dist/util.js.map +1 -1
- package/dist/workspace/escape.d.ts +61 -0
- package/dist/workspace/escape.js +149 -0
- package/dist/workspace/escape.js.map +1 -0
- package/dist/workspace/extract.d.ts +22 -0
- package/dist/workspace/extract.js +308 -0
- package/dist/workspace/extract.js.map +1 -0
- package/dist/workspace/fs.d.ts +12 -0
- package/dist/workspace/fs.js +92 -23
- package/dist/workspace/fs.js.map +1 -1
- package/dist/workspace/git.d.ts +34 -1
- package/dist/workspace/git.js +328 -35
- package/dist/workspace/git.js.map +1 -1
- package/dist/workspace/media.d.ts +16 -13
- package/dist/workspace/media.js +43 -61
- package/dist/workspace/media.js.map +1 -1
- package/dist/workspace/rollback.d.ts +36 -22
- package/dist/workspace/rollback.js +178 -272
- package/dist/workspace/rollback.js.map +1 -1
- package/dist/workspace/unzip.js +4 -1
- package/dist/workspace/unzip.js.map +1 -1
- package/dist/workspace/upload.d.ts +7 -4
- package/dist/workspace/upload.js +5 -2
- package/dist/workspace/upload.js.map +1 -1
- package/dist/workspace/workspaces.d.ts +15 -19
- package/dist/workspace/workspaces.js +55 -127
- package/dist/workspace/workspaces.js.map +1 -1
- package/dist/workspace/worktrees.d.ts +2 -1
- package/dist/workspace/worktrees.js +179 -42
- package/dist/workspace/worktrees.js.map +1 -1
- package/package.json +7 -3
- package/sidecar/agent_dependency.json +4 -4
- package/sidecar/agent_support.json +26 -0
- package/sidecar/scripts/record-fixtures.py +12 -3
- package/sidecar/scripts/replay_sidecar.py +32 -0
- package/sidecar/scripts/suite_runner.py +302 -0
- package/sidecar/scripts/test.sh +12 -4
- package/sidecar/talaria_sidecar/__init__.py +6 -1
- package/sidecar/talaria_sidecar/__main__.py +4 -2
- package/sidecar/talaria_sidecar/agent_mutation.py +975 -0
- package/sidecar/talaria_sidecar/agent_services.py +1053 -0
- package/sidecar/talaria_sidecar/dependency_sync.py +85 -0
- package/sidecar/talaria_sidecar/home.py +56 -3
- package/sidecar/talaria_sidecar/methods/__init__.py +2 -2
- package/sidecar/talaria_sidecar/methods/aux.py +166 -24
- package/sidecar/talaria_sidecar/methods/chat.py +852 -135
- package/sidecar/talaria_sidecar/methods/checkpoints.py +89 -0
- package/sidecar/talaria_sidecar/methods/commands.py +294 -4
- package/sidecar/talaria_sidecar/methods/config.py +123 -4
- package/sidecar/talaria_sidecar/methods/connectors.py +343 -0
- package/sidecar/talaria_sidecar/methods/cron.py +395 -36
- package/sidecar/talaria_sidecar/methods/cron_execution.py +284 -0
- package/sidecar/talaria_sidecar/methods/gateway.py +212 -55
- package/sidecar/talaria_sidecar/methods/gateway_sessions.py +234 -0
- package/sidecar/talaria_sidecar/methods/goals.py +81 -41
- package/sidecar/talaria_sidecar/methods/kanban.py +108 -34
- package/sidecar/talaria_sidecar/methods/mcp.py +1 -1
- package/sidecar/talaria_sidecar/methods/memory.py +84 -0
- package/sidecar/talaria_sidecar/methods/oauth.py +5 -2
- package/sidecar/talaria_sidecar/methods/process.py +218 -15
- package/sidecar/talaria_sidecar/methods/profiles.py +121 -13
- package/sidecar/talaria_sidecar/methods/providers.py +217 -28
- package/sidecar/talaria_sidecar/methods/runtime.py +69 -1
- package/sidecar/talaria_sidecar/methods/skills.py +67 -4
- package/sidecar/talaria_sidecar/methods/state_db.py +316 -75
- package/sidecar/talaria_sidecar/methods/stt.py +159 -78
- package/sidecar/talaria_sidecar/methods/text.py +14 -1
- package/sidecar/talaria_sidecar/methods/toolsets.py +49 -0
- package/sidecar/talaria_sidecar/methods/usage.py +113 -14
- package/sidecar/talaria_sidecar/methods/worktree.py +26 -19
- package/sidecar/talaria_sidecar/methods/write_approval.py +181 -0
- package/sidecar/talaria_sidecar/rpc.py +45 -4
- package/sidecar/talaria_sidecar/runtime.py +98 -13
- package/sidecar/talaria_sidecar/speed.py +35 -0
- package/static/dist/FILES.txt +126 -126
- package/static/dist/assets/AppShell-cey33v9s.js +8 -0
- package/static/dist/assets/ChatPage-i8wnugr7.js +18 -0
- package/static/dist/assets/ConnectTargets-hg19553x.js +1 -0
- package/static/dist/assets/ExtensionRoute-cly4apm5.js +1 -0
- package/static/dist/assets/Field-j8uqoigz.js +9 -0
- package/static/dist/assets/HubRoute-e4bgz41j.js +2 -0
- package/static/dist/assets/Markdown-lahuichm.js +598 -0
- package/static/dist/assets/RightPanel-lbo4i0fn.js +1 -0
- package/static/dist/assets/Select-gqatm2e0.js +1 -0
- package/static/dist/assets/SessionListPanel-mfqayfjh.js +1 -0
- package/static/dist/assets/SettingsLayout-b8980u7k.js +1 -0
- package/static/dist/assets/States-e7dkgtxf.js +1 -0
- package/static/dist/assets/Toaster-bfqqy786.js +1 -0
- package/static/dist/assets/_app-n1n6pfx1.js +1 -0
- package/static/dist/assets/{_app.ext._extensionId-opyh9y0v.js → _app.ext._extensionId-buxjxav3.js} +1 -1
- package/static/dist/assets/_app.index-jt8zwiu2.js +1 -0
- package/static/dist/assets/_app.insights-cv76ml71.js +1 -0
- package/static/dist/assets/_app.kanban-h6ts53j7.js +1 -0
- package/static/dist/assets/_app.logs-dm873z90.js +1 -0
- package/static/dist/assets/_app.memory-glk5y6m8.js +1 -0
- package/static/dist/assets/_app.profiles-ka6zpstq.js +1 -0
- package/static/dist/assets/{_app.session._sessionId-bfd4h3id.js → _app.session._sessionId-g2vzghvc.js} +1 -1
- package/static/dist/assets/_app.settings-hgjdhzcd.js +1 -0
- package/static/dist/assets/_app.settings._section-jf2kmhae.js +3 -0
- package/static/dist/assets/_app.skills-cii852yq.js +1 -0
- package/static/dist/assets/_app.tasks-fp9q7atm.js +1 -0
- package/static/dist/assets/_app.todos-dw94qzue.js +1 -0
- package/static/dist/assets/_app.workspaces-inyygzze.js +1 -0
- package/static/dist/assets/{abnfDiagram-VCTEODGH-b2x1lqot.js → abnfDiagram-VCTEODGH-gjayq3ra.js} +1 -1
- package/static/dist/assets/architecture-7GRP2DOG-lp56972r.js +1 -0
- package/static/dist/assets/{architectureDiagram-5GKGNRK7-h38o5l7b.js → architectureDiagram-5GKGNRK7-nwb3xovn.js} +1 -1
- package/static/dist/assets/archive-b1j004vn.js +1 -0
- package/static/dist/assets/back-g74gkozu.js +1 -0
- package/static/dist/assets/{blockDiagram-I7D4REHJ-bqquxv2u.js → blockDiagram-I7D4REHJ-joedghi3.js} +1 -1
- package/static/dist/assets/{c4Diagram-7LVT6UL2-f3fb8w6z.js → c4Diagram-7LVT6UL2-hyrjrohe.js} +1 -1
- package/static/dist/assets/channel-es95o4y8.js +1 -0
- package/static/dist/assets/{chunk-4HAMMTFA-bzfyyzp3.js → chunk-4HAMMTFA-koouqbut.js} +1 -1
- package/static/dist/assets/{chunk-75Z2AOVW-ly99rfx5.js → chunk-75Z2AOVW-bl4bhdnt.js} +1 -1
- package/static/dist/assets/{chunk-DU6HZSFF-bg6ecfqf.js → chunk-DU6HZSFF-gpedttsp.js} +3 -3
- package/static/dist/assets/{chunk-F27PBJKO-e8k7mmqw.js → chunk-F27PBJKO-d8xxi0zi.js} +1 -1
- package/static/dist/assets/{chunk-GMAD6QVW-cmalnoaj.js → chunk-GMAD6QVW-jro0hl73.js} +1 -1
- package/static/dist/assets/{chunk-GVQU2GXP-gmif5o01.js → chunk-GVQU2GXP-djn6gbyu.js} +1 -1
- package/static/dist/assets/{chunk-IMKFNOWR-f1nwwh6u.js → chunk-IMKFNOWR-vw4p5p7o.js} +1 -1
- package/static/dist/assets/{chunk-L3NEJ4N5-oktfh5v7.js → chunk-L3NEJ4N5-n1hj77q8.js} +1 -1
- package/static/dist/assets/{chunk-OSK3NFVY-b1sdx96z.js → chunk-OSK3NFVY-oy0gwn2n.js} +1 -1
- package/static/dist/assets/{chunk-P2QGCYS3-fhu4nzxt.js → chunk-P2QGCYS3-onf1hz6c.js} +1 -1
- package/static/dist/assets/{chunk-POPQ4Y6H-em31rnef.js → chunk-POPQ4Y6H-m8sqn7cs.js} +1 -1
- package/static/dist/assets/{chunk-PWAF6VOD-bxhhyftw.js → chunk-PWAF6VOD-ek4smc8x.js} +1 -1
- package/static/dist/assets/{chunk-SHT3W25Y-fmrvwcav.js → chunk-SHT3W25Y-g9gfvefo.js} +3 -3
- package/static/dist/assets/{chunk-SVP7TREG-lymukl2j.js → chunk-SVP7TREG-f9nfv2cu.js} +1 -1
- package/static/dist/assets/{chunk-TICWLB2K-lmza6k23.js → chunk-TICWLB2K-bnk3m1mq.js} +1 -1
- package/static/dist/assets/classDiagram-ZZMXUADV-kmihoqxh.js +1 -0
- package/static/dist/assets/classDiagram-v2-VYDZK3BY-kmihoqxh.js +1 -0
- package/static/dist/assets/copied-bli9tbcx.js +1 -0
- package/static/dist/assets/{copy-fw5b1pc6.js → copy-jamtd1pf.js} +1 -1
- package/static/dist/assets/{cynefin-OW5HDTMX-czlhbyhs.js → cynefin-OW5HDTMX-f8xfdd3f.js} +1 -1
- package/static/dist/assets/{cynefinDiagram-5FMLGOSQ-gq7mvswb.js → cynefinDiagram-5FMLGOSQ-n9lb99h9.js} +1 -1
- package/static/dist/assets/{dagre-GXQ25YYZ-cqdbf7dr.js → dagre-GXQ25YYZ-dgailddi.js} +4 -4
- package/static/dist/assets/{diagram-S7CK7UJ4-o6arxa58.js → diagram-S7CK7UJ4-m6aeoe7c.js} +1 -1
- package/static/dist/assets/{diagram-UQ7AKVKN-nhnd68tz.js → diagram-UQ7AKVKN-jall3j0x.js} +1 -1
- package/static/dist/assets/{diagram-VSXAHHWV-dk2sclzn.js → diagram-VSXAHHWV-hbawi7hn.js} +1 -1
- package/static/dist/assets/{diagram-VX7I27RA-n3k5nyx3.js → diagram-VX7I27RA-hendl2tt.js} +1 -1
- package/static/dist/assets/{diagram-Z3DM3KII-m6q9cwdh.js → diagram-Z3DM3KII-igwc35p3.js} +1 -1
- package/static/dist/assets/{ebnfDiagram-PWID7BFC-lsa5641p.js → ebnfDiagram-PWID7BFC-c64knz08.js} +1 -1
- package/static/dist/assets/{erDiagram-RLTQ6QDP-fo2ckbe6.js → erDiagram-RLTQ6QDP-brdu9lcm.js} +1 -1
- package/static/dist/assets/eventmodeling-NTZA5JFV-njk1j8wl.js +1 -0
- package/static/dist/assets/flowDiagram-HODETNUW-nma6f0ga.js +1 -0
- package/static/dist/assets/folder-plus-lvt9kudb.js +1 -0
- package/static/dist/assets/{ganttDiagram-EL5Y4UJY-nzqz6x9g.js → ganttDiagram-EL5Y4UJY-ma6jxj5i.js} +1 -1
- package/static/dist/assets/{gitGraph-4MIJSDKK-gukvcxe6.js → gitGraph-4MIJSDKK-naa9w6xa.js} +1 -1
- package/static/dist/assets/{gitGraphDiagram-WWUBYQGX-lqhdp8f0.js → gitGraphDiagram-WWUBYQGX-hzltvsod.js} +1 -1
- package/static/dist/assets/{highlighted-body-KPVGNVTW-igw6cp39.js → highlighted-body-KPVGNVTW-ghoavj8d.js} +1 -1
- package/static/dist/assets/host-hzm8n85n.js +1 -0
- package/static/dist/assets/index-drdcaqeq.css +2 -0
- package/static/dist/assets/index-jzm844he.js +11 -0
- package/static/dist/assets/{info-A6RAGUB7-gvu7a93l.js → info-A6RAGUB7-mn2ut5ko.js} +1 -1
- package/static/dist/assets/{infoDiagram-27XIBGKW-m8t8g6w1.js → infoDiagram-27XIBGKW-h6kuqvsb.js} +1 -1
- package/static/dist/assets/{ishikawaDiagram-5VMMS53U-l07vkbgj.js → ishikawaDiagram-5VMMS53U-e7bnwq7h.js} +1 -1
- package/static/dist/assets/{journeyDiagram-3NMN7TZE-hybkgj8l.js → journeyDiagram-3NMN7TZE-etd1bi6p.js} +1 -1
- package/static/dist/assets/{kanban-definition-UXKFOSKX-by13uvtn.js → kanban-definition-UXKFOSKX-emb1g9dz.js} +4 -4
- package/static/dist/assets/lazyRouteComponent-o816ytzl.js +1 -0
- package/static/dist/assets/{line-osxq6fq7.js → line-h0ojzsvs.js} +1 -1
- package/static/dist/assets/link-k01ryaf9.js +1 -0
- package/static/dist/assets/login-bsae49ew.js +1 -0
- package/static/dist/assets/mermaid-HWGCJPDP-ihl34s74.js +1 -0
- package/static/dist/assets/{mermaid-parser.core-i91oxmou.js → mermaid-parser.core-bnre27u8.js} +3 -3
- package/static/dist/assets/{mindmap-definition-YA3MSWOX-m82mx8ww.js → mindmap-definition-YA3MSWOX-o1vathns.js} +1 -1
- package/static/dist/assets/onboarding-c65tysya.js +1 -0
- package/static/dist/assets/onboarding_model_label-gpn28uix.js +1 -0
- package/static/dist/assets/{packet-AYTQ26CC-nbtgge2o.js → packet-AYTQ26CC-hatq7m2e.js} +1 -1
- package/static/dist/assets/pcmTap.worklet-74EKjWAZ.js +1 -0
- package/static/dist/assets/{pegDiagram-XKGWAZYB-f1zxzga1.js → pegDiagram-XKGWAZYB-gwisz8jv.js} +1 -1
- package/static/dist/assets/{pie-WAS4IAKB-of8vuhxs.js → pie-WAS4IAKB-fpftf0mk.js} +1 -1
- package/static/dist/assets/{pieDiagram-E7YTZNPT-o7y8ftio.js → pieDiagram-E7YTZNPT-khm1o9a6.js} +1 -1
- package/static/dist/assets/{quadrantDiagram-AXDQQJYC-iqiwia1t.js → quadrantDiagram-AXDQQJYC-owqc4uqn.js} +1 -1
- package/static/dist/assets/{radar-RG4KPBEZ-delnsy2v.js → radar-RG4KPBEZ-cntfwjpq.js} +1 -1
- package/static/dist/assets/{railroad-74A4TZTK-nspnyq9u.js → railroad-74A4TZTK-a7t5eibp.js} +1 -1
- package/static/dist/assets/railroad-abnf-HS5TGJTU-ol8cdktf.js +1 -0
- package/static/dist/assets/railroad-ebnf-LZEXJU2U-i8vzd429.js +1 -0
- package/static/dist/assets/railroad-peg-WCYAUIDC-nw3ulewz.js +1 -0
- package/static/dist/assets/{railroadDiagram-O6MQD6OU-z41tqx5z.js → railroadDiagram-O6MQD6OU-etuh0qa0.js} +1 -1
- package/static/dist/assets/{refresh-cw-nt1dtsx4.js → refresh-cw-mqbkv2a3.js} +1 -1
- package/static/dist/assets/refresh-l29ljp76.js +1 -0
- package/static/dist/assets/{requirementDiagram-BXWQKSXE-bdvif194.js → requirementDiagram-BXWQKSXE-oq2ulk22.js} +1 -1
- package/static/dist/assets/{sankeyDiagram-P5KCCOFB-h73e0rol.js → sankeyDiagram-P5KCCOFB-iqc02emv.js} +1 -1
- package/static/dist/assets/saved-ndd4t2xb.js +1 -0
- package/static/dist/assets/{sequenceDiagram-WJ2MYXX4-iv95mb1z.js → sequenceDiagram-WJ2MYXX4-i0v116q0.js} +2 -2
- package/static/dist/assets/settings_section_extensions_title-jhfo6o8z.js +1 -0
- package/static/dist/assets/share._token-c1ri0hy1.js +2 -0
- package/static/dist/assets/sliders-horizontal-j3jjt9tv.js +1 -0
- package/static/dist/assets/{stateDiagram-D77RDMKH-k417ixmf.js → stateDiagram-D77RDMKH-dnpt1ato.js} +1 -1
- package/static/dist/assets/stateDiagram-v2-MP3YSRHH-bxjacpk6.js +1 -0
- package/static/dist/assets/{swimlanes-42K2YHIH-esola70w.js → swimlanes-42K2YHIH-loqbdazb.js} +1 -1
- package/static/dist/assets/swimlanesDiagram-VR7AAH4N-id62p9hz.js +8 -0
- package/static/dist/assets/{timeline-definition-24CTP7MA-getrz2y8.js → timeline-definition-24CTP7MA-ol2hnvma.js} +1 -1
- package/static/dist/assets/toast-i3h34v6o.js +64 -0
- package/static/dist/assets/{treeView-Q6P3EWNA-hc7ap1q7.js → treeView-Q6P3EWNA-idrj6iox.js} +1 -1
- package/static/dist/assets/{treemap-WGGIJYW6-b7k1syy5.js → treemap-WGGIJYW6-lzr49vv5.js} +1 -1
- package/static/dist/assets/untitled-oaoya4qj.js +1 -0
- package/static/dist/assets/useForm-nfaxgmsk.js +1 -0
- package/static/dist/assets/{useParams-lhg566ew.js → useParams-gjc70qru.js} +1 -1
- package/static/dist/assets/{useSearch-lbrh6ejn.js → useSearch-e6ae539u.js} +1 -1
- package/static/dist/assets/{vennDiagram-4TSXK5OY-n6pcy5qb.js → vennDiagram-4TSXK5OY-bvwr9o2z.js} +1 -1
- package/static/dist/assets/{wardley-WFR3VGLG-lpa18vz1.js → wardley-WFR3VGLG-31ui8tma.js} +1 -1
- package/static/dist/assets/{wardleyDiagram-VM6X3IG4-kpclwwg7.js → wardleyDiagram-VM6X3IG4-k5wqtx4b.js} +1 -1
- package/static/dist/assets/{xychartDiagram-S5SC5T6Z-paa2n8y0.js → xychartDiagram-S5SC5T6Z-aqbgvujg.js} +1 -1
- package/static/dist/index.html +1 -1
- package/static/dist/sw.js +1 -1
- package/static/dist/assets/AppShell-fb2td9zi.js +0 -1
- package/static/dist/assets/ChatPage-cj96kiy9.js +0 -25
- package/static/dist/assets/Dialog-kxcg7ard.js +0 -1
- package/static/dist/assets/ExtensionRoute-jf7h0754.js +0 -1
- package/static/dist/assets/HubRoute-gmanpd5y.js +0 -2
- package/static/dist/assets/Markdown-mdwlvj3w.js +0 -598
- package/static/dist/assets/RightPanel-ftvrjlcp.js +0 -1
- package/static/dist/assets/Select-bilaypej.js +0 -1
- package/static/dist/assets/SessionListPanel-og8n36qs.js +0 -1
- package/static/dist/assets/SettingsLayout-jonjefmj.js +0 -1
- package/static/dist/assets/States-nmejrwrm.js +0 -1
- package/static/dist/assets/Toaster-nnl8zkt9.js +0 -1
- package/static/dist/assets/_app-gdidzd94.js +0 -1
- package/static/dist/assets/_app.index-hbarzbjx.js +0 -1
- package/static/dist/assets/_app.insights-luywlarz.js +0 -1
- package/static/dist/assets/_app.kanban-kincnbr8.js +0 -1
- package/static/dist/assets/_app.logs-oi2gr3gs.js +0 -1
- package/static/dist/assets/_app.memory-b6jfivt6.js +0 -1
- package/static/dist/assets/_app.profiles-lpvixmqp.js +0 -1
- package/static/dist/assets/_app.settings-vowx3iq0.js +0 -1
- package/static/dist/assets/_app.settings._section-cnntg1tu.js +0 -3
- package/static/dist/assets/_app.skills-fb57lpau.js +0 -1
- package/static/dist/assets/_app.tasks-eszpx1q7.js +0 -2
- package/static/dist/assets/_app.todos-nr05ac6w.js +0 -1
- package/static/dist/assets/_app.workspaces-d2luomu6.js +0 -1
- package/static/dist/assets/architecture-7GRP2DOG-hd0o7bde.js +0 -1
- package/static/dist/assets/back-bemaer09.js +0 -1
- package/static/dist/assets/cancel-drd0g6d9.js +0 -1
- package/static/dist/assets/channel-cpdgf867.js +0 -1
- package/static/dist/assets/classDiagram-ZZMXUADV-ko09sguk.js +0 -1
- package/static/dist/assets/classDiagram-v2-VYDZK3BY-ko09sguk.js +0 -1
- package/static/dist/assets/copied-ima3pysb.js +0 -1
- package/static/dist/assets/endpoints-d33siokx.js +0 -64
- package/static/dist/assets/eventmodeling-NTZA5JFV-emctlo64.js +0 -1
- package/static/dist/assets/flowDiagram-HODETNUW-bfi3moqa.js +0 -1
- package/static/dist/assets/index-cxq58xb1.js +0 -11
- package/static/dist/assets/index-hgtx08n5.css +0 -2
- package/static/dist/assets/lazyRouteComponent-af0lvgjx.js +0 -1
- package/static/dist/assets/link-jyxicdhg.js +0 -1
- package/static/dist/assets/login-ec21t39x.js +0 -1
- package/static/dist/assets/mermaid-HWGCJPDP-gfl8z3ep.js +0 -1
- package/static/dist/assets/onboarding-btnltvyz.js +0 -1
- package/static/dist/assets/onboarding_model_label-dp7xffoh.js +0 -1
- package/static/dist/assets/railroad-abnf-HS5TGJTU-nst1qxyn.js +0 -1
- package/static/dist/assets/railroad-ebnf-LZEXJU2U-ci37x8qy.js +0 -1
- package/static/dist/assets/railroad-peg-WCYAUIDC-aimkk07z.js +0 -1
- package/static/dist/assets/refresh-b4uams1i.js +0 -1
- package/static/dist/assets/saved-kg52csy7.js +0 -1
- package/static/dist/assets/settings_section_extensions_title-ej0iapxe.js +0 -1
- package/static/dist/assets/share._token-f97e94r0.js +0 -2
- package/static/dist/assets/sliders-horizontal-fj18it47.js +0 -1
- package/static/dist/assets/sse-fwpqtzbg.js +0 -1
- package/static/dist/assets/stateDiagram-v2-MP3YSRHH-hwn4apct.js +0 -1
- package/static/dist/assets/swimlanesDiagram-VR7AAH4N-d1h97oyg.js +0 -8
- package/static/dist/assets/todoStore-eginf9h4.js +0 -1
- package/static/dist/assets/tts-lxdxnmjd.js +0 -1
- package/static/dist/assets/untitled-ovpfthg4.js +0 -1
- package/static/dist/assets/useForm-bcblv1rx.js +0 -1
- package/static/dist/assets/useLocale-fi5jb8ma.js +0 -1
|
@@ -7,14 +7,30 @@
|
|
|
7
7
|
* redelivered at turn teardown with a bounded retry budget).
|
|
8
8
|
*/
|
|
9
9
|
import { randomUUID } from 'node:crypto';
|
|
10
|
+
import { readFileSync, realpathSync } from 'node:fs';
|
|
11
|
+
import { join, resolve } from 'node:path';
|
|
12
|
+
import { SessionNotFound } from './store.js';
|
|
10
13
|
import { str } from '../util.js';
|
|
11
|
-
import {
|
|
14
|
+
import { expandDotenv, parseDotenv } from '../cli/dotenv.js';
|
|
15
|
+
import { isDict, messageText } from './merge.js';
|
|
16
|
+
import { batchUpdate, recordBackgroundUpdate, completionAccepted } from './background-updates.js';
|
|
17
|
+
import { backgroundEventKind } from './background-events.js';
|
|
18
|
+
import { HeldWakeups, deliveredPerProcess, heldKey, mergeWakeups, poolRecovery, wakeupPaused } from './wakeup-pause.js';
|
|
12
19
|
export const COMPLETION_POLL_MS = 1000;
|
|
13
20
|
const EMIT_COALESCE_WINDOW_S = 1;
|
|
14
21
|
const WAKEUP_RETRY_SECONDS = 30;
|
|
15
22
|
const WAKEUP_RETRY_MAX_ATTEMPTS = 5;
|
|
16
23
|
const WAKEUP_BATCH_MAX_CHARS = 24_000;
|
|
24
|
+
/** A session with held wakeups rechecks its pause at least this often (a credential edit has no deadline). */
|
|
25
|
+
const HELD_RECHECK_SECONDS = 300;
|
|
17
26
|
const DELIVERY_CONSUMER = 'webui';
|
|
27
|
+
const canonicalHome = (home) => { try {
|
|
28
|
+
return realpathSync(home);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return resolve(home);
|
|
32
|
+
} };
|
|
33
|
+
const completionKey = (home, event) => event.type === 'async_delegation' && event.delegation_id && !event.task_failure_notice ? JSON.stringify([canonicalHome(home), str(event.delegation_id)]) : '';
|
|
18
34
|
/** Python `format_wakeup_prompt` for plain completion events; async delegations use the sidecar formatter. */
|
|
19
35
|
export function formatWakeupPrompt(evt) {
|
|
20
36
|
const type = str(evt.type ?? 'completion');
|
|
@@ -31,12 +47,22 @@ export function formatWakeupPrompt(evt) {
|
|
|
31
47
|
body += `\n(${str(evt.suppressed)} earlier matches were suppressed by rate limit)`;
|
|
32
48
|
return body + ']';
|
|
33
49
|
}
|
|
34
|
-
if (
|
|
50
|
+
if (backgroundEventKind(evt) !== 'completion')
|
|
35
51
|
return null;
|
|
36
52
|
if (!(sid || cmd || 'exit_code' in evt || evt.output))
|
|
37
53
|
return null;
|
|
38
54
|
return `[IMPORTANT: Background process ${sid} completed (exit_code=${str(evt.exit_code ?? '?')}).\nCommand: ${cmd}\nOutput:\n${truncate(evt.output, 4000)}]`;
|
|
39
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* TAL-724: an event's delivery identity, the `process_id` of its wakeup entry. A completion (an event with no type is one) or
|
|
58
|
+
* an async delegation is its process: one exit can be enqueued twice when a kill races the reader thread. The Agent enqueues
|
|
59
|
+
* each watch event once, and one process raises several, so each is its own delivery; its event keeps the process id.
|
|
60
|
+
*/
|
|
61
|
+
export function deliveryKey(evt, processId) {
|
|
62
|
+
return !processId || deliveredPerProcess(evt) ? processId : `${processId}:${str(evt.type)}:${randomUUID()}`;
|
|
63
|
+
}
|
|
64
|
+
/** Only a process's exit is consumed by the agent's own wait or poll (TAL-532); its watch events and delegations are not. */
|
|
65
|
+
const isCompletion = (e) => Boolean(e.process_id) && str(e.event?.type ?? 'completion') === 'completion';
|
|
40
66
|
export class CompletionDrain {
|
|
41
67
|
deps;
|
|
42
68
|
timer = null;
|
|
@@ -52,8 +78,28 @@ export class CompletionDrain {
|
|
|
52
78
|
recoveredFor = null;
|
|
53
79
|
recoveryWarnedFor = null;
|
|
54
80
|
lastDrainError = null;
|
|
81
|
+
heldResumed = false;
|
|
82
|
+
drains = new Map();
|
|
83
|
+
/** Admitted wakeups whose release could not be written: never delivered again, and the release is retried. */
|
|
84
|
+
unreleased = new Map();
|
|
85
|
+
/** TAL-576: wakeups held while their session is paused. */
|
|
86
|
+
heldWakeups;
|
|
87
|
+
/** Waiting requires an unadmitted result, not an admitted turn's outstanding ledger acknowledgement. */
|
|
88
|
+
async pendingDelegations(sid) {
|
|
89
|
+
try {
|
|
90
|
+
const session = (await this.deps.store.get(sid)), home = this.ownerHome(session);
|
|
91
|
+
return new Set((await this.heldWakeups.get(sid)).filter((entry) => {
|
|
92
|
+
const key = completionKey(home, entry.event ?? {});
|
|
93
|
+
return Boolean(key) && !completionAccepted(session, key);
|
|
94
|
+
}).map((entry) => str(entry.event?.delegation_id)).filter(Boolean));
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return new Set();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
55
100
|
constructor(deps) {
|
|
56
101
|
this.deps = deps;
|
|
102
|
+
this.heldWakeups = new HeldWakeups(deps.documents);
|
|
57
103
|
}
|
|
58
104
|
start() {
|
|
59
105
|
if (this.timer || this.stopped)
|
|
@@ -107,7 +153,19 @@ export class CompletionDrain {
|
|
|
107
153
|
this.recoveryWarnedFor = describe;
|
|
108
154
|
}
|
|
109
155
|
}
|
|
110
|
-
|
|
156
|
+
// TAL-576: whether or not every profile recovered, the sessions left holding wakeups resume once a sidecar answers.
|
|
157
|
+
if (!this.heldResumed)
|
|
158
|
+
(await this.resumeHeld());
|
|
159
|
+
// The drain is sidecar-wide; an active profile whose home escapes the profiles root (`profileHome` throws) scopes it
|
|
160
|
+
// to the base home instead of stalling every other profile's completions.
|
|
161
|
+
let scope;
|
|
162
|
+
try {
|
|
163
|
+
scope = this.deps.profileHome(this.deps.activeProfile());
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
scope = this.deps.baseHome;
|
|
167
|
+
}
|
|
168
|
+
const { events } = await sidecar.call('process.drain', { profile_home: scope, max_events: 256 });
|
|
111
169
|
let routed = 0;
|
|
112
170
|
const unrouted = [];
|
|
113
171
|
for (const evt of events) {
|
|
@@ -130,19 +188,19 @@ export class CompletionDrain {
|
|
|
130
188
|
}
|
|
131
189
|
return routed;
|
|
132
190
|
}
|
|
133
|
-
resolveTarget(evt) {
|
|
191
|
+
async resolveTarget(evt) {
|
|
134
192
|
const sessionKey = str(evt.session_key).trim();
|
|
135
193
|
const origin = str(evt.origin_ui_session_id).trim();
|
|
136
|
-
const live = (sid) => { if (!sid)
|
|
194
|
+
const live = async (sid) => { if (!sid)
|
|
137
195
|
return ''; try {
|
|
138
|
-
this.deps.store.get(sid, { metadataOnly: true, promote: false, cacheOnMiss: false });
|
|
196
|
+
(await this.deps.store.get(sid, { metadataOnly: true, promote: false, cacheOnMiss: false }));
|
|
139
197
|
return sid;
|
|
140
198
|
}
|
|
141
199
|
catch {
|
|
142
200
|
return '';
|
|
143
201
|
} };
|
|
144
|
-
const resolved = live(sessionKey);
|
|
145
|
-
const owner = live(origin);
|
|
202
|
+
const resolved = (await live(sessionKey));
|
|
203
|
+
const owner = (await live(origin));
|
|
146
204
|
if (!owner)
|
|
147
205
|
return resolved;
|
|
148
206
|
if (resolved && resolved !== owner)
|
|
@@ -156,7 +214,8 @@ export class CompletionDrain {
|
|
|
156
214
|
return false;
|
|
157
215
|
}
|
|
158
216
|
async wakeupPrompt(evt) {
|
|
159
|
-
|
|
217
|
+
const kind = backgroundEventKind(evt);
|
|
218
|
+
if (kind === 'delegation' || kind === 'progress') {
|
|
160
219
|
const sidecar = this.deps.sidecar();
|
|
161
220
|
if (!sidecar)
|
|
162
221
|
return '';
|
|
@@ -169,30 +228,178 @@ export class CompletionDrain {
|
|
|
169
228
|
}
|
|
170
229
|
return (formatWakeupPrompt(evt) ?? '').trim();
|
|
171
230
|
}
|
|
231
|
+
/** The session's owning profile home; a session without a profile belongs to the root profile (`profilesMatch`). */
|
|
232
|
+
ownerHome(session) { return this.deps.profileHome(session.profile ?? 'default'); }
|
|
233
|
+
/** A profile's config; null when it cannot be read. */
|
|
234
|
+
async profileConfig(home) {
|
|
235
|
+
try {
|
|
236
|
+
return (await this.deps.readConfig?.(home)) ?? {};
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/** The owning profile's `delegation.surface_child_process_notifications`; off, the Agent's default, when it cannot be read. */
|
|
243
|
+
async surfacesChildProcesses(sid) {
|
|
244
|
+
let config;
|
|
245
|
+
try {
|
|
246
|
+
config = await this.profileConfig(this.ownerHome((await this.deps.store.get(sid, { metadataOnly: true, promote: false, cacheOnMiss: false }))));
|
|
247
|
+
}
|
|
248
|
+
catch {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
return isDict(config?.delegation) && config.delegation.surface_child_process_notifications === true;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* TAL-907 (Agent `_load_background_notifications_mode`): `HERMES_BACKGROUND_NOTIFICATIONS` from the profile's `.env`
|
|
255
|
+
* (which overrides the shell, as in the Agent) or the server environment, else `display.background_process_notifications`
|
|
256
|
+
* (YAML `false` is off). Only `off` changes Web delivery; null when the setting cannot be read.
|
|
257
|
+
*/
|
|
258
|
+
async notificationsOff(home) {
|
|
259
|
+
let mode;
|
|
260
|
+
try {
|
|
261
|
+
mode = expandDotenv(parseDotenv(readFileSync(join(home, '.env'), 'utf8')), this.deps.env ?? {}).HERMES_BACKGROUND_NOTIFICATIONS?.trim();
|
|
262
|
+
}
|
|
263
|
+
catch (error) {
|
|
264
|
+
if (error.code !== 'ENOENT')
|
|
265
|
+
return null;
|
|
266
|
+
}
|
|
267
|
+
mode ||= this.deps.env?.HERMES_BACKGROUND_NOTIFICATIONS?.trim();
|
|
268
|
+
if (!mode) {
|
|
269
|
+
const config = await this.profileConfig(home);
|
|
270
|
+
if (!config)
|
|
271
|
+
return null;
|
|
272
|
+
mode = isDict(config.display) ? config.display.background_process_notifications : undefined;
|
|
273
|
+
}
|
|
274
|
+
return mode === false || str(mode).trim().toLowerCase() === 'off';
|
|
275
|
+
}
|
|
276
|
+
async isReadOnly(session) { return await this.deps.isReadOnly?.(session) ?? session.read_only; }
|
|
277
|
+
/** Hand durable results back without acknowledging delivery or mutating the canonical session. */
|
|
278
|
+
async relinquish(sid, session, entries, claims = []) {
|
|
279
|
+
try {
|
|
280
|
+
if (!(await this.settleClaims(this.ownerHome(session), 'process.defer_delivery', claims)))
|
|
281
|
+
throw new Error('delivery claim could not be returned');
|
|
282
|
+
const events = entries.flatMap((e) => e.event?.type === 'async_delegation' ? [e.event] : []);
|
|
283
|
+
if (events.length) {
|
|
284
|
+
const sidecar = this.deps.sidecar();
|
|
285
|
+
if (!sidecar)
|
|
286
|
+
throw new Error('sidecar unavailable');
|
|
287
|
+
await sidecar.call('process.requeue', { events });
|
|
288
|
+
}
|
|
289
|
+
this.deferred.delete(sid);
|
|
290
|
+
this.pendingSessions.delete(sid);
|
|
291
|
+
this.retryAttempts.delete(sid);
|
|
292
|
+
const timer = this.retryTimers.get(sid);
|
|
293
|
+
if (timer)
|
|
294
|
+
clearTimeout(timer);
|
|
295
|
+
this.retryTimers.delete(sid);
|
|
296
|
+
await this.release(sid);
|
|
297
|
+
}
|
|
298
|
+
catch (error) {
|
|
299
|
+
for (const entry of entries)
|
|
300
|
+
this.defer(sid, entry);
|
|
301
|
+
this.scheduleRetry(sid);
|
|
302
|
+
this.deps.log(`[webui] WARNING: completion hand-back failed for ${sid}: ${error.message}`);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
172
305
|
/** Python `_process_one`; returns false when the event has no owning WebUI session. */
|
|
173
306
|
async processOne(evt) {
|
|
174
307
|
const processId = str(evt.process_id).trim();
|
|
175
|
-
const sid = this.resolveTarget(evt);
|
|
308
|
+
const sid = (await this.resolveTarget(evt));
|
|
176
309
|
if (!sid)
|
|
177
310
|
return false;
|
|
311
|
+
let owner;
|
|
312
|
+
let home;
|
|
313
|
+
let homeError = '';
|
|
314
|
+
try {
|
|
315
|
+
owner = (await this.deps.store.get(sid));
|
|
316
|
+
}
|
|
317
|
+
catch {
|
|
318
|
+
return false;
|
|
319
|
+
}
|
|
320
|
+
try {
|
|
321
|
+
home = this.ownerHome(owner);
|
|
322
|
+
}
|
|
323
|
+
catch (error) {
|
|
324
|
+
home = '';
|
|
325
|
+
homeError = error.message;
|
|
326
|
+
}
|
|
327
|
+
if (home && (await this.isReadOnly(owner)))
|
|
328
|
+
return false;
|
|
329
|
+
// Reconciliation needs positive profile proof; live events retain the existing admission deferral on home errors.
|
|
330
|
+
if (evt.reconciliation_profile_home && (!home || canonicalHome(str(evt.reconciliation_profile_home)) !== canonicalHome(home)))
|
|
331
|
+
return false;
|
|
332
|
+
if (evt.reconciliation_profile_home && completionAccepted(owner, completionKey(home, evt)))
|
|
333
|
+
return true;
|
|
178
334
|
if (evt.consumed === true)
|
|
179
335
|
return true;
|
|
336
|
+
// TAL-933 (Agent `should_surface_notification`): a subagent's own process notices stay out of the parent chat unless
|
|
337
|
+
// the session's profile opts in. Dropped, not consumed, as in the Agent: an exit nobody read still reaches the parent
|
|
338
|
+
// as the child's `unread_completions`.
|
|
339
|
+
if (evt.child_process === true && !(await this.surfacesChildProcesses(sid)))
|
|
340
|
+
return true;
|
|
180
341
|
const seen = this.seen.get(sid) ?? new Set();
|
|
181
342
|
this.seen.set(sid, seen);
|
|
182
|
-
|
|
343
|
+
// Only a per-process delivery can repeat: a watch event's key is unique, so remembering it would only grow `seen`.
|
|
344
|
+
if (processId && deliveredPerProcess(evt)) {
|
|
345
|
+
if (seen.has(processId))
|
|
346
|
+
return true;
|
|
347
|
+
}
|
|
348
|
+
const prompt = await this.wakeupPrompt(evt);
|
|
349
|
+
if ((await this.isReadOnly(owner))) {
|
|
350
|
+
if (home)
|
|
351
|
+
return false;
|
|
352
|
+
this.defer(sid, { process_id: deliveryKey(evt, processId), wakeup_prompt: prompt, event: evt });
|
|
353
|
+
this.scheduleRetry(sid);
|
|
354
|
+
this.deps.log(`[webui] WARNING: server-side wakeup retained for session ${sid}: ${homeError || 'ownership home unavailable'}; retrying`);
|
|
355
|
+
return true;
|
|
356
|
+
}
|
|
357
|
+
if (evt.reconciliation_profile_home && evt.delegation_id && prompt.includes(str(evt.delegation_id))) {
|
|
358
|
+
// Upgrade a proven pre-receipt Web turn; typed Agent bookkeeping alone never qualifies.
|
|
359
|
+
const previous = owner.messages.find((m) => m._source === 'process_wakeup' && m._turn_id && messageText(m.content) === prompt);
|
|
360
|
+
const turnId = str(previous?._turn_id) || (owner.pending_user_source === 'process_wakeup' && owner.pending_user_message === prompt ? str(owner.active_stream_id) : '');
|
|
361
|
+
if (turnId) {
|
|
362
|
+
const receipts = isDict(owner.extra.completion_acceptances) ? owner.extra.completion_acceptances : {};
|
|
363
|
+
owner.extra.completion_acceptances = { ...receipts, [completionKey(home, evt)]: turnId };
|
|
364
|
+
await this.deps.store.save(owner, { touchUpdatedAt: false });
|
|
365
|
+
return true;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
// The formatter awaits the sidecar; another drain may have retained this event meanwhile.
|
|
369
|
+
if (processId && deliveredPerProcess(evt) && seen.has(processId))
|
|
183
370
|
return true;
|
|
184
|
-
|
|
371
|
+
const entry = { process_id: deliveryKey(evt, processId), wakeup_prompt: prompt, event: evt };
|
|
372
|
+
if (prompt && evt.type === 'async_delegation')
|
|
373
|
+
this.defer(sid, entry);
|
|
374
|
+
if (prompt && evt.type === 'async_delegation' && !evt.task_failure_notice) {
|
|
375
|
+
try {
|
|
376
|
+
// Busy, Stop, sealed and provider-paused entries survive either process restarting.
|
|
377
|
+
await this.heldWakeups.hold(sid, [entry]);
|
|
378
|
+
recordBackgroundUpdate(owner, `delegation:${str(evt.delegation_id)}`, batchUpdate([{ event: evt, prompt }]));
|
|
379
|
+
await this.deps.store.save(owner, { touchUpdatedAt: false });
|
|
380
|
+
}
|
|
381
|
+
catch (error) {
|
|
382
|
+
this.scheduleRetry(sid);
|
|
383
|
+
this.deps.log(`[webui] WARNING: failed to persist delegation wakeup for session ${sid}; retained in memory for retry: ${error.message}`);
|
|
384
|
+
return true;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
if (processId && deliveredPerProcess(evt))
|
|
185
388
|
seen.add(processId);
|
|
186
389
|
this.pendingSessions.add(sid);
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
390
|
+
await this.deps.background?.recordEvent(sid, evt, prompt);
|
|
391
|
+
if (backgroundEventKind(evt) !== 'progress')
|
|
392
|
+
this.emitCoalesced(sid, this.buildPayload(evt, sid, prompt));
|
|
190
393
|
if (!prompt)
|
|
191
394
|
return true;
|
|
192
|
-
if (
|
|
193
|
-
this.
|
|
395
|
+
if (evt.type === 'async_delegation') {
|
|
396
|
+
if (!this.hasActiveTurn(sid))
|
|
397
|
+
await this.drainDeferred(sid);
|
|
398
|
+
}
|
|
399
|
+
else if (this.hasActiveTurn(sid))
|
|
400
|
+
this.defer(sid, entry);
|
|
194
401
|
else
|
|
195
|
-
await this.startWakeup(sid, [
|
|
402
|
+
await this.startWakeup(sid, [entry]);
|
|
196
403
|
return true;
|
|
197
404
|
}
|
|
198
405
|
buildPayload(evt, sid, prompt) {
|
|
@@ -243,21 +450,26 @@ export class CompletionDrain {
|
|
|
243
450
|
this.pendingEmit.set(sid, { payload, timer });
|
|
244
451
|
}
|
|
245
452
|
recordDeferred(sid, processId, prompt, event) {
|
|
246
|
-
|
|
453
|
+
this.defer(sid, { process_id: deliveryKey(event ?? {}, processId), wakeup_prompt: prompt, ...(event ? { event } : {}) });
|
|
454
|
+
}
|
|
455
|
+
/** Re-deferring keeps an entry's delivery identity, so its held copy and this one stay one wakeup. */
|
|
456
|
+
defer(sid, entry) {
|
|
457
|
+
if (!sid || !entry.wakeup_prompt)
|
|
247
458
|
return;
|
|
248
459
|
const entries = this.deferred.get(sid) ?? [];
|
|
249
|
-
if (
|
|
460
|
+
if (entries.some((e) => heldKey(e) === heldKey(entry)))
|
|
250
461
|
return;
|
|
251
|
-
entries.push(
|
|
462
|
+
entries.push(entry);
|
|
252
463
|
this.deferred.set(sid, entries);
|
|
253
464
|
this.pendingSessions.add(sid);
|
|
254
465
|
}
|
|
255
466
|
deferredCount(sid) { return this.deferred.get(sid)?.length ?? 0; }
|
|
256
|
-
|
|
467
|
+
/** Delivering a process's exit consumes it; a watch event leaves the exit to be delivered (TAL-724). */
|
|
468
|
+
async markConsumed(entries) {
|
|
257
469
|
const sidecar = this.deps.sidecar();
|
|
258
470
|
if (!sidecar)
|
|
259
471
|
return;
|
|
260
|
-
for (const pid of
|
|
472
|
+
for (const pid of new Set(entries.filter(isCompletion).map((e) => e.process_id))) {
|
|
261
473
|
try {
|
|
262
474
|
await sidecar.call('process.mark_consumed', { process_id: pid });
|
|
263
475
|
}
|
|
@@ -269,10 +481,12 @@ export class CompletionDrain {
|
|
|
269
481
|
* another consumer delivered (or holds) it, so it leaves the batch; a sidecar failure returns null so the caller keeps
|
|
270
482
|
* every entry pending. Claims are taken at delivery, never while deferred, so a long turn cannot outlive the lease.
|
|
271
483
|
*/
|
|
272
|
-
async claimBatch(home, batched) {
|
|
484
|
+
async claimBatch(home, batched, session) {
|
|
273
485
|
const deliver = [];
|
|
274
486
|
const held = [];
|
|
275
487
|
for (const entry of batched) {
|
|
488
|
+
if ((await this.isReadOnly(session)))
|
|
489
|
+
break;
|
|
276
490
|
if (entry.event?.type !== 'async_delegation') {
|
|
277
491
|
deliver.push(entry);
|
|
278
492
|
continue;
|
|
@@ -282,7 +496,10 @@ export class CompletionDrain {
|
|
|
282
496
|
try {
|
|
283
497
|
if (!sidecar)
|
|
284
498
|
throw new Error('sidecar unavailable');
|
|
285
|
-
|
|
499
|
+
const claim = await sidecar.call('process.claim_delivery', { profile_home: home, event: entry.event, consumer: DELIVERY_CONSUMER });
|
|
500
|
+
if (claim.retryable)
|
|
501
|
+
throw new Error('another consumer holds the pending result');
|
|
502
|
+
claimId = claim.claim_id;
|
|
286
503
|
}
|
|
287
504
|
catch (error) {
|
|
288
505
|
await this.settleClaims(home, 'process.release_delivery', held);
|
|
@@ -305,15 +522,18 @@ export class CompletionDrain {
|
|
|
305
522
|
async settleClaims(home, method, held) {
|
|
306
523
|
const sidecar = this.deps.sidecar();
|
|
307
524
|
if (!sidecar)
|
|
308
|
-
return;
|
|
525
|
+
return held.length === 0;
|
|
526
|
+
let ok = true;
|
|
309
527
|
for (const claim of held) {
|
|
310
528
|
try {
|
|
311
529
|
await sidecar.call(method, { profile_home: home, event: claim.event, claim_id: claim.claim_id });
|
|
312
530
|
}
|
|
313
531
|
catch (error) {
|
|
532
|
+
ok = false;
|
|
314
533
|
this.deps.log(`[webui] WARNING: ${method} failed for ${str(claim.event.delegation_id)}: ${error.message}`);
|
|
315
534
|
}
|
|
316
535
|
}
|
|
536
|
+
return ok;
|
|
317
537
|
}
|
|
318
538
|
scheduleRetry(sid) {
|
|
319
539
|
const attempts = (this.retryAttempts.get(sid) ?? 0) + 1;
|
|
@@ -322,24 +542,159 @@ export class CompletionDrain {
|
|
|
322
542
|
this.deps.log(`[webui] WARNING: server-side wakeup retry budget exhausted for session ${sid}; deferred entries wait for the next turn teardown`);
|
|
323
543
|
return;
|
|
324
544
|
}
|
|
545
|
+
this.scheduleDrain(sid, WAKEUP_RETRY_SECONDS);
|
|
546
|
+
}
|
|
547
|
+
scheduleDrain(sid, delaySeconds) {
|
|
325
548
|
const existing = this.retryTimers.get(sid);
|
|
326
549
|
if (existing)
|
|
327
550
|
clearTimeout(existing);
|
|
328
|
-
const timer = setTimeout(() => { this.retryTimers.delete(sid); void this.drainDeferred(sid); },
|
|
551
|
+
const timer = setTimeout(() => { this.retryTimers.delete(sid); void this.drainDeferred(sid); }, Math.max(0, delaySeconds) * 1000);
|
|
329
552
|
timer.unref();
|
|
330
553
|
this.retryTimers.set(sid, timer);
|
|
331
554
|
}
|
|
555
|
+
/** TAL-576: `usage.pool` for the provider whose pool ran dry, through `poolRecovery`; null when the sidecar cannot say. */
|
|
556
|
+
async poolRecovery(home, session) {
|
|
557
|
+
const sidecar = this.deps.sidecar();
|
|
558
|
+
const pause = session.process_wakeup_pause;
|
|
559
|
+
const provider = str(isDict(pause) ? pause.pool_provider : '').trim() || str(session.model_provider).trim();
|
|
560
|
+
if (!sidecar || !provider)
|
|
561
|
+
return null;
|
|
562
|
+
try {
|
|
563
|
+
return poolRecovery((await sidecar.call('usage.pool', { profile_home: home, provider })).entries, this.deps.now());
|
|
564
|
+
}
|
|
565
|
+
catch {
|
|
566
|
+
return null;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
/** A restarted server resumes every session it left holding wakeups (`startWakeup` drops a deleted session's). */
|
|
570
|
+
async resumeHeld() {
|
|
571
|
+
let sids;
|
|
572
|
+
try {
|
|
573
|
+
sids = (await this.heldWakeups.sessions());
|
|
574
|
+
}
|
|
575
|
+
catch (error) {
|
|
576
|
+
this.deps.log(`[webui] WARNING: held wakeups unreadable; retrying: ${error.message}`);
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
this.heldResumed = true;
|
|
580
|
+
for (const sid of sids)
|
|
581
|
+
void this.drainDeferred(sid);
|
|
582
|
+
}
|
|
583
|
+
async held(sid) {
|
|
584
|
+
if (this.unreleased.has(sid))
|
|
585
|
+
(await this.release(sid, []));
|
|
586
|
+
const done = new Set((this.unreleased.get(sid) ?? []).map(heldKey));
|
|
587
|
+
try {
|
|
588
|
+
return (await this.heldWakeups.get(sid)).filter((e) => !done.has(heldKey(e)));
|
|
589
|
+
}
|
|
590
|
+
catch (error) {
|
|
591
|
+
// An unreadable store is unknown, not empty: recheck later rather than leave the session dormant.
|
|
592
|
+
this.scheduleDrain(sid, HELD_RECHECK_SECONDS);
|
|
593
|
+
this.deps.log(`[webui] WARNING: held wakeups unreadable for session ${sid}; retrying: ${error.message}`);
|
|
594
|
+
return [];
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
/** A session whose file is gone was deleted; any other load failure keeps its wakeups. */
|
|
598
|
+
async deleted(sid, error) {
|
|
599
|
+
return error instanceof SessionNotFound && !await this.deps.store.exists(sid);
|
|
600
|
+
}
|
|
601
|
+
/** Admitted or settled wakeups (every one, with none given) leave the held file. */
|
|
602
|
+
async release(sid, entries) {
|
|
603
|
+
// Earlier releases that could not be written go with this one.
|
|
604
|
+
const batch = entries ? mergeWakeups([...(this.unreleased.get(sid) ?? [])], entries) : undefined;
|
|
605
|
+
try {
|
|
606
|
+
await this.heldWakeups.release(sid, batch);
|
|
607
|
+
this.unreleased.delete(sid);
|
|
608
|
+
}
|
|
609
|
+
catch (error) {
|
|
610
|
+
if (batch)
|
|
611
|
+
this.unreleased.set(sid, batch);
|
|
612
|
+
this.deps.log(`[webui] WARNING: failed to release held wakeups for session ${sid}; they are not delivered again: ${error.message}`);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
async saveSession(sid, session) {
|
|
616
|
+
try {
|
|
617
|
+
(await this.deps.store.save(session, { touchUpdatedAt: false }));
|
|
618
|
+
}
|
|
619
|
+
catch (error) {
|
|
620
|
+
this.deps.log(`[webui] WARNING: failed to save wakeup pause for session ${sid}: ${error.message}`);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
/**
|
|
624
|
+
* TAL-576: while the provider has no usable credentials no wakeup turn starts. The entries are held until a turn
|
|
625
|
+
* admits them, and a timer rechecks the pause at the pool's earliest retry deadline, at least every five minutes.
|
|
626
|
+
* Returns whether the wakeup is handled here (held, or dropped with its deleted session).
|
|
627
|
+
*/
|
|
628
|
+
async holdWhilePaused(sid, session, home, batched) {
|
|
629
|
+
if ((await this.isReadOnly(session))) {
|
|
630
|
+
await this.relinquish(sid, session, batched);
|
|
631
|
+
return true;
|
|
632
|
+
}
|
|
633
|
+
const pause = session.process_wakeup_pause;
|
|
634
|
+
if (!wakeupPaused(session, home, this.deps.configPath?.(home))) {
|
|
635
|
+
if (pause !== session.process_wakeup_pause)
|
|
636
|
+
(await this.saveSession(sid, session));
|
|
637
|
+
return false;
|
|
638
|
+
}
|
|
639
|
+
const recovery = await this.poolRecovery(home, session);
|
|
640
|
+
// A turn that succeeded or a provider switched during the lookup lifted the pause already.
|
|
641
|
+
// A deleted session owns no turn; a transient load failure holds the wakeups for the next recheck.
|
|
642
|
+
let current = null;
|
|
643
|
+
try {
|
|
644
|
+
current = (await this.deps.store.get(sid));
|
|
645
|
+
}
|
|
646
|
+
catch (error) {
|
|
647
|
+
if ((await this.deleted(sid, error))) {
|
|
648
|
+
(await this.release(sid));
|
|
649
|
+
return true;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
if (current) {
|
|
653
|
+
if ((await this.isReadOnly(current))) {
|
|
654
|
+
await this.relinquish(sid, current, batched);
|
|
655
|
+
return true;
|
|
656
|
+
}
|
|
657
|
+
const before = current.process_wakeup_pause;
|
|
658
|
+
if (recovery === true)
|
|
659
|
+
current.process_wakeup_pause = null;
|
|
660
|
+
if (recovery === true || !wakeupPaused(current, home, this.deps.configPath?.(home))) {
|
|
661
|
+
if (before !== current.process_wakeup_pause)
|
|
662
|
+
(await this.saveSession(sid, current));
|
|
663
|
+
return false;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
try {
|
|
667
|
+
(await this.heldWakeups.hold(sid, batched));
|
|
668
|
+
}
|
|
669
|
+
catch (error) {
|
|
670
|
+
for (const e of batched)
|
|
671
|
+
this.defer(sid, e);
|
|
672
|
+
this.deps.log(`[webui] WARNING: failed to persist held wakeups for session ${sid}; kept in memory: ${error.message}`);
|
|
673
|
+
}
|
|
674
|
+
this.retryAttempts.delete(sid);
|
|
675
|
+
this.scheduleDrain(sid, typeof recovery === 'number' ? Math.min(recovery - this.deps.now(), HELD_RECHECK_SECONDS) : HELD_RECHECK_SECONDS);
|
|
676
|
+
this.deps.log(`[webui] server-side wakeup paused for session ${sid}: provider credential pool is empty`);
|
|
677
|
+
return true;
|
|
678
|
+
}
|
|
332
679
|
/** Python `_start_server_side_wakeup_turn`: one batched turn; 409 re-defers, other failures re-defer with a timed retry. */
|
|
333
|
-
async startWakeup(sid,
|
|
680
|
+
async startWakeup(sid, wakeups) {
|
|
681
|
+
let batched = wakeups;
|
|
334
682
|
const redefer = (entries) => { for (const e of entries)
|
|
335
|
-
this.
|
|
683
|
+
this.defer(sid, e); };
|
|
336
684
|
let session;
|
|
337
685
|
try {
|
|
338
|
-
session = this.deps.store.get(sid);
|
|
686
|
+
session = (await this.deps.store.get(sid));
|
|
339
687
|
}
|
|
340
|
-
catch {
|
|
688
|
+
catch (error) {
|
|
689
|
+
// A deleted session owns no turn: its wakeups, held ones included, go with it.
|
|
690
|
+
if ((await this.deleted(sid, error))) {
|
|
691
|
+
(await this.release(sid));
|
|
692
|
+
this.deps.log(`[webui] server-side wakeup dropped for deleted session ${sid}`);
|
|
693
|
+
return false;
|
|
694
|
+
}
|
|
341
695
|
redefer(batched);
|
|
342
|
-
this.
|
|
696
|
+
this.scheduleRetry(sid);
|
|
697
|
+
this.deps.log(`[webui] WARNING: server-side wakeup retained for session ${sid}: session unavailable; retrying`);
|
|
343
698
|
return false;
|
|
344
699
|
}
|
|
345
700
|
if (session.pre_compression_snapshot) {
|
|
@@ -348,17 +703,75 @@ export class CompletionDrain {
|
|
|
348
703
|
return false;
|
|
349
704
|
}
|
|
350
705
|
// TAL-534: the delegation's ledger row lives in the session's own profile, whichever profile is active now.
|
|
351
|
-
|
|
352
|
-
|
|
706
|
+
let home;
|
|
707
|
+
try {
|
|
708
|
+
home = this.ownerHome(session);
|
|
709
|
+
}
|
|
710
|
+
catch (error) {
|
|
711
|
+
redefer(batched);
|
|
712
|
+
this.deps.log(`[webui] WARNING: server-side wakeup retained for session ${sid}: ${error.message}`);
|
|
713
|
+
return false;
|
|
714
|
+
}
|
|
715
|
+
if ((await this.isReadOnly(session))) {
|
|
716
|
+
await this.relinquish(sid, session, batched);
|
|
717
|
+
return false;
|
|
718
|
+
}
|
|
719
|
+
const accepted = batched.filter((e) => completionAccepted(session, completionKey(home, e.event ?? {})));
|
|
720
|
+
if (accepted.length) {
|
|
721
|
+
// A crash may have saved admission before acknowledging the Agent. Finish that handshake without a new turn.
|
|
722
|
+
const claims = await this.claimBatch(home, accepted, session);
|
|
723
|
+
if (claims && (await this.isReadOnly(session))) {
|
|
724
|
+
await this.relinquish(sid, session, batched, claims.held);
|
|
725
|
+
return false;
|
|
726
|
+
}
|
|
727
|
+
if (!claims || !(await this.settleClaims(home, 'process.complete_delivery', claims.held))) {
|
|
728
|
+
redefer(batched);
|
|
729
|
+
this.scheduleRetry(sid);
|
|
730
|
+
return false;
|
|
731
|
+
}
|
|
732
|
+
await this.release(sid, accepted);
|
|
733
|
+
batched = batched.filter((e) => !accepted.includes(e));
|
|
734
|
+
}
|
|
735
|
+
if (!batched.length)
|
|
736
|
+
return false;
|
|
737
|
+
// TAL-907: `off` mutes process-driven wakeups at delivery, so a deferred or held wakeup follows the current setting; the
|
|
738
|
+
// drained event's record and status row are its whole delivery. A subagent result is not a process notification and
|
|
739
|
+
// still lands, as in the Agent. A setting that cannot be read retains the wakeups rather than start a turn.
|
|
740
|
+
const muted = batched.filter((e) => e.event?.type !== 'async_delegation');
|
|
741
|
+
if (muted.length) {
|
|
742
|
+
const off = await this.notificationsOff(home);
|
|
743
|
+
if (off === null) {
|
|
744
|
+
redefer(batched);
|
|
745
|
+
this.scheduleRetry(sid);
|
|
746
|
+
this.deps.log(`[webui] WARNING: server-side wakeup retained for session ${sid}: background_process_notifications is unreadable; retrying`);
|
|
747
|
+
return false;
|
|
748
|
+
}
|
|
749
|
+
if (off) {
|
|
750
|
+
await this.release(sid, muted);
|
|
751
|
+
batched = batched.filter((e) => !muted.includes(e));
|
|
752
|
+
if (!batched.length) {
|
|
753
|
+
this.retryAttempts.delete(sid);
|
|
754
|
+
return false;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
if (await this.holdWhilePaused(sid, session, home, batched))
|
|
759
|
+
return false;
|
|
760
|
+
const claimed = await this.claimBatch(home, batched, session);
|
|
353
761
|
if (!claimed) {
|
|
354
762
|
redefer(batched);
|
|
355
763
|
this.scheduleRetry(sid);
|
|
356
764
|
return false;
|
|
357
765
|
}
|
|
358
766
|
const { deliver, held } = claimed;
|
|
767
|
+
if ((await this.isReadOnly(session))) {
|
|
768
|
+
await this.relinquish(sid, session, batched, held);
|
|
769
|
+
return false;
|
|
770
|
+
}
|
|
359
771
|
// Entries another consumer already delivered are done here too.
|
|
360
772
|
if (!deliver.length) {
|
|
361
|
-
await this.
|
|
773
|
+
(await this.release(sid, batched));
|
|
774
|
+
await this.markConsumed(batched);
|
|
362
775
|
return true;
|
|
363
776
|
}
|
|
364
777
|
// A wakeup that does not start hands its claims back, so those rows stay pending for the retry or the next restart.
|
|
@@ -366,7 +779,7 @@ export class CompletionDrain {
|
|
|
366
779
|
const prompt = deliver.length === 1 ? deliver[0].wakeup_prompt : deliver.map((e) => e.wakeup_prompt).join('\n\n');
|
|
367
780
|
let resp;
|
|
368
781
|
try {
|
|
369
|
-
resp = this.deps.startTurn(session, prompt);
|
|
782
|
+
resp = await this.deps.startTurn(session, prompt, deliver.map((e) => completionKey(home, e.event ?? {})).filter(Boolean), batchUpdate(deliver.map((e) => ({ event: e.event ?? {}, prompt: e.wakeup_prompt }))));
|
|
370
783
|
}
|
|
371
784
|
catch (error) {
|
|
372
785
|
await giveBack();
|
|
@@ -374,9 +787,16 @@ export class CompletionDrain {
|
|
|
374
787
|
this.deps.log(`[webui] WARNING: server-side wakeup turn raised for session ${sid}: ${error.message}`);
|
|
375
788
|
return false;
|
|
376
789
|
}
|
|
790
|
+
if ((await this.isReadOnly(session))) {
|
|
791
|
+
await this.relinquish(sid, session, batched, held);
|
|
792
|
+
return false;
|
|
793
|
+
}
|
|
377
794
|
const status = resp._status ?? (resp.stream_id ? 200 : 500);
|
|
795
|
+
// A busy session redelivers at its turn teardown; a stale runtime admits no turn, so it is retried on a timer (TAL-577).
|
|
378
796
|
if (status === 409) {
|
|
379
797
|
await giveBack('process.defer_delivery');
|
|
798
|
+
if (resp.retryable)
|
|
799
|
+
this.scheduleRetry(sid);
|
|
380
800
|
return false;
|
|
381
801
|
}
|
|
382
802
|
if (status >= 400) {
|
|
@@ -387,8 +807,14 @@ export class CompletionDrain {
|
|
|
387
807
|
}
|
|
388
808
|
this.retryAttempts.delete(sid);
|
|
389
809
|
recordBackgroundUpdate(session, str(resp.stream_id), batchUpdate(deliver.map((e) => ({ event: e.event ?? {}, prompt: e.wakeup_prompt }))));
|
|
390
|
-
await this.
|
|
391
|
-
await this.
|
|
810
|
+
await this.saveSession(sid, session);
|
|
811
|
+
if (await this.settleClaims(home, 'process.complete_delivery', held))
|
|
812
|
+
(await this.release(sid, batched));
|
|
813
|
+
else {
|
|
814
|
+
redefer(deliver);
|
|
815
|
+
this.scheduleRetry(sid);
|
|
816
|
+
}
|
|
817
|
+
await this.markConsumed(batched);
|
|
392
818
|
this.deps.log(`[webui] server-side wakeup turn started for session ${sid} (stream_id=${str(resp.stream_id)})`);
|
|
393
819
|
return true;
|
|
394
820
|
}
|
|
@@ -399,7 +825,7 @@ export class CompletionDrain {
|
|
|
399
825
|
* A failed check delivers everything rather than lose a result.
|
|
400
826
|
*/
|
|
401
827
|
async alreadyConsumed(entries) {
|
|
402
|
-
const completions = entries.filter(
|
|
828
|
+
const completions = entries.filter(isCompletion);
|
|
403
829
|
const sidecar = this.deps.sidecar();
|
|
404
830
|
if (!completions.length || !sidecar)
|
|
405
831
|
return new Set();
|
|
@@ -411,20 +837,31 @@ export class CompletionDrain {
|
|
|
411
837
|
return new Set();
|
|
412
838
|
}
|
|
413
839
|
}
|
|
414
|
-
/**
|
|
415
|
-
|
|
840
|
+
/**
|
|
841
|
+
* Python `drain_deferred_wakeups_for_session`: turn-teardown idle hook; only the last active stream's teardown fires.
|
|
842
|
+
* TAL-576: one drain per session at a time, so two never copy the same held wakeups before either admits them.
|
|
843
|
+
*/
|
|
844
|
+
drainDeferred(sid) {
|
|
845
|
+
const run = (this.drains.get(sid) ?? Promise.resolve(0)).catch(() => 0).then(async () => (await this.drainDeferredNow(sid)));
|
|
846
|
+
this.drains.set(sid, run);
|
|
847
|
+
void run.finally(() => { if (this.drains.get(sid) === run)
|
|
848
|
+
this.drains.delete(sid); }).catch(() => undefined);
|
|
849
|
+
return run;
|
|
850
|
+
}
|
|
851
|
+
async drainDeferredNow(sid) {
|
|
416
852
|
if (!sid || this.hasActiveTurn(sid))
|
|
417
853
|
return 0;
|
|
418
|
-
const entries = this.deferred.get(sid);
|
|
419
|
-
if (!entries
|
|
854
|
+
const entries = mergeWakeups([...(this.deferred.get(sid) ?? [])], (await this.held(sid)));
|
|
855
|
+
if (!entries.length)
|
|
420
856
|
return 0;
|
|
421
857
|
this.deferred.delete(sid);
|
|
422
858
|
this.pendingSessions.delete(sid);
|
|
423
859
|
const prompted = entries.filter((e) => e.wakeup_prompt.trim());
|
|
424
860
|
const held = await this.alreadyConsumed(prompted);
|
|
425
861
|
if (held.size) {
|
|
862
|
+
await this.release(sid, [...held]);
|
|
426
863
|
const ids = [...held].map((e) => e.process_id);
|
|
427
|
-
await this.markConsumed(
|
|
864
|
+
await this.markConsumed([...held]);
|
|
428
865
|
this.deps.log(`[webui] dropped ${String(held.size)} deferred wakeup(s) already consumed by the agent's own turn for session ${sid}: ${ids.join(', ')}`);
|
|
429
866
|
}
|
|
430
867
|
const pending = prompted.filter((e) => !held.has(e));
|
|
@@ -437,7 +874,7 @@ export class CompletionDrain {
|
|
|
437
874
|
for (const entry of pending) {
|
|
438
875
|
const size = entry.wakeup_prompt.length;
|
|
439
876
|
if (batch.length && total + size > WAKEUP_BATCH_MAX_CHARS) {
|
|
440
|
-
this.
|
|
877
|
+
this.defer(sid, entry);
|
|
441
878
|
continue;
|
|
442
879
|
}
|
|
443
880
|
batch.push(entry);
|