@agents-ensemble/core 0.11.0 → 0.13.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 +9 -1
- package/dist/acp/acp-client.d.ts.map +1 -1
- package/dist/acp/acp-client.js +14 -11
- package/dist/acp/acp-client.js.map +1 -1
- package/dist/acp/acp-process.d.ts.map +1 -1
- package/dist/acp/acp-process.js +3 -1
- package/dist/acp/acp-process.js.map +1 -1
- package/dist/acp/index.d.ts +1 -1
- package/dist/acp/index.d.ts.map +1 -1
- package/dist/acp/index.js.map +1 -1
- package/dist/acp/testing/fake-acp-server.d.ts +4 -0
- package/dist/acp/testing/fake-acp-server.d.ts.map +1 -1
- package/dist/acp/testing/fake-acp-server.js +12 -7
- package/dist/acp/testing/fake-acp-server.js.map +1 -1
- package/dist/conductor/conductor-agent-factory.d.ts +5 -0
- package/dist/conductor/conductor-agent-factory.d.ts.map +1 -0
- package/dist/conductor/conductor-agent-factory.js +10 -0
- package/dist/conductor/conductor-agent-factory.js.map +1 -0
- package/dist/conductor/conductor-agent.d.ts +9 -0
- package/dist/conductor/conductor-agent.d.ts.map +1 -1
- package/dist/conductor/conductor-session-driver.d.ts +2 -0
- package/dist/conductor/conductor-session-driver.d.ts.map +1 -1
- package/dist/conductor/conductor-session-driver.js +7 -1
- package/dist/conductor/conductor-session-driver.js.map +1 -1
- package/dist/conductor/conductor-session.d.ts +2 -3
- package/dist/conductor/conductor-session.d.ts.map +1 -1
- package/dist/conductor/conductor-session.js +289 -26
- package/dist/conductor/conductor-session.js.map +1 -1
- package/dist/conductor/index.d.ts +6 -2
- package/dist/conductor/index.d.ts.map +1 -1
- package/dist/conductor/index.js +4 -1
- package/dist/conductor/index.js.map +1 -1
- package/dist/conductor/operator-close.d.ts +3 -0
- package/dist/conductor/operator-close.d.ts.map +1 -0
- package/dist/conductor/operator-close.js +6 -0
- package/dist/conductor/operator-close.js.map +1 -0
- package/dist/conductor/operator-command.d.ts +20 -0
- package/dist/conductor/operator-command.d.ts.map +1 -0
- package/dist/conductor/operator-command.js +29 -0
- package/dist/conductor/operator-command.js.map +1 -0
- package/dist/conductor/operator-exit.d.ts.map +1 -1
- package/dist/conductor/operator-exit.js +2 -2
- package/dist/conductor/operator-exit.js.map +1 -1
- package/dist/conductor/operator-post-loop-gate.d.ts +2 -2
- package/dist/conductor/operator-post-loop-gate.d.ts.map +1 -1
- package/dist/conductor/operator-reconnect.d.ts.map +1 -1
- package/dist/conductor/operator-reconnect.js +2 -2
- package/dist/conductor/operator-reconnect.js.map +1 -1
- package/dist/conductor/pi-conductor-agent.d.ts +7 -5
- package/dist/conductor/pi-conductor-agent.d.ts.map +1 -1
- package/dist/conductor/pi-conductor-agent.js +104 -23
- package/dist/conductor/pi-conductor-agent.js.map +1 -1
- package/dist/conductor/pi-resource-loader.d.ts +2 -0
- package/dist/conductor/pi-resource-loader.d.ts.map +1 -1
- package/dist/conductor/pi-resource-loader.js +16 -8
- package/dist/conductor/pi-resource-loader.js.map +1 -1
- 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/dispatch-hold.js +4 -3
- package/dist/conductor/session/dispatch-hold.js.map +1 -1
- package/dist/conductor/session/dispatch-mode.d.ts +1 -1
- package/dist/conductor/session/events/index.d.ts +3 -2
- 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 +7 -1
- package/dist/conductor/session/events/session-event.d.ts.map +1 -1
- package/dist/conductor/session/events/session-log-event-groups.d.ts +4 -4
- package/dist/conductor/session/events/session-log-event-groups.d.ts.map +1 -1
- package/dist/conductor/session/events/session-log-event-groups.js +3 -0
- package/dist/conductor/session/events/session-log-event-groups.js.map +1 -1
- package/dist/conductor/session/events/session-log-event.d.ts +9 -2
- package/dist/conductor/session/events/session-log-event.d.ts.map +1 -1
- package/dist/conductor/session/events/shared/permission-pending.d.ts +7 -0
- package/dist/conductor/session/events/shared/permission-pending.d.ts.map +1 -1
- package/dist/conductor/session/format-session-event.d.ts.map +1 -1
- package/dist/conductor/session/format-session-event.js +37 -2
- package/dist/conductor/session/format-session-event.js.map +1 -1
- package/dist/conductor/session/select-dispatch-batch.d.ts.map +1 -1
- package/dist/conductor/session/select-dispatch-batch.js +21 -4
- 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/session/session-logger.d.ts.map +1 -1
- package/dist/conductor/session/session-logger.js +2 -0
- package/dist/conductor/session/session-logger.js.map +1 -1
- package/dist/dispatch/get-tool-call-tool.d.ts +8 -0
- package/dist/dispatch/get-tool-call-tool.d.ts.map +1 -0
- package/dist/dispatch/get-tool-call-tool.js +46 -0
- package/dist/dispatch/get-tool-call-tool.js.map +1 -0
- package/dist/dispatch/index.d.ts +3 -0
- package/dist/dispatch/index.d.ts.map +1 -1
- package/dist/dispatch/index.js +2 -0
- package/dist/dispatch/index.js.map +1 -1
- package/dist/dispatch/report-session-state-tool.d.ts +4 -0
- package/dist/dispatch/report-session-state-tool.d.ts.map +1 -0
- package/dist/dispatch/report-session-state-tool.js +38 -0
- package/dist/dispatch/report-session-state-tool.js.map +1 -0
- package/dist/dispatch/session-usage-tool.js +1 -1
- package/dist/dispatch/session-usage-tool.js.map +1 -1
- package/dist/escalation/answer-open-question-tool.d.ts.map +1 -1
- package/dist/escalation/answer-open-question-tool.js +1 -6
- package/dist/escalation/answer-open-question-tool.js.map +1 -1
- package/dist/escalation/ask-human-tool.d.ts.map +1 -1
- package/dist/escalation/ask-human-tool.js +7 -5
- package/dist/escalation/ask-human-tool.js.map +1 -1
- package/dist/escalation/open-question.d.ts.map +1 -1
- package/dist/escalation/open-question.js +5 -8
- package/dist/escalation/open-question.js.map +1 -1
- package/dist/escalation/record-open-question-answer.js +4 -2
- package/dist/escalation/record-open-question-answer.js.map +1 -1
- package/dist/escalation/yes-no-assent.d.ts.map +1 -1
- package/dist/escalation/yes-no-assent.js +5 -3
- package/dist/escalation/yes-no-assent.js.map +1 -1
- package/dist/github/github-monitor-cursor.d.ts +3 -1
- package/dist/github/github-monitor-cursor.d.ts.map +1 -1
- package/dist/github/github-monitor-cursor.js +11 -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 +35 -0
- package/dist/github/github-monitor-error.js.map +1 -1
- package/dist/github/github-monitor.d.ts +4 -0
- package/dist/github/github-monitor.d.ts.map +1 -1
- package/dist/github/github-monitor.js +60 -2
- package/dist/github/github-monitor.js.map +1 -1
- package/dist/operator-runtime.d.ts +20 -0
- package/dist/operator-runtime.d.ts.map +1 -0
- package/dist/operator-runtime.js +14 -0
- package/dist/operator-runtime.js.map +1 -0
- package/dist/permission/format-permission-summary-for-operator.d.ts.map +1 -1
- package/dist/permission/format-permission-summary-for-operator.js +44 -12
- package/dist/permission/format-permission-summary-for-operator.js.map +1 -1
- package/dist/permission/index.d.ts +2 -0
- package/dist/permission/index.d.ts.map +1 -1
- package/dist/permission/index.js +1 -0
- package/dist/permission/index.js.map +1 -1
- package/dist/permission/permission-brief.d.ts +22 -0
- package/dist/permission/permission-brief.d.ts.map +1 -0
- package/dist/permission/permission-brief.js +245 -0
- package/dist/permission/permission-brief.js.map +1 -0
- package/dist/permission/permission-request.js +7 -2
- package/dist/permission/permission-request.js.map +1 -1
- package/dist/prompt/index.d.ts +1 -0
- package/dist/prompt/index.d.ts.map +1 -1
- package/dist/prompt/index.js +1 -0
- package/dist/prompt/index.js.map +1 -1
- package/dist/prompt/modules/ensemble/conductor-base-module.d.ts.map +1 -1
- package/dist/prompt/modules/ensemble/conductor-base-module.js +12 -0
- package/dist/prompt/modules/ensemble/conductor-base-module.js.map +1 -1
- package/dist/runtime/index.d.ts +3 -0
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +2 -0
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/tool-call-snapshot-registry.d.ts +69 -0
- package/dist/runtime/tool-call-snapshot-registry.d.ts.map +1 -0
- package/dist/runtime/tool-call-snapshot-registry.js +275 -0
- package/dist/runtime/tool-call-snapshot-registry.js.map +1 -0
- package/dist/runtime/types.d.ts +2 -0
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/worker-runtime.d.ts.map +1 -1
- package/dist/runtime/worker-runtime.js +6 -2
- package/dist/runtime/worker-runtime.js.map +1 -1
- package/dist/session/index.d.ts +2 -0
- package/dist/session/index.d.ts.map +1 -1
- package/dist/session/index.js +1 -0
- package/dist/session/index.js.map +1 -1
- package/dist/session/open-questions-store.d.ts +12 -0
- package/dist/session/open-questions-store.d.ts.map +1 -0
- package/dist/session/open-questions-store.js +161 -0
- package/dist/session/open-questions-store.js.map +1 -0
- package/dist/session/session-sidecar.d.ts +1 -1
- package/dist/session/session-sidecar.d.ts.map +1 -1
- package/dist/session/tool-call-snapshot-history.d.ts +32 -0
- package/dist/session/tool-call-snapshot-history.d.ts.map +1 -0
- package/dist/session/tool-call-snapshot-history.js +203 -0
- package/dist/session/tool-call-snapshot-history.js.map +1 -0
- package/dist/usage/enrich-session-usage-cost.d.ts +4 -1
- package/dist/usage/enrich-session-usage-cost.d.ts.map +1 -1
- package/dist/usage/enrich-session-usage-cost.js +8 -2
- package/dist/usage/enrich-session-usage-cost.js.map +1 -1
- package/dist/usage/index.d.ts +1 -1
- package/dist/usage/index.d.ts.map +1 -1
- package/dist/usage/session-usage-tracker.d.ts +7 -1
- package/dist/usage/session-usage-tracker.d.ts.map +1 -1
- package/dist/usage/session-usage-tracker.js +51 -0
- package/dist/usage/session-usage-tracker.js.map +1 -1
- package/dist/usage/types.d.ts +30 -2
- package/dist/usage/types.d.ts.map +1 -1
- package/package.json +5 -1
|
@@ -9,20 +9,23 @@ import { deny } from '../permission/permission-broker.js';
|
|
|
9
9
|
import { PermissionPipeline } from '../permission/permission-pipeline.js';
|
|
10
10
|
import { createPermissionDeadlockMonitor, } from '../permission/permission-deadlock-monitor.js';
|
|
11
11
|
import { createResolvePermissionTool } from '../permission/resolve-permission-tool.js';
|
|
12
|
+
import { buildPermissionBrief, getPermissionToolCallId, } from '../permission/permission-brief.js';
|
|
12
13
|
import { acpSpawnFingerprint, resolveWorkerAcpSpawn, resolvedAcpSpawnToOptions, } from '../acp/resolve-acp-spawn.js';
|
|
13
14
|
import { finalizeResolvedAcpSpawn, validateWorkerAcpPrerequisites, } from '../acp/validate-acp-preset-prerequisites.js';
|
|
14
15
|
import { profileWorkersToSessionSpecs, sessionStateFromProfile, resolveAgentPromptModule, } from '../profile/types.js';
|
|
15
16
|
import { WorkerSession } from '../runtime/worker-session.js';
|
|
17
|
+
import { ToolCallSnapshotRegistry, } from '../runtime/tool-call-snapshot-registry.js';
|
|
16
18
|
import { createPromptWorkerTool } from '../dispatch/prompt-worker-tool.js';
|
|
17
19
|
import { createWorkerStatusTools } from '../dispatch/worker-status-tool.js';
|
|
20
|
+
import { createGetToolCallTool } from '../dispatch/get-tool-call-tool.js';
|
|
18
21
|
import { createSessionUsageTools } from '../dispatch/session-usage-tool.js';
|
|
22
|
+
import { createReportSessionStateTool } from '../dispatch/report-session-state-tool.js';
|
|
19
23
|
import { createSetDispatchHoldTool } from '../dispatch/set-dispatch-hold-tool.js';
|
|
20
24
|
import { parseIssueUrl } from '../issue/issue-ref.js';
|
|
21
25
|
import { resolveWorkerWorkspace, removeWorkerWorktree, } from '../worktree/worktree.js';
|
|
22
26
|
import { WorkerOutboundQueue } from '../runtime/worker-outbound-queue.js';
|
|
23
27
|
import { ConductorToolRegistry } from './conductor-tool.js';
|
|
24
|
-
import {
|
|
25
|
-
import { createPiConductorAgentFactory } from './pi-conductor-agent.js';
|
|
28
|
+
import { createConductorAgentFactory } from './conductor-agent-factory.js';
|
|
26
29
|
import { formatConductorAuthRecoveryHint, isConductorSendAuthError, } from './conductor-auth.js';
|
|
27
30
|
import { resolvePiConductorProvider } from './conductor-pi-auth.js';
|
|
28
31
|
import { SessionLogger } from './session/session-logger.js';
|
|
@@ -31,8 +34,12 @@ import { bufferDispatchHoldEvents, createDispatchHoldState, pruneStalePermission
|
|
|
31
34
|
import { operatorInputMaxTurns, resolveMaxTurns, } from './session-policy.js';
|
|
32
35
|
import { runConductorSessionDriver } from './conductor-session-driver.js';
|
|
33
36
|
import { isOperatorExitCommand } from './operator-exit.js';
|
|
37
|
+
import { isOperatorCloseCommand } from './operator-close.js';
|
|
34
38
|
import { isOperatorReconnectCommand } from './operator-reconnect.js';
|
|
35
39
|
import { assertSessionSidecarMatches, requireSessionSidecarForResume, saveSessionSidecar, SESSION_SIDECAR_VERSION, sessionSidecarPath, } from '../session/session-sidecar.js';
|
|
40
|
+
import { loadToolCallSnapshotHistory, pruneExpiredToolCallSnapshotHistoryFiles, saveToolCallSnapshotHistory, toolCallSnapshotHistoryPath, } from '../session/tool-call-snapshot-history.js';
|
|
41
|
+
import { loadOpenQuestionsStore, openQuestionsStorePath, saveOpenQuestionsStore, } from '../session/open-questions-store.js';
|
|
42
|
+
import { formatPermissionSummaryForOperator } from '../permission/format-permission-summary-for-operator.js';
|
|
36
43
|
import { enrichSessionUsageWithCost } from '../usage/enrich-session-usage-cost.js';
|
|
37
44
|
import { SessionUsageTracker } from '../usage/session-usage-tracker.js';
|
|
38
45
|
import { submitOperatorInput } from './submit-operator-input.js';
|
|
@@ -63,6 +70,13 @@ export async function runConductorSession(options) {
|
|
|
63
70
|
repoRoot: options.repoRoot,
|
|
64
71
|
});
|
|
65
72
|
attachLegacySessionCallbacks(sessionLogger, options);
|
|
73
|
+
const expiredHistory = await pruneExpiredToolCallSnapshotHistoryFiles(options.repoRoot);
|
|
74
|
+
if (expiredHistory.failedCount > 0) {
|
|
75
|
+
sessionLogger.emit({
|
|
76
|
+
type: 'harness.warning',
|
|
77
|
+
message: 'Some expired tool-call snapshot history files could not be removed.',
|
|
78
|
+
});
|
|
79
|
+
}
|
|
66
80
|
const escalations = [];
|
|
67
81
|
const openQuestions = new OpenQuestionRegistry();
|
|
68
82
|
const eventQueue = new SessionEventQueue();
|
|
@@ -83,10 +97,13 @@ export async function runConductorSession(options) {
|
|
|
83
97
|
const workerSessions = new Map();
|
|
84
98
|
let githubMonitorCursor;
|
|
85
99
|
let githubMonitor;
|
|
100
|
+
const pendingGitHubRecoveries = [];
|
|
86
101
|
const conductorCwd = options.conductorCwd ?? process.cwd();
|
|
87
102
|
const mcpServers = await resolveMcpServers(options.repoRoot, options.mcpConfigOptions);
|
|
88
103
|
const mcpConfigDigest = computeMcpConfigDigest(mcpServers);
|
|
89
104
|
const mcpConfigConfigured = Object.keys(mcpServers).length > 0;
|
|
105
|
+
let resumeToolCallSnapshots = [];
|
|
106
|
+
let toolCallHistoryNeedsRewrite = false;
|
|
90
107
|
if (options.resumeAgentId) {
|
|
91
108
|
const sidecar = await requireSessionSidecarForResume({
|
|
92
109
|
repoRoot: options.repoRoot,
|
|
@@ -100,10 +117,43 @@ export async function runConductorSession(options) {
|
|
|
100
117
|
mcpConfigDigest,
|
|
101
118
|
mcpConfigConfigured,
|
|
102
119
|
});
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
120
|
+
const history = await loadToolCallSnapshotHistory({
|
|
121
|
+
repoRoot: options.repoRoot,
|
|
122
|
+
conductorAgentId: options.resumeAgentId,
|
|
106
123
|
});
|
|
124
|
+
resumeToolCallSnapshots = history.entries;
|
|
125
|
+
toolCallHistoryNeedsRewrite = history.needsRewrite;
|
|
126
|
+
if (history.warning) {
|
|
127
|
+
sessionLogger.emit({
|
|
128
|
+
type: 'harness.warning',
|
|
129
|
+
message: `${history.warning}; the session will continue without affected history`,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
const openQuestionsPath = openQuestionsStorePath({
|
|
133
|
+
repoRoot: options.repoRoot,
|
|
134
|
+
conductorAgentId: options.resumeAgentId,
|
|
135
|
+
});
|
|
136
|
+
const openQuestionsSnapshot = await loadOpenQuestionsStore(openQuestionsPath);
|
|
137
|
+
if (openQuestionsSnapshot) {
|
|
138
|
+
openQuestions.restore(openQuestionsSnapshot);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
const legacySnapshot = {
|
|
142
|
+
sequence: sidecar.sequence,
|
|
143
|
+
openQuestions: sidecar.openQuestions,
|
|
144
|
+
};
|
|
145
|
+
openQuestions.restore(legacySnapshot);
|
|
146
|
+
try {
|
|
147
|
+
await saveOpenQuestionsStore(openQuestionsPath, legacySnapshot);
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
151
|
+
sessionLogger.emit({
|
|
152
|
+
type: 'harness.warning',
|
|
153
|
+
message: `旧 sidecar から復元した open question を YAML にバックフィルできませんでした。今回のセッションは継続します。 error=${detail}`,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
107
157
|
activeProfile = sidecar.profile;
|
|
108
158
|
// Sidecars written before this setting always started every worker eagerly.
|
|
109
159
|
activeLazyWorkers = sidecar.lazyWorkers ?? false;
|
|
@@ -145,10 +195,10 @@ export async function runConductorSession(options) {
|
|
|
145
195
|
? new AbortController()
|
|
146
196
|
: undefined;
|
|
147
197
|
const shutdownSignal = options.shutdownSignal ?? shutdownController.signal;
|
|
148
|
-
const
|
|
198
|
+
const operatorTerminationController = new AbortController();
|
|
149
199
|
const driverShutdownSignal = AbortSignal.any([
|
|
150
200
|
shutdownSignal,
|
|
151
|
-
|
|
201
|
+
operatorTerminationController.signal,
|
|
152
202
|
]);
|
|
153
203
|
let unregisterProcessSignalHandlers = () => { };
|
|
154
204
|
if (ownsShutdownController &&
|
|
@@ -164,6 +214,9 @@ export async function runConductorSession(options) {
|
|
|
164
214
|
const permissionPipeline = options.permissionPipeline ??
|
|
165
215
|
new PermissionPipeline({ policy: options.permissionPolicy });
|
|
166
216
|
let scheduleSidecarFlush = () => { };
|
|
217
|
+
let scheduleToolCallHistoryFlush = () => { };
|
|
218
|
+
let flushToolCallHistory = async () => { };
|
|
219
|
+
let toolCallHistoryDirty = toolCallHistoryNeedsRewrite;
|
|
167
220
|
const sessionState = sessionStateFromProfile(activeProfile);
|
|
168
221
|
const issue = parseIssueUrl(options.issueUrl);
|
|
169
222
|
const spawnBase = {
|
|
@@ -214,7 +267,11 @@ export async function runConductorSession(options) {
|
|
|
214
267
|
}
|
|
215
268
|
const sessionUsageTracker = new SessionUsageTracker({
|
|
216
269
|
contextLimitTokens: options.contextLimitTokens,
|
|
270
|
+
trackCompactions: conductorBackend === 'pi' && options.conductorAgentFactory == null,
|
|
217
271
|
});
|
|
272
|
+
const toolCallSnapshots = new ToolCallSnapshotRegistry();
|
|
273
|
+
let toolCallHistoryLimitWarningEmitted = false;
|
|
274
|
+
let toolCallHistoryOversizeWarningEmitted = false;
|
|
218
275
|
const workerSession = new WorkerSession({
|
|
219
276
|
issueUrl: options.issueUrl,
|
|
220
277
|
repoRoot: options.repoRoot,
|
|
@@ -244,12 +301,28 @@ export async function runConductorSession(options) {
|
|
|
244
301
|
const pending = permissionPipeline.pending.get(requestId);
|
|
245
302
|
if (pending) {
|
|
246
303
|
const workerLabel = workerSession.runtime.resolveWorkerLabel(workerId) ?? workerId;
|
|
304
|
+
const operatorSummary = formatPermissionSummaryForOperator(pending, {
|
|
305
|
+
workerLabel,
|
|
306
|
+
});
|
|
307
|
+
const toolCallId = getPermissionToolCallId(pending.request);
|
|
308
|
+
const toolCallSnapshot = toolCallId && pending.request.sessionId
|
|
309
|
+
? toolCallSnapshots.get(toolCallId, {
|
|
310
|
+
workerId,
|
|
311
|
+
sessionId: pending.request.sessionId,
|
|
312
|
+
})
|
|
313
|
+
: undefined;
|
|
247
314
|
sessionLogger.emit({
|
|
248
315
|
type: 'permission.pending',
|
|
249
316
|
permission: pending,
|
|
250
317
|
workerLabel,
|
|
251
318
|
});
|
|
252
|
-
eventQueue.enqueue({
|
|
319
|
+
eventQueue.enqueue({
|
|
320
|
+
type: 'permission.pending',
|
|
321
|
+
permission: pending,
|
|
322
|
+
worker: workerLabel,
|
|
323
|
+
brief: buildPermissionBrief(pending.request, toolCallSnapshot),
|
|
324
|
+
operatorSummary,
|
|
325
|
+
});
|
|
253
326
|
}
|
|
254
327
|
return null;
|
|
255
328
|
},
|
|
@@ -322,6 +395,36 @@ export async function runConductorSession(options) {
|
|
|
322
395
|
}
|
|
323
396
|
},
|
|
324
397
|
onAcpUpdate: (event) => {
|
|
398
|
+
if (event.toolCallUpdate) {
|
|
399
|
+
const result = toolCallSnapshots.applyWithResult({
|
|
400
|
+
workerId: event.workerId,
|
|
401
|
+
workerName: event.name,
|
|
402
|
+
sessionId: event.sessionId ?? '',
|
|
403
|
+
}, event.toolCallUpdate);
|
|
404
|
+
if (result.status === 'applied') {
|
|
405
|
+
toolCallHistoryDirty = true;
|
|
406
|
+
scheduleToolCallHistoryFlush();
|
|
407
|
+
if (result.evictedCount > 0 &&
|
|
408
|
+
!toolCallHistoryLimitWarningEmitted) {
|
|
409
|
+
toolCallHistoryLimitWarningEmitted = true;
|
|
410
|
+
sessionLogger.emit({
|
|
411
|
+
type: 'harness.warning',
|
|
412
|
+
message: 'Tool-call snapshot history reached its retention limit; oldest snapshots were removed.',
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
else if (result.reason === 'too-large') {
|
|
417
|
+
toolCallHistoryDirty = true;
|
|
418
|
+
scheduleToolCallHistoryFlush();
|
|
419
|
+
if (!toolCallHistoryOversizeWarningEmitted) {
|
|
420
|
+
toolCallHistoryOversizeWarningEmitted = true;
|
|
421
|
+
sessionLogger.emit({
|
|
422
|
+
type: 'harness.warning',
|
|
423
|
+
message: 'A tool-call snapshot exceeds the history size limit and was not retained.',
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
325
428
|
sessionLogger.emit({
|
|
326
429
|
type: 'harness.worker.acp.update',
|
|
327
430
|
name: event.name,
|
|
@@ -360,6 +463,22 @@ export async function runConductorSession(options) {
|
|
|
360
463
|
});
|
|
361
464
|
}
|
|
362
465
|
workerSession.startWorkers();
|
|
466
|
+
if (resumeToolCallSnapshots.length > 0) {
|
|
467
|
+
const workerIdsByName = new Map();
|
|
468
|
+
workers.forEach((worker, index) => {
|
|
469
|
+
const workerId = workerSession.startedWorkerIds[index];
|
|
470
|
+
if (workerId)
|
|
471
|
+
workerIdsByName.set(worker.name, workerId);
|
|
472
|
+
});
|
|
473
|
+
const restoreResult = toolCallSnapshots.restore(resumeToolCallSnapshots, workerIdsByName);
|
|
474
|
+
if (restoreResult.skippedCount > 0) {
|
|
475
|
+
toolCallHistoryDirty = true;
|
|
476
|
+
sessionLogger.emit({
|
|
477
|
+
type: 'harness.warning',
|
|
478
|
+
message: `${restoreResult.skippedCount} tool-call snapshot entr${restoreResult.skippedCount === 1 ? 'y was' : 'ies were'} skipped because its worker is no longer available or its data is invalid.`,
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
}
|
|
363
482
|
const recordAnsweredQuestion = (answered) => {
|
|
364
483
|
const record = openQuestionToEscalationRecord(answered);
|
|
365
484
|
if (record) {
|
|
@@ -388,6 +507,9 @@ export async function runConductorSession(options) {
|
|
|
388
507
|
pipeline: permissionPipeline,
|
|
389
508
|
inbox: workerSession.inbox,
|
|
390
509
|
});
|
|
510
|
+
const getToolCallTools = createGetToolCallTool({
|
|
511
|
+
snapshots: toolCallSnapshots,
|
|
512
|
+
});
|
|
391
513
|
let outboundDispatchesThisSend = 0;
|
|
392
514
|
const outboundWorkersThisSend = new Set();
|
|
393
515
|
const workerOutboundQueue = new WorkerOutboundQueue((worker, instruction, options) => {
|
|
@@ -438,6 +560,7 @@ export async function runConductorSession(options) {
|
|
|
438
560
|
return usage.cost;
|
|
439
561
|
},
|
|
440
562
|
});
|
|
563
|
+
const reportSessionStateTool = createReportSessionStateTool();
|
|
441
564
|
const dispatchHoldTools = createSetDispatchHoldTool({
|
|
442
565
|
state: dispatchHoldState,
|
|
443
566
|
onChanged: onDispatchHoldChanged,
|
|
@@ -461,11 +584,13 @@ export async function runConductorSession(options) {
|
|
|
461
584
|
.registerAll(answerOpenQuestionTools)
|
|
462
585
|
.registerAll(openQuestionListTools)
|
|
463
586
|
.registerAll(resolvePermissionTools)
|
|
587
|
+
.registerAll(getToolCallTools)
|
|
464
588
|
.registerAll(promptWorkerTools)
|
|
465
589
|
.registerAll(workerStatusTools)
|
|
466
590
|
.registerAll(registerGitHubWatchTools)
|
|
467
591
|
.registerAll(unregisterGitHubWatchTools)
|
|
468
592
|
.registerAll(sessionUsageTools)
|
|
593
|
+
.registerAll(reportSessionStateTool)
|
|
469
594
|
.registerAll(dispatchHoldTools);
|
|
470
595
|
const conductorOptions = {
|
|
471
596
|
cwd: conductorCwd,
|
|
@@ -486,6 +611,11 @@ export async function runConductorSession(options) {
|
|
|
486
611
|
: {}),
|
|
487
612
|
...(Object.keys(mcpServers).length > 0 ? { mcpServers } : {}),
|
|
488
613
|
customTools: conductorToolRegistry.toRecord(),
|
|
614
|
+
...(conductorBackend === 'pi' && options.conductorAgentFactory == null
|
|
615
|
+
? {
|
|
616
|
+
onContextCompaction: () => sessionUsageTracker.recordContextCompaction(),
|
|
617
|
+
}
|
|
618
|
+
: {}),
|
|
489
619
|
};
|
|
490
620
|
const conductorProvider = conductorBackend === 'pi'
|
|
491
621
|
? (await resolvePiConductorProvider({
|
|
@@ -553,6 +683,10 @@ export async function runConductorSession(options) {
|
|
|
553
683
|
...(githubMonitorCursor ? { githubMonitor: githubMonitorCursor } : {}),
|
|
554
684
|
updatedAt: Date.now(),
|
|
555
685
|
};
|
|
686
|
+
await saveOpenQuestionsStore(openQuestionsStorePath({
|
|
687
|
+
repoRoot: options.repoRoot,
|
|
688
|
+
conductorAgentId: conductorHandle.conductor.agentId,
|
|
689
|
+
}), snapshot);
|
|
556
690
|
await saveSessionSidecar(sessionSidecarPath({
|
|
557
691
|
repoRoot: options.repoRoot,
|
|
558
692
|
conductorAgentId: conductorHandle.conductor.agentId,
|
|
@@ -561,11 +695,68 @@ export async function runConductorSession(options) {
|
|
|
561
695
|
sidecarFlushQueue = nextFlush.catch(() => { });
|
|
562
696
|
return nextFlush;
|
|
563
697
|
};
|
|
698
|
+
const reportSidecarFlushFailure = (error) => {
|
|
699
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
700
|
+
sessionLogger.emit({
|
|
701
|
+
type: 'harness.warning',
|
|
702
|
+
message: `Open Question YAML / session sidecar を保存できませんでした。最新状態から再開できず、直前に保存された状態からの再開になる場合があります。 error=${detail}`,
|
|
703
|
+
});
|
|
704
|
+
};
|
|
564
705
|
scheduleSidecarFlush = () => {
|
|
565
|
-
void flushSidecar().catch(
|
|
566
|
-
|
|
706
|
+
void flushSidecar().catch(reportSidecarFlushFailure);
|
|
707
|
+
};
|
|
708
|
+
const toolCallHistoryPath = toolCallSnapshotHistoryPath({
|
|
709
|
+
repoRoot: options.repoRoot,
|
|
710
|
+
conductorAgentId: conductorHandle.conductor.agentId,
|
|
711
|
+
});
|
|
712
|
+
let toolCallHistoryFlushTimer;
|
|
713
|
+
let toolCallHistoryFlushQueue = Promise.resolve();
|
|
714
|
+
let toolCallHistoryFlushWarningEmitted = false;
|
|
715
|
+
const emitToolCallHistoryFlushWarning = () => {
|
|
716
|
+
if (toolCallHistoryFlushWarningEmitted)
|
|
717
|
+
return;
|
|
718
|
+
toolCallHistoryFlushWarningEmitted = true;
|
|
719
|
+
sessionLogger.emit({
|
|
720
|
+
type: 'harness.warning',
|
|
721
|
+
message: 'Tool-call snapshot history could not be saved; the latest history may be unavailable after resume.',
|
|
567
722
|
});
|
|
568
723
|
};
|
|
724
|
+
flushToolCallHistory = () => {
|
|
725
|
+
if (toolCallHistoryFlushTimer) {
|
|
726
|
+
clearTimeout(toolCallHistoryFlushTimer);
|
|
727
|
+
toolCallHistoryFlushTimer = undefined;
|
|
728
|
+
}
|
|
729
|
+
if (!toolCallHistoryDirty)
|
|
730
|
+
return toolCallHistoryFlushQueue;
|
|
731
|
+
toolCallHistoryDirty = false;
|
|
732
|
+
const nextFlush = toolCallHistoryFlushQueue.then(() => saveToolCallSnapshotHistory(toolCallHistoryPath, toolCallSnapshots.snapshot()));
|
|
733
|
+
toolCallHistoryFlushQueue = nextFlush.catch(() => { });
|
|
734
|
+
return nextFlush;
|
|
735
|
+
};
|
|
736
|
+
scheduleToolCallHistoryFlush = () => {
|
|
737
|
+
toolCallHistoryDirty = true;
|
|
738
|
+
if (toolCallHistoryFlushTimer)
|
|
739
|
+
return;
|
|
740
|
+
toolCallHistoryFlushTimer = setTimeout(() => {
|
|
741
|
+
toolCallHistoryFlushTimer = undefined;
|
|
742
|
+
void flushToolCallHistory().catch(() => {
|
|
743
|
+
toolCallHistoryDirty = true;
|
|
744
|
+
emitToolCallHistoryFlushWarning();
|
|
745
|
+
});
|
|
746
|
+
}, 100);
|
|
747
|
+
toolCallHistoryFlushTimer.unref?.();
|
|
748
|
+
};
|
|
749
|
+
const flushToolCallHistoryBestEffort = async () => {
|
|
750
|
+
try {
|
|
751
|
+
await flushToolCallHistory();
|
|
752
|
+
}
|
|
753
|
+
catch {
|
|
754
|
+
toolCallHistoryDirty = true;
|
|
755
|
+
emitToolCallHistoryFlushWarning();
|
|
756
|
+
}
|
|
757
|
+
};
|
|
758
|
+
if (toolCallHistoryDirty)
|
|
759
|
+
scheduleToolCallHistoryFlush();
|
|
569
760
|
let sendCount = 0;
|
|
570
761
|
let autonomousTurns = 0;
|
|
571
762
|
const monitorDefaults = ensembleConfig.github.monitor;
|
|
@@ -592,6 +783,14 @@ export async function runConductorSession(options) {
|
|
|
592
783
|
type: 'harness.github.update',
|
|
593
784
|
itemCount: payload.items.length,
|
|
594
785
|
});
|
|
786
|
+
for (const suppressedErrorCount of pendingGitHubRecoveries.splice(0)) {
|
|
787
|
+
eventQueue.enqueue({
|
|
788
|
+
type: 'harness.connectivity.recovered',
|
|
789
|
+
source: 'github_monitor',
|
|
790
|
+
suppressedErrorCount,
|
|
791
|
+
dispatchMode: 'inform',
|
|
792
|
+
});
|
|
793
|
+
}
|
|
595
794
|
eventQueue.enqueue({
|
|
596
795
|
type: 'github.update',
|
|
597
796
|
items: payload.items,
|
|
@@ -617,6 +816,22 @@ export async function runConductorSession(options) {
|
|
|
617
816
|
message,
|
|
618
817
|
});
|
|
619
818
|
},
|
|
819
|
+
onPollRecovered: (suppressedErrorCount, hasUpdates) => {
|
|
820
|
+
sessionLogger.emit({
|
|
821
|
+
type: 'harness.github.monitor_recovered',
|
|
822
|
+
suppressedErrorCount,
|
|
823
|
+
});
|
|
824
|
+
if (hasUpdates) {
|
|
825
|
+
pendingGitHubRecoveries.push(suppressedErrorCount);
|
|
826
|
+
}
|
|
827
|
+
else {
|
|
828
|
+
eventQueue.enqueue({
|
|
829
|
+
type: 'harness.connectivity.recovered',
|
|
830
|
+
source: 'github_monitor',
|
|
831
|
+
suppressedErrorCount,
|
|
832
|
+
});
|
|
833
|
+
}
|
|
834
|
+
},
|
|
620
835
|
});
|
|
621
836
|
githubMonitor.start();
|
|
622
837
|
}
|
|
@@ -654,6 +869,7 @@ export async function runConductorSession(options) {
|
|
|
654
869
|
const continueOnConductorError = options.continueOnConductorError ?? false;
|
|
655
870
|
const waitForOperatorExit = options.waitForOperatorExit ?? false;
|
|
656
871
|
let operatorRequestedExit = false;
|
|
872
|
+
let operatorRequestedClose = false;
|
|
657
873
|
let disposeOperatorInput;
|
|
658
874
|
if (options.bindOperatorInput) {
|
|
659
875
|
const bindingDispose = options.bindOperatorInput({
|
|
@@ -662,7 +878,14 @@ export async function runConductorSession(options) {
|
|
|
662
878
|
sessionLogger.emit({ type: 'session.operator_exit' });
|
|
663
879
|
workerSession.runtime.cancelAllActivePrompts();
|
|
664
880
|
operatorRequestedExit = true;
|
|
665
|
-
|
|
881
|
+
operatorTerminationController.abort();
|
|
882
|
+
return false;
|
|
883
|
+
}
|
|
884
|
+
if (isOperatorCloseCommand(message)) {
|
|
885
|
+
sessionLogger.emit({ type: 'session.operator_close' });
|
|
886
|
+
workerSession.runtime.cancelAllActivePrompts();
|
|
887
|
+
operatorRequestedClose = true;
|
|
888
|
+
operatorTerminationController.abort();
|
|
666
889
|
return false;
|
|
667
890
|
}
|
|
668
891
|
if (isOperatorReconnectCommand(message)) {
|
|
@@ -764,13 +987,20 @@ export async function runConductorSession(options) {
|
|
|
764
987
|
stopReason = driverResult.stopReason;
|
|
765
988
|
sendCount = driverResult.sendCount;
|
|
766
989
|
autonomousTurns = driverResult.autonomousTurns;
|
|
767
|
-
if (operatorRequestedExit
|
|
990
|
+
if ((operatorRequestedExit || operatorRequestedClose) &&
|
|
991
|
+
stopReason === 'interrupted') {
|
|
768
992
|
stopReason = 'completed';
|
|
769
993
|
}
|
|
770
994
|
return await buildResult();
|
|
771
995
|
function recordSendComplete(info) {
|
|
772
996
|
sendCount = info.sendCount;
|
|
773
997
|
autonomousTurns = info.autonomousTurns;
|
|
998
|
+
const githubUpdateIds = info.githubUpdateIds ?? [];
|
|
999
|
+
if (info.status === 'finished' &&
|
|
1000
|
+
!operatorRequestedClose &&
|
|
1001
|
+
githubUpdateIds.length > 0) {
|
|
1002
|
+
githubMonitor?.acknowledgeUpdates?.(githubUpdateIds);
|
|
1003
|
+
}
|
|
774
1004
|
sessionUsageTracker.recordConductorRound({
|
|
775
1005
|
runId: info.runId,
|
|
776
1006
|
status: info.status,
|
|
@@ -817,7 +1047,9 @@ export async function runConductorSession(options) {
|
|
|
817
1047
|
}
|
|
818
1048
|
async function buildResult() {
|
|
819
1049
|
sessionLogger.finish(stopReason);
|
|
820
|
-
const skipUsageCostFetch = operatorRequestedExit ||
|
|
1050
|
+
const skipUsageCostFetch = operatorRequestedExit ||
|
|
1051
|
+
operatorRequestedClose ||
|
|
1052
|
+
shutdownSignal.aborted;
|
|
821
1053
|
const sessionUsage = await enrichSessionUsageWithCost(sessionUsageTracker.getSessionSummary(), skipUsageCostFetch
|
|
822
1054
|
? undefined
|
|
823
1055
|
: async () => {
|
|
@@ -828,7 +1060,9 @@ export async function runConductorSession(options) {
|
|
|
828
1060
|
agentId: conductorHandle.conductor.agentId,
|
|
829
1061
|
escalations,
|
|
830
1062
|
openQuestions: openQuestions.list(),
|
|
831
|
-
sessionUsage: sessionUsage.totals.rounds > 0 ||
|
|
1063
|
+
sessionUsage: sessionUsage.totals.rounds > 0 ||
|
|
1064
|
+
sessionUsage.cost != null ||
|
|
1065
|
+
sessionUsage.compactionCount != null
|
|
832
1066
|
? sessionUsage
|
|
833
1067
|
: undefined,
|
|
834
1068
|
});
|
|
@@ -836,7 +1070,9 @@ export async function runConductorSession(options) {
|
|
|
836
1070
|
}
|
|
837
1071
|
finally {
|
|
838
1072
|
teardownStarted = true;
|
|
839
|
-
const forceShutdown = operatorRequestedExit ||
|
|
1073
|
+
const forceShutdown = operatorRequestedExit ||
|
|
1074
|
+
operatorRequestedClose ||
|
|
1075
|
+
shutdownSignal.aborted;
|
|
840
1076
|
const teardownStartedAt = Date.now();
|
|
841
1077
|
const teardownPhases = {};
|
|
842
1078
|
unregisterProcessSignalHandlers();
|
|
@@ -864,12 +1100,27 @@ export async function runConductorSession(options) {
|
|
|
864
1100
|
emitTeardownPhase('permissionDeadlockMonitor');
|
|
865
1101
|
permissionDeadlockMonitor.stop();
|
|
866
1102
|
}
|
|
867
|
-
if (githubMonitor) {
|
|
1103
|
+
if (githubMonitor && !operatorRequestedClose) {
|
|
868
1104
|
githubMonitor.flush();
|
|
869
1105
|
}
|
|
870
1106
|
// Stop active prompts before closing ACP bridges. Requests that arrive
|
|
871
1107
|
// after this point are rejected by the teardown guard above.
|
|
872
1108
|
workerSession.runtime.cancelAllActivePrompts();
|
|
1109
|
+
if (operatorRequestedClose) {
|
|
1110
|
+
// A worker's ACP session exists before its first prompt completes, but
|
|
1111
|
+
// workerSessions is normally updated by onWorkerCompleted. Snapshot
|
|
1112
|
+
// attached sessions now so force shutdown cannot discard the only
|
|
1113
|
+
// completion event that would have persisted a resumable session ID.
|
|
1114
|
+
for (const attached of workerSession.runtime.listAttached()) {
|
|
1115
|
+
workerSessions.set(attached.name, {
|
|
1116
|
+
acpSessionId: attached.session.sessionId,
|
|
1117
|
+
acpCwd: attached.session.acpCwd,
|
|
1118
|
+
...(workerAcpFingerprints.get(attached.name)
|
|
1119
|
+
? { acpSpawn: workerAcpFingerprints.get(attached.name) }
|
|
1120
|
+
: {}),
|
|
1121
|
+
});
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
873
1124
|
const rejectedPendingPermissions = rejectAllPendingPermissions(permissionPipeline, workerSession.inbox);
|
|
874
1125
|
if (rejectedPendingPermissions.length > 0) {
|
|
875
1126
|
sessionLogger.emit({
|
|
@@ -881,17 +1132,27 @@ export async function runConductorSession(options) {
|
|
|
881
1132
|
})),
|
|
882
1133
|
});
|
|
883
1134
|
}
|
|
1135
|
+
let githubMonitorStopped = false;
|
|
1136
|
+
if (githubMonitor && operatorRequestedClose) {
|
|
1137
|
+
emitTeardownPhase('githubMonitor');
|
|
1138
|
+
const phaseStart = Date.now();
|
|
1139
|
+
await githubMonitor.stop();
|
|
1140
|
+
githubMonitorCursor = githubMonitor.getCursor();
|
|
1141
|
+
teardownPhases.githubMonitor = Date.now() - phaseStart;
|
|
1142
|
+
githubMonitorStopped = true;
|
|
1143
|
+
}
|
|
884
1144
|
try {
|
|
885
1145
|
emitTeardownPhase('flushSidecar');
|
|
886
1146
|
const phaseStart = Date.now();
|
|
887
1147
|
await flushSidecar();
|
|
888
1148
|
teardownPhases.flushSidecar = Date.now() - phaseStart;
|
|
889
1149
|
}
|
|
890
|
-
catch {
|
|
891
|
-
|
|
1150
|
+
catch (error) {
|
|
1151
|
+
reportSidecarFlushFailure(error);
|
|
892
1152
|
}
|
|
1153
|
+
await flushToolCallHistoryBestEffort();
|
|
893
1154
|
const runGithubMonitorStop = async () => {
|
|
894
|
-
if (!githubMonitor) {
|
|
1155
|
+
if (!githubMonitor || githubMonitorStopped) {
|
|
895
1156
|
return;
|
|
896
1157
|
}
|
|
897
1158
|
emitTeardownPhase('githubMonitor');
|
|
@@ -909,7 +1170,12 @@ export async function runConductorSession(options) {
|
|
|
909
1170
|
const runConductorClose = async () => {
|
|
910
1171
|
emitTeardownPhase('conductor');
|
|
911
1172
|
const phaseStart = Date.now();
|
|
912
|
-
|
|
1173
|
+
if (operatorRequestedClose && conductorHandle.conductor.closeForResume) {
|
|
1174
|
+
await conductorHandle.conductor.closeForResume();
|
|
1175
|
+
}
|
|
1176
|
+
else {
|
|
1177
|
+
await conductorHandle.conductor.close();
|
|
1178
|
+
}
|
|
913
1179
|
teardownPhases.conductor = Date.now() - phaseStart;
|
|
914
1180
|
};
|
|
915
1181
|
if (forceShutdown) {
|
|
@@ -928,6 +1194,9 @@ export async function runConductorSession(options) {
|
|
|
928
1194
|
await runWorkerStop();
|
|
929
1195
|
await runConductorClose();
|
|
930
1196
|
}
|
|
1197
|
+
// ACP updates can arrive while cancellation and bridge shutdown settle.
|
|
1198
|
+
// Flush once more after all workers stop to capture their final snapshot.
|
|
1199
|
+
await flushToolCallHistoryBestEffort();
|
|
931
1200
|
sessionLogger.emit({
|
|
932
1201
|
type: 'harness.teardown',
|
|
933
1202
|
force: forceShutdown,
|
|
@@ -948,12 +1217,6 @@ export async function runConductorSession(options) {
|
|
|
948
1217
|
}
|
|
949
1218
|
}
|
|
950
1219
|
}
|
|
951
|
-
export function createConductorAgentFactory(backend) {
|
|
952
|
-
if (backend === 'cursor') {
|
|
953
|
-
return createCursorSdkConductorAgentFactory();
|
|
954
|
-
}
|
|
955
|
-
return createPiConductorAgentFactory();
|
|
956
|
-
}
|
|
957
1220
|
function createPiKickoffPrompt(issueUrl) {
|
|
958
1221
|
return (`Start the conductor workflow for ${issueUrl}. ` +
|
|
959
1222
|
'Review the Issue context in your system instructions and dispatch the first required worker with prompt_worker.');
|