visionclaw 0.1.218 → 0.1.219-dev.codex-issue-2805-worker-runtime.1
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/dist/agent/api-proxy.d.ts +0 -16
- package/dist/agent/api-proxy.d.ts.map +1 -1
- package/dist/agent/api-proxy.js +9 -8
- package/dist/agent/api-proxy.js.map +1 -1
- package/dist/agent/browser-launcher.d.ts +3 -0
- package/dist/agent/browser-launcher.d.ts.map +1 -1
- package/dist/agent/browser-launcher.js +101 -43
- package/dist/agent/browser-launcher.js.map +1 -1
- package/dist/agent/coding-conventions.d.ts +8 -0
- package/dist/agent/coding-conventions.d.ts.map +1 -0
- package/dist/agent/coding-conventions.js +19 -0
- package/dist/agent/coding-conventions.js.map +1 -0
- package/dist/agent/command-handlers.d.ts.map +1 -1
- package/dist/agent/command-handlers.js +4 -16
- package/dist/agent/command-handlers.js.map +1 -1
- package/dist/agent/context-action-restart-fallback.d.ts.map +1 -1
- package/dist/agent/context-action-restart-fallback.js +9 -3
- package/dist/agent/context-action-restart-fallback.js.map +1 -1
- package/dist/agent/context-refresh.d.ts.map +1 -1
- package/dist/agent/context-refresh.js +0 -7
- package/dist/agent/context-refresh.js.map +1 -1
- package/dist/agent/context.d.ts +2 -4
- package/dist/agent/context.d.ts.map +1 -1
- package/dist/agent/context.js +12 -21
- package/dist/agent/context.js.map +1 -1
- package/dist/agent/engine-fallback.d.ts +0 -35
- package/dist/agent/engine-fallback.d.ts.map +1 -1
- package/dist/agent/engine-fallback.js +4 -3
- package/dist/agent/engine-fallback.js.map +1 -1
- package/dist/agent/engine-switch.d.ts +19 -38
- package/dist/agent/engine-switch.d.ts.map +1 -1
- package/dist/agent/engine-switch.js +46 -111
- package/dist/agent/engine-switch.js.map +1 -1
- package/dist/agent/engines/browser-tool-policy.d.ts +12 -1
- package/dist/agent/engines/browser-tool-policy.d.ts.map +1 -1
- package/dist/agent/engines/browser-tool-policy.js +17 -2
- package/dist/agent/engines/browser-tool-policy.js.map +1 -1
- package/dist/agent/engines/claude/executor-shell-groups.d.ts +11 -0
- package/dist/agent/engines/claude/executor-shell-groups.d.ts.map +1 -0
- package/dist/agent/engines/claude/executor-shell-groups.js +22 -0
- package/dist/agent/engines/claude/executor-shell-groups.js.map +1 -0
- package/dist/agent/engines/claude/session.d.ts +13 -4
- package/dist/agent/engines/claude/session.d.ts.map +1 -1
- package/dist/agent/engines/claude/session.js +165 -84
- package/dist/agent/engines/claude/session.js.map +1 -1
- package/dist/agent/engines/pi/shared/usage.d.ts +5 -0
- package/dist/agent/engines/pi/shared/usage.d.ts.map +1 -1
- package/dist/agent/engines/pi/shared/usage.js +22 -3
- package/dist/agent/engines/pi/shared/usage.js.map +1 -1
- package/dist/agent/engines/pi/tools.d.ts +3 -10
- package/dist/agent/engines/pi/tools.d.ts.map +1 -1
- package/dist/agent/engines/pi/tools.js +6 -17
- package/dist/agent/engines/pi/tools.js.map +1 -1
- package/dist/agent/engines/pi-coding/executor-shell.d.ts +4 -0
- package/dist/agent/engines/pi-coding/executor-shell.d.ts.map +1 -0
- package/dist/agent/engines/pi-coding/executor-shell.js +175 -0
- package/dist/agent/engines/pi-coding/executor-shell.js.map +1 -0
- package/dist/agent/engines/pi-coding/session.d.ts +4 -4
- package/dist/agent/engines/pi-coding/session.d.ts.map +1 -1
- package/dist/agent/engines/pi-coding/session.js +118 -66
- package/dist/agent/engines/pi-coding/session.js.map +1 -1
- package/dist/agent/engines/pi-coding/tools.d.ts +2 -5
- package/dist/agent/engines/pi-coding/tools.d.ts.map +1 -1
- package/dist/agent/engines/pi-coding/tools.js +7 -5
- package/dist/agent/engines/pi-coding/tools.js.map +1 -1
- package/dist/agent/engines/session-types.d.ts +8 -8
- package/dist/agent/engines/session-types.d.ts.map +1 -1
- package/dist/agent/external-context/interrupt.d.ts +0 -2
- package/dist/agent/external-context/interrupt.d.ts.map +1 -1
- package/dist/agent/external-context/interrupt.js +0 -1
- package/dist/agent/external-context/interrupt.js.map +1 -1
- package/dist/agent/external-context/registry.d.ts +0 -2
- package/dist/agent/external-context/registry.d.ts.map +1 -1
- package/dist/agent/external-context/registry.js +2 -4
- package/dist/agent/external-context/registry.js.map +1 -1
- package/dist/agent/external-context/runtime.d.ts.map +1 -1
- package/dist/agent/external-context/runtime.js +15 -14
- package/dist/agent/external-context/runtime.js.map +1 -1
- package/dist/agent/external-context/types.d.ts +0 -2
- package/dist/agent/external-context/types.d.ts.map +1 -1
- package/dist/agent/fast-responder.d.ts +4 -20
- package/dist/agent/fast-responder.d.ts.map +1 -1
- package/dist/agent/fast-responder.js +28 -42
- package/dist/agent/fast-responder.js.map +1 -1
- package/dist/agent/interrupt-handler.d.ts +0 -6
- package/dist/agent/interrupt-handler.d.ts.map +1 -1
- package/dist/agent/interrupt-handler.js +5 -47
- package/dist/agent/interrupt-handler.js.map +1 -1
- package/dist/agent/lab-run-system-prompt.d.ts.map +1 -1
- package/dist/agent/lab-run-system-prompt.js +4 -1
- package/dist/agent/lab-run-system-prompt.js.map +1 -1
- package/dist/agent/lifecycle-trace.d.ts.map +1 -1
- package/dist/agent/lifecycle-trace.js +6 -5
- package/dist/agent/lifecycle-trace.js.map +1 -1
- package/dist/agent/loop.d.ts +8 -2
- package/dist/agent/loop.d.ts.map +1 -1
- package/dist/agent/loop.js +291 -156
- package/dist/agent/loop.js.map +1 -1
- package/dist/agent/memory-protocol.d.ts +2 -2
- package/dist/agent/memory-protocol.d.ts.map +1 -1
- package/dist/agent/memory-protocol.js +3 -15
- package/dist/agent/memory-protocol.js.map +1 -1
- package/dist/agent/memory-store.d.ts +58 -0
- package/dist/agent/memory-store.d.ts.map +1 -0
- package/dist/agent/memory-store.js +152 -0
- package/dist/agent/memory-store.js.map +1 -0
- package/dist/agent/model-provider.d.ts +18 -5
- package/dist/agent/model-provider.d.ts.map +1 -1
- package/dist/agent/model-provider.js +58 -18
- package/dist/agent/model-provider.js.map +1 -1
- package/dist/agent/nightly-maintenance/dreaming-batch.d.ts +184 -0
- package/dist/agent/nightly-maintenance/dreaming-batch.d.ts.map +1 -0
- package/dist/agent/nightly-maintenance/dreaming-batch.js +192 -0
- package/dist/agent/nightly-maintenance/dreaming-batch.js.map +1 -0
- package/dist/agent/nightly-maintenance/dreaming-files.d.ts +48 -0
- package/dist/agent/nightly-maintenance/dreaming-files.d.ts.map +1 -0
- package/dist/agent/nightly-maintenance/dreaming-files.js +109 -0
- package/dist/agent/nightly-maintenance/dreaming-files.js.map +1 -0
- package/dist/agent/nightly-maintenance/dreaming-ledger.d.ts +62 -0
- package/dist/agent/nightly-maintenance/dreaming-ledger.d.ts.map +1 -0
- package/dist/agent/nightly-maintenance/dreaming-ledger.js +146 -0
- package/dist/agent/nightly-maintenance/dreaming-ledger.js.map +1 -0
- package/dist/agent/nightly-maintenance/dreaming-planner.d.ts +86 -0
- package/dist/agent/nightly-maintenance/dreaming-planner.d.ts.map +1 -0
- package/dist/agent/nightly-maintenance/dreaming-planner.js +304 -0
- package/dist/agent/nightly-maintenance/dreaming-planner.js.map +1 -0
- package/dist/agent/nightly-maintenance/dreaming-runner.d.ts +93 -0
- package/dist/agent/nightly-maintenance/dreaming-runner.d.ts.map +1 -0
- package/dist/agent/nightly-maintenance/dreaming-runner.js +156 -0
- package/dist/agent/nightly-maintenance/dreaming-runner.js.map +1 -0
- package/dist/agent/nightly-maintenance/dreaming-sources.d.ts +115 -0
- package/dist/agent/nightly-maintenance/dreaming-sources.d.ts.map +1 -0
- package/dist/agent/nightly-maintenance/dreaming-sources.js +270 -0
- package/dist/agent/nightly-maintenance/dreaming-sources.js.map +1 -0
- package/dist/agent/nightly-maintenance/index.d.ts +28 -8
- package/dist/agent/nightly-maintenance/index.d.ts.map +1 -1
- package/dist/agent/nightly-maintenance/index.js +42 -15
- package/dist/agent/nightly-maintenance/index.js.map +1 -1
- package/dist/agent/nightly-maintenance/skill-learning-gate.js +1 -1
- package/dist/agent/nightly-maintenance/skill-learning-gate.js.map +1 -1
- package/dist/agent/nightly-maintenance/vocabulary-processor.d.ts +1 -1
- package/dist/agent/nightly-maintenance/vocabulary-processor.d.ts.map +1 -1
- package/dist/agent/owner-channel-resolver.d.ts +2 -0
- package/dist/agent/owner-channel-resolver.d.ts.map +1 -1
- package/dist/agent/owner-channel-resolver.js +4 -0
- package/dist/agent/owner-channel-resolver.js.map +1 -1
- package/dist/agent/product-identity.d.ts +5 -4
- package/dist/agent/product-identity.d.ts.map +1 -1
- package/dist/agent/product-identity.js +7 -6
- package/dist/agent/product-identity.js.map +1 -1
- package/dist/agent/public-activity.js +1 -1
- package/dist/agent/public-activity.js.map +1 -1
- package/dist/agent/runtime-context.d.ts +27 -0
- package/dist/agent/runtime-context.d.ts.map +1 -0
- package/dist/agent/runtime-context.js +60 -0
- package/dist/agent/runtime-context.js.map +1 -0
- package/dist/agent/runtime-disclosure-policy.d.ts +6 -0
- package/dist/agent/runtime-disclosure-policy.d.ts.map +1 -0
- package/dist/agent/runtime-disclosure-policy.js +16 -0
- package/dist/agent/runtime-disclosure-policy.js.map +1 -0
- package/dist/agent/runtime-surface.d.ts +15 -4
- package/dist/agent/runtime-surface.d.ts.map +1 -1
- package/dist/agent/runtime-surface.js +0 -1
- package/dist/agent/runtime-surface.js.map +1 -1
- package/dist/agent/session-manager.d.ts +30 -126
- package/dist/agent/session-manager.d.ts.map +1 -1
- package/dist/agent/session-manager.js +60 -484
- package/dist/agent/session-manager.js.map +1 -1
- package/dist/agent/state.d.ts +42 -2
- package/dist/agent/state.d.ts.map +1 -1
- package/dist/agent/state.js +21 -11
- package/dist/agent/state.js.map +1 -1
- package/dist/agent/stream-handler.d.ts +6 -13
- package/dist/agent/stream-handler.d.ts.map +1 -1
- package/dist/agent/stream-handler.js +8 -62
- package/dist/agent/stream-handler.js.map +1 -1
- package/dist/agent/system-prompt.d.ts +2 -0
- package/dist/agent/system-prompt.d.ts.map +1 -1
- package/dist/agent/system-prompt.js +21 -20
- package/dist/agent/system-prompt.js.map +1 -1
- package/dist/agent/tool-usage.d.ts.map +1 -1
- package/dist/agent/tool-usage.js +0 -1
- package/dist/agent/tool-usage.js.map +1 -1
- package/dist/agent/transcript/transcript-backfill.js +3 -3
- package/dist/agent/transcript/transcript-backfill.js.map +1 -1
- package/dist/agent/transcript/transcript-indexer.d.ts +3 -31
- package/dist/agent/transcript/transcript-indexer.d.ts.map +1 -1
- package/dist/agent/transcript/transcript-indexer.js +58 -57
- package/dist/agent/transcript/transcript-indexer.js.map +1 -1
- package/dist/agent/transcript-parsers/trivial-tools.d.ts.map +1 -1
- package/dist/agent/transcript-parsers/trivial-tools.js +0 -2
- package/dist/agent/transcript-parsers/trivial-tools.js.map +1 -1
- package/dist/agent/transcript-parsers/types.d.ts +1 -1
- package/dist/agent/transcript-summarizer.d.ts +14 -0
- package/dist/agent/transcript-summarizer.d.ts.map +1 -1
- package/dist/agent/transcript-summarizer.js +69 -45
- package/dist/agent/transcript-summarizer.js.map +1 -1
- package/dist/agent/usage/usage-report-queue.d.ts.map +1 -1
- package/dist/agent/usage/usage-report-queue.js +53 -52
- package/dist/agent/usage/usage-report-queue.js.map +1 -1
- package/dist/agent/usage/usage-report-types.d.ts +1 -1
- package/dist/agent/usage/usage-report-types.d.ts.map +1 -1
- package/dist/agent/vocabulary-glossary.d.ts +3 -3
- package/dist/agent/wake-cycle-runner.d.ts +22 -17
- package/dist/agent/wake-cycle-runner.d.ts.map +1 -1
- package/dist/agent/wake-cycle-runner.js +190 -320
- package/dist/agent/wake-cycle-runner.js.map +1 -1
- package/dist/builtin-skills/owner-manual/SKILL.md +2 -2
- package/dist/calendar/occurrence-ownership.d.ts.map +1 -1
- package/dist/calendar/occurrence-ownership.js +6 -5
- package/dist/calendar/occurrence-ownership.js.map +1 -1
- package/dist/calendar/scheduler.d.ts.map +1 -1
- package/dist/calendar/scheduler.js +4 -3
- package/dist/calendar/scheduler.js.map +1 -1
- package/dist/channels/interface.d.ts +8 -2
- package/dist/channels/interface.d.ts.map +1 -1
- package/dist/channels/interface.js +8 -1
- package/dist/channels/interface.js.map +1 -1
- package/dist/channels/manager.d.ts +12 -0
- package/dist/channels/manager.d.ts.map +1 -1
- package/dist/channels/manager.js +97 -8
- package/dist/channels/manager.js.map +1 -1
- package/dist/channels/queue.d.ts.map +1 -1
- package/dist/channels/queue.js +8 -0
- package/dist/channels/queue.js.map +1 -1
- package/dist/channels/telegram.d.ts.map +1 -1
- package/dist/channels/telegram.js +28 -2
- package/dist/channels/telegram.js.map +1 -1
- package/dist/channels/tui.d.ts +14 -1
- package/dist/channels/tui.d.ts.map +1 -1
- package/dist/channels/tui.js +64 -2
- package/dist/channels/tui.js.map +1 -1
- package/dist/channels/unavailable-target.d.ts +20 -0
- package/dist/channels/unavailable-target.d.ts.map +1 -0
- package/dist/channels/unavailable-target.js +82 -0
- package/dist/channels/unavailable-target.js.map +1 -0
- package/dist/cli/index.d.ts +2 -2
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +22 -53
- package/dist/cli/index.js.map +1 -1
- package/dist/config/index.d.ts +13 -7
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +51 -64
- package/dist/config/index.js.map +1 -1
- package/dist/config/types.d.ts +28 -7
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js +22 -20
- package/dist/config/types.js.map +1 -1
- package/dist/conversations/lazy-runtime.d.ts +5 -0
- package/dist/conversations/lazy-runtime.d.ts.map +1 -0
- package/dist/conversations/lazy-runtime.js +12 -0
- package/dist/conversations/lazy-runtime.js.map +1 -0
- package/dist/conversations/runtime.d.ts +17 -0
- package/dist/conversations/runtime.d.ts.map +1 -0
- package/dist/conversations/runtime.js +92 -0
- package/dist/conversations/runtime.js.map +1 -0
- package/dist/conversations/scheduler.d.ts +57 -0
- package/dist/conversations/scheduler.d.ts.map +1 -0
- package/dist/conversations/scheduler.js +175 -0
- package/dist/conversations/scheduler.js.map +1 -0
- package/dist/data-processing/pipeline.d.ts +0 -2
- package/dist/data-processing/pipeline.d.ts.map +1 -1
- package/dist/data-processing/pipeline.js +19 -24
- package/dist/data-processing/pipeline.js.map +1 -1
- package/dist/data-processing/restructure.d.ts +0 -2
- package/dist/data-processing/restructure.d.ts.map +1 -1
- package/dist/data-processing/restructure.js +6 -9
- package/dist/data-processing/restructure.js.map +1 -1
- package/dist/data-processing/types.d.ts +2 -9
- package/dist/data-processing/types.d.ts.map +1 -1
- package/dist/data-processing/types.js +2 -13
- package/dist/data-processing/types.js.map +1 -1
- package/dist/email/email-route-store.d.ts.map +1 -1
- package/dist/email/email-route-store.js +6 -5
- package/dist/email/email-route-store.js.map +1 -1
- package/dist/i18n/messages.d.ts +26 -2
- package/dist/i18n/messages.d.ts.map +1 -1
- package/dist/i18n/messages.js +30 -5
- package/dist/i18n/messages.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +11 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +49 -1
- package/dist/logger.js.map +1 -1
- package/dist/obs/mini-app/status.d.ts.map +1 -1
- package/dist/obs/mini-app/status.js +0 -1
- package/dist/obs/mini-app/status.js.map +1 -1
- package/dist/onboarding/onboarding-service-client.d.ts +1 -0
- package/dist/onboarding/onboarding-service-client.d.ts.map +1 -1
- package/dist/onboarding/onboarding-service-client.js.map +1 -1
- package/dist/onboarding/remote-set-owner.d.ts.map +1 -1
- package/dist/onboarding/remote-set-owner.js +0 -1
- package/dist/onboarding/remote-set-owner.js.map +1 -1
- package/dist/onboarding/set-owner.d.ts +1 -1
- package/dist/onboarding/set-owner.d.ts.map +1 -1
- package/dist/onboarding/set-owner.js +3 -6
- package/dist/onboarding/set-owner.js.map +1 -1
- package/dist/reconfigure.d.ts.map +1 -1
- package/dist/reconfigure.js +1 -32
- package/dist/reconfigure.js.map +1 -1
- package/dist/reset.d.ts.map +1 -1
- package/dist/reset.js +3 -1
- package/dist/reset.js.map +1 -1
- package/dist/threads/active-threads-store.d.ts.map +1 -1
- package/dist/threads/active-threads-store.js +8 -27
- package/dist/threads/active-threads-store.js.map +1 -1
- package/dist/threads/dreaming-execution.d.ts +10 -0
- package/dist/threads/dreaming-execution.d.ts.map +1 -0
- package/dist/threads/dreaming-execution.js +78 -0
- package/dist/threads/dreaming-execution.js.map +1 -0
- package/dist/threads/execution-authority.d.ts +43 -0
- package/dist/threads/execution-authority.d.ts.map +1 -0
- package/dist/threads/execution-authority.js +75 -0
- package/dist/threads/execution-authority.js.map +1 -0
- package/dist/threads/execution-budget.d.ts +107 -0
- package/dist/threads/execution-budget.d.ts.map +1 -0
- package/dist/threads/execution-budget.js +257 -0
- package/dist/threads/execution-budget.js.map +1 -0
- package/dist/threads/execution-host.d.ts +17 -0
- package/dist/threads/execution-host.d.ts.map +1 -0
- package/dist/threads/execution-host.js +66 -0
- package/dist/threads/execution-host.js.map +1 -0
- package/dist/threads/execution-scheduler.d.ts +162 -0
- package/dist/threads/execution-scheduler.d.ts.map +1 -0
- package/dist/threads/execution-scheduler.js +413 -0
- package/dist/threads/execution-scheduler.js.map +1 -0
- package/dist/threads/execution-snapshot.d.ts +91 -0
- package/dist/threads/execution-snapshot.d.ts.map +1 -0
- package/dist/threads/execution-snapshot.js +146 -0
- package/dist/threads/execution-snapshot.js.map +1 -0
- package/dist/threads/execution-store.d.ts +374 -0
- package/dist/threads/execution-store.d.ts.map +1 -0
- package/dist/threads/execution-store.js +910 -0
- package/dist/threads/execution-store.js.map +1 -0
- package/dist/threads/execution-thread-error.d.ts +9 -0
- package/dist/threads/execution-thread-error.d.ts.map +1 -0
- package/dist/threads/execution-thread-error.js +12 -0
- package/dist/threads/execution-thread-error.js.map +1 -0
- package/dist/threads/executor-exit.d.ts +18 -0
- package/dist/threads/executor-exit.d.ts.map +1 -0
- package/dist/threads/executor-exit.js +21 -0
- package/dist/threads/executor-exit.js.map +1 -0
- package/dist/threads/foreground-task.d.ts +91 -0
- package/dist/threads/foreground-task.d.ts.map +1 -0
- package/dist/threads/foreground-task.js +191 -0
- package/dist/threads/foreground-task.js.map +1 -0
- package/dist/threads/foreman-business.d.ts +9 -0
- package/dist/threads/foreman-business.d.ts.map +1 -0
- package/dist/threads/foreman-business.js +117 -0
- package/dist/threads/foreman-business.js.map +1 -0
- package/dist/threads/foreman-client.d.ts +18 -0
- package/dist/threads/foreman-client.d.ts.map +1 -0
- package/dist/threads/foreman-client.js +51 -0
- package/dist/threads/foreman-client.js.map +1 -0
- package/dist/threads/foreman-delivery.d.ts +5 -0
- package/dist/threads/foreman-delivery.d.ts.map +1 -0
- package/dist/threads/foreman-delivery.js +21 -0
- package/dist/threads/foreman-delivery.js.map +1 -0
- package/dist/threads/foreman-execution.d.ts +32 -0
- package/dist/threads/foreman-execution.d.ts.map +1 -0
- package/dist/threads/foreman-execution.js +90 -0
- package/dist/threads/foreman-execution.js.map +1 -0
- package/dist/threads/foreman-host.d.ts +77 -0
- package/dist/threads/foreman-host.d.ts.map +1 -0
- package/dist/threads/foreman-host.js +891 -0
- package/dist/threads/foreman-host.js.map +1 -0
- package/dist/threads/foreman-protocol.d.ts +242 -0
- package/dist/threads/foreman-protocol.d.ts.map +1 -0
- package/dist/threads/foreman-protocol.js +116 -0
- package/dist/threads/foreman-protocol.js.map +1 -0
- package/dist/threads/foreman-store.d.ts +151 -0
- package/dist/threads/foreman-store.d.ts.map +1 -0
- package/dist/threads/foreman-store.js +299 -0
- package/dist/threads/foreman-store.js.map +1 -0
- package/dist/threads/generic-execution.d.ts +25 -0
- package/dist/threads/generic-execution.d.ts.map +1 -0
- package/dist/threads/generic-execution.js +86 -0
- package/dist/threads/generic-execution.js.map +1 -0
- package/dist/threads/init-thread-dir.d.ts +2 -2
- package/dist/threads/init-thread-dir.d.ts.map +1 -1
- package/dist/threads/init-thread-dir.js +6 -6
- package/dist/threads/init-thread-dir.js.map +1 -1
- package/dist/threads/ipc.d.ts +108 -2
- package/dist/threads/ipc.d.ts.map +1 -1
- package/dist/threads/ipc.js +14 -2
- package/dist/threads/ipc.js.map +1 -1
- package/dist/threads/lab-run-thread.d.ts +3 -5
- package/dist/threads/lab-run-thread.d.ts.map +1 -1
- package/dist/threads/lab-run-thread.js +3 -5
- package/dist/threads/lab-run-thread.js.map +1 -1
- package/dist/threads/lab-runtime-policy.d.ts +26 -21
- package/dist/threads/lab-runtime-policy.d.ts.map +1 -1
- package/dist/threads/lab-runtime-policy.js +31 -126
- package/dist/threads/lab-runtime-policy.js.map +1 -1
- package/dist/threads/process-group.d.ts +41 -0
- package/dist/threads/process-group.d.ts.map +1 -0
- package/dist/threads/process-group.js +161 -0
- package/dist/threads/process-group.js.map +1 -0
- package/dist/threads/relay-adapter.d.ts +8 -0
- package/dist/threads/relay-adapter.d.ts.map +1 -1
- package/dist/threads/relay-adapter.js +26 -1
- package/dist/threads/relay-adapter.js.map +1 -1
- package/dist/threads/supervisor.d.ts +191 -57
- package/dist/threads/supervisor.d.ts.map +1 -1
- package/dist/threads/supervisor.js +766 -427
- package/dist/threads/supervisor.js.map +1 -1
- package/dist/threads/task-workspace.d.ts +8 -0
- package/dist/threads/task-workspace.d.ts.map +1 -0
- package/dist/threads/task-workspace.js +52 -0
- package/dist/threads/task-workspace.js.map +1 -0
- package/dist/threads/worker-entry.d.ts.map +1 -1
- package/dist/threads/worker-entry.js +314 -34
- package/dist/threads/worker-entry.js.map +1 -1
- package/dist/threads/worker-execution-runtime.d.ts +75 -0
- package/dist/threads/worker-execution-runtime.d.ts.map +1 -0
- package/dist/threads/worker-execution-runtime.js +142 -0
- package/dist/threads/worker-execution-runtime.js.map +1 -0
- package/dist/threads/worker-execution.d.ts +35 -0
- package/dist/threads/worker-execution.d.ts.map +1 -0
- package/dist/threads/worker-execution.js +2 -0
- package/dist/threads/worker-execution.js.map +1 -0
- package/dist/threads/worker-runtime-policy.d.ts +42 -0
- package/dist/threads/worker-runtime-policy.d.ts.map +1 -0
- package/dist/threads/worker-runtime-policy.js +98 -0
- package/dist/threads/worker-runtime-policy.js.map +1 -0
- package/dist/tools/adapter-tool.d.ts +12 -0
- package/dist/tools/adapter-tool.d.ts.map +1 -0
- package/dist/tools/adapter-tool.js +2 -0
- package/dist/tools/adapter-tool.js.map +1 -0
- package/dist/tools/data-service.d.ts +2 -2
- package/dist/tools/delegation.d.ts +121 -0
- package/dist/tools/delegation.d.ts.map +1 -0
- package/dist/tools/delegation.js +106 -0
- package/dist/tools/delegation.js.map +1 -0
- package/dist/tools/dream-memory.d.ts +122 -0
- package/dist/tools/dream-memory.d.ts.map +1 -0
- package/dist/tools/dream-memory.js +513 -0
- package/dist/tools/dream-memory.js.map +1 -0
- package/dist/tools/email.d.ts +1 -1
- package/dist/tools/execution-control.d.ts +31 -0
- package/dist/tools/execution-control.d.ts.map +1 -0
- package/dist/tools/execution-control.js +71 -0
- package/dist/tools/execution-control.js.map +1 -0
- package/dist/tools/index.d.ts +5 -7
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +7 -13
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/mcp-manager.d.ts +1 -1
- package/dist/tools/memory.d.ts +1 -1
- package/dist/tools/memory.d.ts.map +1 -1
- package/dist/tools/memory.js +69 -45
- package/dist/tools/memory.js.map +1 -1
- package/dist/tools/notify.d.ts +5 -0
- package/dist/tools/notify.d.ts.map +1 -1
- package/dist/tools/notify.js +45 -10
- package/dist/tools/notify.js.map +1 -1
- package/dist/tools/skill.d.ts +1 -1
- package/dist/tools/totp.d.ts +1 -1
- package/dist/tui/client.d.ts +1 -16
- package/dist/tui/client.d.ts.map +1 -1
- package/dist/tui/client.js +0 -4
- package/dist/tui/client.js.map +1 -1
- package/dist/tui/index.d.ts.map +1 -1
- package/dist/tui/index.js +0 -41
- package/dist/tui/index.js.map +1 -1
- package/dist/tui/protocol.d.ts +2 -1
- package/dist/tui/protocol.d.ts.map +1 -1
- package/dist/tui/protocol.js +2 -1
- package/dist/tui/protocol.js.map +1 -1
- package/dist/tui/renderer.d.ts.map +1 -1
- package/dist/tui/renderer.js +0 -5
- package/dist/tui/renderer.js.map +1 -1
- package/dist/tui/request-store.d.ts +1 -1
- package/dist/tui/request-store.d.ts.map +1 -1
- package/dist/tui/request-store.js +2 -2
- package/dist/tui/request-store.js.map +1 -1
- package/dist/tui/server.d.ts.map +1 -1
- package/dist/tui/server.js +137 -25
- package/dist/tui/server.js.map +1 -1
- package/dist/utils/claude-transcripts.d.ts +6 -0
- package/dist/utils/claude-transcripts.d.ts.map +1 -1
- package/dist/utils/claude-transcripts.js +8 -2
- package/dist/utils/claude-transcripts.js.map +1 -1
- package/dist/utils/restart.d.ts.map +1 -1
- package/dist/utils/restart.js +6 -0
- package/dist/utils/restart.js.map +1 -1
- package/dist-agent/bundle.cjs +2 -2
- package/package.json +1 -1
- package/dist/agent/mailbox.d.ts +0 -50
- package/dist/agent/mailbox.d.ts.map +0 -1
- package/dist/agent/mailbox.js +0 -124
- package/dist/agent/mailbox.js.map +0 -1
- package/dist/agent/nightly-maintenance/memory-dreaming-sweep.d.ts +0 -77
- package/dist/agent/nightly-maintenance/memory-dreaming-sweep.d.ts.map +0 -1
- package/dist/agent/nightly-maintenance/memory-dreaming-sweep.js +0 -158
- package/dist/agent/nightly-maintenance/memory-dreaming-sweep.js.map +0 -1
- package/dist/agent/nightly-maintenance/memory-dreaming.d.ts +0 -116
- package/dist/agent/nightly-maintenance/memory-dreaming.d.ts.map +0 -1
- package/dist/agent/nightly-maintenance/memory-dreaming.js +0 -458
- package/dist/agent/nightly-maintenance/memory-dreaming.js.map +0 -1
- package/dist/builtin-skills/catalog/phone-adb-automation/SKILL.md +0 -412
- package/dist/builtin-skills/catalog/phone-adb-automation/phone_input.sh +0 -132
- package/dist/builtin-skills/catalog/phone-adb-automation/phone_launch.sh +0 -166
- package/dist/builtin-skills/catalog/phone-adb-automation/phone_screenshot.sh +0 -87
- package/dist/builtin-skills/catalog/phone-adb-automation/phone_security_kbd.py +0 -174
- package/dist/builtin-skills/catalog/phone-adb-automation/phone_setup.sh +0 -274
- package/dist/builtin-skills/catalog/phone-adb-automation/phone_swipe.sh +0 -111
- package/dist/builtin-skills/catalog/phone-adb-automation/phone_tap.sh +0 -87
- package/dist/builtin-skills/catalog/phone-adb-automation/phone_ui_parse.py +0 -176
- package/dist/builtin-skills/catalog/phone-adb-automation/phone_wake_unlock.sh +0 -67
- package/dist/builtin-skills/macos-automation/SKILL.md +0 -132
- package/dist/builtin-skills/transcribe-audio/SKILL.md +0 -122
- package/dist/builtin-skills/visionclaw-manual/SKILL.md +0 -337
- package/dist/obs/rdp/icons/icons/app_windows.svg +0 -4
- package/dist/obs/rdp/icons/icons/clip_get.svg +0 -4
- package/dist/obs/rdp/icons/icons/clip_send.svg +0 -4
- package/dist/obs/rdp/icons/icons/clip_shared.svg +0 -4
- package/dist/obs/rdp/icons/icons/clipboard.svg +0 -4
- package/dist/obs/rdp/icons/icons/clipboard_shared.svg +0 -4
- package/dist/obs/rdp/icons/icons/control.svg +0 -4
- package/dist/obs/rdp/icons/icons/desktop.svg +0 -4
- package/dist/obs/rdp/icons/icons/display.svg +0 -4
- package/dist/obs/rdp/icons/icons/launchpad.svg +0 -4
- package/dist/obs/rdp/icons/icons/mission_control.svg +0 -4
- package/dist/obs/rdp/icons/icons/screenshot.svg +0 -4
- package/dist/obs/rdp/icons/icons/zoom_actual.svg +0 -4
- package/dist/obs/rdp/icons/icons/zoom_fit.svg +0 -4
- package/dist/obs/rdp/icons/icons/zoom_in.svg +0 -4
- package/dist/obs/rdp/icons/icons/zoom_out.svg +0 -4
- package/dist/realtime/assets/index.html +0 -1058
- package/dist/realtime/assets/samples/alloy.mp3 +0 -0
- package/dist/realtime/assets/samples/ash.mp3 +0 -0
- package/dist/realtime/assets/samples/ballad.mp3 +0 -0
- package/dist/realtime/assets/samples/cedar.mp3 +0 -0
- package/dist/realtime/assets/samples/coral.mp3 +0 -0
- package/dist/realtime/assets/samples/echo.mp3 +0 -0
- package/dist/realtime/assets/samples/marin.mp3 +0 -0
- package/dist/realtime/assets/samples/sage.mp3 +0 -0
- package/dist/realtime/assets/samples/shimmer.mp3 +0 -0
- package/dist/realtime/assets/samples/verse.mp3 +0 -0
- package/dist/threads/task-contracts.d.ts +0 -194
- package/dist/threads/task-contracts.d.ts.map +0 -1
- package/dist/threads/task-contracts.js +0 -82
- package/dist/threads/task-contracts.js.map +0 -1
- package/dist/threads/task-sidecar.d.ts +0 -143
- package/dist/threads/task-sidecar.d.ts.map +0 -1
- package/dist/threads/task-sidecar.js +0 -309
- package/dist/threads/task-sidecar.js.map +0 -1
- package/dist/threads/task-store.d.ts +0 -172
- package/dist/threads/task-store.d.ts.map +0 -1
- package/dist/threads/task-store.js +0 -594
- package/dist/threads/task-store.js.map +0 -1
- package/dist/threads/thread-task-context.d.ts +0 -40
- package/dist/threads/thread-task-context.d.ts.map +0 -1
- package/dist/threads/thread-task-context.js +0 -159
- package/dist/threads/thread-task-context.js.map +0 -1
- package/dist/threads/thread-task-controller.d.ts +0 -122
- package/dist/threads/thread-task-controller.d.ts.map +0 -1
- package/dist/threads/thread-task-controller.js +0 -276
- package/dist/threads/thread-task-controller.js.map +0 -1
- package/dist/threads/thread-task-runtime.d.ts +0 -320
- package/dist/threads/thread-task-runtime.d.ts.map +0 -1
- package/dist/threads/thread-task-runtime.js +0 -843
- package/dist/threads/thread-task-runtime.js.map +0 -1
- package/dist/tools/switch-session.d.ts +0 -15
- package/dist/tools/switch-session.d.ts.map +0 -1
- package/dist/tools/switch-session.js +0 -88
- package/dist/tools/switch-session.js.map +0 -1
- package/dist/tools/thread-tasks.d.ts +0 -10
- package/dist/tools/thread-tasks.d.ts.map +0 -1
- package/dist/tools/thread-tasks.js +0 -88
- package/dist/tools/thread-tasks.js.map +0 -1
- package/dist-agent/assets/index.html +0 -1058
- package/dist-agent/assets/samples/alloy.mp3 +0 -0
- package/dist-agent/assets/samples/ash.mp3 +0 -0
- package/dist-agent/assets/samples/ballad.mp3 +0 -0
- package/dist-agent/assets/samples/cedar.mp3 +0 -0
- package/dist-agent/assets/samples/coral.mp3 +0 -0
- package/dist-agent/assets/samples/echo.mp3 +0 -0
- package/dist-agent/assets/samples/marin.mp3 +0 -0
- package/dist-agent/assets/samples/sage.mp3 +0 -0
- package/dist-agent/assets/samples/shimmer.mp3 +0 -0
- package/dist-agent/assets/samples/verse.mp3 +0 -0
- package/dist-agent/playwriter-relay.cjs +0 -95
- package/dist-agent/realtime/assets/index.html +0 -1058
- package/dist-agent/realtime/assets/samples/alloy.mp3 +0 -0
- package/dist-agent/realtime/assets/samples/ash.mp3 +0 -0
- package/dist-agent/realtime/assets/samples/ballad.mp3 +0 -0
- package/dist-agent/realtime/assets/samples/cedar.mp3 +0 -0
- package/dist-agent/realtime/assets/samples/coral.mp3 +0 -0
- package/dist-agent/realtime/assets/samples/echo.mp3 +0 -0
- package/dist-agent/realtime/assets/samples/marin.mp3 +0 -0
- package/dist-agent/realtime/assets/samples/sage.mp3 +0 -0
- package/dist-agent/realtime/assets/samples/shimmer.mp3 +0 -0
- package/dist-agent/realtime/assets/samples/verse.mp3 +0 -0
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* WakeCycleRunner — encapsulates the
|
|
2
|
+
* WakeCycleRunner — encapsulates the wake loop, Claude
|
|
3
3
|
* stream processing, error classification / retry logic, transcript
|
|
4
4
|
* sanitization, and post-cycle transcript memory indexing.
|
|
5
5
|
*
|
|
6
6
|
* Extracted from loop.ts so the main loop is a thin orchestrator.
|
|
7
7
|
*/
|
|
8
|
-
import { isEmailChannel,
|
|
8
|
+
import { isEmailChannel, presentsAssistantText } from "../channels/interface.js";
|
|
9
9
|
import { isCalendarInterruptMessage } from "./owner-initiated-eligibility.js";
|
|
10
10
|
import { emailAddressesMatch } from "../utils/email.js";
|
|
11
|
+
import { EXTERNAL_WAKE_KIND } from "../channels/queue.js";
|
|
12
|
+
import { nextRecoveryPhase } from "./lifecycle-transitions.js";
|
|
11
13
|
import { COMPACTION_FAILURE_CONTINUATION, CompactionFailureError } from "./compaction-failure.js";
|
|
12
14
|
import { ToolOutputRepairError } from "./transcript-output-repair.js";
|
|
13
15
|
import { getFallbackEngine, getLlmEffort, getLlmRetryEffort, setFallbackEngine } from "./model-provider.js";
|
|
@@ -31,36 +33,7 @@ import path from "path";
|
|
|
31
33
|
import { randomUUID } from "node:crypto";
|
|
32
34
|
import { runContextRefresh } from "./context-refresh.js";
|
|
33
35
|
import { loadToolAbortRecoveryChain, saveToolAbortRecoveryChain } from "./recovery-chain.js";
|
|
34
|
-
import {
|
|
35
|
-
import { isThreadTaskContextBlock } from "../threads/thread-task-context.js";
|
|
36
|
-
/**
|
|
37
|
-
* Session memos are internal working text (handoff instructions, worktree
|
|
38
|
-
* paths, "do not notify" constraints). They must never be sent as owner chat.
|
|
39
|
-
*
|
|
40
|
-
* Last-resort ping when a coding completion was armed and this wake never
|
|
41
|
-
* successfully notified (PR #839: do not silently drop the result). The
|
|
42
|
-
* body is a fixed human line — never the memo, never a paraphrase of it.
|
|
43
|
-
*/
|
|
44
|
-
async function deliverCodingCompletionFallbackPing(ownerConfig) {
|
|
45
|
-
const message = t("coding.completion_unnotified", resolveLocale(ownerConfig.language));
|
|
46
|
-
try {
|
|
47
|
-
const result = await sendUserNotification({ message, purpose: "completion" });
|
|
48
|
-
if (result.isError) {
|
|
49
|
-
const text = result.content
|
|
50
|
-
.map((c) => "text" in c ? c.text : "")
|
|
51
|
-
.filter((s) => s.length > 0)
|
|
52
|
-
.join(" ");
|
|
53
|
-
logger.warn(`Coding completion notification failed: ${text || "unknown error"}`);
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
logger.system("Delivered coding completion fallback ping (generic; not the session memo)");
|
|
57
|
-
return true;
|
|
58
|
-
}
|
|
59
|
-
catch (err) {
|
|
60
|
-
logger.warn(`Coding completion notification threw: ${err instanceof Error ? err.message : String(err)}`);
|
|
61
|
-
return false;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
36
|
+
import { getWorkerExecutionRuntime } from "../threads/worker-execution-runtime.js";
|
|
64
37
|
const AUTH_PATTERNS = /\b(401|402|403|authentication|billing|unauthorized|forbidden|api.?key)\b/i;
|
|
65
38
|
// Fatal environment/installation problems that won't fix themselves on retry.
|
|
66
39
|
// In particular: the Claude Agent SDK immediately exits with code 1 when its
|
|
@@ -303,15 +276,15 @@ export function isSharedCredentialFailure(err) {
|
|
|
303
276
|
}
|
|
304
277
|
return classifyError(err) === "provider_failed" && !isEngineScopedFailure(err);
|
|
305
278
|
}
|
|
306
|
-
function formatOwnerErrorNotice(category, consecutiveErrors,
|
|
279
|
+
function formatOwnerErrorNotice(category, consecutiveErrors, errMsg) {
|
|
307
280
|
if (category === "fatal") {
|
|
308
|
-
return
|
|
281
|
+
return "Agent encountered an internal runtime error. This wake has stopped; the next message or heartbeat will retry.";
|
|
309
282
|
}
|
|
310
283
|
if (category === "local") {
|
|
311
284
|
// Name the cause. The old text blamed the model provider for an error the
|
|
312
285
|
// provider never saw, which is what made the original alert storm
|
|
313
286
|
// impossible to diagnose from the notification alone.
|
|
314
|
-
return `Agent hit a local session-coordination error (not a provider failure): ${errMsg ?? "unknown cause"}.
|
|
287
|
+
return `Agent hit a local session-coordination error (not a provider failure): ${errMsg ?? "unknown cause"}. This wake has stopped; the next message or heartbeat will retry.`;
|
|
315
288
|
}
|
|
316
289
|
if (category === "request_invalid") {
|
|
317
290
|
return `Agent stopped this wake because the provider rejected a malformed request (${errMsg ?? "unknown cause"}).`;
|
|
@@ -322,7 +295,7 @@ function formatOwnerErrorNotice(category, consecutiveErrors, sleepMin, errMsg) {
|
|
|
322
295
|
if (category === "empty_turn") {
|
|
323
296
|
return "The assistant returned another empty turn without confirming completion. The task may be incomplete. I stopped automatic continuation to avoid repeating work; existing results should be checked before continuing.";
|
|
324
297
|
}
|
|
325
|
-
return `Agent encountered an internal model/provider error ${consecutiveErrors} times in a row.
|
|
298
|
+
return `Agent encountered an internal model/provider error ${consecutiveErrors} times in a row. This wake has stopped; the next message or heartbeat will retry.`;
|
|
326
299
|
}
|
|
327
300
|
function isPromptTooLong(err) {
|
|
328
301
|
const terminalReason = getTerminalReason(err);
|
|
@@ -390,7 +363,6 @@ export const MAX_EMPTY_TURN_RETRIES = 1;
|
|
|
390
363
|
const ERROR_RETRY_COMPACT_USED_PCT = 0.7;
|
|
391
364
|
const BASE_DELAY_MS = 5_000;
|
|
392
365
|
const MAX_DELAY_MS = 5 * 60_000;
|
|
393
|
-
const FATAL_SLEEP_MS = 5 * 60_000;
|
|
394
366
|
/** Max times to retry the LLM call on stream silence timeout before aborting. */
|
|
395
367
|
export const MAX_SILENCE_RETRIES = 3;
|
|
396
368
|
/** Bounded retries for transient stream/network disconnects in any wake cycle. */
|
|
@@ -404,26 +376,7 @@ export const MAX_OUTPUT_RECOVERY_ATTEMPTS = 2;
|
|
|
404
376
|
/** Escalating silence timeouts (ms) per attempt: 5min, 10min, 15min. */
|
|
405
377
|
const SILENCE_TIMEOUT_SCHEDULE_MS = [300_000, 600_000, 900_000];
|
|
406
378
|
/** Decreasing effort levels per attempt to reduce thinking overhead on retries. */
|
|
407
|
-
const EFFORT_SCHEDULE =
|
|
408
|
-
coding: ["xhigh", "high", "medium"],
|
|
409
|
-
general: ["xhigh", "high", "medium"],
|
|
410
|
-
};
|
|
411
|
-
/**
|
|
412
|
-
* A wake retried on a reset session re-sends its first message, whose thread
|
|
413
|
-
* task block (#1996) was built before the reset's reconcile. Swap it for a
|
|
414
|
-
* fresh one so the new session sees exactly one, current copy. Without a
|
|
415
|
-
* task runtime this returns the blocks unchanged.
|
|
416
|
-
*/
|
|
417
|
-
export function withFreshThreadTaskBlock(blocks) {
|
|
418
|
-
const fresh = buildThreadTaskContext();
|
|
419
|
-
const index = blocks.findIndex((block) => block.type === "text" && isThreadTaskContextBlock(block.text));
|
|
420
|
-
if (index === -1)
|
|
421
|
-
return fresh ? [...blocks, { type: "text", text: fresh }] : blocks;
|
|
422
|
-
const rest = blocks.filter((_, i) => i !== index);
|
|
423
|
-
if (fresh)
|
|
424
|
-
rest.splice(index, 0, { type: "text", text: fresh });
|
|
425
|
-
return rest;
|
|
426
|
-
}
|
|
379
|
+
const EFFORT_SCHEDULE = ["xhigh", "high", "medium"];
|
|
427
380
|
export class WakeCycleRunner {
|
|
428
381
|
externalContextRegistry;
|
|
429
382
|
deps;
|
|
@@ -435,13 +388,20 @@ export class WakeCycleRunner {
|
|
|
435
388
|
localCoordinationErrors = 0;
|
|
436
389
|
/** Empty Claude assistant turns in this wake (not counted as network failures). */
|
|
437
390
|
emptyTurnRetries = 0;
|
|
391
|
+
/**
|
|
392
|
+
* Set once a call's silence ceiling is spent. Silence retries live inside
|
|
393
|
+
* the call, so the outer error handler must not spend another backoff on
|
|
394
|
+
* the same call. Cleared with the next wake.
|
|
395
|
+
*/
|
|
396
|
+
silenceRecoveryExhausted = false;
|
|
397
|
+
/** Recovering only while a spendable bucket is in use. Reset when the wake ends. */
|
|
398
|
+
recoveryPhase = "Running";
|
|
438
399
|
/**
|
|
439
400
|
* Watchdog recoveries span multiple queue-driven wakes, so this state lives
|
|
440
401
|
* on the resident runner rather than inside a single run() invocation.
|
|
441
402
|
* Attempt count is retained across clean wakes that lack finish/stop so a
|
|
442
|
-
* recovery chain can actually reach MAX_TOOL_ABORT_RECOVERIES.
|
|
443
|
-
*
|
|
444
|
-
* switch_session(complete) clear it.
|
|
403
|
+
* recovery chain can actually reach MAX_TOOL_ABORT_RECOVERIES. Only finish
|
|
404
|
+
* or stop clear it.
|
|
445
405
|
*
|
|
446
406
|
* Ordinary threads also persist the chain, so a restart cannot refill the
|
|
447
407
|
* budget. LabRun queues are process-local and stay in memory.
|
|
@@ -521,28 +481,30 @@ export class WakeCycleRunner {
|
|
|
521
481
|
}
|
|
522
482
|
}
|
|
523
483
|
/**
|
|
524
|
-
* Execute one full wake cycle: the
|
|
525
|
-
*
|
|
484
|
+
* Execute one full wake cycle: the wake loop, stream processing, error
|
|
485
|
+
* recovery, and post-cycle transcript indexing.
|
|
526
486
|
*
|
|
527
487
|
* @param contentBlocks The multimodal user-message blocks for this cycle.
|
|
528
488
|
* @param trigger Whether this wake was from a message or heartbeat.
|
|
529
489
|
* @param messages Inbound messages (empty for heartbeat).
|
|
530
|
-
* @param calendarSummary Calendar summary string for session-switch context.
|
|
531
490
|
* @param consecutiveErrors Current error counter from previous cycles.
|
|
532
491
|
* @returns Updated consecutive error count.
|
|
533
492
|
*/
|
|
534
|
-
async run(contentBlocks, trigger, messages,
|
|
493
|
+
async run(contentBlocks, trigger, messages, consecutiveErrors) {
|
|
535
494
|
const { config, ownerConfig, session, activityTracker, interruptHandler, messageQueue } = this.deps;
|
|
536
495
|
this.malformedRequestRefreshAttempted = false;
|
|
537
496
|
this.emptyTurnRetries = 0;
|
|
497
|
+
this.silenceRecoveryExhausted = false;
|
|
498
|
+
this.recoveryPhase = "Running";
|
|
538
499
|
// --- Capture transcript start lines for post-cycle indexing ---
|
|
539
|
-
//
|
|
540
|
-
// of using a single start line captured
|
|
541
|
-
//
|
|
500
|
+
// Recovery can rotate the session to a new transcript, so anchor by
|
|
501
|
+
// transcript path instead of using a single start line captured at cycle
|
|
502
|
+
// entry.
|
|
542
503
|
const wakeCycleId = generateWakeCycleId();
|
|
543
504
|
/** Numbers model turns within this wake for their task-event keys. */
|
|
544
|
-
let responseSeq = 0;
|
|
545
505
|
let awaitingUser = false;
|
|
506
|
+
/** The model ended the wake with an accepted finish (not a timeout or exhausted recovery). */
|
|
507
|
+
let wakeFinished = false;
|
|
546
508
|
let terminalError = false;
|
|
547
509
|
const wakeCycleTimestampStart = new Date().toISOString();
|
|
548
510
|
const transcriptAnchors = new Map();
|
|
@@ -552,17 +514,6 @@ export class WakeCycleRunner {
|
|
|
552
514
|
transcriptAnchors.set(activeTranscript.path, await countFileLines(activeTranscript.path));
|
|
553
515
|
};
|
|
554
516
|
await ensureTranscriptAnchor(resolveIndexableTranscript(session.activeSession.getTranscriptInfo(), session.activeSession.getTranscriptPath()));
|
|
555
|
-
// Session switch loop: if the agent calls switch_session, we close the
|
|
556
|
-
// current stream, switch sessions, and re-enter with a new stream.
|
|
557
|
-
let didSwitch = false;
|
|
558
|
-
let switchForwardMessage = "";
|
|
559
|
-
let pendingMemoAck = true;
|
|
560
|
-
// Armed on a coding→general completion handoff when the coding session
|
|
561
|
-
// did not notify the owner itself. The re-entered general session is
|
|
562
|
-
// expected to humanize the memo via notify_user. If this wake never
|
|
563
|
-
// successfully notifies, runtime last-resorts a fixed human ping (PR #839)
|
|
564
|
-
// — never the memo body.
|
|
565
|
-
let pendingCompletionFallback = null;
|
|
566
517
|
// Survives premature-end continuations: a later turn that repeats the
|
|
567
518
|
// answer as prose must not re-deliver after notify_user already landed.
|
|
568
519
|
let notifyUserDeliveredThisWake = false;
|
|
@@ -573,7 +524,6 @@ export class WakeCycleRunner {
|
|
|
573
524
|
let silenceCompactionDone = false;
|
|
574
525
|
const externalContext = await this.externalContextRegistry.collect({
|
|
575
526
|
trigger,
|
|
576
|
-
sessionMode: session.activeMode,
|
|
577
527
|
messages,
|
|
578
528
|
});
|
|
579
529
|
setCurrentExternalContext(externalContext.section, externalContext.digest, externalContext.providerBlocks);
|
|
@@ -589,62 +539,18 @@ export class WakeCycleRunner {
|
|
|
589
539
|
// failover. If the session cannot be rotated, stay on the current engine
|
|
590
540
|
// and try again next wake rather than replaying its history elsewhere.
|
|
591
541
|
if (recovered) {
|
|
592
|
-
if (await this.rotateSessionForEngineSwitch(session, String(activeBefore), recovered.recovered, "recovery")) {
|
|
593
|
-
contentBlocks = withFreshThreadTaskBlock(contentBlocks);
|
|
594
|
-
}
|
|
595
|
-
else {
|
|
542
|
+
if (!await this.rotateSessionForEngineSwitch(session, String(activeBefore), recovered.recovered, "recovery")) {
|
|
596
543
|
setFallbackEngine(fallbackBefore);
|
|
597
544
|
}
|
|
598
545
|
}
|
|
599
546
|
}
|
|
600
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- intentional
|
|
547
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- intentional: recovery paths re-enter via continue
|
|
601
548
|
wakeLoop: while (true) {
|
|
602
549
|
const activeSession = session.activeSession;
|
|
603
550
|
try {
|
|
604
551
|
await activeSession.warmUp();
|
|
605
552
|
await ensureTranscriptAnchor(resolveIndexableTranscript(activeSession.getTranscriptInfo(), activeSession.getTranscriptPath()));
|
|
606
|
-
let messageContent;
|
|
607
|
-
if (didSwitch) {
|
|
608
|
-
// Handoff boundary (#1996): fold what the previous session did into
|
|
609
|
-
// the task checkpoints before the other session reads them. Bounded.
|
|
610
|
-
await reconcileThreadTasks("handoff", RECONCILE_WAIT_MS.handoff);
|
|
611
|
-
const switchMemos = session.consumeMemosForActive();
|
|
612
|
-
const switchParts = [];
|
|
613
|
-
switchParts.push(`[Session Switch] time=${new Date().toLocaleString()} active_session=${session.activeMode}`);
|
|
614
|
-
if (switchMemos) {
|
|
615
|
-
switchParts.push("");
|
|
616
|
-
switchParts.push(switchMemos);
|
|
617
|
-
}
|
|
618
|
-
const codingStatus = session.getCodingSessionStatus();
|
|
619
|
-
if (codingStatus && session.activeMode === "general") {
|
|
620
|
-
switchParts.push("");
|
|
621
|
-
switchParts.push(`## Active Coding Task`);
|
|
622
|
-
switchParts.push(codingStatus);
|
|
623
|
-
}
|
|
624
|
-
if (calendarSummary) {
|
|
625
|
-
switchParts.push("");
|
|
626
|
-
switchParts.push("## Upcoming Calendar Events");
|
|
627
|
-
switchParts.push(calendarSummary);
|
|
628
|
-
}
|
|
629
|
-
if (switchForwardMessage) {
|
|
630
|
-
switchParts.push("");
|
|
631
|
-
switchParts.push(switchForwardMessage);
|
|
632
|
-
}
|
|
633
|
-
// The destination session has its own context: give it the
|
|
634
|
-
// thread's tasks as they are now.
|
|
635
|
-
const threadTaskBlock = buildThreadTaskContext();
|
|
636
|
-
messageContent = [
|
|
637
|
-
{ type: "text", text: switchParts.join("\n") },
|
|
638
|
-
...(threadTaskBlock ? [{ type: "text", text: threadTaskBlock }] : []),
|
|
639
|
-
];
|
|
640
|
-
didSwitch = false;
|
|
641
|
-
switchForwardMessage = "";
|
|
642
|
-
pendingMemoAck = true;
|
|
643
|
-
}
|
|
644
|
-
else {
|
|
645
|
-
messageContent =
|
|
646
|
-
contentBlocks;
|
|
647
|
-
}
|
|
553
|
+
let messageContent = contentBlocks;
|
|
648
554
|
let streamResult = {
|
|
649
555
|
toolTimeout: null,
|
|
650
556
|
finishCalled: false,
|
|
@@ -654,6 +560,10 @@ export class WakeCycleRunner {
|
|
|
654
560
|
notifyUserDelivered: false,
|
|
655
561
|
awaitingUser: false,
|
|
656
562
|
};
|
|
563
|
+
// A lifecycle-only continuation may call finish without repeating the
|
|
564
|
+
// answer from the previous turn. Keep that answer through this wake.
|
|
565
|
+
let lastReplyText = "";
|
|
566
|
+
let lastReplyPresented = false;
|
|
657
567
|
let subagentContinuations = 0;
|
|
658
568
|
let prematureEndContinuations = 0;
|
|
659
569
|
// turnLoop: each iteration drains one streamed turn (including all
|
|
@@ -667,7 +577,7 @@ export class WakeCycleRunner {
|
|
|
667
577
|
// Retry this inner business turn only for transient stream/socket failures.
|
|
668
578
|
while (transientStreamRetries <= MAX_TRANSIENT_STREAM_RETRIES) {
|
|
669
579
|
try {
|
|
670
|
-
for (let silenceAttempt = 1; silenceAttempt <= MAX_SILENCE_RETRIES; silenceAttempt++) {
|
|
580
|
+
silenceLoop: for (let silenceAttempt = 1; silenceAttempt <= MAX_SILENCE_RETRIES; silenceAttempt++) {
|
|
671
581
|
const scheduledSilenceMs = SILENCE_TIMEOUT_SCHEDULE_MS[silenceAttempt - 1] ?? SILENCE_TIMEOUT_SCHEDULE_MS[SILENCE_TIMEOUT_SCHEDULE_MS.length - 1];
|
|
672
582
|
// Pass the scheduled bound. Pi auto-compaction starts after the
|
|
673
583
|
// stream is already open (system/compaction_start); processAgentStream
|
|
@@ -676,23 +586,20 @@ export class WakeCycleRunner {
|
|
|
676
586
|
if (silenceAttempt > 1) {
|
|
677
587
|
activityTracker.notePublicPhase("Still working");
|
|
678
588
|
}
|
|
679
|
-
const effortSchedule = EFFORT_SCHEDULE
|
|
680
|
-
const tierEffort = getLlmEffort(config,
|
|
589
|
+
const effortSchedule = EFFORT_SCHEDULE;
|
|
590
|
+
const tierEffort = getLlmEffort(config, "main_general");
|
|
681
591
|
const effort = tierEffort && silenceAttempt > 1
|
|
682
592
|
? getLlmRetryEffort(tierEffort, silenceAttempt - 1)
|
|
683
593
|
: tierEffort ?? effortSchedule[silenceAttempt - 1];
|
|
684
594
|
const queryStream = activeSession.sendAndStream(messageContent, { effort, externalContextDigest: externalContext.digest });
|
|
685
|
-
if (pendingMemoAck) {
|
|
686
|
-
session.ackMemosForActive();
|
|
687
|
-
pendingMemoAck = false;
|
|
688
|
-
}
|
|
689
595
|
try {
|
|
690
|
-
streamResult = await processAgentStream(queryStream, activeSession, activityTracker,
|
|
596
|
+
streamResult = await processAgentStream(queryStream, activeSession, activityTracker, config, silenceTimeoutMs);
|
|
691
597
|
if (streamResult.notifyUserDelivered)
|
|
692
598
|
notifyUserDeliveredThisWake = true;
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
599
|
+
if (streamResult.lastAssistantText) {
|
|
600
|
+
lastReplyText = streamResult.lastAssistantText;
|
|
601
|
+
lastReplyPresented = streamResult.lastAssistantTextPresented === true;
|
|
602
|
+
}
|
|
696
603
|
// A successful SDK envelope can still contain a legitimate empty
|
|
697
604
|
// model turn. Apply the same task-state policy as SDK diagnostics.
|
|
698
605
|
if (!this.deps.singleShot && streamResult.emptyTurn && !streamResult.finishCalled && !streamResult.toolTimeout) {
|
|
@@ -733,22 +640,37 @@ export class WakeCycleRunner {
|
|
|
733
640
|
`skipping the remaining ${MAX_SILENCE_RETRIES - silenceAttempt} silence retries`);
|
|
734
641
|
}
|
|
735
642
|
}
|
|
736
|
-
|
|
643
|
+
// silenceAttempt counts the tries already made in this call. A dead
|
|
644
|
+
// engine does not get the remaining ones: that is Stopping, not
|
|
645
|
+
// another Recovering retry.
|
|
646
|
+
const silencePhase = nextRecoveryPhase({
|
|
647
|
+
from: this.recoveryPhase,
|
|
648
|
+
bucket: "silence",
|
|
649
|
+
spent: engineAnswersProbe ? silenceAttempt : MAX_SILENCE_RETRIES,
|
|
650
|
+
});
|
|
651
|
+
if (silencePhase === "Recovering")
|
|
652
|
+
this.recoveryPhase = "Recovering";
|
|
653
|
+
if (silencePhase === "Recovering" && engineAnswersProbe) {
|
|
737
654
|
const nextTimeoutMs = SILENCE_TIMEOUT_SCHEDULE_MS[silenceAttempt] ?? SILENCE_TIMEOUT_SCHEDULE_MS[SILENCE_TIMEOUT_SCHEDULE_MS.length - 1];
|
|
738
655
|
const nextEffort = tierEffort
|
|
739
656
|
? getLlmRetryEffort(tierEffort, silenceAttempt)
|
|
740
657
|
: effortSchedule[silenceAttempt];
|
|
741
658
|
logger.system(`Stream silence timeout after ${silenceTimeoutMs / 1000}s (attempt ${silenceAttempt}/${MAX_SILENCE_RETRIES}) — engine still answering, retrying LLM call with ${nextTimeoutMs / 1000}s timeout and effort=${nextEffort}...`);
|
|
742
|
-
// Re-send the same messageContent on next
|
|
743
|
-
continue;
|
|
659
|
+
// Re-send the same messageContent on the next attempt of this call.
|
|
660
|
+
continue silenceLoop;
|
|
744
661
|
}
|
|
745
662
|
// Retries exhausted, or cut short because the engine failed its
|
|
746
|
-
// health probe.
|
|
663
|
+
// health probe. Both are Stopping for this call. A hot engine
|
|
664
|
+
// switch or a successful compaction below continues this wake, so
|
|
665
|
+
// the outer handler is only blocked once this call is actually
|
|
666
|
+
// abandoned.
|
|
747
667
|
logger.err(engineAnswersProbe
|
|
748
668
|
? `Stream silence timeout: all ${MAX_SILENCE_RETRIES} attempts exhausted — aborting`
|
|
749
669
|
: `Stream silence timeout on attempt ${silenceAttempt}/${MAX_SILENCE_RETRIES} with a failed health probe — aborting`);
|
|
750
|
-
if (this.deps.singleShot)
|
|
670
|
+
if (this.deps.singleShot) {
|
|
671
|
+
this.silenceRecoveryExhausted = true;
|
|
751
672
|
throw streamErr;
|
|
673
|
+
}
|
|
752
674
|
const locale = resolveLocale(ownerConfig.language);
|
|
753
675
|
// Report what actually happened: a probe-driven short circuit may
|
|
754
676
|
// have spent only one of the three attempts, and telling the owner
|
|
@@ -765,7 +687,6 @@ export class WakeCycleRunner {
|
|
|
765
687
|
const degraded = await this.degradeActiveEngine(engineFallback, "silence_exhausted", session);
|
|
766
688
|
if (degraded === "hot") {
|
|
767
689
|
consecutiveErrors = 0;
|
|
768
|
-
contentBlocks = withFreshThreadTaskBlock(contentBlocks);
|
|
769
690
|
continue wakeLoop;
|
|
770
691
|
}
|
|
771
692
|
if (degraded === "restarting") {
|
|
@@ -784,9 +705,6 @@ export class WakeCycleRunner {
|
|
|
784
705
|
try {
|
|
785
706
|
await activeSession.requestCompaction();
|
|
786
707
|
consecutiveErrors = 0;
|
|
787
|
-
// The compacted session must see the tasks as the compaction
|
|
788
|
-
// reconcile just left them, not the wake-start block (#1996).
|
|
789
|
-
contentBlocks = withFreshThreadTaskBlock(contentBlocks);
|
|
790
708
|
continue wakeLoop;
|
|
791
709
|
}
|
|
792
710
|
catch (compactErr) {
|
|
@@ -803,6 +721,7 @@ export class WakeCycleRunner {
|
|
|
803
721
|
...taskContinuationRouting(this.deps.agentState.currentTaskReplyTarget),
|
|
804
722
|
});
|
|
805
723
|
logger.system("Enqueued interrupted-task recovery message for next wake cycle");
|
|
724
|
+
this.silenceRecoveryExhausted = true;
|
|
806
725
|
throw streamErr; // propagate so the outer handler records the error
|
|
807
726
|
}
|
|
808
727
|
}
|
|
@@ -810,7 +729,18 @@ export class WakeCycleRunner {
|
|
|
810
729
|
}
|
|
811
730
|
catch (streamErr) {
|
|
812
731
|
// TODO: guard retry against simultaneous stop requests and settle the failed input generator before retrying; both are rare stream/stop races.
|
|
813
|
-
|
|
732
|
+
// transientStreamRetries counts the disconnects already retried in
|
|
733
|
+
// this turn. Another one is Recovering; the ceiling throws, and
|
|
734
|
+
// the outer handler records it instead of retrying this turn.
|
|
735
|
+
const networkPhase = isTransientStreamFailure(streamErr)
|
|
736
|
+
? nextRecoveryPhase({
|
|
737
|
+
from: this.recoveryPhase,
|
|
738
|
+
bucket: "network",
|
|
739
|
+
spent: transientStreamRetries,
|
|
740
|
+
})
|
|
741
|
+
: null;
|
|
742
|
+
if (networkPhase === "Recovering") {
|
|
743
|
+
this.recoveryPhase = "Recovering";
|
|
814
744
|
transientStreamRetries++;
|
|
815
745
|
logger.system(`Transient stream failure (retry ${transientStreamRetries}/${MAX_TRANSIENT_STREAM_RETRIES}) — retrying the current business turn...`);
|
|
816
746
|
continue;
|
|
@@ -818,30 +748,10 @@ export class WakeCycleRunner {
|
|
|
818
748
|
throw streamErr;
|
|
819
749
|
}
|
|
820
750
|
}
|
|
821
|
-
// An owner-facing notification was DELIVERED this turn — any armed
|
|
822
|
-
// coding completion fallback has been superseded by the model's own
|
|
823
|
-
// summary. A notify_user call whose tool result errored (channel
|
|
824
|
-
// outage, bad explicit target) must not disarm the fallback, or the
|
|
825
|
-
// completion is silently lost.
|
|
826
|
-
if (streamResult.notifyUserDelivered) {
|
|
827
|
-
pendingCompletionFallback = null;
|
|
828
|
-
}
|
|
829
751
|
if (streamResult.finishCalled && streamResult.awaitingUser)
|
|
830
752
|
awaitingUser = true;
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
// and can be used after a successful completion notification. In
|
|
834
|
-
// that case finish only closes the wake at the stream layer; finalize
|
|
835
|
-
// the task here when the receipt is for this exact active task so a
|
|
836
|
-
// later general heartbeat cannot resurrect it.
|
|
837
|
-
const completionReceiptMatchesActiveCodingTask = session.activeMode === "coding" &&
|
|
838
|
-
!session.pendingSwitch &&
|
|
839
|
-
!streamResult.awaitingUser &&
|
|
840
|
-
Boolean(this.deps.agentState.codingCompletionTaskStartedAt &&
|
|
841
|
-
this.deps.agentState.codingCompletionTaskStartedAt === session.getActiveCodingTaskStartedAt());
|
|
842
|
-
if (streamResult.finishCalled && completionReceiptMatchesActiveCodingTask) {
|
|
843
|
-
session.finalizeCodingCompletionAfterFinish();
|
|
844
|
-
}
|
|
753
|
+
if (streamResult.finishCalled)
|
|
754
|
+
wakeFinished = true;
|
|
845
755
|
// A watchdog abort is scoped to the active tool. Preserve the result
|
|
846
756
|
// for the next queue-driven wake rather than resuming the same provider
|
|
847
757
|
// turn, which keeps lifecycle handling identical for Claude and Pi.
|
|
@@ -899,7 +809,7 @@ export class WakeCycleRunner {
|
|
|
899
809
|
}
|
|
900
810
|
// A successful SDK result only means the stream ended; it does not
|
|
901
811
|
// prove the task ended intentionally. Keep the original wake context
|
|
902
|
-
// alive until the model calls finish
|
|
812
|
+
// alive until the model calls finish.
|
|
903
813
|
// Gated on "no subagents currently active" (not on whether a subagent
|
|
904
814
|
// continuation ever fired): while subagents run, the subagent-wait
|
|
905
815
|
// mechanism above owns the turn; once they are done, the explicit
|
|
@@ -907,22 +817,30 @@ export class WakeCycleRunner {
|
|
|
907
817
|
// subagent continuation earlier.
|
|
908
818
|
if (!this.deps.singleShot &&
|
|
909
819
|
endedWithoutLifecycleAction &&
|
|
910
|
-
!session.pendingSwitch &&
|
|
911
820
|
runningSubagents.length === 0) {
|
|
912
|
-
|
|
821
|
+
// prematureEndContinuations counts the continuations already sent in
|
|
822
|
+
// this wake. One more is Recovering; the ceiling is Stopping, and
|
|
823
|
+
// this wake ends instead of starting another continuation.
|
|
824
|
+
const prematurePhase = nextRecoveryPhase({
|
|
825
|
+
from: this.recoveryPhase,
|
|
826
|
+
bucket: "premature_result",
|
|
827
|
+
spent: prematureEndContinuations,
|
|
828
|
+
});
|
|
829
|
+
if (prematurePhase === "Recovering") {
|
|
830
|
+
this.recoveryPhase = "Recovering";
|
|
913
831
|
prematureEndContinuations++;
|
|
914
|
-
logger.warn(`Turn ended without finish
|
|
832
|
+
logger.warn(`Turn ended without finish — continuing (${prematureEndContinuations}/${MAX_PREMATURE_END_CONTINUATIONS})`);
|
|
915
833
|
messageContent = [{
|
|
916
834
|
type: "text",
|
|
917
835
|
text: [
|
|
918
|
-
"Your previous turn ended without an explicit finish
|
|
836
|
+
"Your previous turn ended without an explicit finish call, so this wake cycle is still active.",
|
|
919
837
|
"Inspect the transcript and existing tool results before acting. Do not repeat successful notifications, emails, uploads, or other mutations/side effects.",
|
|
920
|
-
"If the requested work is already complete, only call finish now. Otherwise complete the remaining work, notify the user if needed, then call finish
|
|
838
|
+
"If the requested work is already complete, only call finish now. Otherwise complete the remaining work, notify the user if needed, then call finish.",
|
|
921
839
|
].join("\n"),
|
|
922
840
|
}];
|
|
923
841
|
continue turnLoop;
|
|
924
842
|
}
|
|
925
|
-
const errorMessage = `Wake cycle ended without finish
|
|
843
|
+
const errorMessage = `Wake cycle ended without finish after ${MAX_PREMATURE_END_CONTINUATIONS} continuations`;
|
|
926
844
|
logger.err(errorMessage);
|
|
927
845
|
// The alert is only actionable when the owner is actually waiting on
|
|
928
846
|
// something, and it fires at most once per wake cycle — so a long run
|
|
@@ -943,7 +861,7 @@ export class WakeCycleRunner {
|
|
|
943
861
|
const alreadyNotifiedOwner = this.deps.agentState.notifiedUserThisWake === true;
|
|
944
862
|
const recoveryAlertEligible = trigger === "message" && !alreadyNotifiedOwner;
|
|
945
863
|
if (recoveryAlertEligible) {
|
|
946
|
-
void notifyOwner(`Agent wake recovery stopped after ${MAX_PREMATURE_END_CONTINUATIONS} attempts
|
|
864
|
+
void notifyOwner(`Agent wake recovery stopped after ${MAX_PREMATURE_END_CONTINUATIONS} attempts. The task may be incomplete; please ask me to resume it.`, config).catch((notifyErr) => {
|
|
947
865
|
logger.warn(`Failed to notify owner about exhausted wake recovery: ${notifyErr instanceof Error ? notifyErr.message : String(notifyErr)}`);
|
|
948
866
|
});
|
|
949
867
|
}
|
|
@@ -976,9 +894,18 @@ export class WakeCycleRunner {
|
|
|
976
894
|
}
|
|
977
895
|
}
|
|
978
896
|
else {
|
|
897
|
+
// The persisted count is this chain's own budget. It survives
|
|
898
|
+
// wakes and restarts, so a new wake must not refill it.
|
|
899
|
+
const toolAbortPhase = nextRecoveryPhase({
|
|
900
|
+
from: this.recoveryPhase,
|
|
901
|
+
bucket: "tool_abort",
|
|
902
|
+
spent: this.toolAbortRecoveries,
|
|
903
|
+
});
|
|
979
904
|
this.toolAbortRecoveryChainId ??= randomUUID();
|
|
980
905
|
this.toolAbortRecoveries += 1;
|
|
981
|
-
const retryable =
|
|
906
|
+
const retryable = toolAbortPhase === "Recovering";
|
|
907
|
+
if (retryable)
|
|
908
|
+
this.recoveryPhase = "Recovering";
|
|
982
909
|
if (!retryable)
|
|
983
910
|
this.toolAbortRecoveryExhausted = true;
|
|
984
911
|
this.persistToolAbortRecoveryChain();
|
|
@@ -1020,12 +947,7 @@ export class WakeCycleRunner {
|
|
|
1020
947
|
this.clearToolAbortRecoveryBudget();
|
|
1021
948
|
}
|
|
1022
949
|
else if (streamResult.finishCalled) {
|
|
1023
|
-
|
|
1024
|
-
// handoffs must retain the budget; only a real finish tool clears
|
|
1025
|
-
// here. switch_session(complete) clears below via reason.
|
|
1026
|
-
if (streamResult.lifecycleTool !== "switch_session") {
|
|
1027
|
-
this.clearToolAbortRecoveryBudget();
|
|
1028
|
-
}
|
|
950
|
+
this.clearToolAbortRecoveryBudget();
|
|
1029
951
|
}
|
|
1030
952
|
// --- Direct assistant text delivery ---
|
|
1031
953
|
// When the model writes the answer as prose, calls finish, and never
|
|
@@ -1033,44 +955,34 @@ export class WakeCycleRunner {
|
|
|
1033
955
|
// adapters drop `assistant_text`). Send the LAST text block as a
|
|
1034
956
|
// normal notify so the originating channel actually delivers it.
|
|
1035
957
|
// Concatenated earlier blocks, thinking, and tool narration stay out.
|
|
1036
|
-
// Heartbeat,
|
|
958
|
+
// Heartbeat, singleShot, and toolTimeout stay silent.
|
|
1037
959
|
// Fin-App matches Telegram: live assistant_text is dropped, so this
|
|
1038
960
|
// last-block notify is the courtesy delivery when finish has no
|
|
1039
961
|
// notify_user. TUI still presents assistant_text in-thread.
|
|
1040
|
-
const fallbackText =
|
|
1041
|
-
// An accepted switch_session always leaves a pending request here --
|
|
1042
|
-
// `executePendingSwitch` only runs later in this wake -- so
|
|
1043
|
-
// `pendingSwitch` already covers that exit on its own. Requiring an
|
|
1044
|
-
// accepted `finish` below excludes it a second time.
|
|
1045
|
-
const skipBecauseSwitch = Boolean(session.pendingSwitch);
|
|
962
|
+
const fallbackText = lastReplyText;
|
|
1046
963
|
const skipBecauseNotified = notifyUserDeliveredThisWake || streamResult.notifyUserDelivered;
|
|
1047
964
|
const finishAccepted = streamResult.lifecycleTool === "finish";
|
|
1048
965
|
// Only replies to messages in the initial wake batch are eligible.
|
|
1049
966
|
// Resumes, external wakes and calendars may carry a delivery target
|
|
1050
967
|
// without requesting a reply. Mid-turn work uses explicit notify_user
|
|
1051
968
|
// for its result; a quick acknowledgment does not enable this fallback.
|
|
1052
|
-
const replyMessages = messages.filter((message) =>
|
|
969
|
+
const replyMessages = messages.filter((message) => message.channel !== "system" && message.meta?.kind !== EXTERNAL_WAKE_KIND && !isCalendarInterruptMessage(message));
|
|
1053
970
|
const fallbackEligible = !this.deps.singleShot &&
|
|
1054
971
|
!streamResult.toolTimeout &&
|
|
1055
972
|
!skipBecauseNotified &&
|
|
1056
973
|
fallbackText.length > 0 &&
|
|
1057
974
|
trigger === "message" &&
|
|
1058
975
|
finishAccepted &&
|
|
1059
|
-
!skipBecauseSwitch &&
|
|
1060
976
|
replyMessages.length > 0;
|
|
1061
977
|
if (replyMessages.length === 0 && fallbackText.length > 0 && finishAccepted && !skipBecauseNotified) {
|
|
1062
978
|
logger.info("Skipped finish-without-notify fallback: no reply message in the initial wake batch");
|
|
1063
979
|
}
|
|
1064
|
-
if (skipBecauseSwitch && fallbackText.length > 0 && trigger === "message") {
|
|
1065
|
-
logger.warn(`Skipped assistant_text delivery: the turn took switch_session without notify_user, so this text was NOT delivered to the owner: ${fallbackText.slice(0, 2000)}`);
|
|
1066
|
-
}
|
|
1067
980
|
// Premature-end recovery re-prompts, so unfinished prose is deliberately
|
|
1068
981
|
// not delivered (a rejected `finish` lands here too: it sets neither
|
|
1069
982
|
// `finishCalled` nor `lifecycleTool`). The owner still gets the generic
|
|
1070
983
|
// exhausted-recovery alert, but the text itself would vanish without a
|
|
1071
984
|
// trace -- record it so the drop is diagnosable.
|
|
1072
985
|
if (!finishAccepted &&
|
|
1073
|
-
!skipBecauseSwitch &&
|
|
1074
986
|
!skipBecauseNotified &&
|
|
1075
987
|
!streamResult.toolTimeout &&
|
|
1076
988
|
fallbackText.length > 0 &&
|
|
@@ -1080,16 +992,10 @@ export class WakeCycleRunner {
|
|
|
1080
992
|
if (fallbackEligible) {
|
|
1081
993
|
const fallbackTarget = resolveDirectAssistantFallbackTarget(replyMessages, ownerConfig.ownerEmail);
|
|
1082
994
|
const livePresentedOnChat = Boolean(fallbackTarget && presentsAssistantText(fallbackTarget.channel)) &&
|
|
1083
|
-
|
|
995
|
+
lastReplyPresented;
|
|
1084
996
|
if (livePresentedOnChat) {
|
|
1085
997
|
// Last live block actually landed in chat. Do not splice a
|
|
1086
998
|
// second last-block notify into the same thread.
|
|
1087
|
-
pendingCompletionFallback = null;
|
|
1088
|
-
}
|
|
1089
|
-
else if (fallbackTarget &&
|
|
1090
|
-
normalizeChannelName(fallbackTarget.channel) === "finapp" &&
|
|
1091
|
-
session.activeMode === "coding") {
|
|
1092
|
-
// Coding narration never becomes a Fin-App chat bubble. TUI still last-block notifies.
|
|
1093
999
|
}
|
|
1094
1000
|
else if (fallbackTarget) {
|
|
1095
1001
|
// Best-effort courtesy delivery: never let a fallback failure
|
|
@@ -1111,7 +1017,6 @@ export class WakeCycleRunner {
|
|
|
1111
1017
|
}
|
|
1112
1018
|
else {
|
|
1113
1019
|
logger.warn(`Delivered finish-without-notify fallback via ${fallbackTarget.channel} to ${fallbackTarget.to}`);
|
|
1114
|
-
pendingCompletionFallback = null;
|
|
1115
1020
|
}
|
|
1116
1021
|
}
|
|
1117
1022
|
catch (err) {
|
|
@@ -1180,46 +1085,6 @@ export class WakeCycleRunner {
|
|
|
1180
1085
|
logger.warn(`Post-query compaction failed: ${compactErr instanceof Error ? compactErr.message : String(compactErr)}`);
|
|
1181
1086
|
}
|
|
1182
1087
|
}
|
|
1183
|
-
const switchResult = session.executePendingSwitch();
|
|
1184
|
-
if (switchResult) {
|
|
1185
|
-
// switch_session sets finishCalled, so the finishCalled branch above
|
|
1186
|
-
// skips clearing when lifecycleTool is switch_session. Only complete
|
|
1187
|
-
// clears here; temporary handoff retains the budget.
|
|
1188
|
-
if (switchResult.reason === "complete") {
|
|
1189
|
-
this.clearToolAbortRecoveryBudget();
|
|
1190
|
-
}
|
|
1191
|
-
didSwitch = true;
|
|
1192
|
-
switchForwardMessage = [switchResult.workspaceNotice, switchResult.forwardMessage]
|
|
1193
|
-
.filter(Boolean)
|
|
1194
|
-
.join("\n\n");
|
|
1195
|
-
// Completion handoffs are user-visible outcomes. The re-entered
|
|
1196
|
-
// general session is expected to humanize the memo via notify_user.
|
|
1197
|
-
// Do not dump the memo as chat (internal working text). Arm a marker:
|
|
1198
|
-
// a later notify_user / last-block send disarms it; if the cycle
|
|
1199
|
-
// ends with no successful owner ping, last-resort a fixed human line
|
|
1200
|
-
// (PR #839: do not silently drop the result). Newest memo wins.
|
|
1201
|
-
if (switchResult.target === "general" &&
|
|
1202
|
-
switchResult.ownerNotificationRequired &&
|
|
1203
|
-
switchResult.completionMemo) {
|
|
1204
|
-
pendingCompletionFallback = switchResult.completionMemo;
|
|
1205
|
-
}
|
|
1206
|
-
// Coding already sent this task's final result. No memo was created,
|
|
1207
|
-
// so end the wake instead of invoking general for a duplicate summary.
|
|
1208
|
-
if (switchResult.target === "general" &&
|
|
1209
|
-
switchResult.ownerNotificationRequired === false &&
|
|
1210
|
-
switchResult.completionMemo) {
|
|
1211
|
-
// reason="complete" already cleared the recovery budget above.
|
|
1212
|
-
logger.system("Coding completion already delivered — ending wake without re-entering general");
|
|
1213
|
-
this.deps.engineFallback.noteEngineSuccess();
|
|
1214
|
-
this.invalidJsonBodyRecoveryCount = 0;
|
|
1215
|
-
this.localCoordinationErrors = 0;
|
|
1216
|
-
this.emptyTurnRetries = 0;
|
|
1217
|
-
consecutiveErrors = 0;
|
|
1218
|
-
break;
|
|
1219
|
-
}
|
|
1220
|
-
logger.system(`Re-entering wake cycle for ${switchResult.target} session`);
|
|
1221
|
-
continue;
|
|
1222
|
-
}
|
|
1223
1088
|
this.deps.engineFallback.noteEngineSuccess();
|
|
1224
1089
|
this.invalidJsonBodyRecoveryCount = 0;
|
|
1225
1090
|
this.localCoordinationErrors = 0;
|
|
@@ -1245,23 +1110,14 @@ export class WakeCycleRunner {
|
|
|
1245
1110
|
if (errorResult.kind === "continue_with_message") {
|
|
1246
1111
|
consecutiveErrors = errorResult.consecutiveErrors;
|
|
1247
1112
|
contentBlocks = [{ type: "text", text: errorResult.message }];
|
|
1248
|
-
// A rebuilt session starts without the thread's tasks (#1996).
|
|
1249
|
-
if (errorResult.newSession)
|
|
1250
|
-
contentBlocks = withFreshThreadTaskBlock(contentBlocks);
|
|
1251
|
-
didSwitch = false;
|
|
1252
|
-
switchForwardMessage = "";
|
|
1253
1113
|
continue;
|
|
1254
1114
|
}
|
|
1255
1115
|
if (errorResult.kind === "continue_with_reset") {
|
|
1256
1116
|
consecutiveErrors = 0;
|
|
1257
|
-
contentBlocks = withFreshThreadTaskBlock(contentBlocks);
|
|
1258
1117
|
continue;
|
|
1259
1118
|
}
|
|
1260
1119
|
if (errorResult.kind === "continue_preserve_count") {
|
|
1261
1120
|
consecutiveErrors = errorResult.consecutiveErrors;
|
|
1262
|
-
// Invalid-json recovery may have compacted (#1996): resend the
|
|
1263
|
-
// current task block. A no-op when nothing changed.
|
|
1264
|
-
contentBlocks = withFreshThreadTaskBlock(contentBlocks);
|
|
1265
1121
|
continue;
|
|
1266
1122
|
}
|
|
1267
1123
|
consecutiveErrors = errorResult.consecutiveErrors;
|
|
@@ -1269,17 +1125,7 @@ export class WakeCycleRunner {
|
|
|
1269
1125
|
}
|
|
1270
1126
|
}
|
|
1271
1127
|
break;
|
|
1272
|
-
} // end
|
|
1273
|
-
// --- Coding completion last-resort ping (PR #839) ---
|
|
1274
|
-
// The wake cycle is over and no owner notification superseded the armed
|
|
1275
|
-
// completion (general silent, errored, or stopped). Send a fixed human
|
|
1276
|
-
// line so the result is not silently lost. Never send the session memo
|
|
1277
|
-
// (handoff instructions, paths, do-not-notify constraints).
|
|
1278
|
-
if (pendingCompletionFallback) {
|
|
1279
|
-
logger.warn("Wake cycle ended without an owner notification for a coding completion — sending a generic ping, not the session memo");
|
|
1280
|
-
await deliverCodingCompletionFallbackPing(ownerConfig);
|
|
1281
|
-
pendingCompletionFallback = null;
|
|
1282
|
-
}
|
|
1128
|
+
} // end wake loop
|
|
1283
1129
|
// --- Post-wake-cycle transcript indexing (best-effort) ---
|
|
1284
1130
|
// Usage reports are no longer enqueued immediately here. Instead,
|
|
1285
1131
|
// indexWakeCycle extracts and stores tool call facts, and the background
|
|
@@ -1293,9 +1139,7 @@ export class WakeCycleRunner {
|
|
|
1293
1139
|
const wakeCycleOutcome = session.isStopRequested()
|
|
1294
1140
|
? "stopped"
|
|
1295
1141
|
: !terminalError && consecutiveErrors === 0
|
|
1296
|
-
?
|
|
1297
|
-
? "switched"
|
|
1298
|
-
: "completed"
|
|
1142
|
+
? "completed"
|
|
1299
1143
|
: "error";
|
|
1300
1144
|
// Always index wake cycles — including stopped/error cycles — so that
|
|
1301
1145
|
// usage metering is consistent for all cycles. The outcome field records
|
|
@@ -1304,7 +1148,7 @@ export class WakeCycleRunner {
|
|
|
1304
1148
|
const wakeCycleEndLine = await countFileLines(postCycleTranscript.path);
|
|
1305
1149
|
void indexWakeCycle({
|
|
1306
1150
|
wakeCycleId,
|
|
1307
|
-
sessionType:
|
|
1151
|
+
sessionType: "general",
|
|
1308
1152
|
sourceFile: postCycleTranscript.path,
|
|
1309
1153
|
sourceFormat: postCycleTranscript.format,
|
|
1310
1154
|
startLine: postCycleStartLine,
|
|
@@ -1330,10 +1174,11 @@ export class WakeCycleRunner {
|
|
|
1330
1174
|
: awaitingUser
|
|
1331
1175
|
? "waiting_user"
|
|
1332
1176
|
: "completed",
|
|
1177
|
+
finished: wakeFinished,
|
|
1333
1178
|
};
|
|
1334
1179
|
}
|
|
1335
1180
|
/**
|
|
1336
|
-
* Handle an error from the
|
|
1181
|
+
* Handle an error from the wake loop. Returns:
|
|
1337
1182
|
* - `continue_with_reset` for recovery paths that should retry immediately
|
|
1338
1183
|
* with a clean error counter (compaction/sanitization succeeded)
|
|
1339
1184
|
* - `continue_preserve_count` for normal retryable failures that should
|
|
@@ -1352,6 +1197,12 @@ export class WakeCycleRunner {
|
|
|
1352
1197
|
logger.system(err.message);
|
|
1353
1198
|
return { kind: "done", consecutiveErrors };
|
|
1354
1199
|
}
|
|
1200
|
+
if (this.silenceRecoveryExhausted) {
|
|
1201
|
+
// The call already spent its own silence ceiling and moved to Stopping.
|
|
1202
|
+
// Another backoff here would replay that call instead of ending it.
|
|
1203
|
+
logger.system("Stream silence ceiling already spent — ending this wake cycle");
|
|
1204
|
+
return { kind: "done", consecutiveErrors: consecutiveErrors + 1 };
|
|
1205
|
+
}
|
|
1355
1206
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
1356
1207
|
const category = classifyError(err);
|
|
1357
1208
|
// A local coordination error never reached a provider, so it must not
|
|
@@ -1369,6 +1220,8 @@ export class WakeCycleRunner {
|
|
|
1369
1220
|
// terminal facts for this run, not a reason to start conversational
|
|
1370
1221
|
// recovery, notify the owner directly, sleep, or enqueue another wake.
|
|
1371
1222
|
if (this.deps.singleShot) {
|
|
1223
|
+
// Kept for the failure report, so the caller sees the cause.
|
|
1224
|
+
getWorkerExecutionRuntime()?.noteError(errMsg);
|
|
1372
1225
|
return { kind: "done", consecutiveErrors };
|
|
1373
1226
|
}
|
|
1374
1227
|
if (err instanceof CompactionFailureError ||
|
|
@@ -1430,7 +1283,6 @@ export class WakeCycleRunner {
|
|
|
1430
1283
|
message: `${config.agentName}: invalid Pi session could not be reset`,
|
|
1431
1284
|
details: {
|
|
1432
1285
|
code: "INVALID_PI_SESSION_RECOVERY_FAILED",
|
|
1433
|
-
activeSession: session.activeMode,
|
|
1434
1286
|
sessionId: invalidSessionId ?? "unknown",
|
|
1435
1287
|
provider: config.provider,
|
|
1436
1288
|
model: reportedModel(config),
|
|
@@ -1493,7 +1345,6 @@ export class WakeCycleRunner {
|
|
|
1493
1345
|
message: `${config.agentName}: stale session could not be reset`,
|
|
1494
1346
|
details: {
|
|
1495
1347
|
code: "SESSION_NOT_FOUND_RECOVERY_FAILED",
|
|
1496
|
-
activeSession: session.activeMode,
|
|
1497
1348
|
sessionId: deadSessionId ?? "unknown",
|
|
1498
1349
|
provider: config.provider,
|
|
1499
1350
|
model: reportedModel(config),
|
|
@@ -1580,7 +1431,7 @@ export class WakeCycleRunner {
|
|
|
1580
1431
|
}
|
|
1581
1432
|
if (recoveryCount === 2) {
|
|
1582
1433
|
const oldSessionId = session.activeSession.getSessionId();
|
|
1583
|
-
logger.warn(
|
|
1434
|
+
logger.warn("Invalid JSON body repeated after compaction; resetting session before retry");
|
|
1584
1435
|
session.activeSession.resetForNewSession("Previous session was reset automatically after repeated provider `400 Invalid JSON body` errors. " +
|
|
1585
1436
|
"This usually means the provider rejected the context/payload even after compaction. Continue from memory and the current user request; avoid reloading large prior tool outputs unless needed.");
|
|
1586
1437
|
logger.system(`Invalid-json-body recovery reset session: old=${oldSessionId ?? "unknown"} new=${session.activeSession.getSessionId() ?? "pending"}`);
|
|
@@ -1595,7 +1446,6 @@ export class WakeCycleRunner {
|
|
|
1595
1446
|
code: "INVALID_JSON_BODY_RECOVERY_FAILED",
|
|
1596
1447
|
consecutiveInvalidJsonBodyErrors: recoveryCount,
|
|
1597
1448
|
actionsAttempted: ["compaction", "session_reset", "controlled_restart"],
|
|
1598
|
-
activeSession: session.activeSession.mode,
|
|
1599
1449
|
provider: config.provider,
|
|
1600
1450
|
model: reportedModel(config),
|
|
1601
1451
|
},
|
|
@@ -1620,16 +1470,15 @@ export class WakeCycleRunner {
|
|
|
1620
1470
|
return { kind: "continue_preserve_count", consecutiveErrors };
|
|
1621
1471
|
}
|
|
1622
1472
|
// Retries exhausted: tell the owner what actually broke, naming the
|
|
1623
|
-
// local cause instead of blaming the model provider.
|
|
1624
|
-
|
|
1473
|
+
// local cause instead of blaming the model provider. The wake ends here.
|
|
1474
|
+
// Sleeping would keep the foreground slot busy until the timer fired.
|
|
1625
1475
|
logger.warn(`Notifying owner about persistent local coordination error: ${errMsg}`);
|
|
1626
1476
|
try {
|
|
1627
|
-
await notifyOwner(formatOwnerErrorNotice(category, consecutiveErrors,
|
|
1477
|
+
await notifyOwner(formatOwnerErrorNotice(category, consecutiveErrors, errMsg), config);
|
|
1628
1478
|
}
|
|
1629
1479
|
catch (notifyErr) {
|
|
1630
1480
|
logger.warn(`Failed to send error notification to owner: ${notifyErr instanceof Error ? notifyErr.message : String(notifyErr)}`);
|
|
1631
1481
|
}
|
|
1632
|
-
await new Promise((r) => setTimeout(r, FATAL_SLEEP_MS));
|
|
1633
1482
|
return { kind: "done", consecutiveErrors };
|
|
1634
1483
|
}
|
|
1635
1484
|
// --- Known malformed Responses replay ---
|
|
@@ -1668,7 +1517,7 @@ export class WakeCycleRunner {
|
|
|
1668
1517
|
}
|
|
1669
1518
|
logger.err(`Malformed Responses replay recovery failed — ending wake: ${errMsg}`);
|
|
1670
1519
|
try {
|
|
1671
|
-
await notifyOwner(formatOwnerErrorNotice(category, consecutiveErrors,
|
|
1520
|
+
await notifyOwner(formatOwnerErrorNotice(category, consecutiveErrors, errMsg), config);
|
|
1672
1521
|
}
|
|
1673
1522
|
catch (notifyErr) {
|
|
1674
1523
|
logger.warn(`Failed to send error notification to owner: ${notifyErr instanceof Error ? notifyErr.message : String(notifyErr)}`);
|
|
@@ -1680,10 +1529,7 @@ export class WakeCycleRunner {
|
|
|
1680
1529
|
// whether this wake has work that still needs an explicit resolution.
|
|
1681
1530
|
if (category === "empty_turn") {
|
|
1682
1531
|
const { activityTracker, interruptHandler } = this.deps;
|
|
1683
|
-
const hasPendingWork = activityTracker.getTodos().some((todo) => todo.status === "pending" || todo.status === "in_progress") || activityTracker.getActiveSubagents().length > 0
|
|
1684
|
-
// Paused tasks persist across wakes; they do not make an otherwise
|
|
1685
|
-
// idle heartbeat responsible for resuming coding work.
|
|
1686
|
-
|| session.getCodingSessionState() === "in_progress";
|
|
1532
|
+
const hasPendingWork = activityTracker.getTodos().some((todo) => todo.status === "pending" || todo.status === "in_progress") || activityTracker.getActiveSubagents().length > 0;
|
|
1687
1533
|
const idleHeartbeat = wake.trigger === "heartbeat"
|
|
1688
1534
|
&& wake.messages.length === 0
|
|
1689
1535
|
&& !interruptHandler.hasAcceptedWorkThisCycle()
|
|
@@ -1692,39 +1538,45 @@ export class WakeCycleRunner {
|
|
|
1692
1538
|
logger.system("Empty assistant turn on an idle heartbeat — ending normally without retry");
|
|
1693
1539
|
return { kind: "completed", consecutiveErrors: 0 };
|
|
1694
1540
|
}
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
].join("\n");
|
|
1703
|
-
logger.system("Empty assistant turn with unresolved work — sending one explicit continuation");
|
|
1704
|
-
// Context pressure is independent of the empty response. Only compact
|
|
1705
|
-
// when the usage snapshot warrants it, and retain bounded recovery.
|
|
1541
|
+
const phase = nextRecoveryPhase({
|
|
1542
|
+
from: this.recoveryPhase,
|
|
1543
|
+
bucket: "empty_turn",
|
|
1544
|
+
spent: this.emptyTurnRetries,
|
|
1545
|
+
});
|
|
1546
|
+
if (phase === "Stopping") {
|
|
1547
|
+
logger.warn(`Empty-turn continuation did not confirm task completion: ${errMsg}`);
|
|
1706
1548
|
try {
|
|
1707
|
-
await this.
|
|
1549
|
+
await notifyOwner(formatOwnerErrorNotice(category, this.emptyTurnRetries, errMsg), config);
|
|
1708
1550
|
}
|
|
1709
|
-
catch (
|
|
1710
|
-
|
|
1711
|
-
throw compactErr;
|
|
1712
|
-
const recovery = await this.recoverOversizedContext(compactErr, session, consecutiveErrors);
|
|
1713
|
-
if (recovery.kind !== "continue_with_reset")
|
|
1714
|
-
return recovery;
|
|
1715
|
-
// The session was rebuilt: it has no task block in its history.
|
|
1716
|
-
return { kind: "continue_with_message", consecutiveErrors: 0, message, newSession: true };
|
|
1551
|
+
catch (notifyErr) {
|
|
1552
|
+
logger.warn(`Failed to send empty-turn notification to owner: ${notifyErr instanceof Error ? notifyErr.message : String(notifyErr)}`);
|
|
1717
1553
|
}
|
|
1718
|
-
return { kind: "
|
|
1554
|
+
return { kind: "done", consecutiveErrors };
|
|
1719
1555
|
}
|
|
1720
|
-
|
|
1556
|
+
this.recoveryPhase = "Recovering";
|
|
1557
|
+
this.emptyTurnRetries++;
|
|
1558
|
+
const message = [
|
|
1559
|
+
"Your previous turn ended with no additional content. This alone does not indicate whether the task is complete.",
|
|
1560
|
+
"Review the current request, task state, and existing tool results before acting. Do not repeat successful notifications, emails, uploads, or other side effects.",
|
|
1561
|
+
"If no work remains, only call finish. Otherwise continue only the unfinished work, wait for running subagents as needed, then finish.",
|
|
1562
|
+
"If completion cannot be verified or user input is needed, explain what remains uncertain to the user and call finish(awaiting_user=true).",
|
|
1563
|
+
].join("\n");
|
|
1564
|
+
logger.system("Empty assistant turn with unresolved work — sending one explicit continuation");
|
|
1565
|
+
// Context pressure is independent of the empty response. Only compact
|
|
1566
|
+
// when the usage snapshot warrants it, and retain bounded recovery.
|
|
1721
1567
|
try {
|
|
1722
|
-
await
|
|
1568
|
+
await this.compactBeforeErrorRetry(session, "empty-turn continuation");
|
|
1723
1569
|
}
|
|
1724
|
-
catch (
|
|
1725
|
-
|
|
1570
|
+
catch (compactErr) {
|
|
1571
|
+
if (!(compactErr instanceof CompactionFailureError))
|
|
1572
|
+
throw compactErr;
|
|
1573
|
+
const recovery = await this.recoverOversizedContext(compactErr, session, consecutiveErrors);
|
|
1574
|
+
if (recovery.kind !== "continue_with_reset")
|
|
1575
|
+
return recovery;
|
|
1576
|
+
// The session was rebuilt: it has no task block in its history.
|
|
1577
|
+
return { kind: "continue_with_message", consecutiveErrors: 0, message, newSession: true };
|
|
1726
1578
|
}
|
|
1727
|
-
return { kind: "
|
|
1579
|
+
return { kind: "continue_with_message", consecutiveErrors, message };
|
|
1728
1580
|
}
|
|
1729
1581
|
// --- Engine fallback (issue #2519) ---
|
|
1730
1582
|
// Engine-scoped failures cool the engine down and move on; failures of the
|
|
@@ -1763,10 +1615,22 @@ export class WakeCycleRunner {
|
|
|
1763
1615
|
logger.system("No alternate engine available for transient network failures; keeping consecutiveErrors and the cooldown");
|
|
1764
1616
|
}
|
|
1765
1617
|
}
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1618
|
+
// consecutiveErrors counts the failures already seen in this wake. The
|
|
1619
|
+
// notify threshold is the unknown bucket, not the network disconnect
|
|
1620
|
+
// ceiling. Reaching it is Stopping: notify, then end the wake. The next
|
|
1621
|
+
// attempt waits for a queued message or the proactive timer, not a sleep
|
|
1622
|
+
// that holds this slot.
|
|
1623
|
+
const unknownPhase = category === "fatal"
|
|
1624
|
+
? "Stopping"
|
|
1625
|
+
: nextRecoveryPhase({
|
|
1626
|
+
from: this.recoveryPhase,
|
|
1627
|
+
bucket: "unknown",
|
|
1628
|
+
spent: consecutiveErrors,
|
|
1629
|
+
});
|
|
1630
|
+
if (unknownPhase === "Recovering")
|
|
1631
|
+
this.recoveryPhase = "Recovering";
|
|
1632
|
+
if (unknownPhase === "Stopping") {
|
|
1633
|
+
const notice = formatOwnerErrorNotice(category, consecutiveErrors);
|
|
1770
1634
|
logger.warn(`Notifying owner about repeated agent error: ${errMsg}`);
|
|
1771
1635
|
try {
|
|
1772
1636
|
await notifyOwner(notice, config);
|
|
@@ -1775,7 +1639,6 @@ export class WakeCycleRunner {
|
|
|
1775
1639
|
logger.warn(`Failed to send error notification to owner: ${notifyErr instanceof Error ? notifyErr.message : String(notifyErr)}`);
|
|
1776
1640
|
}
|
|
1777
1641
|
consecutiveErrors = 0;
|
|
1778
|
-
await new Promise((r) => setTimeout(r, FATAL_SLEEP_MS));
|
|
1779
1642
|
}
|
|
1780
1643
|
else {
|
|
1781
1644
|
try {
|
|
@@ -1815,8 +1678,8 @@ export class WakeCycleRunner {
|
|
|
1815
1678
|
return;
|
|
1816
1679
|
}
|
|
1817
1680
|
// Between the failed `/compact` and the end of the cycle the session may
|
|
1818
|
-
// have been
|
|
1819
|
-
//
|
|
1681
|
+
// have already been rotated by the error path. Only rotate the session
|
|
1682
|
+
// that actually failed to compact.
|
|
1820
1683
|
if (pending.sessionId === null || session.activeSession.getSessionId() !== pending.sessionId) {
|
|
1821
1684
|
logger.system(`Post-query compaction failed terminally (${err.errorCode}) but the active session changed before the cycle ended; leaving rotation to the next check`);
|
|
1822
1685
|
return;
|
|
@@ -1854,8 +1717,15 @@ export class WakeCycleRunner {
|
|
|
1854
1717
|
// Two recovery turns total: repair, then one refresh. The second branch is
|
|
1855
1718
|
// gated by the ceiling, so raising MAX_OUTPUT_RECOVERY_ATTEMPTS is what
|
|
1856
1719
|
// allows another turn. Advancing before I/O keeps a failed repair from
|
|
1857
|
-
// resetting the allowance.
|
|
1858
|
-
|
|
1720
|
+
// resetting the allowance. The two kinds keep separate counts.
|
|
1721
|
+
const outputPhase = nextRecoveryPhase({
|
|
1722
|
+
from: this.recoveryPhase,
|
|
1723
|
+
bucket: recoveryKind === "policy_refused" ? "policy_refusal" : "oversized",
|
|
1724
|
+
spent: attempts[recoveryKind],
|
|
1725
|
+
});
|
|
1726
|
+
if (outputPhase === "Recovering")
|
|
1727
|
+
this.recoveryPhase = "Recovering";
|
|
1728
|
+
if (attempts[recoveryKind] === 0 && outputPhase === "Recovering") {
|
|
1859
1729
|
attempts[recoveryKind]++;
|
|
1860
1730
|
if (!compactionAlreadyFailed) {
|
|
1861
1731
|
try {
|
|
@@ -1874,7 +1744,7 @@ export class WakeCycleRunner {
|
|
|
1874
1744
|
logger.system("SDK auto-compaction already failed — skipping same-session transcript repair and rotating context");
|
|
1875
1745
|
}
|
|
1876
1746
|
}
|
|
1877
|
-
if (attempts[recoveryKind] < MAX_OUTPUT_RECOVERY_ATTEMPTS) {
|
|
1747
|
+
if (attempts[recoveryKind] < MAX_OUTPUT_RECOVERY_ATTEMPTS && outputPhase === "Recovering") {
|
|
1878
1748
|
attempts[recoveryKind]++;
|
|
1879
1749
|
const previousId = session.activeSession.getSessionId();
|
|
1880
1750
|
try {
|