agentic-orchestrator 0.1.26 → 0.1.28
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/AGENTS.md +2 -2
- package/CLAUDE.md +2 -2
- package/README.md +47 -14
- package/agentic/orchestrator/agents.yaml +13 -0
- package/agentic/orchestrator/policy.yaml +3 -0
- package/agentic/orchestrator/schemas/agents.schema.json +76 -0
- package/agentic/orchestrator/schemas/policy.schema.json +16 -0
- package/agentic/orchestrator/schemas/policy.user.schema.json +16 -0
- package/agentic/orchestrator/schemas/state.schema.json +53 -0
- package/apps/control-plane/src/application/configuration-service.ts +181 -0
- package/apps/control-plane/src/application/kernel-tool-wiring.ts +292 -0
- package/apps/control-plane/src/application/services/checkpoint-service.ts +523 -0
- package/apps/control-plane/src/application/services/feature-send-message-service.ts +132 -0
- package/apps/control-plane/src/application/services/patch-service.ts +29 -5
- package/apps/control-plane/src/application/services/repo-operations-service.ts +276 -0
- package/apps/control-plane/src/application/services/worktree-watchdog-service.ts +156 -0
- package/apps/control-plane/src/cli/cli-argument-parser.ts +12 -0
- package/apps/control-plane/src/cli/help-command-handler.ts +17 -0
- package/apps/control-plane/src/cli/init-command-handler.ts +31 -0
- package/apps/control-plane/src/cli/resume-command-handler.ts +31 -4
- package/apps/control-plane/src/cli/rollback-command-handler.ts +217 -0
- package/apps/control-plane/src/cli/run-command-handler.ts +8 -0
- package/apps/control-plane/src/cli/types.ts +3 -0
- package/apps/control-plane/src/core/kernel-types.ts +55 -0
- package/apps/control-plane/src/core/kernel.ts +61 -878
- package/apps/control-plane/src/core/tool-caller.ts +10 -0
- package/apps/control-plane/src/core/utils/field-readers.ts +38 -0
- package/apps/control-plane/src/core/utils/index-normalizer.ts +119 -0
- package/apps/control-plane/src/core/utils/path-normalizers.ts +22 -0
- package/apps/control-plane/src/interfaces/cli/bootstrap.ts +15 -0
- package/apps/control-plane/src/providers/api-worker-provider.ts +14 -12
- package/apps/control-plane/src/providers/cli-worker-provider.ts +82 -12
- package/apps/control-plane/src/providers/providers.ts +45 -24
- package/apps/control-plane/src/providers/worker-provider-factory.ts +36 -1
- package/apps/control-plane/src/supervisor/run-coordinator.ts +91 -36
- package/apps/control-plane/src/supervisor/runtime.ts +107 -1
- package/apps/control-plane/src/supervisor/types.ts +9 -0
- package/apps/control-plane/src/supervisor/worker-decision-loop.ts +253 -14
- package/apps/control-plane/test/checkpoint-service.spec.ts +537 -0
- package/apps/control-plane/test/cli-helpers.spec.ts +28 -0
- package/apps/control-plane/test/cli.unit.spec.ts +52 -0
- package/apps/control-plane/test/configuration-service.spec.ts +466 -0
- package/apps/control-plane/test/dashboard-api.integration.spec.ts +537 -0
- package/apps/control-plane/test/dashboard-client.spec.ts +233 -0
- package/apps/control-plane/test/feature-send-message-service.spec.ts +314 -0
- package/apps/control-plane/test/init-wizard.spec.ts +35 -0
- package/apps/control-plane/test/path-normalizers.spec.ts +41 -0
- package/apps/control-plane/test/repo-operations-service.spec.ts +339 -0
- package/apps/control-plane/test/resume-command.spec.ts +33 -0
- package/apps/control-plane/test/review-workspace-logic.spec.ts +130 -0
- package/apps/control-plane/test/rollback-command.spec.ts +208 -0
- package/apps/control-plane/test/run-coordinator.spec.ts +119 -0
- package/apps/control-plane/test/worker-decision-loop.spec.ts +209 -0
- package/apps/control-plane/test/worker-provider-adapters.spec.ts +102 -0
- package/apps/control-plane/test/worker-provider-factory.spec.ts +14 -0
- package/apps/control-plane/test/worktree-watchdog-service.spec.ts +147 -0
- package/config/agentic/orchestrator/agents.yaml +13 -0
- package/dist/apps/control-plane/application/configuration-service.d.ts +19 -0
- package/dist/apps/control-plane/application/configuration-service.js +123 -0
- package/dist/apps/control-plane/application/configuration-service.js.map +1 -0
- package/dist/apps/control-plane/application/kernel-tool-wiring.d.ts +39 -0
- package/dist/apps/control-plane/application/kernel-tool-wiring.js +38 -0
- package/dist/apps/control-plane/application/kernel-tool-wiring.js.map +1 -0
- package/dist/apps/control-plane/application/services/checkpoint-service.d.ts +84 -0
- package/dist/apps/control-plane/application/services/checkpoint-service.js +367 -0
- package/dist/apps/control-plane/application/services/checkpoint-service.js.map +1 -0
- package/dist/apps/control-plane/application/services/feature-send-message-service.d.ts +25 -0
- package/dist/apps/control-plane/application/services/feature-send-message-service.js +105 -0
- package/dist/apps/control-plane/application/services/feature-send-message-service.js.map +1 -0
- package/dist/apps/control-plane/application/services/patch-service.d.ts +6 -0
- package/dist/apps/control-plane/application/services/patch-service.js +11 -2
- package/dist/apps/control-plane/application/services/patch-service.js.map +1 -1
- package/dist/apps/control-plane/application/services/repo-operations-service.d.ts +70 -0
- package/dist/apps/control-plane/application/services/repo-operations-service.js +213 -0
- package/dist/apps/control-plane/application/services/repo-operations-service.js.map +1 -0
- package/dist/apps/control-plane/application/services/worktree-watchdog-service.d.ts +23 -0
- package/dist/apps/control-plane/application/services/worktree-watchdog-service.js +119 -0
- package/dist/apps/control-plane/application/services/worktree-watchdog-service.js.map +1 -0
- package/dist/apps/control-plane/cli/cli-argument-parser.js +12 -0
- package/dist/apps/control-plane/cli/cli-argument-parser.js.map +1 -1
- package/dist/apps/control-plane/cli/help-command-handler.js +17 -0
- package/dist/apps/control-plane/cli/help-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/init-command-handler.js +23 -0
- package/dist/apps/control-plane/cli/init-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/resume-command-handler.js +25 -5
- package/dist/apps/control-plane/cli/resume-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/rollback-command-handler.d.ts +6 -0
- package/dist/apps/control-plane/cli/rollback-command-handler.js +177 -0
- package/dist/apps/control-plane/cli/rollback-command-handler.js.map +1 -0
- package/dist/apps/control-plane/cli/run-command-handler.js +7 -1
- package/dist/apps/control-plane/cli/run-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/types.d.ts +3 -0
- package/dist/apps/control-plane/cli/types.js +1 -0
- package/dist/apps/control-plane/cli/types.js.map +1 -1
- package/dist/apps/control-plane/core/configuration-service.d.ts +25 -0
- package/dist/apps/control-plane/core/configuration-service.js +130 -0
- package/dist/apps/control-plane/core/configuration-service.js.map +1 -0
- package/dist/apps/control-plane/core/kernel-tool-wiring.d.ts +50 -0
- package/dist/apps/control-plane/core/kernel-tool-wiring.js +44 -0
- package/dist/apps/control-plane/core/kernel-tool-wiring.js.map +1 -0
- package/dist/apps/control-plane/core/kernel-types.d.ts +48 -0
- package/dist/apps/control-plane/core/kernel-types.js +2 -0
- package/dist/apps/control-plane/core/kernel-types.js.map +1 -0
- package/dist/apps/control-plane/core/kernel.d.ts +17 -48
- package/dist/apps/control-plane/core/kernel.js +44 -539
- package/dist/apps/control-plane/core/kernel.js.map +1 -1
- package/dist/apps/control-plane/core/tool-caller.d.ts +10 -0
- package/dist/apps/control-plane/core/utils/error-normalizer.d.ts +2 -0
- package/dist/apps/control-plane/core/utils/error-normalizer.js +51 -0
- package/dist/apps/control-plane/core/utils/error-normalizer.js.map +1 -0
- package/dist/apps/control-plane/core/utils/field-readers.d.ts +9 -0
- package/dist/apps/control-plane/core/utils/field-readers.js +30 -0
- package/dist/apps/control-plane/core/utils/field-readers.js.map +1 -0
- package/dist/apps/control-plane/core/utils/index-normalizer.d.ts +7 -0
- package/dist/apps/control-plane/core/utils/index-normalizer.js +92 -0
- package/dist/apps/control-plane/core/utils/index-normalizer.js.map +1 -0
- package/dist/apps/control-plane/core/utils/path-normalizers.d.ts +2 -0
- package/dist/apps/control-plane/core/utils/path-normalizers.js +17 -0
- package/dist/apps/control-plane/core/utils/path-normalizers.js.map +1 -0
- package/dist/apps/control-plane/interfaces/cli/bootstrap.js +13 -1
- package/dist/apps/control-plane/interfaces/cli/bootstrap.js.map +1 -1
- package/dist/apps/control-plane/providers/api-worker-provider.d.ts +4 -13
- package/dist/apps/control-plane/providers/api-worker-provider.js +10 -0
- package/dist/apps/control-plane/providers/api-worker-provider.js.map +1 -1
- package/dist/apps/control-plane/providers/cli-worker-provider.d.ts +11 -13
- package/dist/apps/control-plane/providers/cli-worker-provider.js +64 -0
- package/dist/apps/control-plane/providers/cli-worker-provider.js.map +1 -1
- package/dist/apps/control-plane/providers/providers.d.ts +31 -24
- package/dist/apps/control-plane/providers/providers.js +10 -0
- package/dist/apps/control-plane/providers/providers.js.map +1 -1
- package/dist/apps/control-plane/providers/worker-provider-factory.d.ts +11 -0
- package/dist/apps/control-plane/providers/worker-provider-factory.js +20 -1
- package/dist/apps/control-plane/providers/worker-provider-factory.js.map +1 -1
- package/dist/apps/control-plane/supervisor/run-coordinator.d.ts +3 -0
- package/dist/apps/control-plane/supervisor/run-coordinator.js +81 -33
- package/dist/apps/control-plane/supervisor/run-coordinator.js.map +1 -1
- package/dist/apps/control-plane/supervisor/runtime.d.ts +8 -1
- package/dist/apps/control-plane/supervisor/runtime.js +90 -0
- package/dist/apps/control-plane/supervisor/runtime.js.map +1 -1
- package/dist/apps/control-plane/supervisor/types.d.ts +11 -0
- package/dist/apps/control-plane/supervisor/types.js.map +1 -1
- package/dist/apps/control-plane/supervisor/worker-decision-loop.d.ts +21 -1
- package/dist/apps/control-plane/supervisor/worker-decision-loop.js +207 -13
- package/dist/apps/control-plane/supervisor/worker-decision-loop.js.map +1 -1
- package/package.json +1 -1
- package/packages/web-dashboard/package.json +2 -0
- package/packages/web-dashboard/src/app/analytics/page.tsx +83 -2
- package/packages/web-dashboard/src/app/api/actions/route.ts +92 -1
- package/packages/web-dashboard/src/app/api/analytics/route.ts +5 -2
- package/packages/web-dashboard/src/app/api/features/[id]/checkpoints/[checkpointId]/diff/route.ts +43 -0
- package/packages/web-dashboard/src/app/api/features/[id]/checkpoints/compare/route.ts +45 -0
- package/packages/web-dashboard/src/app/api/features/[id]/checkpoints/stream/route.ts +170 -0
- package/packages/web-dashboard/src/app/api/features/[id]/file-diff/route.ts +144 -0
- package/packages/web-dashboard/src/app/api/features/[id]/log-stream/route.ts +167 -0
- package/packages/web-dashboard/src/app/api/features/[id]/raw-logs/[filename]/route.ts +65 -0
- package/packages/web-dashboard/src/app/api/features/[id]/raw-logs/route.ts +63 -0
- package/packages/web-dashboard/src/app/api/features/[id]/timeline/route.ts +60 -0
- package/packages/web-dashboard/src/app/feature/[id]/page.tsx +32 -11
- package/packages/web-dashboard/src/app/globals.css +2 -0
- package/packages/web-dashboard/src/components/detail-panel.tsx +483 -0
- package/packages/web-dashboard/src/components/review-workspace.tsx +1162 -0
- package/packages/web-dashboard/src/lib/aop-client.ts +725 -0
- package/packages/web-dashboard/src/lib/review-contracts.ts +182 -0
- package/packages/web-dashboard/src/lib/review-workspace-logic.ts +64 -0
- package/packages/web-dashboard/src/lib/types.ts +131 -0
- package/packages/web-dashboard/src/styles/dashboard.module.css +333 -0
- package/spec-files/completed/agentic_orchestrator_execution_mode_spec.md +1905 -0
- package/spec-files/outstanding/agentic_orchestrator_runtime_inspection_spec.md +940 -0
- package/spec-files/outstanding/execution_mode_critical_review.md +355 -0
- package/spec-files/outstanding/shadow_workspace_implementation_spec.md +1271 -0
- package/spec-files/outstanding/shadow_workspace_spec_summary.md +222 -0
- package/spec-files/progress.md +269 -1
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { TOOLS } from '../core/constants.js';
|
|
2
2
|
import { ERROR_CODES } from '../core/error-codes.js';
|
|
3
|
-
import type { WorkerProvider } from '../providers/providers.js';
|
|
3
|
+
import type { ExecutionMode, WorkerProvider, WorkerRunInput } from '../providers/providers.js';
|
|
4
4
|
import type { RuntimeRole, SupervisorToolCaller } from './types.js';
|
|
5
5
|
import type { ActivityMonitorService } from '../application/services/activity-monitor-service.js';
|
|
6
6
|
import { appendWorkerRuntimeEvent } from './worker-event-journal.js';
|
|
7
|
+
import type {
|
|
8
|
+
CheckpointRecord,
|
|
9
|
+
CheckpointService,
|
|
10
|
+
InteractiveExecutionConfig,
|
|
11
|
+
} from '../application/services/checkpoint-service.js';
|
|
12
|
+
import type { WorktreeWatchdogService } from '../application/services/worktree-watchdog-service.js';
|
|
7
13
|
|
|
8
14
|
type AnyRecord = Record<string, unknown>;
|
|
9
15
|
const PLAN_TOP_LEVEL_KEYS = new Set([
|
|
@@ -125,6 +131,19 @@ interface WorkerDecisionLoopDependencies {
|
|
|
125
131
|
activityMonitor?: ActivityMonitorService;
|
|
126
132
|
repoRoot?: string;
|
|
127
133
|
runId?: string | (() => string);
|
|
134
|
+
resolveExecutionMode?: (featureId: string, role: RuntimeRole) => Promise<ExecutionMode>;
|
|
135
|
+
resolveInteractiveConfig?: () => InteractiveExecutionConfig;
|
|
136
|
+
watchdog?: WorktreeWatchdogService;
|
|
137
|
+
checkpointService?: CheckpointService;
|
|
138
|
+
resolveWorktreePath?: (featureId: string) => string;
|
|
139
|
+
resolveRoleSessionId?: (role: RuntimeRole, featureId: string) => string | null;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
interface InteractiveRunSummary {
|
|
143
|
+
workerOutput: Record<string, unknown>;
|
|
144
|
+
finalCheckpoint: CheckpointRecord;
|
|
145
|
+
changedFiles: string[];
|
|
146
|
+
checkpointInvalid: boolean;
|
|
128
147
|
}
|
|
129
148
|
|
|
130
149
|
export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
@@ -133,6 +152,16 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
133
152
|
private readonly activityMonitor: ActivityMonitorService | undefined;
|
|
134
153
|
private readonly repoRoot: string | null;
|
|
135
154
|
private readonly runId: string | (() => string) | null;
|
|
155
|
+
private readonly resolveExecutionModeOverride:
|
|
156
|
+
| ((featureId: string, role: RuntimeRole) => Promise<ExecutionMode>)
|
|
157
|
+
| undefined;
|
|
158
|
+
private readonly resolveInteractiveConfigOverride: (() => InteractiveExecutionConfig) | undefined;
|
|
159
|
+
private readonly watchdog: WorktreeWatchdogService | undefined;
|
|
160
|
+
private readonly checkpointService: CheckpointService | undefined;
|
|
161
|
+
private readonly resolveWorktreePath: ((featureId: string) => string) | undefined;
|
|
162
|
+
private readonly resolveRoleSessionId:
|
|
163
|
+
| ((role: RuntimeRole, featureId: string) => string | null)
|
|
164
|
+
| undefined;
|
|
136
165
|
|
|
137
166
|
constructor(dependencies: WorkerDecisionLoopDependencies) {
|
|
138
167
|
this.provider = dependencies.provider;
|
|
@@ -140,6 +169,12 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
140
169
|
this.activityMonitor = dependencies.activityMonitor;
|
|
141
170
|
this.repoRoot = dependencies.repoRoot ?? null;
|
|
142
171
|
this.runId = dependencies.runId ?? null;
|
|
172
|
+
this.resolveExecutionModeOverride = dependencies.resolveExecutionMode;
|
|
173
|
+
this.resolveInteractiveConfigOverride = dependencies.resolveInteractiveConfig;
|
|
174
|
+
this.watchdog = dependencies.watchdog;
|
|
175
|
+
this.checkpointService = dependencies.checkpointService;
|
|
176
|
+
this.resolveWorktreePath = dependencies.resolveWorktreePath;
|
|
177
|
+
this.resolveRoleSessionId = dependencies.resolveRoleSessionId;
|
|
143
178
|
}
|
|
144
179
|
|
|
145
180
|
async execute(input: WorkerDecisionInput): Promise<WorkerDecisionResult> {
|
|
@@ -147,6 +182,27 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
147
182
|
if (typeof this.provider.runWorker !== 'function') {
|
|
148
183
|
return result;
|
|
149
184
|
}
|
|
185
|
+
const requestedExecutionMode = await this.resolveExecutionMode(input.featureId, input.role);
|
|
186
|
+
const interactiveEligible = this.isInteractiveEligible(requestedExecutionMode, input.role);
|
|
187
|
+
const executionMode: ExecutionMode =
|
|
188
|
+
requestedExecutionMode === 'interactive' && interactiveEligible
|
|
189
|
+
? 'interactive'
|
|
190
|
+
: 'deterministic';
|
|
191
|
+
if (requestedExecutionMode === 'interactive' && !interactiveEligible) {
|
|
192
|
+
await this.appendWorkerEvent({
|
|
193
|
+
eventType: 'interactive_fallback',
|
|
194
|
+
featureId: input.featureId,
|
|
195
|
+
role: input.role,
|
|
196
|
+
outputTypes: [],
|
|
197
|
+
patchCount: 0,
|
|
198
|
+
planSubmissionCount: 0,
|
|
199
|
+
requestCount: 0,
|
|
200
|
+
noteCount: 0,
|
|
201
|
+
valid: true,
|
|
202
|
+
errorCode: null,
|
|
203
|
+
executionMode,
|
|
204
|
+
});
|
|
205
|
+
}
|
|
150
206
|
await this.appendWorkerEvent({
|
|
151
207
|
eventType: 'worker_started',
|
|
152
208
|
featureId: input.featureId,
|
|
@@ -158,22 +214,20 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
158
214
|
noteCount: 0,
|
|
159
215
|
valid: true,
|
|
160
216
|
errorCode: null,
|
|
217
|
+
executionMode,
|
|
161
218
|
});
|
|
162
219
|
|
|
163
220
|
let workerOutput: Record<string, unknown>;
|
|
221
|
+
let interactiveSummary: InteractiveRunSummary | null = null;
|
|
164
222
|
try {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
model: this.provider.selection.model,
|
|
174
|
-
provider_config_ref: this.provider.selection.provider_config_ref,
|
|
175
|
-
},
|
|
176
|
-
});
|
|
223
|
+
if (interactiveEligible) {
|
|
224
|
+
interactiveSummary = await this.runInteractiveWorker(input);
|
|
225
|
+
workerOutput = interactiveSummary.workerOutput;
|
|
226
|
+
} else {
|
|
227
|
+
workerOutput = await this.provider.runWorker(
|
|
228
|
+
this.buildRunInput(input, executionMode, undefined),
|
|
229
|
+
);
|
|
230
|
+
}
|
|
177
231
|
} catch (error) {
|
|
178
232
|
const typed = error as { code?: string; details?: Record<string, unknown> };
|
|
179
233
|
const errorCode =
|
|
@@ -216,6 +270,7 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
216
270
|
signal: typeof typed.details?.signal === 'string' ? typed.details.signal : null,
|
|
217
271
|
exitCode:
|
|
218
272
|
typeof typed.details?.exit_code === 'number' ? typed.details.exit_code : undefined,
|
|
273
|
+
executionMode,
|
|
219
274
|
});
|
|
220
275
|
throw error;
|
|
221
276
|
}
|
|
@@ -246,7 +301,14 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
246
301
|
}
|
|
247
302
|
if (outputType === 'PATCH') {
|
|
248
303
|
patchCount += 1;
|
|
249
|
-
|
|
304
|
+
if (interactiveSummary) {
|
|
305
|
+
const hasPatchPayload = Boolean(asNonEmptyString(output.unified_diff ?? output.diff));
|
|
306
|
+
if (hasPatchPayload) {
|
|
307
|
+
result.patchApplied = true;
|
|
308
|
+
}
|
|
309
|
+
} else {
|
|
310
|
+
await this.routePatch(input, output, result);
|
|
311
|
+
}
|
|
250
312
|
continue;
|
|
251
313
|
}
|
|
252
314
|
if (outputType === 'NOTE') {
|
|
@@ -260,6 +322,18 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
260
322
|
}
|
|
261
323
|
}
|
|
262
324
|
|
|
325
|
+
if (interactiveSummary) {
|
|
326
|
+
result.toolResults.push({
|
|
327
|
+
checkpoint: structuredClone(interactiveSummary.finalCheckpoint),
|
|
328
|
+
});
|
|
329
|
+
if (interactiveSummary.changedFiles.length > 0) {
|
|
330
|
+
result.patchApplied = true;
|
|
331
|
+
}
|
|
332
|
+
if (interactiveSummary.checkpointInvalid) {
|
|
333
|
+
result.invalidOutput = true;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
263
337
|
const hasProgress = result.planSubmission || result.patchApplied || result.requestHandled;
|
|
264
338
|
result.noProgress = !hasProgress;
|
|
265
339
|
|
|
@@ -274,6 +348,7 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
274
348
|
noteCount,
|
|
275
349
|
valid: !result.invalidOutput,
|
|
276
350
|
errorCode: result.invalidOutput ? ERROR_CODES.PROVIDER_OUTPUT_INVALID : null,
|
|
351
|
+
executionMode,
|
|
277
352
|
});
|
|
278
353
|
|
|
279
354
|
if (this.activityMonitor) {
|
|
@@ -283,6 +358,168 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
283
358
|
return result;
|
|
284
359
|
}
|
|
285
360
|
|
|
361
|
+
private async resolveExecutionMode(featureId: string, role: RuntimeRole): Promise<ExecutionMode> {
|
|
362
|
+
if (this.resolveExecutionModeOverride) {
|
|
363
|
+
return await this.resolveExecutionModeOverride(featureId, role);
|
|
364
|
+
}
|
|
365
|
+
return 'deterministic';
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
private isInteractiveEligible(executionMode: ExecutionMode, role: RuntimeRole): boolean {
|
|
369
|
+
if (executionMode !== 'interactive') {
|
|
370
|
+
return false;
|
|
371
|
+
}
|
|
372
|
+
if (role !== 'builder' && role !== 'qa') {
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
if (!this.repoRoot || !this.watchdog || !this.checkpointService || !this.resolveWorktreePath) {
|
|
376
|
+
return false;
|
|
377
|
+
}
|
|
378
|
+
const capabilities = this.provider.getCapabilities?.();
|
|
379
|
+
if (!capabilities) {
|
|
380
|
+
return true;
|
|
381
|
+
}
|
|
382
|
+
return capabilities.supportsInteractiveMode && capabilities.supportsWorkingDirectory;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
private resolveInteractiveConfig(): InteractiveExecutionConfig {
|
|
386
|
+
if (this.resolveInteractiveConfigOverride) {
|
|
387
|
+
return this.resolveInteractiveConfigOverride();
|
|
388
|
+
}
|
|
389
|
+
return {
|
|
390
|
+
checkpointIntervalMs: 30_000,
|
|
391
|
+
watchdogPollIntervalMs: 2_000,
|
|
392
|
+
maxUncommittedChanges: 50,
|
|
393
|
+
validationOnCheckpoint: true,
|
|
394
|
+
revertOnViolation: false,
|
|
395
|
+
violationSeverity: 'warning',
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
private buildRunInput(
|
|
400
|
+
input: WorkerDecisionInput,
|
|
401
|
+
executionMode: ExecutionMode,
|
|
402
|
+
workingDirectory: string | undefined,
|
|
403
|
+
): WorkerRunInput {
|
|
404
|
+
return {
|
|
405
|
+
role: input.role,
|
|
406
|
+
feature_id: input.featureId,
|
|
407
|
+
context_bundle: input.contextBundle,
|
|
408
|
+
instructions: input.instructions,
|
|
409
|
+
last_tool_results: input.lastToolResults ?? [],
|
|
410
|
+
runtime_selection: {
|
|
411
|
+
provider: this.provider.selection.provider,
|
|
412
|
+
model: this.provider.selection.model,
|
|
413
|
+
provider_config_ref: this.provider.selection.provider_config_ref,
|
|
414
|
+
},
|
|
415
|
+
execution_mode: executionMode,
|
|
416
|
+
working_directory: workingDirectory,
|
|
417
|
+
pause_resume_protocol: 'none',
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
private async runInteractiveWorker(input: WorkerDecisionInput): Promise<InteractiveRunSummary> {
|
|
422
|
+
if (!this.repoRoot || !this.watchdog || !this.checkpointService || !this.resolveWorktreePath) {
|
|
423
|
+
const fallbackOutput = await this.provider.runWorker(
|
|
424
|
+
this.buildRunInput(input, 'deterministic', undefined),
|
|
425
|
+
);
|
|
426
|
+
return {
|
|
427
|
+
workerOutput: fallbackOutput,
|
|
428
|
+
finalCheckpoint: this.createSyntheticCheckpoint(input.featureId),
|
|
429
|
+
changedFiles: [],
|
|
430
|
+
checkpointInvalid: false,
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
const interactiveConfig = this.resolveInteractiveConfig();
|
|
435
|
+
const worktreePath = this.resolveWorktreePath(input.featureId);
|
|
436
|
+
const sessionId = this.resolveRoleSessionId?.(input.role, input.featureId) ?? null;
|
|
437
|
+
await this.watchdog.startWatching({
|
|
438
|
+
featureId: input.featureId,
|
|
439
|
+
repoRoot: this.repoRoot,
|
|
440
|
+
worktreePath,
|
|
441
|
+
pollIntervalMs: interactiveConfig.watchdogPollIntervalMs,
|
|
442
|
+
maxUncommittedChanges: interactiveConfig.maxUncommittedChanges,
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
let latestCheckpoint: CheckpointRecord | null = null;
|
|
446
|
+
let checkpointInvalid = false;
|
|
447
|
+
let lastCheckpointAt = 0;
|
|
448
|
+
const checkpointDebounceMs = 5_000;
|
|
449
|
+
let checkpointQueue = Promise.resolve();
|
|
450
|
+
|
|
451
|
+
const enqueueCheckpoint = (
|
|
452
|
+
trigger: 'interval' | 'change_threshold' | 'final',
|
|
453
|
+
): Promise<void> => {
|
|
454
|
+
checkpointQueue = checkpointQueue.then(async () => {
|
|
455
|
+
const now = Date.now();
|
|
456
|
+
if (trigger !== 'final' && now - lastCheckpointAt < checkpointDebounceMs) {
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
try {
|
|
460
|
+
const checkpoint = await this.checkpointService?.createCheckpoint({
|
|
461
|
+
featureId: input.featureId,
|
|
462
|
+
sessionId,
|
|
463
|
+
trigger,
|
|
464
|
+
});
|
|
465
|
+
if (checkpoint) {
|
|
466
|
+
latestCheckpoint = checkpoint.checkpoint;
|
|
467
|
+
checkpointInvalid = checkpointInvalid || !checkpoint.valid || checkpoint.blockMerge;
|
|
468
|
+
}
|
|
469
|
+
} catch {
|
|
470
|
+
checkpointInvalid = true;
|
|
471
|
+
} finally {
|
|
472
|
+
lastCheckpointAt = Date.now();
|
|
473
|
+
}
|
|
474
|
+
});
|
|
475
|
+
checkpointQueue = checkpointQueue.catch(() => undefined);
|
|
476
|
+
return checkpointQueue;
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
const thresholdListener = (featureId: string): void => {
|
|
480
|
+
if (featureId !== input.featureId) {
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
void enqueueCheckpoint('change_threshold');
|
|
484
|
+
};
|
|
485
|
+
|
|
486
|
+
this.watchdog.on('changeThreshold', thresholdListener);
|
|
487
|
+
const timer = setInterval(() => {
|
|
488
|
+
void enqueueCheckpoint('interval');
|
|
489
|
+
}, interactiveConfig.checkpointIntervalMs);
|
|
490
|
+
timer.unref?.();
|
|
491
|
+
|
|
492
|
+
try {
|
|
493
|
+
const workerOutput = await this.provider.runWorker(
|
|
494
|
+
this.buildRunInput(input, 'interactive', worktreePath),
|
|
495
|
+
);
|
|
496
|
+
await enqueueCheckpoint('final');
|
|
497
|
+
const changedFiles = latestCheckpoint?.files_changed ?? [];
|
|
498
|
+
return {
|
|
499
|
+
workerOutput,
|
|
500
|
+
finalCheckpoint: latestCheckpoint ?? this.createSyntheticCheckpoint(input.featureId),
|
|
501
|
+
changedFiles,
|
|
502
|
+
checkpointInvalid,
|
|
503
|
+
};
|
|
504
|
+
} finally {
|
|
505
|
+
clearInterval(timer);
|
|
506
|
+
this.watchdog.off('changeThreshold', thresholdListener);
|
|
507
|
+
await checkpointQueue.catch(() => undefined);
|
|
508
|
+
await this.watchdog.stopWatching(input.featureId);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
private createSyntheticCheckpoint(featureId: string): CheckpointRecord {
|
|
513
|
+
return {
|
|
514
|
+
checkpoint_id: `checkpoint-synthetic-${Date.now()}`,
|
|
515
|
+
timestamp: new Date().toISOString(),
|
|
516
|
+
files_changed: [],
|
|
517
|
+
validation_status: 'skipped',
|
|
518
|
+
violations: [],
|
|
519
|
+
diff_snapshot: `.aop/features/${featureId}/checkpoints/synthetic.diff`,
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
|
|
286
523
|
private async routePlanSubmission(
|
|
287
524
|
input: WorkerDecisionInput,
|
|
288
525
|
output: AnyRecord,
|
|
@@ -464,6 +701,7 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
464
701
|
eventType: string;
|
|
465
702
|
featureId: string;
|
|
466
703
|
role: RuntimeRole;
|
|
704
|
+
executionMode?: ExecutionMode;
|
|
467
705
|
outputTypes: string[];
|
|
468
706
|
patchCount: number;
|
|
469
707
|
planSubmissionCount: number;
|
|
@@ -492,6 +730,7 @@ export class WorkerDecisionLoop implements WorkerDecisionRunner {
|
|
|
492
730
|
role: event.role,
|
|
493
731
|
phase: 'execution',
|
|
494
732
|
event_type: event.eventType,
|
|
733
|
+
execution_mode: event.executionMode ?? 'deterministic',
|
|
495
734
|
output_types: event.outputTypes,
|
|
496
735
|
patch_count: event.patchCount,
|
|
497
736
|
plan_submission_count: event.planSubmissionCount,
|