@agents-ensemble/core 0.14.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/acp/acp-client.d.ts.map +1 -1
- package/dist/acp/acp-client.js +19 -1
- package/dist/acp/acp-client.js.map +1 -1
- package/dist/acp/resolve-acp-spawn.d.ts +1 -1
- package/dist/acp/resolve-acp-spawn.d.ts.map +1 -1
- package/dist/acp/resolve-acp-spawn.js +2 -2
- package/dist/acp/resolve-acp-spawn.js.map +1 -1
- package/dist/acp/testing/fake-acp-server.d.ts +3 -2
- package/dist/acp/testing/fake-acp-server.d.ts.map +1 -1
- package/dist/acp/testing/fake-acp-server.js +1 -0
- package/dist/acp/testing/fake-acp-server.js.map +1 -1
- package/dist/conductor/conductor-agent.d.ts +2 -0
- package/dist/conductor/conductor-agent.d.ts.map +1 -1
- package/dist/conductor/conductor-session-driver.d.ts +5 -2
- package/dist/conductor/conductor-session-driver.d.ts.map +1 -1
- package/dist/conductor/conductor-session-driver.js +65 -5
- package/dist/conductor/conductor-session-driver.js.map +1 -1
- package/dist/conductor/conductor-session.d.ts +2 -0
- package/dist/conductor/conductor-session.d.ts.map +1 -1
- package/dist/conductor/conductor-session.js +276 -85
- package/dist/conductor/conductor-session.js.map +1 -1
- package/dist/conductor/cursor-sdk-conductor-agent.d.ts +3 -0
- package/dist/conductor/cursor-sdk-conductor-agent.d.ts.map +1 -1
- package/dist/conductor/cursor-sdk-conductor-agent.js +48 -15
- package/dist/conductor/cursor-sdk-conductor-agent.js.map +1 -1
- package/dist/conductor/index.d.ts +5 -1
- package/dist/conductor/index.d.ts.map +1 -1
- package/dist/conductor/index.js +2 -0
- package/dist/conductor/index.js.map +1 -1
- package/dist/conductor/operator-command.d.ts +22 -0
- package/dist/conductor/operator-command.d.ts.map +1 -1
- package/dist/conductor/operator-command.js +29 -0
- package/dist/conductor/operator-command.js.map +1 -1
- package/dist/conductor/operator-input-binding.d.ts +3 -0
- package/dist/conductor/operator-input-binding.d.ts.map +1 -1
- package/dist/conductor/pi-conductor-agent.d.ts +1 -0
- package/dist/conductor/pi-conductor-agent.d.ts.map +1 -1
- package/dist/conductor/pi-conductor-agent.js +23 -1
- package/dist/conductor/pi-conductor-agent.js.map +1 -1
- package/dist/conductor/session/dispatch-hold-reminder-monitor.d.ts +28 -0
- package/dist/conductor/session/dispatch-hold-reminder-monitor.d.ts.map +1 -0
- package/dist/conductor/session/dispatch-hold-reminder-monitor.js +88 -0
- package/dist/conductor/session/dispatch-hold-reminder-monitor.js.map +1 -0
- package/dist/conductor/session/dispatch-hold.d.ts +1 -1
- package/dist/conductor/session/dispatch-hold.d.ts.map +1 -1
- package/dist/conductor/session/events/index.d.ts +1 -1
- package/dist/conductor/session/events/index.d.ts.map +1 -1
- package/dist/conductor/session/events/index.js.map +1 -1
- package/dist/conductor/session/events/session-event.d.ts +2 -0
- package/dist/conductor/session/events/session-event.d.ts.map +1 -1
- package/dist/conductor/session/events/session-log-event.d.ts +3 -1
- package/dist/conductor/session/events/session-log-event.d.ts.map +1 -1
- package/dist/conductor/session/select-dispatch-batch.d.ts +2 -0
- package/dist/conductor/session/select-dispatch-batch.d.ts.map +1 -1
- package/dist/conductor/session/select-dispatch-batch.js +8 -5
- package/dist/conductor/session/select-dispatch-batch.js.map +1 -1
- package/dist/conductor/session/session-event.d.ts +1 -1
- package/dist/conductor/session/session-event.d.ts.map +1 -1
- package/dist/conductor/submit-operator-input.d.ts +12 -1
- package/dist/conductor/submit-operator-input.d.ts.map +1 -1
- package/dist/conductor/submit-operator-input.js +28 -7
- package/dist/conductor/submit-operator-input.js.map +1 -1
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +3 -0
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/load-ensemble-config.d.ts +2 -0
- package/dist/config/load-ensemble-config.d.ts.map +1 -1
- package/dist/config/load-ensemble-config.js +18 -5
- package/dist/config/load-ensemble-config.js.map +1 -1
- package/dist/config/parse-config.d.ts.map +1 -1
- package/dist/config/parse-config.js +12 -0
- package/dist/config/parse-config.js.map +1 -1
- package/dist/config/types.d.ts +5 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/dispatch/attach-worker.d.ts +2 -1
- package/dist/dispatch/attach-worker.d.ts.map +1 -1
- package/dist/dispatch/attach-worker.js +1 -0
- package/dist/dispatch/attach-worker.js.map +1 -1
- package/dist/dispatch/worker-acp-session.d.ts +2 -2
- package/dist/dispatch/worker-acp-session.d.ts.map +1 -1
- package/dist/dispatch/worker-acp-session.js +1 -1
- package/dist/dispatch/worker-acp-session.js.map +1 -1
- package/dist/github/github-auth.d.ts +4 -0
- package/dist/github/github-auth.d.ts.map +1 -1
- package/dist/github/github-auth.js +37 -0
- package/dist/github/github-auth.js.map +1 -1
- package/dist/github/github-monitor-cursor.d.ts +10 -10
- package/dist/github/github-monitor-cursor.d.ts.map +1 -1
- package/dist/github/github-monitor-cursor.js +1 -1
- package/dist/github/github-monitor-cursor.js.map +1 -1
- package/dist/github/github-monitor-error.d.ts +1 -1
- package/dist/github/github-monitor-error.d.ts.map +1 -1
- package/dist/github/github-monitor-error.js +13 -1
- package/dist/github/github-monitor-error.js.map +1 -1
- package/dist/github/github-monitor.d.ts +3 -3
- package/dist/github/github-monitor.d.ts.map +1 -1
- package/dist/github/github-monitor.js +3 -3
- package/dist/github/github-monitor.js.map +1 -1
- package/dist/github/index.d.ts +1 -1
- package/dist/github/index.d.ts.map +1 -1
- package/dist/github/index.js +1 -1
- package/dist/github/index.js.map +1 -1
- package/dist/mcp/load-mcp-config.d.ts +1 -1
- package/dist/mcp/load-mcp-config.js +1 -1
- package/dist/operator-runtime.d.ts +11 -4
- package/dist/operator-runtime.d.ts.map +1 -1
- package/dist/operator-runtime.js +6 -2
- package/dist/operator-runtime.js.map +1 -1
- package/dist/prompt/build-worker-attach-prompt.d.ts +2 -1
- package/dist/prompt/build-worker-attach-prompt.d.ts.map +1 -1
- package/dist/prompt/build-worker-attach-prompt.js +4 -1
- package/dist/prompt/build-worker-attach-prompt.js.map +1 -1
- package/dist/prompt/build-worker-prompt.d.ts +2 -1
- package/dist/prompt/build-worker-prompt.d.ts.map +1 -1
- package/dist/prompt/build-worker-prompt.js +4 -1
- package/dist/prompt/build-worker-prompt.js.map +1 -1
- package/dist/prompt/load-user-instructions.d.ts +1 -1
- package/dist/prompt/load-user-instructions.js +1 -1
- package/dist/prompt/modules/ensemble/worker-base-module.d.ts.map +1 -1
- package/dist/prompt/modules/ensemble/worker-base-module.js +8 -0
- package/dist/prompt/modules/ensemble/worker-base-module.js.map +1 -1
- package/dist/runtime/worker-runtime.d.ts +2 -0
- package/dist/runtime/worker-runtime.d.ts.map +1 -1
- package/dist/runtime/worker-runtime.js +1 -0
- package/dist/runtime/worker-runtime.js.map +1 -1
- package/dist/runtime/worker-session.d.ts +2 -1
- package/dist/runtime/worker-session.d.ts.map +1 -1
- package/dist/runtime/worker-session.js +3 -0
- package/dist/runtime/worker-session.js.map +1 -1
- package/dist/session/index.d.ts +8 -4
- package/dist/session/index.d.ts.map +1 -1
- package/dist/session/index.js +4 -2
- package/dist/session/index.js.map +1 -1
- package/dist/session/open-question-control.d.ts +46 -2
- package/dist/session/open-question-control.d.ts.map +1 -1
- package/dist/session/open-question-control.js +127 -11
- package/dist/session/open-question-control.js.map +1 -1
- package/dist/session/session-resume-store.d.ts +119 -0
- package/dist/session/session-resume-store.d.ts.map +1 -0
- package/dist/session/session-resume-store.js +354 -0
- package/dist/session/session-resume-store.js.map +1 -0
- package/dist/session/tool-call-snapshot-history.d.ts +1 -1
- package/dist/session/tool-call-snapshot-history.js +4 -4
- package/dist/session/tool-call-snapshot-history.js.map +1 -1
- package/package.json +2 -2
- package/dist/session/session-sidecar.d.ts +0 -76
- package/dist/session/session-sidecar.d.ts.map +0 -1
- package/dist/session/session-sidecar.js +0 -261
- package/dist/session/session-sidecar.js.map +0 -1
|
@@ -31,20 +31,22 @@ import { resolvePiConductorProvider } from './conductor-pi-auth.js';
|
|
|
31
31
|
import { SessionLogger } from './session/session-logger.js';
|
|
32
32
|
import { SessionEventQueue } from './session/session-event-queue.js';
|
|
33
33
|
import { bufferDispatchHoldEvents, createDispatchHoldState, pruneStalePermissionEvents, } from './session/dispatch-hold.js';
|
|
34
|
+
import { createDispatchHoldReminderMonitor, formatDispatchHoldReminderMessage, } from './session/dispatch-hold-reminder-monitor.js';
|
|
34
35
|
import { operatorInputMaxTurns, resolveMaxTurns, } from './session-policy.js';
|
|
35
36
|
import { runConductorSessionDriver } from './conductor-session-driver.js';
|
|
36
37
|
import { isOperatorExitCommand } from './operator-exit.js';
|
|
37
38
|
import { isOperatorCloseCommand } from './operator-close.js';
|
|
38
39
|
import { isOperatorReconnectCommand } from './operator-reconnect.js';
|
|
39
|
-
import {
|
|
40
|
-
import {
|
|
40
|
+
import { parseOperatorMessageDelivery } from './operator-command.js';
|
|
41
|
+
import { assertSessionResumeStoreMatches, requireSessionResumeStoreForResume, saveSessionResumeStore, SESSION_RESUME_STORE_VERSION, sessionResumeStorePath, } from '../session/session-resume-store.js';
|
|
42
|
+
import { saveSessionStatusLine, sessionStateStorePath, loadSessionStateStore, } from '../session/session-state-store.js';
|
|
41
43
|
import { loadToolCallSnapshotHistory, pruneExpiredToolCallSnapshotHistoryFiles, saveToolCallSnapshotHistory, toolCallSnapshotHistoryPath, } from '../session/tool-call-snapshot-history.js';
|
|
42
44
|
import { loadOpenQuestionsStore, openQuestionsStorePath, saveOpenQuestionsStore, } from '../session/open-questions-store.js';
|
|
43
|
-
import { OpenQuestionControlOperationError, startOpenQuestionControlServer, } from '../session/open-question-control.js';
|
|
45
|
+
import { CONDUCTOR_MESSAGE_HISTORY_MAX_ENTRIES, OpenQuestionControlOperationError, startOpenQuestionControlServer, } from '../session/open-question-control.js';
|
|
44
46
|
import { formatPermissionSummaryForOperator } from '../permission/format-permission-summary-for-operator.js';
|
|
45
47
|
import { enrichSessionUsageWithCost } from '../usage/enrich-session-usage-cost.js';
|
|
46
48
|
import { SessionUsageTracker } from '../usage/session-usage-tracker.js';
|
|
47
|
-
import { submitOperatorInput } from './submit-operator-input.js';
|
|
49
|
+
import { enqueueOperatorMessage as enqueueOperatorMessageEvent, submitOperatorInput, } from './submit-operator-input.js';
|
|
48
50
|
import { createGitHubMonitor, } from '../github/github-monitor.js';
|
|
49
51
|
import { resolveConductorBackendSetting, resolveConductorPiResourcePaths, resolveGitHubMonitorEnabled, } from '../config/resolve-settings.js';
|
|
50
52
|
import { GitHubMonitorError } from '../github/github-monitor-error.js';
|
|
@@ -88,11 +90,17 @@ export async function runConductorSession(options) {
|
|
|
88
90
|
const escalations = [];
|
|
89
91
|
const openQuestions = new OpenQuestionRegistry();
|
|
90
92
|
let harnessSocketPath;
|
|
93
|
+
let harnessPhase;
|
|
94
|
+
let harnessModifiedAt;
|
|
95
|
+
let reportHarnessActivity = () => { };
|
|
91
96
|
let openQuestionControlServer;
|
|
97
|
+
let lastConductorMessage = null;
|
|
98
|
+
const conductorMessages = [];
|
|
92
99
|
const eventQueue = new SessionEventQueue();
|
|
93
100
|
const openQuestionDispatchReceipts = new WeakMap();
|
|
94
101
|
const pendingOpenQuestionDispatchReceipts = new Set();
|
|
95
102
|
const dispatchHoldState = createDispatchHoldState();
|
|
103
|
+
let dispatchHoldReminderMonitor;
|
|
96
104
|
const onDispatchHoldChanged = (change) => {
|
|
97
105
|
sessionLogger.emit({
|
|
98
106
|
type: 'conductor.dispatch_hold',
|
|
@@ -103,6 +111,7 @@ export async function runConductorSession(options) {
|
|
|
103
111
|
? { flushedEventCount: change.flushedEventCount }
|
|
104
112
|
: {}),
|
|
105
113
|
});
|
|
114
|
+
dispatchHoldReminderMonitor?.onHoldChanged(change.hold);
|
|
106
115
|
};
|
|
107
116
|
let activeProfile = options.profile;
|
|
108
117
|
let activeLazyWorkers = ensembleConfig.session.lazyWorkers;
|
|
@@ -117,11 +126,11 @@ export async function runConductorSession(options) {
|
|
|
117
126
|
let resumeToolCallSnapshots = [];
|
|
118
127
|
let toolCallHistoryNeedsRewrite = false;
|
|
119
128
|
if (options.resumeAgentId) {
|
|
120
|
-
const
|
|
129
|
+
const loadedResumeStore = await requireSessionResumeStoreForResume({
|
|
121
130
|
repoRoot: options.repoRoot,
|
|
122
131
|
conductorAgentId: options.resumeAgentId,
|
|
123
132
|
});
|
|
124
|
-
|
|
133
|
+
assertSessionResumeStoreMatches(loadedResumeStore, {
|
|
125
134
|
conductorAgentId: options.resumeAgentId,
|
|
126
135
|
issueUrl: options.issueUrl,
|
|
127
136
|
repoRoot: options.repoRoot,
|
|
@@ -131,18 +140,22 @@ export async function runConductorSession(options) {
|
|
|
131
140
|
});
|
|
132
141
|
// A previously completed lifecycle no longer describes this instance once
|
|
133
142
|
// resume begins. Persist unknown before restoring or attaching anything so
|
|
134
|
-
// a crash before the first regular
|
|
143
|
+
// a crash before the first regular SessionResumeStore flush cannot leave stale
|
|
135
144
|
// `closed` / `exited` data behind.
|
|
136
|
-
const
|
|
137
|
-
...
|
|
145
|
+
const resumeStore = {
|
|
146
|
+
...loadedResumeStore,
|
|
138
147
|
lifecycle: 'unknown',
|
|
148
|
+
harnessPhase: 'running',
|
|
149
|
+
modifiedAt: Date.now(),
|
|
139
150
|
harnessSocketPath: undefined,
|
|
140
151
|
updatedAt: Date.now(),
|
|
141
152
|
};
|
|
142
|
-
|
|
153
|
+
harnessPhase = 'running';
|
|
154
|
+
harnessModifiedAt = resumeStore.modifiedAt;
|
|
155
|
+
await saveSessionResumeStore(sessionResumeStorePath({
|
|
143
156
|
repoRoot: options.repoRoot,
|
|
144
157
|
conductorAgentId: options.resumeAgentId,
|
|
145
|
-
}),
|
|
158
|
+
}), resumeStore);
|
|
146
159
|
const history = await loadToolCallSnapshotHistory({
|
|
147
160
|
repoRoot: options.repoRoot,
|
|
148
161
|
conductorAgentId: options.resumeAgentId,
|
|
@@ -165,8 +178,8 @@ export async function runConductorSession(options) {
|
|
|
165
178
|
}
|
|
166
179
|
else {
|
|
167
180
|
const legacySnapshot = {
|
|
168
|
-
sequence:
|
|
169
|
-
openQuestions:
|
|
181
|
+
sequence: resumeStore.sequence,
|
|
182
|
+
openQuestions: resumeStore.openQuestions,
|
|
170
183
|
};
|
|
171
184
|
openQuestions.restore(legacySnapshot);
|
|
172
185
|
try {
|
|
@@ -176,15 +189,15 @@ export async function runConductorSession(options) {
|
|
|
176
189
|
const detail = error instanceof Error ? error.message : String(error);
|
|
177
190
|
sessionLogger.emit({
|
|
178
191
|
type: 'harness.warning',
|
|
179
|
-
message:
|
|
192
|
+
message: `旧形式の SessionResumeStore から復元した open question を YAML にバックフィルできませんでした。今回のセッションは継続します。 error=${detail}`,
|
|
180
193
|
});
|
|
181
194
|
}
|
|
182
195
|
}
|
|
183
|
-
activeProfile =
|
|
184
|
-
//
|
|
185
|
-
activeLazyWorkers =
|
|
186
|
-
githubMonitorCursor =
|
|
187
|
-
for (const [name, worker] of Object.entries(
|
|
196
|
+
activeProfile = resumeStore.profile;
|
|
197
|
+
// ResumeStores written before this setting always started every worker eagerly.
|
|
198
|
+
activeLazyWorkers = resumeStore.lazyWorkers ?? false;
|
|
199
|
+
githubMonitorCursor = resumeStore.githubMonitor;
|
|
200
|
+
for (const [name, worker] of Object.entries(resumeStore.workers)) {
|
|
188
201
|
workerSessions.set(name, {
|
|
189
202
|
acpSessionId: worker.acpSessionId,
|
|
190
203
|
...(worker.acpCwd ? { acpCwd: worker.acpCwd } : {}),
|
|
@@ -290,8 +303,8 @@ export async function runConductorSession(options) {
|
|
|
290
303
|
}
|
|
291
304
|
const permissionPipeline = options.permissionPipeline ??
|
|
292
305
|
new PermissionPipeline({ policy: options.permissionPolicy });
|
|
293
|
-
let
|
|
294
|
-
let
|
|
306
|
+
let scheduleSessionResumeStoreFlush = () => { };
|
|
307
|
+
let flushSessionResumeStore = async () => { };
|
|
295
308
|
let scheduleToolCallHistoryFlush = () => { };
|
|
296
309
|
let flushToolCallHistory = async () => { };
|
|
297
310
|
let toolCallHistoryDirty = toolCallHistoryNeedsRewrite;
|
|
@@ -357,6 +370,7 @@ export async function runConductorSession(options) {
|
|
|
357
370
|
workers,
|
|
358
371
|
lazyWorkers: activeLazyWorkers,
|
|
359
372
|
sessionState,
|
|
373
|
+
...(userInstructions ? { userInstructions } : {}),
|
|
360
374
|
restoredWorkerSessions: Object.fromEntries(workerSessions),
|
|
361
375
|
permissionPipeline,
|
|
362
376
|
...(options.connectAcp ? { connectAcp: options.connectAcp } : {}),
|
|
@@ -433,7 +447,7 @@ export async function runConductorSession(options) {
|
|
|
433
447
|
: {}),
|
|
434
448
|
});
|
|
435
449
|
eventQueue.enqueue({ type: 'worker.completed', result });
|
|
436
|
-
|
|
450
|
+
scheduleSessionResumeStoreFlush();
|
|
437
451
|
},
|
|
438
452
|
onWorkerFailed: (failure) => {
|
|
439
453
|
sessionLogger.emit({ type: 'worker.failed', failure });
|
|
@@ -442,6 +456,7 @@ export async function runConductorSession(options) {
|
|
|
442
456
|
onPromptTelemetry: (event) => {
|
|
443
457
|
switch (event.phase) {
|
|
444
458
|
case 'started':
|
|
459
|
+
reportHarnessActivity('worker', true);
|
|
445
460
|
sessionLogger.emit({
|
|
446
461
|
type: 'harness.worker.prompt.started',
|
|
447
462
|
name: event.name,
|
|
@@ -451,6 +466,7 @@ export async function runConductorSession(options) {
|
|
|
451
466
|
});
|
|
452
467
|
break;
|
|
453
468
|
case 'completed':
|
|
469
|
+
reportHarnessActivity('worker', false);
|
|
454
470
|
sessionLogger.emit({
|
|
455
471
|
type: 'harness.worker.prompt.completed',
|
|
456
472
|
name: event.name,
|
|
@@ -461,6 +477,7 @@ export async function runConductorSession(options) {
|
|
|
461
477
|
});
|
|
462
478
|
break;
|
|
463
479
|
case 'failed':
|
|
480
|
+
reportHarnessActivity('worker', false);
|
|
464
481
|
sessionLogger.emit({
|
|
465
482
|
type: 'harness.worker.prompt.failed',
|
|
466
483
|
name: event.name,
|
|
@@ -564,14 +581,14 @@ export async function runConductorSession(options) {
|
|
|
564
581
|
sessionLogger.emit({ type: 'escalation.recorded', record });
|
|
565
582
|
options.onEscalated?.(record);
|
|
566
583
|
}
|
|
567
|
-
|
|
584
|
+
scheduleSessionResumeStoreFlush();
|
|
568
585
|
};
|
|
569
586
|
const askHumanTools = createAskHumanTool({
|
|
570
587
|
registry: openQuestions,
|
|
571
588
|
onEnqueued: (question) => {
|
|
572
589
|
sessionLogger.emit({ type: 'open.question.enqueued', question });
|
|
573
590
|
options.onOpenQuestionEnqueued?.(question);
|
|
574
|
-
|
|
591
|
+
scheduleSessionResumeStoreFlush();
|
|
575
592
|
},
|
|
576
593
|
});
|
|
577
594
|
const answerOpenQuestionTools = createAnswerOpenQuestionTool({
|
|
@@ -618,7 +635,7 @@ export async function runConductorSession(options) {
|
|
|
618
635
|
// Do not report success to the conductor until the explicit watch is
|
|
619
636
|
// durable. This closes the crash window between the tool result and a
|
|
620
637
|
// later best-effort flush.
|
|
621
|
-
await
|
|
638
|
+
await flushSessionResumeStore();
|
|
622
639
|
},
|
|
623
640
|
});
|
|
624
641
|
const unregisterGitHubWatchTools = createUnregisterGitHubWatchTool({
|
|
@@ -629,7 +646,7 @@ export async function runConductorSession(options) {
|
|
|
629
646
|
},
|
|
630
647
|
onUnregistered: async (prNumber) => {
|
|
631
648
|
githubMonitor?.unregisterPullRequest?.(prNumber);
|
|
632
|
-
await
|
|
649
|
+
await flushSessionResumeStore();
|
|
633
650
|
},
|
|
634
651
|
});
|
|
635
652
|
let conductorAgent;
|
|
@@ -749,14 +766,15 @@ export async function runConductorSession(options) {
|
|
|
749
766
|
});
|
|
750
767
|
},
|
|
751
768
|
};
|
|
752
|
-
let
|
|
769
|
+
let sessionResumeStoreWriteQueue = Promise.resolve();
|
|
753
770
|
let terminalLifecycle;
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
771
|
+
let terminalResumeStoreFinalFlushQueued = false;
|
|
772
|
+
const enqueueSessionResumeStoreWrite = (write) => {
|
|
773
|
+
const nextWrite = sessionResumeStoreWriteQueue.then(write);
|
|
774
|
+
sessionResumeStoreWriteQueue = nextWrite.catch(() => { });
|
|
757
775
|
return nextWrite;
|
|
758
776
|
};
|
|
759
|
-
const
|
|
777
|
+
const createSessionResumeStore = (snapshot, lifecycle) => {
|
|
760
778
|
const workers = {};
|
|
761
779
|
for (const [name, worker] of workerSessions) {
|
|
762
780
|
workers[name] = {
|
|
@@ -765,8 +783,13 @@ export async function runConductorSession(options) {
|
|
|
765
783
|
...(worker.acpSpawn ? { acpSpawn: worker.acpSpawn } : {}),
|
|
766
784
|
};
|
|
767
785
|
}
|
|
786
|
+
const persistedLifecycle = terminalLifecycle ??
|
|
787
|
+
lifecycle ??
|
|
788
|
+
(harnessPhase === 'running' || harnessPhase === 'idle'
|
|
789
|
+
? 'unknown'
|
|
790
|
+
: undefined);
|
|
768
791
|
return {
|
|
769
|
-
version:
|
|
792
|
+
version: SESSION_RESUME_STORE_VERSION,
|
|
770
793
|
conductorAgentId: conductorHandle.conductor.agentId,
|
|
771
794
|
conductorBackend,
|
|
772
795
|
lazyWorkers: activeLazyWorkers,
|
|
@@ -775,13 +798,15 @@ export async function runConductorSession(options) {
|
|
|
775
798
|
repoRoot: options.repoRoot,
|
|
776
799
|
profile: structuredClone(activeProfile),
|
|
777
800
|
...(options.profilePath ? { profilePath: options.profilePath } : {}),
|
|
801
|
+
...(harnessPhase ? { harnessPhase } : {}),
|
|
802
|
+
...(harnessModifiedAt !== undefined
|
|
803
|
+
? { modifiedAt: harnessModifiedAt }
|
|
804
|
+
: {}),
|
|
778
805
|
openQuestions: snapshot.openQuestions,
|
|
779
806
|
sequence: snapshot.sequence,
|
|
780
807
|
workers,
|
|
781
808
|
mcpConfigDigest,
|
|
782
|
-
...(
|
|
783
|
-
? { lifecycle: terminalLifecycle ?? lifecycle }
|
|
784
|
-
: {}),
|
|
809
|
+
...(persistedLifecycle ? { lifecycle: persistedLifecycle } : {}),
|
|
785
810
|
...(githubMonitorCursor ? { githubMonitor: githubMonitorCursor } : {}),
|
|
786
811
|
updatedAt: Date.now(),
|
|
787
812
|
};
|
|
@@ -792,33 +817,90 @@ export async function runConductorSession(options) {
|
|
|
792
817
|
conductorAgentId: conductorHandle.conductor.agentId,
|
|
793
818
|
}), snapshot);
|
|
794
819
|
};
|
|
795
|
-
const
|
|
796
|
-
await
|
|
820
|
+
const persistSessionResumeStore = async (snapshot, lifecycle) => {
|
|
821
|
+
await saveSessionResumeStore(sessionResumeStorePath({
|
|
797
822
|
repoRoot: options.repoRoot,
|
|
798
823
|
conductorAgentId: conductorHandle.conductor.agentId,
|
|
799
|
-
}),
|
|
824
|
+
}), createSessionResumeStore(snapshot, lifecycle));
|
|
800
825
|
};
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
826
|
+
flushSessionResumeStore = (lifecycle) => {
|
|
827
|
+
if (terminalResumeStoreFinalFlushQueued && lifecycle === undefined) {
|
|
828
|
+
return sessionResumeStoreWriteQueue;
|
|
829
|
+
}
|
|
830
|
+
if (lifecycle !== undefined && lifecycle !== 'unknown') {
|
|
831
|
+
terminalResumeStoreFinalFlushQueued = true;
|
|
832
|
+
}
|
|
833
|
+
return enqueueSessionResumeStoreWrite(async () => {
|
|
834
|
+
if (lifecycle !== undefined) {
|
|
835
|
+
terminalLifecycle = lifecycle;
|
|
836
|
+
harnessPhase =
|
|
837
|
+
lifecycle === 'closed'
|
|
838
|
+
? 'close'
|
|
839
|
+
: lifecycle === 'exited'
|
|
840
|
+
? 'exit'
|
|
841
|
+
: lifecycle === 'interrupted'
|
|
842
|
+
? 'abort'
|
|
843
|
+
: undefined;
|
|
844
|
+
harnessModifiedAt = harnessPhase ? Date.now() : undefined;
|
|
845
|
+
}
|
|
846
|
+
const snapshot = openQuestions.snapshot();
|
|
847
|
+
await persistOpenQuestionsSnapshot(snapshot);
|
|
848
|
+
await persistSessionResumeStore(snapshot, lifecycle);
|
|
849
|
+
});
|
|
850
|
+
};
|
|
851
|
+
const reportResumeStoreFlushFailure = (error) => {
|
|
807
852
|
const detail = error instanceof Error ? error.message : String(error);
|
|
808
853
|
sessionLogger.emit({
|
|
809
854
|
type: 'harness.warning',
|
|
810
|
-
message: `Open Question YAML /
|
|
855
|
+
message: `Open Question YAML / SessionResumeStore を保存できませんでした。最新状態から再開できず、直前に保存された状態からの再開になる場合があります。 error=${detail}`,
|
|
811
856
|
});
|
|
812
857
|
};
|
|
813
|
-
const
|
|
858
|
+
const reportSessionResumeStoreWriteFailure = (error) => {
|
|
814
859
|
const detail = error instanceof Error ? error.message : String(error);
|
|
815
860
|
sessionLogger.emit({
|
|
816
861
|
type: 'harness.warning',
|
|
817
|
-
message: `
|
|
862
|
+
message: `SessionResumeStore の更新に失敗しました。Open Question YAML の保存は完了しており、保存状態は後続 flush で同期します。 error=${detail}`,
|
|
818
863
|
});
|
|
819
864
|
};
|
|
820
|
-
|
|
821
|
-
void
|
|
865
|
+
scheduleSessionResumeStoreFlush = () => {
|
|
866
|
+
void flushSessionResumeStore().catch(reportResumeStoreFlushFailure);
|
|
867
|
+
};
|
|
868
|
+
let conductorSendCount = 0;
|
|
869
|
+
let workerPromptCount = 0;
|
|
870
|
+
let idlePhaseTimer;
|
|
871
|
+
const persistHarnessPhase = (phase) => {
|
|
872
|
+
if (teardownStarted || harnessPhase === phase)
|
|
873
|
+
return;
|
|
874
|
+
if (idlePhaseTimer) {
|
|
875
|
+
clearTimeout(idlePhaseTimer);
|
|
876
|
+
idlePhaseTimer = undefined;
|
|
877
|
+
}
|
|
878
|
+
harnessPhase = phase;
|
|
879
|
+
harnessModifiedAt = Date.now();
|
|
880
|
+
void flushSessionResumeStore().catch(reportResumeStoreFlushFailure);
|
|
881
|
+
};
|
|
882
|
+
reportHarnessActivity = (kind, active) => {
|
|
883
|
+
if (teardownStarted)
|
|
884
|
+
return;
|
|
885
|
+
if (kind === 'conductor') {
|
|
886
|
+
conductorSendCount = Math.max(0, conductorSendCount + (active ? 1 : -1));
|
|
887
|
+
}
|
|
888
|
+
else {
|
|
889
|
+
workerPromptCount = Math.max(0, workerPromptCount + (active ? 1 : -1));
|
|
890
|
+
}
|
|
891
|
+
if (conductorSendCount + workerPromptCount > 0) {
|
|
892
|
+
persistHarnessPhase('running');
|
|
893
|
+
return;
|
|
894
|
+
}
|
|
895
|
+
if (idlePhaseTimer || harnessPhase === 'idle')
|
|
896
|
+
return;
|
|
897
|
+
idlePhaseTimer = setTimeout(() => {
|
|
898
|
+
idlePhaseTimer = undefined;
|
|
899
|
+
if (conductorSendCount + workerPromptCount === 0) {
|
|
900
|
+
persistHarnessPhase('idle');
|
|
901
|
+
}
|
|
902
|
+
}, 250);
|
|
903
|
+
idlePhaseTimer.unref?.();
|
|
822
904
|
};
|
|
823
905
|
const toolCallHistoryPath = toolCallSnapshotHistoryPath({
|
|
824
906
|
repoRoot: options.repoRoot,
|
|
@@ -891,7 +973,7 @@ export async function runConductorSession(options) {
|
|
|
891
973
|
shutdownSignal,
|
|
892
974
|
onCursorChange: (cursor) => {
|
|
893
975
|
githubMonitorCursor = cursor;
|
|
894
|
-
|
|
976
|
+
scheduleSessionResumeStoreFlush();
|
|
895
977
|
},
|
|
896
978
|
onUpdate: (payload) => {
|
|
897
979
|
sessionLogger.emit({
|
|
@@ -950,6 +1032,21 @@ export async function runConductorSession(options) {
|
|
|
950
1032
|
});
|
|
951
1033
|
githubMonitor.start();
|
|
952
1034
|
}
|
|
1035
|
+
dispatchHoldReminderMonitor = createDispatchHoldReminderMonitor({
|
|
1036
|
+
getSnapshot: () => ({
|
|
1037
|
+
hold: dispatchHoldState.dispatchHold,
|
|
1038
|
+
heldEventCount: dispatchHoldState.heldEvents.length,
|
|
1039
|
+
}),
|
|
1040
|
+
onReminder: ({ heldEventCount }) => {
|
|
1041
|
+
sessionLogger.emit({
|
|
1042
|
+
type: 'harness.warning',
|
|
1043
|
+
message: formatDispatchHoldReminderMessage(heldEventCount, options.dispatchHoldReminderMs),
|
|
1044
|
+
});
|
|
1045
|
+
},
|
|
1046
|
+
reminderIntervalMs: options.dispatchHoldReminderMs,
|
|
1047
|
+
shutdownSignal,
|
|
1048
|
+
});
|
|
1049
|
+
dispatchHoldReminderMonitor.start();
|
|
953
1050
|
let permissionDeadlockMonitor;
|
|
954
1051
|
if (!options.disablePermissionDeadlockMonitor) {
|
|
955
1052
|
permissionDeadlockMonitor = createPermissionDeadlockMonitor({
|
|
@@ -986,6 +1083,57 @@ export async function runConductorSession(options) {
|
|
|
986
1083
|
let operatorRequestedExit = false;
|
|
987
1084
|
let operatorRequestedClose = false;
|
|
988
1085
|
let disposeOperatorInput;
|
|
1086
|
+
const onOperatorMessageQueued = (delivery) => {
|
|
1087
|
+
scheduleSessionResumeStoreFlush();
|
|
1088
|
+
if (delivery !== 'interrupt')
|
|
1089
|
+
return;
|
|
1090
|
+
const cancel = conductorHandle.conductor.cancel;
|
|
1091
|
+
if (!cancel) {
|
|
1092
|
+
sessionLogger.emit({
|
|
1093
|
+
type: 'harness.warning',
|
|
1094
|
+
message: 'Operator interrupt cancellation is unavailable; the message will use normal next dispatch.',
|
|
1095
|
+
});
|
|
1096
|
+
return;
|
|
1097
|
+
}
|
|
1098
|
+
void cancel.call(conductorHandle.conductor).catch((error) => {
|
|
1099
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
1100
|
+
sessionLogger.emit({
|
|
1101
|
+
type: 'harness.warning',
|
|
1102
|
+
message: `Operator interrupt cancellation failed; the message will use normal next dispatch: ${detail}`,
|
|
1103
|
+
});
|
|
1104
|
+
});
|
|
1105
|
+
};
|
|
1106
|
+
const submitOperatorMessage = (input) => {
|
|
1107
|
+
const delivery = input.delivery ?? 'next';
|
|
1108
|
+
const received = submitOperatorInput({
|
|
1109
|
+
...input,
|
|
1110
|
+
delivery,
|
|
1111
|
+
conductorTurn: sendCount + 1,
|
|
1112
|
+
openQuestions,
|
|
1113
|
+
escalations,
|
|
1114
|
+
eventQueue,
|
|
1115
|
+
sessionLogger,
|
|
1116
|
+
onEscalated: input.onEscalated ?? ((record) => options.onEscalated?.(record)),
|
|
1117
|
+
});
|
|
1118
|
+
if (!received)
|
|
1119
|
+
return false;
|
|
1120
|
+
onOperatorMessageQueued(delivery);
|
|
1121
|
+
return true;
|
|
1122
|
+
};
|
|
1123
|
+
const sendOperatorMessage = (input) => {
|
|
1124
|
+
const delivery = input.delivery ?? 'next';
|
|
1125
|
+
const received = enqueueOperatorMessageEvent({
|
|
1126
|
+
...input,
|
|
1127
|
+
delivery,
|
|
1128
|
+
conductorTurn: sendCount + 1,
|
|
1129
|
+
eventQueue,
|
|
1130
|
+
sessionLogger,
|
|
1131
|
+
});
|
|
1132
|
+
if (!received)
|
|
1133
|
+
return false;
|
|
1134
|
+
onOperatorMessageQueued(delivery);
|
|
1135
|
+
return true;
|
|
1136
|
+
};
|
|
989
1137
|
if (options.bindOperatorInput) {
|
|
990
1138
|
const bindingDispose = options.bindOperatorInput({
|
|
991
1139
|
submit: (message, submitOptions) => {
|
|
@@ -1009,20 +1157,16 @@ export async function runConductorSession(options) {
|
|
|
1009
1157
|
eventQueue.enqueue({ type: 'operator.reconnect' });
|
|
1010
1158
|
return true;
|
|
1011
1159
|
}
|
|
1012
|
-
const
|
|
1013
|
-
message,
|
|
1160
|
+
const parsed = submitOptions?.targetOpenQuestionId !== undefined
|
|
1161
|
+
? { message, delivery: 'next' }
|
|
1162
|
+
: submitOptions?.delivery === undefined
|
|
1163
|
+
? parseOperatorMessageDelivery(message)
|
|
1164
|
+
: { message, delivery: submitOptions.delivery };
|
|
1165
|
+
return submitOperatorMessage({
|
|
1166
|
+
message: parsed.message,
|
|
1167
|
+
delivery: parsed.delivery,
|
|
1014
1168
|
targetOpenQuestionId: submitOptions?.targetOpenQuestionId,
|
|
1015
|
-
conductorTurn: sendCount + 1,
|
|
1016
|
-
openQuestions,
|
|
1017
|
-
escalations,
|
|
1018
|
-
eventQueue,
|
|
1019
|
-
sessionLogger,
|
|
1020
|
-
onEscalated: (record) => options.onEscalated?.(record),
|
|
1021
1169
|
});
|
|
1022
|
-
if (received) {
|
|
1023
|
-
scheduleSidecarFlush();
|
|
1024
|
-
}
|
|
1025
|
-
return received;
|
|
1026
1170
|
},
|
|
1027
1171
|
getContext: () => ({
|
|
1028
1172
|
conductorTurn: sendCount + 1,
|
|
@@ -1038,6 +1182,25 @@ export async function runConductorSession(options) {
|
|
|
1038
1182
|
try {
|
|
1039
1183
|
openQuestionControlServer = await startOpenQuestionControlServer({
|
|
1040
1184
|
listOpenQuestions: () => openQuestions.listOpen(),
|
|
1185
|
+
getLastConductorMessage: () => lastConductorMessage,
|
|
1186
|
+
listConductorMessages: () => conductorMessages,
|
|
1187
|
+
observeSession: async () => {
|
|
1188
|
+
await sessionStateWriteQueue;
|
|
1189
|
+
const sessionState = await loadSessionStateStore(sessionStateStorePath({
|
|
1190
|
+
repoRoot: options.repoRoot,
|
|
1191
|
+
conductorAgentId: conductorAgent.agentId,
|
|
1192
|
+
}));
|
|
1193
|
+
return {
|
|
1194
|
+
...openQuestions.snapshot(),
|
|
1195
|
+
...(sessionState ? { sessionState } : {}),
|
|
1196
|
+
};
|
|
1197
|
+
},
|
|
1198
|
+
sendOperatorMessage: ({ text, delivery }) => {
|
|
1199
|
+
if (teardownStarted) {
|
|
1200
|
+
throw new OpenQuestionControlOperationError(-32000, 'The session is shutting down.');
|
|
1201
|
+
}
|
|
1202
|
+
return sendOperatorMessage({ message: text, delivery });
|
|
1203
|
+
},
|
|
1041
1204
|
answerOpenQuestion: async ({ questionId, answer }) => {
|
|
1042
1205
|
if (teardownStarted) {
|
|
1043
1206
|
throw new OpenQuestionControlOperationError(-32000, 'The session is shutting down.');
|
|
@@ -1047,11 +1210,11 @@ export async function runConductorSession(options) {
|
|
|
1047
1210
|
throw new OpenQuestionControlOperationError(-32004, 'Open Question is not available.');
|
|
1048
1211
|
}
|
|
1049
1212
|
let accepted = false;
|
|
1050
|
-
let
|
|
1213
|
+
let resumeStoreWriteError;
|
|
1051
1214
|
let dispatchReceipt;
|
|
1052
1215
|
let answered;
|
|
1053
1216
|
const escalatedRecords = [];
|
|
1054
|
-
await
|
|
1217
|
+
await enqueueSessionResumeStoreWrite(async () => {
|
|
1055
1218
|
const stagedOpenQuestions = new OpenQuestionRegistry();
|
|
1056
1219
|
stagedOpenQuestions.restore(openQuestions.snapshot());
|
|
1057
1220
|
const stagedAccepted = submitOperatorInput({
|
|
@@ -1078,15 +1241,11 @@ export async function runConductorSession(options) {
|
|
|
1078
1241
|
await persistOpenQuestionsSnapshot(openQuestions.snapshot());
|
|
1079
1242
|
return;
|
|
1080
1243
|
}
|
|
1081
|
-
accepted =
|
|
1244
|
+
accepted = submitOperatorMessage({
|
|
1082
1245
|
message: answer,
|
|
1246
|
+
delivery: 'next',
|
|
1083
1247
|
targetOpenQuestionId: questionId,
|
|
1084
1248
|
answeredAt: stagedAnswer.answeredAt,
|
|
1085
|
-
conductorTurn: sendCount + 1,
|
|
1086
|
-
openQuestions,
|
|
1087
|
-
escalations,
|
|
1088
|
-
eventQueue,
|
|
1089
|
-
sessionLogger,
|
|
1090
1249
|
onEscalated: (record) => escalatedRecords.push(record),
|
|
1091
1250
|
onOperatorMessageQueued: (event) => {
|
|
1092
1251
|
let receipt;
|
|
@@ -1108,12 +1267,12 @@ export async function runConductorSession(options) {
|
|
|
1108
1267
|
return;
|
|
1109
1268
|
}
|
|
1110
1269
|
try {
|
|
1111
|
-
await
|
|
1270
|
+
await persistSessionResumeStore(openQuestions.snapshot());
|
|
1112
1271
|
}
|
|
1113
1272
|
catch (error) {
|
|
1114
1273
|
// YAML is authoritative and is already durable. Keep the accepted
|
|
1115
1274
|
// answer/notification, report the mirror failure, then repair it.
|
|
1116
|
-
|
|
1275
|
+
resumeStoreWriteError = error;
|
|
1117
1276
|
}
|
|
1118
1277
|
});
|
|
1119
1278
|
if (!accepted || !answered || answered.status !== 'answered') {
|
|
@@ -1131,9 +1290,9 @@ export async function runConductorSession(options) {
|
|
|
1131
1290
|
});
|
|
1132
1291
|
}
|
|
1133
1292
|
}
|
|
1134
|
-
if (
|
|
1135
|
-
|
|
1136
|
-
|
|
1293
|
+
if (resumeStoreWriteError !== undefined) {
|
|
1294
|
+
reportSessionResumeStoreWriteFailure(resumeStoreWriteError);
|
|
1295
|
+
scheduleSessionResumeStoreFlush();
|
|
1137
1296
|
}
|
|
1138
1297
|
if (!dispatchReceipt) {
|
|
1139
1298
|
throw new OpenQuestionControlOperationError(-32603, 'The answer was recorded, but its conductor notification was not queued. The outcome is unknown; do not resubmit the answer and inspect the session state.', RECORDED_ANSWER_UNKNOWN_DISPATCH);
|
|
@@ -1143,7 +1302,7 @@ export async function runConductorSession(options) {
|
|
|
1143
1302
|
},
|
|
1144
1303
|
});
|
|
1145
1304
|
harnessSocketPath = openQuestionControlServer.socketPath;
|
|
1146
|
-
await
|
|
1305
|
+
await flushSessionResumeStore().catch(reportResumeStoreFlushFailure);
|
|
1147
1306
|
const driverResult = await runConductorSessionDriver({
|
|
1148
1307
|
issueUrl: options.issueUrl,
|
|
1149
1308
|
initialPrompt: conductorBackend === 'pi'
|
|
@@ -1189,6 +1348,7 @@ export async function runConductorSession(options) {
|
|
|
1189
1348
|
// session briefing.
|
|
1190
1349
|
skipInitialSend: Boolean(options.resumeAgentId),
|
|
1191
1350
|
onSendStarted: (info) => {
|
|
1351
|
+
reportHarnessActivity('conductor', true);
|
|
1192
1352
|
sessionLogger.emit({
|
|
1193
1353
|
type: 'conductor.send.started',
|
|
1194
1354
|
sendCount: info.sendCount,
|
|
@@ -1237,6 +1397,29 @@ export async function runConductorSession(options) {
|
|
|
1237
1397
|
function recordSendComplete(info) {
|
|
1238
1398
|
sendCount = info.sendCount;
|
|
1239
1399
|
autonomousTurns = info.autonomousTurns;
|
|
1400
|
+
const responseText = info.result?.trim();
|
|
1401
|
+
if (info.status === 'finished' && responseText) {
|
|
1402
|
+
const at = Date.now();
|
|
1403
|
+
lastConductorMessage = {
|
|
1404
|
+
text: responseText,
|
|
1405
|
+
at,
|
|
1406
|
+
sendCount: info.sendCount,
|
|
1407
|
+
};
|
|
1408
|
+
if (info.dispatchSource !== 'initial') {
|
|
1409
|
+
conductorMessages.push({
|
|
1410
|
+
text: responseText,
|
|
1411
|
+
inbound: info.inbound,
|
|
1412
|
+
at,
|
|
1413
|
+
sendCount: info.sendCount,
|
|
1414
|
+
...(info.dispatchSource
|
|
1415
|
+
? { dispatchSource: info.dispatchSource }
|
|
1416
|
+
: {}),
|
|
1417
|
+
});
|
|
1418
|
+
if (conductorMessages.length > CONDUCTOR_MESSAGE_HISTORY_MAX_ENTRIES) {
|
|
1419
|
+
conductorMessages.shift();
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1240
1423
|
const githubUpdateIds = info.githubUpdateIds ?? [];
|
|
1241
1424
|
if (info.status === 'finished' &&
|
|
1242
1425
|
!operatorRequestedClose &&
|
|
@@ -1266,6 +1449,7 @@ export async function runConductorSession(options) {
|
|
|
1266
1449
|
workerDispatches: info.workerDispatches,
|
|
1267
1450
|
workerFailures: info.workerFailures,
|
|
1268
1451
|
});
|
|
1452
|
+
reportHarnessActivity('conductor', false);
|
|
1269
1453
|
outboundWorkersThisSend.clear();
|
|
1270
1454
|
if (isConductorSendAuthError({
|
|
1271
1455
|
runId: info.runId,
|
|
@@ -1285,7 +1469,7 @@ export async function runConductorSession(options) {
|
|
|
1285
1469
|
: { backend: 'cursor' }),
|
|
1286
1470
|
});
|
|
1287
1471
|
}
|
|
1288
|
-
|
|
1472
|
+
scheduleSessionResumeStoreFlush();
|
|
1289
1473
|
}
|
|
1290
1474
|
async function buildResult() {
|
|
1291
1475
|
sessionLogger.finish(stopReason);
|
|
@@ -1318,8 +1502,11 @@ export async function runConductorSession(options) {
|
|
|
1318
1502
|
: shutdownSignal.aborted
|
|
1319
1503
|
? 'interrupted'
|
|
1320
1504
|
: 'unknown';
|
|
1321
|
-
terminalLifecycle = lifecycle;
|
|
1322
1505
|
teardownStarted = true;
|
|
1506
|
+
if (idlePhaseTimer) {
|
|
1507
|
+
clearTimeout(idlePhaseTimer);
|
|
1508
|
+
idlePhaseTimer = undefined;
|
|
1509
|
+
}
|
|
1323
1510
|
for (const receipt of pendingOpenQuestionDispatchReceipts) {
|
|
1324
1511
|
receipt.reject(new OpenQuestionControlOperationError(-32005, 'The answer was recorded and persisted, but the conductor session stopped before notification completed. The outcome is unknown; do not resubmit the answer and inspect the session state.', RECORDED_ANSWER_UNKNOWN_DISPATCH));
|
|
1325
1512
|
}
|
|
@@ -1368,6 +1555,10 @@ export async function runConductorSession(options) {
|
|
|
1368
1555
|
teardownPhases.openQuestionControl = Date.now() - phaseStart;
|
|
1369
1556
|
}
|
|
1370
1557
|
disposeOperatorInput?.();
|
|
1558
|
+
if (dispatchHoldReminderMonitor) {
|
|
1559
|
+
emitTeardownPhase('dispatchHoldReminderMonitor');
|
|
1560
|
+
dispatchHoldReminderMonitor.stop();
|
|
1561
|
+
}
|
|
1371
1562
|
if (permissionDeadlockMonitor) {
|
|
1372
1563
|
emitTeardownPhase('permissionDeadlockMonitor');
|
|
1373
1564
|
permissionDeadlockMonitor.stop();
|
|
@@ -1414,13 +1605,13 @@ export async function runConductorSession(options) {
|
|
|
1414
1605
|
githubMonitorStopped = true;
|
|
1415
1606
|
}
|
|
1416
1607
|
try {
|
|
1417
|
-
emitTeardownPhase('
|
|
1608
|
+
emitTeardownPhase('flushSessionResumeStore');
|
|
1418
1609
|
const phaseStart = Date.now();
|
|
1419
|
-
await
|
|
1420
|
-
teardownPhases.
|
|
1610
|
+
await flushSessionResumeStore();
|
|
1611
|
+
teardownPhases.flushSessionResumeStore = Date.now() - phaseStart;
|
|
1421
1612
|
}
|
|
1422
1613
|
catch (error) {
|
|
1423
|
-
|
|
1614
|
+
reportResumeStoreFlushFailure(error);
|
|
1424
1615
|
}
|
|
1425
1616
|
await flushToolCallHistoryBestEffort();
|
|
1426
1617
|
const runGithubMonitorStop = async () => {
|
|
@@ -1485,12 +1676,12 @@ export async function runConductorSession(options) {
|
|
|
1485
1676
|
}
|
|
1486
1677
|
finally {
|
|
1487
1678
|
try {
|
|
1488
|
-
emitTeardownPhase('
|
|
1679
|
+
emitTeardownPhase('flushSessionResumeStore');
|
|
1489
1680
|
await sessionStateWriteQueue;
|
|
1490
|
-
await
|
|
1681
|
+
await flushSessionResumeStore(lifecycle);
|
|
1491
1682
|
}
|
|
1492
1683
|
catch (error) {
|
|
1493
|
-
|
|
1684
|
+
reportResumeStoreFlushFailure(error);
|
|
1494
1685
|
}
|
|
1495
1686
|
process.off('SIGINT', onTeardownSignal);
|
|
1496
1687
|
process.off('SIGTERM', onTeardownSignal);
|