visionclaw 0.1.219-dev.codex-issue-2805-worker-runtime.3 → 0.1.219-dev.codex-fix-2941-activity-foreground.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 +16 -0
- package/dist/agent/api-proxy.d.ts.map +1 -1
- package/dist/agent/api-proxy.js +8 -9
- package/dist/agent/api-proxy.js.map +1 -1
- package/dist/agent/browser-launcher.d.ts +0 -3
- package/dist/agent/browser-launcher.d.ts.map +1 -1
- package/dist/agent/browser-launcher.js +43 -101
- package/dist/agent/browser-launcher.js.map +1 -1
- package/dist/agent/coding-conventions.d.ts +3 -2
- package/dist/agent/coding-conventions.d.ts.map +1 -1
- package/dist/agent/coding-conventions.js +8 -7
- package/dist/agent/coding-conventions.js.map +1 -1
- package/dist/agent/command-handlers.d.ts.map +1 -1
- package/dist/agent/command-handlers.js +16 -4
- 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 +3 -9
- 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 +7 -0
- package/dist/agent/context-refresh.js.map +1 -1
- package/dist/agent/context.d.ts.map +1 -1
- package/dist/agent/context.js +8 -6
- package/dist/agent/context.js.map +1 -1
- package/dist/agent/engine-fallback.d.ts +35 -0
- package/dist/agent/engine-fallback.d.ts.map +1 -1
- package/dist/agent/engine-fallback.js +3 -4
- package/dist/agent/engine-fallback.js.map +1 -1
- package/dist/agent/engines/browser-tool-policy.d.ts +1 -12
- package/dist/agent/engines/browser-tool-policy.d.ts.map +1 -1
- package/dist/agent/engines/browser-tool-policy.js +2 -17
- package/dist/agent/engines/browser-tool-policy.js.map +1 -1
- package/dist/agent/engines/claude/session.d.ts +0 -1
- package/dist/agent/engines/claude/session.d.ts.map +1 -1
- package/dist/agent/engines/claude/session.js +36 -21
- package/dist/agent/engines/claude/session.js.map +1 -1
- package/dist/agent/engines/pi/tools.d.ts.map +1 -1
- package/dist/agent/engines/pi/tools.js +10 -2
- package/dist/agent/engines/pi/tools.js.map +1 -1
- package/dist/agent/engines/pi-coding/session.d.ts +0 -3
- package/dist/agent/engines/pi-coding/session.d.ts.map +1 -1
- package/dist/agent/engines/pi-coding/session.js +22 -19
- package/dist/agent/engines/pi-coding/session.js.map +1 -1
- package/dist/agent/engines/session-types.d.ts +0 -6
- package/dist/agent/engines/session-types.d.ts.map +1 -1
- package/dist/agent/external-context/runtime.d.ts.map +1 -1
- package/dist/agent/external-context/runtime.js +14 -15
- package/dist/agent/external-context/runtime.js.map +1 -1
- package/dist/agent/fast-responder.d.ts +20 -4
- package/dist/agent/fast-responder.d.ts.map +1 -1
- package/dist/agent/fast-responder.js +39 -9
- package/dist/agent/fast-responder.js.map +1 -1
- package/dist/agent/interrupt-handler.d.ts +18 -4
- package/dist/agent/interrupt-handler.d.ts.map +1 -1
- package/dist/agent/interrupt-handler.js +284 -49
- 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 +0 -3
- 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 +5 -6
- package/dist/agent/lifecycle-trace.js.map +1 -1
- package/dist/agent/loop.d.ts +1 -4
- package/dist/agent/loop.d.ts.map +1 -1
- package/dist/agent/loop.js +129 -105
- 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 +15 -3
- package/dist/agent/memory-protocol.js.map +1 -1
- package/dist/agent/memory-store.d.ts.map +1 -1
- package/dist/agent/memory-store.js +1 -11
- package/dist/agent/memory-store.js.map +1 -1
- package/dist/agent/model-provider.d.ts +0 -2
- package/dist/agent/model-provider.d.ts.map +1 -1
- package/dist/agent/model-provider.js +25 -31
- package/dist/agent/model-provider.js.map +1 -1
- package/dist/agent/product-identity.d.ts +4 -5
- package/dist/agent/product-identity.d.ts.map +1 -1
- package/dist/agent/product-identity.js +6 -7
- package/dist/agent/product-identity.js.map +1 -1
- package/dist/agent/public-activity.d.ts +1 -1
- package/dist/agent/public-activity.d.ts.map +1 -1
- package/dist/agent/public-activity.js.map +1 -1
- package/dist/agent/reply-watchdog.d.ts +3 -5
- package/dist/agent/reply-watchdog.d.ts.map +1 -1
- package/dist/agent/reply-watchdog.js +4 -6
- package/dist/agent/reply-watchdog.js.map +1 -1
- package/dist/agent/session-manager.d.ts +0 -5
- package/dist/agent/session-manager.d.ts.map +1 -1
- package/dist/agent/session-manager.js +0 -7
- package/dist/agent/session-manager.js.map +1 -1
- package/dist/agent/state.d.ts +0 -7
- package/dist/agent/state.d.ts.map +1 -1
- package/dist/agent/state.js +11 -21
- package/dist/agent/state.js.map +1 -1
- package/dist/agent/stream-handler.d.ts.map +1 -1
- package/dist/agent/stream-handler.js +17 -0
- package/dist/agent/stream-handler.js.map +1 -1
- package/dist/agent/system-prompt.d.ts.map +1 -1
- package/dist/agent/system-prompt.js +6 -10
- package/dist/agent/system-prompt.js.map +1 -1
- package/dist/agent/transcript/transcript-indexer.d.ts +28 -0
- package/dist/agent/transcript/transcript-indexer.d.ts.map +1 -1
- package/dist/agent/transcript/transcript-indexer.js +57 -58
- package/dist/agent/transcript/transcript-indexer.js.map +1 -1
- package/dist/agent/usage/usage-report-queue.d.ts.map +1 -1
- package/dist/agent/usage/usage-report-queue.js +52 -53
- package/dist/agent/usage/usage-report-queue.js.map +1 -1
- package/dist/agent/wake-cycle-runner.d.ts +8 -7
- package/dist/agent/wake-cycle-runner.d.ts.map +1 -1
- package/dist/agent/wake-cycle-runner.js +66 -105
- 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 +5 -6
- package/dist/calendar/occurrence-ownership.js.map +1 -1
- package/dist/calendar/scheduler.d.ts.map +1 -1
- package/dist/calendar/scheduler.js +3 -4
- package/dist/calendar/scheduler.js.map +1 -1
- package/dist/channels/interface.d.ts +2 -8
- package/dist/channels/interface.d.ts.map +1 -1
- package/dist/channels/interface.js +1 -8
- package/dist/channels/interface.js.map +1 -1
- package/dist/channels/manager.d.ts.map +1 -1
- package/dist/channels/manager.js +0 -2
- package/dist/channels/manager.js.map +1 -1
- package/dist/channels/qq-status.d.ts.map +1 -1
- package/dist/channels/qq-status.js +1 -0
- package/dist/channels/qq-status.js.map +1 -1
- package/dist/channels/queue.d.ts.map +1 -1
- package/dist/channels/queue.js +0 -8
- package/dist/channels/queue.js.map +1 -1
- package/dist/channels/telegram-status.d.ts.map +1 -1
- package/dist/channels/telegram-status.js +2 -0
- package/dist/channels/telegram-status.js.map +1 -1
- package/dist/channels/tui.d.ts +2 -2
- package/dist/channels/tui.d.ts.map +1 -1
- package/dist/channels/tui.js +2 -7
- package/dist/channels/tui.js.map +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +15 -16
- package/dist/config/index.js.map +1 -1
- package/dist/config/types.d.ts +8 -16
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js +24 -13
- package/dist/config/types.js.map +1 -1
- package/dist/email/email-route-store.d.ts.map +1 -1
- package/dist/email/email-route-store.js +5 -6
- package/dist/email/email-route-store.js.map +1 -1
- package/dist/i18n/messages.d.ts +0 -12
- package/dist/i18n/messages.d.ts.map +1 -1
- package/dist/i18n/messages.js +9 -21
- package/dist/i18n/messages.js.map +1 -1
- package/dist/logger.d.ts +0 -2
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +1 -19
- package/dist/logger.js.map +1 -1
- package/dist/threads/active-threads-store.d.ts.map +1 -1
- package/dist/threads/active-threads-store.js +27 -8
- package/dist/threads/active-threads-store.js.map +1 -1
- package/dist/threads/execution-host.d.ts.map +1 -1
- package/dist/threads/execution-host.js +0 -1
- package/dist/threads/execution-host.js.map +1 -1
- package/dist/threads/execution-scheduler.d.ts +0 -4
- package/dist/threads/execution-scheduler.d.ts.map +1 -1
- package/dist/threads/execution-scheduler.js +2 -38
- package/dist/threads/execution-scheduler.js.map +1 -1
- package/dist/threads/execution-store.d.ts +5 -20
- package/dist/threads/execution-store.d.ts.map +1 -1
- package/dist/threads/execution-store.js +8 -45
- package/dist/threads/execution-store.js.map +1 -1
- package/dist/threads/foreground-task.d.ts +6 -10
- package/dist/threads/foreground-task.d.ts.map +1 -1
- package/dist/threads/foreground-task.js +26 -34
- package/dist/threads/foreground-task.js.map +1 -1
- package/dist/threads/foreman-client.d.ts.map +1 -1
- package/dist/threads/foreman-client.js +1 -3
- package/dist/threads/foreman-client.js.map +1 -1
- package/dist/threads/foreman-execution.d.ts +12 -12
- package/dist/threads/foreman-execution.d.ts.map +1 -1
- package/dist/threads/foreman-execution.js +19 -30
- package/dist/threads/foreman-execution.js.map +1 -1
- package/dist/threads/foreman-host.d.ts +2 -17
- package/dist/threads/foreman-host.d.ts.map +1 -1
- package/dist/threads/foreman-host.js +63 -452
- package/dist/threads/foreman-host.js.map +1 -1
- package/dist/threads/foreman-protocol.d.ts +12 -113
- package/dist/threads/foreman-protocol.d.ts.map +1 -1
- package/dist/threads/foreman-protocol.js +15 -41
- package/dist/threads/foreman-protocol.js.map +1 -1
- package/dist/threads/foreman-store.d.ts +10 -44
- package/dist/threads/foreman-store.d.ts.map +1 -1
- package/dist/threads/foreman-store.js +19 -78
- package/dist/threads/foreman-store.js.map +1 -1
- package/dist/threads/generic-execution.d.ts +2 -2
- package/dist/threads/generic-execution.d.ts.map +1 -1
- package/dist/threads/generic-execution.js +6 -9
- package/dist/threads/generic-execution.js.map +1 -1
- package/dist/threads/ipc.d.ts +0 -3
- package/dist/threads/ipc.d.ts.map +1 -1
- package/dist/threads/ipc.js.map +1 -1
- package/dist/threads/relay-adapter.d.ts +2 -0
- package/dist/threads/relay-adapter.d.ts.map +1 -1
- package/dist/threads/relay-adapter.js +7 -1
- package/dist/threads/relay-adapter.js.map +1 -1
- package/dist/threads/supervisor.d.ts +51 -21
- package/dist/threads/supervisor.d.ts.map +1 -1
- package/dist/threads/supervisor.js +449 -160
- package/dist/threads/supervisor.js.map +1 -1
- package/dist/threads/task-contracts.d.ts +194 -0
- package/dist/threads/task-contracts.d.ts.map +1 -0
- package/dist/threads/task-contracts.js +82 -0
- package/dist/threads/task-contracts.js.map +1 -0
- package/dist/threads/task-sidecar.d.ts +145 -0
- package/dist/threads/task-sidecar.d.ts.map +1 -0
- package/dist/threads/task-sidecar.js +311 -0
- package/dist/threads/task-sidecar.js.map +1 -0
- package/dist/threads/task-store.d.ts +172 -0
- package/dist/threads/task-store.d.ts.map +1 -0
- package/dist/threads/task-store.js +599 -0
- package/dist/threads/task-store.js.map +1 -0
- package/dist/threads/thread-activity-controller.d.ts +7 -0
- package/dist/threads/thread-activity-controller.d.ts.map +1 -1
- package/dist/threads/thread-activity-controller.js +52 -2
- package/dist/threads/thread-activity-controller.js.map +1 -1
- package/dist/threads/thread-task-context.d.ts +40 -0
- package/dist/threads/thread-task-context.d.ts.map +1 -0
- package/dist/threads/thread-task-context.js +160 -0
- package/dist/threads/thread-task-context.js.map +1 -0
- package/dist/threads/thread-task-controller.d.ts +122 -0
- package/dist/threads/thread-task-controller.d.ts.map +1 -0
- package/dist/threads/thread-task-controller.js +276 -0
- package/dist/threads/thread-task-controller.js.map +1 -0
- package/dist/threads/thread-task-runtime.d.ts +350 -0
- package/dist/threads/thread-task-runtime.d.ts.map +1 -0
- package/dist/threads/thread-task-runtime.js +896 -0
- package/dist/threads/thread-task-runtime.js.map +1 -0
- package/dist/threads/worker-entry.d.ts.map +1 -1
- package/dist/threads/worker-entry.js +28 -29
- package/dist/threads/worker-entry.js.map +1 -1
- package/dist/threads/worker-execution-runtime.d.ts +2 -3
- package/dist/threads/worker-execution-runtime.d.ts.map +1 -1
- package/dist/threads/worker-execution-runtime.js +2 -5
- package/dist/threads/worker-execution-runtime.js.map +1 -1
- package/dist/tools/delegation.d.ts +2 -75
- package/dist/tools/delegation.d.ts.map +1 -1
- package/dist/tools/delegation.js +29 -63
- package/dist/tools/delegation.js.map +1 -1
- package/dist/tools/email.d.ts +1 -1
- package/dist/tools/execution-control.d.ts +0 -5
- package/dist/tools/execution-control.d.ts.map +1 -1
- package/dist/tools/execution-control.js +2 -9
- package/dist/tools/execution-control.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +6 -2
- 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/notify.d.ts +0 -2
- package/dist/tools/notify.d.ts.map +1 -1
- package/dist/tools/notify.js +5 -21
- package/dist/tools/notify.js.map +1 -1
- package/dist/tools/skill.d.ts +1 -1
- package/dist/tools/thread-tasks.d.ts +23 -0
- package/dist/tools/thread-tasks.d.ts.map +1 -0
- package/dist/tools/thread-tasks.js +122 -0
- package/dist/tools/thread-tasks.js.map +1 -0
- package/dist/tools/totp.d.ts +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 +2 -17
- package/dist/tui/server.js.map +1 -1
- package/dist/utils/restart.d.ts.map +1 -1
- package/dist/utils/restart.js +0 -6
- package/dist/utils/restart.js.map +1 -1
- package/dist-agent/bundle.cjs +2 -2
- package/package.json +1 -1
- package/dist/agent/runtime-context.d.ts +0 -27
- package/dist/agent/runtime-context.d.ts.map +0 -1
- package/dist/agent/runtime-context.js +0 -60
- package/dist/agent/runtime-context.js.map +0 -1
- package/dist/agent/runtime-disclosure-policy.d.ts +0 -6
- package/dist/agent/runtime-disclosure-policy.d.ts.map +0 -1
- package/dist/agent/runtime-disclosure-policy.js +0 -16
- package/dist/agent/runtime-disclosure-policy.js.map +0 -1
- package/dist/conversations/lazy-runtime.d.ts +0 -5
- package/dist/conversations/lazy-runtime.d.ts.map +0 -1
- package/dist/conversations/lazy-runtime.js +0 -12
- package/dist/conversations/lazy-runtime.js.map +0 -1
- package/dist/conversations/runtime.d.ts +0 -17
- package/dist/conversations/runtime.d.ts.map +0 -1
- package/dist/conversations/runtime.js +0 -92
- package/dist/conversations/runtime.js.map +0 -1
- package/dist/conversations/scheduler.d.ts +0 -57
- package/dist/conversations/scheduler.d.ts.map +0 -1
- package/dist/conversations/scheduler.js +0 -175
- package/dist/conversations/scheduler.js.map +0 -1
- package/dist/threads/foreman-business.d.ts +0 -9
- package/dist/threads/foreman-business.d.ts.map +0 -1
- package/dist/threads/foreman-business.js +0 -117
- package/dist/threads/foreman-business.js.map +0 -1
- package/dist/threads/foreman-delivery.d.ts +0 -5
- package/dist/threads/foreman-delivery.d.ts.map +0 -1
- package/dist/threads/foreman-delivery.js +0 -21
- package/dist/threads/foreman-delivery.js.map +0 -1
- package/dist/threads/task-workspace.d.ts +0 -8
- package/dist/threads/task-workspace.d.ts.map +0 -1
- package/dist/threads/task-workspace.js +0 -52
- package/dist/threads/task-workspace.js.map +0 -1
package/dist/agent/loop.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* sleep/wake loop. Each concern is delegated to a focused module:
|
|
6
6
|
*
|
|
7
7
|
* - HeartbeatManager: runtime heartbeat lifecycle
|
|
8
|
-
* - ReplyWatchdog:
|
|
8
|
+
* - ReplyWatchdog: fast-responder fallback timer
|
|
9
9
|
* - WakeCycleRunner: wake loop, stream processing, error retry,
|
|
10
10
|
* transcript indexing
|
|
11
11
|
* - InterruptHandler: mid-turn message injection
|
|
@@ -13,11 +13,11 @@
|
|
|
13
13
|
* - ChannelManager: messaging channel adapters
|
|
14
14
|
*/
|
|
15
15
|
import { createDefaultExternalContextRegistry, ExternalContextRegistry } from "./external-context/registry.js";
|
|
16
|
-
import {
|
|
16
|
+
import { randomUUID } from "node:crypto";
|
|
17
17
|
import { beginLifecycleRun, createLifecycleRunId, deriveShadowLifecycleState, endLifecycleRun, traceLifecycle, traceShadowLifecycle } from "./lifecycle-trace.js";
|
|
18
|
-
import {
|
|
19
|
-
import { isProactiveWakeEnabled, isTunnelEnabled, isWorkspaceEnabled } from "../config/types.js";
|
|
20
|
-
import { DEFAULT_THREAD_ID,
|
|
18
|
+
import { endForegroundWake } from "./lifecycle-transitions.js";
|
|
19
|
+
import { isProactiveWakeEnabled, isThreadTasksEnabled, isTunnelEnabled, isWorkspaceEnabled } from "../config/types.js";
|
|
20
|
+
import { DEFAULT_THREAD_ID, resolveThreadId } from "../channels/interface.js";
|
|
21
21
|
import { buildSystemPrompt } from "./system-prompt.js";
|
|
22
22
|
import { SessionManager } from "./session-manager.js";
|
|
23
23
|
import { buildWakeContext } from "./context.js";
|
|
@@ -27,7 +27,7 @@ import { ActivityTracker } from "./activity-tracker.js";
|
|
|
27
27
|
import { ThreadActivityController } from "../threads/thread-activity-controller.js";
|
|
28
28
|
import { shouldNotifyUpdate } from "../utils/version-check.js";
|
|
29
29
|
import { shouldRunProactiveUpgradeCheck } from "./update-reminder-policy.js";
|
|
30
|
-
import { loadOwnerConfig, consumePendingUpgrade, consumePendingRestart, writePendingRestart, getConfigDir, ownerConfigExists, saveOwnerConfig, deleteOnboardingSession, } from "../config/index.js";
|
|
30
|
+
import { getConfigFile, loadOwnerConfig, consumePendingUpgrade, consumePendingRestart, writePendingRestart, getConfigDir, ownerConfigExists, saveOwnerConfig, deleteOnboardingSession, } from "../config/index.js";
|
|
31
31
|
import { syncSystemTimezone } from "../utils/timezone.js";
|
|
32
32
|
import { logger } from "../logger.js";
|
|
33
33
|
import { cleanOldScreenshots } from "../tools/screenshot.js";
|
|
@@ -40,7 +40,7 @@ import { runOnboardingGate } from "./onboarding-gate.js";
|
|
|
40
40
|
import { OnboardingServiceClient } from "../onboarding/onboarding-service-client.js";
|
|
41
41
|
import { deliverPendingQqWelcome, sendWelcomeMessages } from "../onboarding/send-invite.js";
|
|
42
42
|
import { resumePendingChannelBinding } from "../onboarding/resume-channel-binding.js";
|
|
43
|
-
import { answerAndDrop, executionGateReply, runServiceGate, serviceGateMessage, shouldEnforceServiceGate } from "./service-gate.js";
|
|
43
|
+
import { answerAndDrop, executionGateReply, persistedServiceStopped, runServiceGate, serviceGateMessage, shouldEnforceServiceGate } from "./service-gate.js";
|
|
44
44
|
import { InterruptHandler } from "./interrupt-handler.js";
|
|
45
45
|
import { ownerTranscriptionContext } from "../transcription-context.js";
|
|
46
46
|
import { transcribeVoiceMessages } from "../utils/transcribe.js";
|
|
@@ -55,8 +55,7 @@ import { t, resolveLocale } from "../i18n/index.js";
|
|
|
55
55
|
import { formatMessageSummary, previewIncomingForConsole, buildIncomingLogData } from "./message-format.js";
|
|
56
56
|
import { buildReplyMapKeyFromMessage, buildReplyTarget, groupActivityDeliveryTargetForMessage, resolveTaskReplyTarget } from "./reply-target.js";
|
|
57
57
|
import { notifyOwnerViaResolvedChain } from "./owner-notify.js";
|
|
58
|
-
import { hasUsableOwnerChannel,
|
|
59
|
-
import { runForemanBusinessRead } from "../threads/foreman-business.js";
|
|
58
|
+
import { hasUsableOwnerChannel, resolveOwnerDefaultTarget } from "./owner-channel-resolver.js";
|
|
60
59
|
import { buildRuntimeSurface, } from "./runtime-surface.js";
|
|
61
60
|
import { getAgentEngine } from "./engines/engine-factory.js";
|
|
62
61
|
import { prepareEngineSwitchBoundary } from "./engine-switch.js";
|
|
@@ -92,11 +91,12 @@ import { backfillMissingThreadApplications, migrateLegacyThreadApplications, thr
|
|
|
92
91
|
import { currentApplicationContext, inheritThreadApplication, threadApplication } from "../threads/application-context.js";
|
|
93
92
|
import { ForemanHost } from "../threads/foreman-host.js";
|
|
94
93
|
import { ForemanStore } from "../threads/foreman-store.js";
|
|
95
|
-
import {
|
|
94
|
+
import { foremanEventsOf, getForemanClient, installForemanClient, isForemanRuntime } from "../threads/foreman-protocol.js";
|
|
96
95
|
import { ForegroundTaskTracker, installForegroundTaskTracker } from "../threads/foreground-task.js";
|
|
97
96
|
import { ThreadApplicationConflict } from "../threads/thread-meta.js";
|
|
98
97
|
import { assertRuntimeApplicationId } from "../config/application-config.js";
|
|
99
98
|
import { migrateProfileToAgentsMd } from "../config/agents-md-migration.js";
|
|
99
|
+
import { ThreadTaskRuntime, endWakeThreadTasks, isTaskRelevantMessage, isTaskResumeMessage, retireStaleResume, setThreadTaskRuntime, } from "../threads/thread-task-runtime.js";
|
|
100
100
|
/**
|
|
101
101
|
* Grace period before an idle cross-runtime engine recovery restarts.
|
|
102
102
|
* Short on purpose: the gate only fires when nothing is in flight.
|
|
@@ -112,8 +112,6 @@ const WORKER_EXECUTION_IDLE_GRACE_MS = 10_000;
|
|
|
112
112
|
* Main agent loop. This is the entry point that runs forever.
|
|
113
113
|
*/
|
|
114
114
|
export async function startAgentLoop(config, options) {
|
|
115
|
-
if (options?.signal?.aborted)
|
|
116
|
-
return;
|
|
117
115
|
const workerMode = options?.workerMode ?? null;
|
|
118
116
|
const workerExecution = workerMode?.execution ?? null;
|
|
119
117
|
if (workerMode && workerExecution) {
|
|
@@ -179,6 +177,19 @@ export async function startAgentLoop(config, options) {
|
|
|
179
177
|
// orphaned worker can no longer commit claims owned by its successor.
|
|
180
178
|
...(workerMode ? { ownerId: workerMode.relay.workerInstanceId } : {}),
|
|
181
179
|
});
|
|
180
|
+
// Thread task store (#1996): opened by the same queue owner at the same
|
|
181
|
+
// moment it recovers in-flight claims, and fenced by the same identity.
|
|
182
|
+
// Bounded executions keep caller-owned task state outside this loop.
|
|
183
|
+
// Conversational task tracking is off unless the local config opts in
|
|
184
|
+
// (`threadTasksEnabled: true`). Null means disabled for this process.
|
|
185
|
+
const threadTasks = workerExecution || !isThreadTasksEnabled(config)
|
|
186
|
+
? null
|
|
187
|
+
: ThreadTaskRuntime.start({
|
|
188
|
+
threadId: executionContext.threadId,
|
|
189
|
+
writerId: workerMode ? workerMode.relay.workerInstanceId : randomUUID(),
|
|
190
|
+
config,
|
|
191
|
+
});
|
|
192
|
+
setThreadTaskRuntime(threadTasks);
|
|
182
193
|
const channelManager = new ChannelManager(config, messageQueue);
|
|
183
194
|
const activityTracker = new ActivityTracker();
|
|
184
195
|
const mainActivityController = workerMode
|
|
@@ -197,20 +208,20 @@ export async function startAgentLoop(config, options) {
|
|
|
197
208
|
// --- Thread supervisor (multi-thread architecture) ---
|
|
198
209
|
// Install before adapters start: connect/hello can immediately replay work.
|
|
199
210
|
// Recover old queues after channels are available for replies.
|
|
200
|
-
//
|
|
201
|
-
// the
|
|
202
|
-
|
|
211
|
+
// Main process only. Spawns/routes worker processes for non-default threads
|
|
212
|
+
// via the ChannelManager threadRouter hook. Disabled in worker mode (workers
|
|
213
|
+
// never route to sub-workers) and when multiThread is turned off in config.
|
|
214
|
+
if (!workerMode && config.multiThread.enabled) {
|
|
203
215
|
const { ThreadSupervisor } = await import("../threads/supervisor.js");
|
|
204
216
|
// Foreman (#2805): the host owns General's background tasks, their
|
|
205
217
|
// delivery obligations and fallback. Built before the supervisor so the
|
|
206
218
|
// supervisor can route workers' commands and `general` events to it.
|
|
207
219
|
let foremanHost = null;
|
|
208
|
-
let taskStore = null;
|
|
209
220
|
const supervisor = new ThreadSupervisor({
|
|
210
221
|
channelManager,
|
|
211
222
|
messageQueue,
|
|
212
223
|
deferRecovery: true,
|
|
213
|
-
maxConcurrentThreads: config.
|
|
224
|
+
maxConcurrentThreads: config.multiThread.maxConcurrentThreads,
|
|
214
225
|
idleTimeoutMs: config.multiThread.idleTtlMs,
|
|
215
226
|
config,
|
|
216
227
|
desktopRuntimeResolution: options?.desktopRuntimeResolution,
|
|
@@ -232,24 +243,16 @@ export async function startAgentLoop(config, options) {
|
|
|
232
243
|
// for the worker the supervisor actually talks to.
|
|
233
244
|
handleForemanCommand: (threadId, command) => foremanHost?.handle(threadId, command)
|
|
234
245
|
?? Promise.resolve({ ok: false, text: "Error: background tasks are not available in this conversation." }),
|
|
235
|
-
handleForemanBusinessRead: (executionId, command, workspace) => foremanHost?.readBusiness(executionId, command.tool, command.args, workspace)
|
|
236
|
-
?? Promise.resolve({ ok: false, text: "Business reads are unavailable" }),
|
|
237
246
|
});
|
|
238
247
|
supervisor.onExecutionEvent((event, caller) => {
|
|
239
248
|
if (caller.kind !== "tui")
|
|
240
249
|
return;
|
|
241
250
|
channelManager.getAdapter("tui")?.publishExecutionEvent(event);
|
|
242
251
|
});
|
|
243
|
-
const foremanExecutions = supervisor.executionService();
|
|
252
|
+
const foremanExecutions = isForemanRuntime(config) ? supervisor.executionService() : null;
|
|
244
253
|
if (foremanExecutions) {
|
|
245
254
|
const store = new ForemanStore();
|
|
246
|
-
taskStore = store;
|
|
247
255
|
foremanHost = new ForemanHost({
|
|
248
|
-
canReadBusiness: (_threadId, target) => isWorkspaceEnabled(config) && target !== null
|
|
249
|
-
&& listBoundOwnerChannels(config, loadOwnerConfig()).some((owner) => owner.validationStatus === "verified"
|
|
250
|
-
&& owner.kind === "dm" && normalizeChannelName(owner.channel) === normalizeChannelName(target.channel) && owner.to === target.to),
|
|
251
|
-
readBusiness: runForemanBusinessRead,
|
|
252
|
-
allowDelegation: () => isForemanRuntime(config),
|
|
253
256
|
executions: foremanExecutions,
|
|
254
257
|
store,
|
|
255
258
|
enqueueToGeneral: (threadId, message) => {
|
|
@@ -258,15 +261,16 @@ export async function startAgentLoop(config, options) {
|
|
|
258
261
|
wakeGeneralLoop?.();
|
|
259
262
|
return;
|
|
260
263
|
}
|
|
261
|
-
//
|
|
264
|
+
// A thread's own durable queue; the supervisor starts its worker.
|
|
265
|
+
// The thread's recorded application keeps strict admission satisfied.
|
|
262
266
|
const app = threadApplication(threadId, config);
|
|
263
267
|
if (!supervisor.tryRouteMessage({ ...message, threadId, ...(app ? { app } : {}) }, threadId)) {
|
|
264
268
|
throw new Error(`Thread ${threadId} did not accept a background-task update`);
|
|
265
269
|
}
|
|
266
270
|
},
|
|
267
271
|
deliver: (target, text, threadId) => channelManager.tryDeliver(target, text, {
|
|
268
|
-
logContext: "background task
|
|
269
|
-
context:
|
|
272
|
+
logContext: "background task fallback",
|
|
273
|
+
context: threadId === DEFAULT_THREAD_ID ? {} : { businessThreadId: threadId },
|
|
270
274
|
}),
|
|
271
275
|
ownerTarget: () => {
|
|
272
276
|
const owner = resolveOwnerDefaultTarget(config, loadOwnerConfig());
|
|
@@ -275,16 +279,14 @@ export async function startAgentLoop(config, options) {
|
|
|
275
279
|
locale: () => resolveLocale(loadOwnerConfig().language),
|
|
276
280
|
});
|
|
277
281
|
const host = foremanHost;
|
|
278
|
-
installForemanClient(
|
|
282
|
+
installForemanClient({ request: (command) => host.handle(DEFAULT_THREAD_ID, command) });
|
|
283
|
+
registerShutdownCallback(() => {
|
|
284
|
+
host.stop();
|
|
285
|
+
store.close();
|
|
286
|
+
return Promise.resolve();
|
|
287
|
+
});
|
|
279
288
|
}
|
|
280
289
|
activeForemanHost = foremanHost;
|
|
281
|
-
// Keep the Task ledger and delivery adapters alive until conversations and
|
|
282
|
-
// workers settle. Their final receipts may still arrive during shutdown.
|
|
283
|
-
registerShutdownCallback(async () => {
|
|
284
|
-
foremanHost?.stop();
|
|
285
|
-
await supervisor.shutdownAll();
|
|
286
|
-
taskStore?.close();
|
|
287
|
-
});
|
|
288
290
|
channelManager.setThreadRouter((msg, threadId) => supervisor.routeMessage(msg, threadId));
|
|
289
291
|
// Expose for the main-loop wake context to refresh its own awareness.
|
|
290
292
|
threadSupervisor = supervisor;
|
|
@@ -321,6 +323,9 @@ export async function startAgentLoop(config, options) {
|
|
|
321
323
|
catch (err) {
|
|
322
324
|
logger.warn(`Graceful shutdown did not complete cleanly: ${err instanceof Error ? err.message : String(err)}`);
|
|
323
325
|
}
|
|
326
|
+
// After the channels, so it never delays them. A short grace lets an
|
|
327
|
+
// in-flight sidecar call commit; unconsumed events wait for the next start.
|
|
328
|
+
await threadTasks?.close(2_000);
|
|
324
329
|
messageQueue.close();
|
|
325
330
|
logger.system("Graceful shutdown complete.");
|
|
326
331
|
});
|
|
@@ -340,6 +345,11 @@ export async function startAgentLoop(config, options) {
|
|
|
340
345
|
threadSupervisor.startExecutions();
|
|
341
346
|
// Its first sweep sends fallbacks a restart left overdue.
|
|
342
347
|
activeForemanHost?.start();
|
|
348
|
+
const supervisor = threadSupervisor;
|
|
349
|
+
registerShutdownCallback(async () => {
|
|
350
|
+
logger.system("Graceful shutdown: stopping thread workers...");
|
|
351
|
+
await supervisor.shutdownAll();
|
|
352
|
+
});
|
|
343
353
|
}
|
|
344
354
|
// --- Resume an interrupted channel binding ---
|
|
345
355
|
// Runs BEFORE the onboarding gate on purpose. A binding whose completion tail
|
|
@@ -545,7 +555,7 @@ export async function startAgentLoop(config, options) {
|
|
|
545
555
|
// Foreman's foreground limit, for conversational sessions that can delegate.
|
|
546
556
|
// Thread-local: getConfigDir() is the thread's own directory in a worker.
|
|
547
557
|
// Skill Learning drives this same session and is exempt.
|
|
548
|
-
const foregroundTasks = !workerExecution &&
|
|
558
|
+
const foregroundTasks = !workerExecution && getForemanClient()
|
|
549
559
|
? new ForegroundTaskTracker(getConfigDir(), () => new Date(), () => agentState.learning)
|
|
550
560
|
: null;
|
|
551
561
|
installForegroundTaskTracker(foregroundTasks);
|
|
@@ -677,7 +687,7 @@ export async function startAgentLoop(config, options) {
|
|
|
677
687
|
browserSelection: runtimeSurface.browserSelection,
|
|
678
688
|
credentialBacked: runtimeSurface.credentialBacked,
|
|
679
689
|
conversation: { threadId: workerMode?.threadId },
|
|
680
|
-
foreman:
|
|
690
|
+
foreman: getForemanClient() !== null,
|
|
681
691
|
});
|
|
682
692
|
}, runtimeSurface, options?.workspaceCwd ? { workspaceCwd: options.workspaceCwd } : {});
|
|
683
693
|
// Hand the engine-switch summary to the freshly created session (rotation
|
|
@@ -727,6 +737,26 @@ export async function startAgentLoop(config, options) {
|
|
|
727
737
|
// Expose the wake function so out-of-loop components can trigger an
|
|
728
738
|
// immediate wake without threading the closure through every call site.
|
|
729
739
|
agentState.wakeMainLoop = wakeMainLoop;
|
|
740
|
+
// Thread task resumes (#1996 PR 5): after a wake the runtime queues the
|
|
741
|
+
// next runnable task as a system row and wakes the loop, so queued work
|
|
742
|
+
// continues without a new owner message, with proactive wakes off and in
|
|
743
|
+
// workers. It never queues while a wake runs or execution is gated; the
|
|
744
|
+
// row is still checked against the task when it is dequeued.
|
|
745
|
+
// TODO: a resume queued just before the service gate engages is discarded
|
|
746
|
+
// with the gated queue (main) or still runs (workers, which have no gate
|
|
747
|
+
// pass and whose system rows skip the gate reply). The window is tiny.
|
|
748
|
+
threadTasks?.enableResumes({
|
|
749
|
+
queue: messageQueue,
|
|
750
|
+
isBusy: () => agentState.busy || !messageQueue.isEmpty(),
|
|
751
|
+
isGated: () => readFundLeagueHold() !== null
|
|
752
|
+
// A worker's heartbeat holds the status from its start; the main
|
|
753
|
+
// process persists every change, so read that instead.
|
|
754
|
+
|| (workerMode ? persistedServiceStopped(getConfigFile()) : shouldEnforceServiceGate(heartbeat.lastServiceStatus)),
|
|
755
|
+
wake: wakeMainLoop,
|
|
756
|
+
});
|
|
757
|
+
// Startup: work that was queued, or resumed and interrupted, before the
|
|
758
|
+
// previous process stopped continues now.
|
|
759
|
+
void threadTasks?.requestResume();
|
|
730
760
|
const interruptHandler = new InterruptHandler({
|
|
731
761
|
externalContextRegistry,
|
|
732
762
|
session: session.activeSession,
|
|
@@ -883,7 +913,6 @@ export async function startAgentLoop(config, options) {
|
|
|
883
913
|
else {
|
|
884
914
|
registerShutdownCallback(() => {
|
|
885
915
|
closeTranscriptMemoryDb();
|
|
886
|
-
closeUsageReportQueue();
|
|
887
916
|
return Promise.resolve();
|
|
888
917
|
});
|
|
889
918
|
}
|
|
@@ -927,17 +956,10 @@ export async function startAgentLoop(config, options) {
|
|
|
927
956
|
dreamingRunner?.beginStep();
|
|
928
957
|
heartbeat.nudge();
|
|
929
958
|
return () => {
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
cleanup: () => { agentState.learning = false; },
|
|
935
|
-
release: () => {
|
|
936
|
-
executionOwner.setBusy(false, "maintenance_release");
|
|
937
|
-
resumeWorkers?.();
|
|
938
|
-
heartbeat.nudge();
|
|
939
|
-
},
|
|
940
|
-
});
|
|
959
|
+
agentState.learning = false;
|
|
960
|
+
executionOwner.setBusy(false, "maintenance_release");
|
|
961
|
+
resumeWorkers?.();
|
|
962
|
+
heartbeat.nudge();
|
|
941
963
|
};
|
|
942
964
|
},
|
|
943
965
|
hasPendingSkills: hasPendingSkillLearning,
|
|
@@ -981,12 +1003,6 @@ export async function startAgentLoop(config, options) {
|
|
|
981
1003
|
if (options?.onReady) {
|
|
982
1004
|
options.onReady({ agentState, sessionManager: session, messageQueue, ownerConfig });
|
|
983
1005
|
}
|
|
984
|
-
const wakeOnShutdown = () => { session.requestStop(); wakeMainLoop(); };
|
|
985
|
-
options?.signal?.addEventListener("abort", wakeOnShutdown, { once: true });
|
|
986
|
-
registerShutdownCallback(() => {
|
|
987
|
-
options?.signal?.removeEventListener("abort", wakeOnShutdown);
|
|
988
|
-
return Promise.resolve();
|
|
989
|
-
});
|
|
990
1006
|
logger.system(workerExecution
|
|
991
1007
|
? "Single-shot worker loop started. Waiting for its execution dispatch..."
|
|
992
1008
|
: "Agent loop started. Waiting for messages or heartbeat...");
|
|
@@ -1006,21 +1022,10 @@ export async function startAgentLoop(config, options) {
|
|
|
1006
1022
|
let lastWakeScreenshotMs = 0;
|
|
1007
1023
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- intentional infinite loop
|
|
1008
1024
|
while (true) {
|
|
1009
|
-
if (options?.signal?.aborted)
|
|
1010
|
-
break;
|
|
1011
1025
|
const leagueHold = readFundLeagueHold();
|
|
1012
1026
|
if (leagueHold) {
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
// confirms an engine barrier.
|
|
1016
|
-
closeHostEntry({
|
|
1017
|
-
busy: agentState.busy,
|
|
1018
|
-
requestStop: () => { agentState.requestStop(); },
|
|
1019
|
-
markClosed: () => {
|
|
1020
|
-
executionOwner.setBusy(false, "league_hold");
|
|
1021
|
-
agentState.gated = true;
|
|
1022
|
-
},
|
|
1023
|
-
});
|
|
1027
|
+
executionOwner.setBusy(false, "league_hold");
|
|
1028
|
+
agentState.gated = true;
|
|
1024
1029
|
await new Promise((resolve) => { wakeResolver = resolve; });
|
|
1025
1030
|
wakeResolver = null;
|
|
1026
1031
|
continue;
|
|
@@ -1068,6 +1073,11 @@ export async function startAgentLoop(config, options) {
|
|
|
1068
1073
|
});
|
|
1069
1074
|
nextProactiveWakeAt = sleepMs === null ? null : nextProactiveWakeAt ?? Date.now() + sleepMs;
|
|
1070
1075
|
const isFirstWake = firstIteration;
|
|
1076
|
+
// Worker: report idle status before sleeping so the supervisor's
|
|
1077
|
+
// cross-thread awareness snapshot reflects this thread as idle.
|
|
1078
|
+
if (workerMode && !isFirstWake) {
|
|
1079
|
+
workerMode.relay.relayStatus(false, "idle");
|
|
1080
|
+
}
|
|
1071
1081
|
// We are about to go idle, which is the only safe moment to move back
|
|
1072
1082
|
// across a runtime boundary: that costs a restart and collapses the
|
|
1073
1083
|
// session into a summary, so doing it mid-conversation would cut a live
|
|
@@ -1116,8 +1126,6 @@ export async function startAgentLoop(config, options) {
|
|
|
1116
1126
|
resolve();
|
|
1117
1127
|
}
|
|
1118
1128
|
});
|
|
1119
|
-
if (options?.signal?.aborted)
|
|
1120
|
-
break;
|
|
1121
1129
|
if (proactiveWakeSchedule.changed && messageQueue.isEmpty()) {
|
|
1122
1130
|
proactiveWakeSchedule.changed = false;
|
|
1123
1131
|
nextProactiveWakeAt = null;
|
|
@@ -1227,23 +1235,21 @@ export async function startAgentLoop(config, options) {
|
|
|
1227
1235
|
stopRequested: agentState.stopRequested,
|
|
1228
1236
|
busy: agentState.busy,
|
|
1229
1237
|
recovering,
|
|
1230
|
-
//
|
|
1231
|
-
//
|
|
1232
|
-
barrierConfirmed:
|
|
1238
|
+
// No engine has a confirmed execution barrier yet. Pi settlement
|
|
1239
|
+
// only prevents a send collision; it does not prove the engine stopped.
|
|
1240
|
+
barrierConfirmed: false,
|
|
1233
1241
|
}),
|
|
1234
1242
|
legacy: {
|
|
1235
1243
|
busy: agentState.busy,
|
|
1236
1244
|
gated: agentState.gated,
|
|
1237
1245
|
stopRequested: agentState.stopRequested,
|
|
1238
1246
|
},
|
|
1239
|
-
barrierConfirmed:
|
|
1247
|
+
barrierConfirmed: false,
|
|
1240
1248
|
});
|
|
1241
1249
|
};
|
|
1242
1250
|
const releaseLifecycleRun = (reason) => {
|
|
1243
1251
|
// Stopping is one beat when nothing is still in flight. The slot stays
|
|
1244
1252
|
// busy until cleanup finishes, so busy=false is not what ends the wake.
|
|
1245
|
-
// A worker thread is the same loop: its busy flag lives on the
|
|
1246
|
-
// supervisor, and it is cleared only after this cleanup.
|
|
1247
1253
|
endForegroundWake({
|
|
1248
1254
|
// A failed compaction is still this same foreground run. Phase 3 is
|
|
1249
1255
|
// what moves that path into Recovering before the wake ends.
|
|
@@ -1264,10 +1270,6 @@ export async function startAgentLoop(config, options) {
|
|
|
1264
1270
|
endLifecycleRun(lifecycleRunId);
|
|
1265
1271
|
},
|
|
1266
1272
|
release: () => {
|
|
1267
|
-
// The supervisor learns a worker is idle here, after cleanup, not
|
|
1268
|
-
// at the next sleep. The local slot is released for both loops.
|
|
1269
|
-
if (workerMode)
|
|
1270
|
-
workerMode.relay.relayStatus(false, "idle");
|
|
1271
1273
|
executionOwner.setBusy(false, reason, lifecycleRunId);
|
|
1272
1274
|
},
|
|
1273
1275
|
});
|
|
@@ -1308,6 +1310,10 @@ export async function startAgentLoop(config, options) {
|
|
|
1308
1310
|
continue;
|
|
1309
1311
|
}
|
|
1310
1312
|
}
|
|
1313
|
+
// Re-check a queued task resume against the task itself: a cancel,
|
|
1314
|
+
// change, wait or block since it was queued retires it unexecuted.
|
|
1315
|
+
if (retireStaleResume(messageQueue, threadTasks, msg))
|
|
1316
|
+
continue;
|
|
1311
1317
|
const gateReply = msg.channel === "system" ? null : executionGateReply(heartbeat, resolveLocale(ownerConfig.language));
|
|
1312
1318
|
if (gateReply !== null) {
|
|
1313
1319
|
await answerAndDrop(channelManager, messageQueue, msg, gateReply, tuiAdapter);
|
|
@@ -1320,6 +1326,9 @@ export async function startAgentLoop(config, options) {
|
|
|
1320
1326
|
if (trigger === "message" && messages.length === 0) {
|
|
1321
1327
|
releaseLifecycleRun("empty_message_batch");
|
|
1322
1328
|
heartbeat.nudge();
|
|
1329
|
+
// A retired stale resume ends here without a wake end; queue the next
|
|
1330
|
+
// runnable task (or the same one at its new version) instead.
|
|
1331
|
+
void threadTasks?.requestResume();
|
|
1323
1332
|
continue;
|
|
1324
1333
|
}
|
|
1325
1334
|
const correlatedTuiMessage = messages.find((message) => typeof message.meta?.tuiRequestId === "string");
|
|
@@ -1335,10 +1344,16 @@ export async function startAgentLoop(config, options) {
|
|
|
1335
1344
|
// other channels get the same cloud/local pipeline.
|
|
1336
1345
|
if (trigger === "message" && !workerExecution) {
|
|
1337
1346
|
for (const msg of messages) {
|
|
1347
|
+
// A task resume is internal: no "typing…" for the owner.
|
|
1348
|
+
if (isTaskResumeMessage(msg))
|
|
1349
|
+
continue;
|
|
1338
1350
|
sendTypingToMessage(channelManager, msg).catch(() => { });
|
|
1339
1351
|
}
|
|
1340
1352
|
}
|
|
1341
1353
|
await transcribeVoiceMessages(messages, ownerTranscriptionContext(ownerConfig));
|
|
1354
|
+
// Event first, sidecar second (#1996): after transcription so a voice
|
|
1355
|
+
// request is stored with its text. Idempotent and fail-safe.
|
|
1356
|
+
threadTasks?.recordMessages(messages.filter(isTaskRelevantMessage));
|
|
1342
1357
|
for (const msg of messages) {
|
|
1343
1358
|
agentState.replyMap.set(buildReplyMapKeyFromMessage(msg), buildReplyTarget(msg));
|
|
1344
1359
|
}
|
|
@@ -1485,18 +1500,8 @@ export async function startAgentLoop(config, options) {
|
|
|
1485
1500
|
operation: "query",
|
|
1486
1501
|
outcome: "started",
|
|
1487
1502
|
});
|
|
1488
|
-
let releaseConversationTurn;
|
|
1489
|
-
agentState.currentDispatchId = createHash("sha256").update(JSON.stringify(messages.map((message) => message.id))).digest("hex");
|
|
1490
1503
|
try {
|
|
1491
|
-
|
|
1492
|
-
releaseConversationTurn = await (options?.acquireConversationTurn?.(options.signal)
|
|
1493
|
-
?? threadSupervisor?.acquireConversationTurn(options?.signal));
|
|
1494
|
-
}
|
|
1495
|
-
if (options?.signal?.aborted) {
|
|
1496
|
-
messageQueue.requeueOwnedClaims();
|
|
1497
|
-
break;
|
|
1498
|
-
}
|
|
1499
|
-
// Accepted inputs are also replayed from the ledger on executor recovery.
|
|
1504
|
+
// Execution inputs in this batch reach the model with this turn.
|
|
1500
1505
|
noteMessagesHandedToModel(messages);
|
|
1501
1506
|
const result = await cycleRunner.run(contentBlocks, trigger, messages, consecutiveErrors);
|
|
1502
1507
|
traceLifecycle({
|
|
@@ -1507,10 +1512,6 @@ export async function startAgentLoop(config, options) {
|
|
|
1507
1512
|
evidence: { terminalState: result.terminalState },
|
|
1508
1513
|
});
|
|
1509
1514
|
consecutiveErrors = result.consecutiveErrors;
|
|
1510
|
-
if (options?.signal?.aborted) {
|
|
1511
|
-
messageQueue.requeueOwnedClaims();
|
|
1512
|
-
break;
|
|
1513
|
-
}
|
|
1514
1515
|
// A queue claim is not terminal until the complete wake cycle returns.
|
|
1515
1516
|
// If the worker dies during model/tool execution, the in-flight rows
|
|
1516
1517
|
// remain durable and are replayed by the next queue owner.
|
|
@@ -1521,26 +1522,47 @@ export async function startAgentLoop(config, options) {
|
|
|
1521
1522
|
// Foreman: the background-task updates this turn handled, read before
|
|
1522
1523
|
// their claims are released (mid-turn interrupts included).
|
|
1523
1524
|
const handledForemanEvents = failoverRestartPending ? [] : foremanEventsOf(messageQueue.currentCycleClaims());
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1525
|
+
const foregroundRecord = foregroundTasks?.current;
|
|
1526
|
+
const handedOffTaskId = foregroundRecord?.handedOff ? foregroundRecord.taskId : undefined;
|
|
1527
|
+
// Claims become handled only once each message is a durable task event,
|
|
1528
|
+
// so their follow-up survives the queue row (#1996). handled ≠ completed.
|
|
1529
|
+
endWakeThreadTasks(messageQueue, threadTasks, { failoverRestartPending });
|
|
1528
1530
|
if (!failoverRestartPending) {
|
|
1529
1531
|
// An accepted finish that is not waiting for the user ends the
|
|
1530
1532
|
// foreground task; the next one starts from zero. A wake that only
|
|
1531
1533
|
// ran out of recovery attempts or timed out keeps the count.
|
|
1532
|
-
if (result.finished === true && result.terminalState === "completed")
|
|
1534
|
+
if (result.finished === true && result.terminalState === "completed" && !handedOffTaskId)
|
|
1533
1535
|
foregroundTasks?.reset();
|
|
1534
1536
|
// Whatever the turn did not deliver to the user is due for the fallback now.
|
|
1535
1537
|
if (handledForemanEvents.length > 0) {
|
|
1536
1538
|
void getForemanClient()?.request({ type: "turn_ended", events: handledForemanEvents });
|
|
1537
1539
|
}
|
|
1538
1540
|
}
|
|
1541
|
+
if (result.finished === true && result.terminalState === "completed" && handedOffTaskId) {
|
|
1542
|
+
if (workerMode)
|
|
1543
|
+
workerMode.relay.markActivityWaitingForBackground(handedOffTaskId);
|
|
1544
|
+
else
|
|
1545
|
+
mainActivityController?.markWaitingForBackground(handedOffTaskId);
|
|
1546
|
+
foregroundTasks?.reset();
|
|
1547
|
+
}
|
|
1548
|
+
for (const event of handledForemanEvents) {
|
|
1549
|
+
if (event.kind !== "result")
|
|
1550
|
+
continue;
|
|
1551
|
+
const state = event.status === "succeeded" ? "completed" : "failed";
|
|
1552
|
+
if (workerMode)
|
|
1553
|
+
workerMode.relay.finishBackgroundActivity(event.taskId, state);
|
|
1554
|
+
else
|
|
1555
|
+
mainActivityController?.finishBackgroundTask(event.taskId, state);
|
|
1556
|
+
}
|
|
1539
1557
|
if (workerMode) {
|
|
1540
|
-
|
|
1558
|
+
if (!(result.finished === true && result.terminalState === "completed" && handedOffTaskId)) {
|
|
1559
|
+
workerMode.relay.finishActivityRun(result.terminalState);
|
|
1560
|
+
}
|
|
1541
1561
|
}
|
|
1542
1562
|
else {
|
|
1543
|
-
|
|
1563
|
+
if (!(result.finished === true && result.terminalState === "completed" && handedOffTaskId)) {
|
|
1564
|
+
mainActivityController?.finishRun(result.terminalState);
|
|
1565
|
+
}
|
|
1544
1566
|
}
|
|
1545
1567
|
tuiTerminalOutcome = resolveTuiTerminalOutcome(result.terminalState);
|
|
1546
1568
|
}
|
|
@@ -1549,6 +1571,9 @@ export async function startAgentLoop(config, options) {
|
|
|
1549
1571
|
// terminal boundary. A later wake must not inherit this turn's claims
|
|
1550
1572
|
// and accidentally confirm them together with unrelated work.
|
|
1551
1573
|
try {
|
|
1574
|
+
// Released before the requeue: a replayed resume for an interrupted
|
|
1575
|
+
// task must run when it comes back (#2664 review P1-B).
|
|
1576
|
+
threadTasks?.releaseResume(messageQueue.currentCycleClaims());
|
|
1552
1577
|
messageQueue.requeueOwnedClaims();
|
|
1553
1578
|
}
|
|
1554
1579
|
catch (requeueErr) {
|
|
@@ -1570,7 +1595,6 @@ export async function startAgentLoop(config, options) {
|
|
|
1570
1595
|
throw err;
|
|
1571
1596
|
}
|
|
1572
1597
|
finally {
|
|
1573
|
-
releaseConversationTurn?.();
|
|
1574
1598
|
// Cleanup must always run, even if the extracted cycle runner throws
|
|
1575
1599
|
// unexpectedly, otherwise the reply watchdog timer can leak across
|
|
1576
1600
|
// wake cycles. The runtime heartbeat loop runs independently and
|