agentic-orchestrator 0.1.13 → 0.1.15

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.
Files changed (108) hide show
  1. package/AGENTS.md +139 -0
  2. package/CLAUDE.md +12 -0
  3. package/agentic/orchestrator/agents.yaml +3 -0
  4. package/agentic/orchestrator/defaults/policy.defaults.yaml +3 -0
  5. package/agentic/orchestrator/policy.yaml +3 -0
  6. package/agentic/orchestrator/schemas/agents.schema.json +15 -0
  7. package/agentic/orchestrator/schemas/policy.schema.json +14 -0
  8. package/apps/control-plane/src/cli/cli-argument-parser.ts +7 -0
  9. package/apps/control-plane/src/cli/help-command-handler.ts +8 -0
  10. package/apps/control-plane/src/cli/init-command-handler.ts +6 -0
  11. package/apps/control-plane/src/cli/resume-command-handler.ts +31 -2
  12. package/apps/control-plane/src/cli/run-command-handler.ts +31 -3
  13. package/apps/control-plane/src/cli/types.ts +1 -0
  14. package/apps/control-plane/src/core/error-codes.ts +4 -0
  15. package/apps/control-plane/src/core/kernel.ts +3 -0
  16. package/apps/control-plane/src/index.ts +14 -0
  17. package/apps/control-plane/src/interfaces/cli/bootstrap.ts +25 -3
  18. package/apps/control-plane/src/providers/api-worker-provider.ts +115 -0
  19. package/apps/control-plane/src/providers/cli-worker-provider.ts +385 -0
  20. package/apps/control-plane/src/providers/output-parsers/generic-output-parser.ts +100 -0
  21. package/apps/control-plane/src/providers/output-parsers/index.ts +11 -0
  22. package/apps/control-plane/src/providers/output-parsers/types.ts +23 -0
  23. package/apps/control-plane/src/providers/providers.ts +19 -0
  24. package/apps/control-plane/src/providers/worker-provider-factory.ts +198 -0
  25. package/apps/control-plane/src/supervisor/build-wave-executor.ts +140 -3
  26. package/apps/control-plane/src/supervisor/planning-wave-executor.ts +125 -5
  27. package/apps/control-plane/src/supervisor/qa-wave-executor.ts +144 -2
  28. package/apps/control-plane/src/supervisor/runtime.ts +24 -0
  29. package/apps/control-plane/src/supervisor/worker-decision-loop.ts +134 -12
  30. package/apps/control-plane/test/cli.unit.spec.ts +36 -0
  31. package/apps/control-plane/test/dashboard-api.integration.spec.ts +2 -2
  32. package/apps/control-plane/test/resume-command.spec.ts +31 -1
  33. package/apps/control-plane/test/worker-decision-loop.spec.ts +3 -0
  34. package/apps/control-plane/test/worker-execution-policy.spec.ts +284 -0
  35. package/apps/control-plane/test/worker-provider-adapters.spec.ts +440 -0
  36. package/apps/control-plane/test/worker-provider-factory.spec.ts +151 -0
  37. package/config/agentic/orchestrator/agents.yaml +3 -0
  38. package/dist/apps/control-plane/cli/cli-argument-parser.js +7 -0
  39. package/dist/apps/control-plane/cli/cli-argument-parser.js.map +1 -1
  40. package/dist/apps/control-plane/cli/help-command-handler.js +8 -0
  41. package/dist/apps/control-plane/cli/help-command-handler.js.map +1 -1
  42. package/dist/apps/control-plane/cli/init-command-handler.js +6 -0
  43. package/dist/apps/control-plane/cli/init-command-handler.js.map +1 -1
  44. package/dist/apps/control-plane/cli/resume-command-handler.d.ts +3 -0
  45. package/dist/apps/control-plane/cli/resume-command-handler.js +18 -2
  46. package/dist/apps/control-plane/cli/resume-command-handler.js.map +1 -1
  47. package/dist/apps/control-plane/cli/run-command-handler.d.ts +3 -1
  48. package/dist/apps/control-plane/cli/run-command-handler.js +17 -3
  49. package/dist/apps/control-plane/cli/run-command-handler.js.map +1 -1
  50. package/dist/apps/control-plane/cli/types.d.ts +1 -0
  51. package/dist/apps/control-plane/core/error-codes.d.ts +4 -0
  52. package/dist/apps/control-plane/core/error-codes.js +4 -0
  53. package/dist/apps/control-plane/core/error-codes.js.map +1 -1
  54. package/dist/apps/control-plane/core/kernel.d.ts +3 -0
  55. package/dist/apps/control-plane/core/kernel.js.map +1 -1
  56. package/dist/apps/control-plane/index.d.ts +2 -0
  57. package/dist/apps/control-plane/index.js +1 -0
  58. package/dist/apps/control-plane/index.js.map +1 -1
  59. package/dist/apps/control-plane/interfaces/cli/bootstrap.js +14 -2
  60. package/dist/apps/control-plane/interfaces/cli/bootstrap.js.map +1 -1
  61. package/dist/apps/control-plane/providers/api-worker-provider.d.ts +31 -0
  62. package/dist/apps/control-plane/providers/api-worker-provider.js +73 -0
  63. package/dist/apps/control-plane/providers/api-worker-provider.js.map +1 -0
  64. package/dist/apps/control-plane/providers/cli-worker-provider.d.ts +46 -0
  65. package/dist/apps/control-plane/providers/cli-worker-provider.js +274 -0
  66. package/dist/apps/control-plane/providers/cli-worker-provider.js.map +1 -0
  67. package/dist/apps/control-plane/providers/output-parsers/generic-output-parser.d.ts +10 -0
  68. package/dist/apps/control-plane/providers/output-parsers/generic-output-parser.js +79 -0
  69. package/dist/apps/control-plane/providers/output-parsers/generic-output-parser.js.map +1 -0
  70. package/dist/apps/control-plane/providers/output-parsers/index.d.ts +2 -0
  71. package/dist/apps/control-plane/providers/output-parsers/index.js +2 -0
  72. package/dist/apps/control-plane/providers/output-parsers/index.js.map +1 -0
  73. package/dist/apps/control-plane/providers/output-parsers/types.d.ts +21 -0
  74. package/dist/apps/control-plane/providers/output-parsers/types.js +2 -0
  75. package/dist/apps/control-plane/providers/output-parsers/types.js.map +1 -0
  76. package/dist/apps/control-plane/providers/providers.d.ts +4 -0
  77. package/dist/apps/control-plane/providers/providers.js +15 -0
  78. package/dist/apps/control-plane/providers/providers.js.map +1 -1
  79. package/dist/apps/control-plane/providers/worker-provider-factory.d.ts +41 -0
  80. package/dist/apps/control-plane/providers/worker-provider-factory.js +104 -0
  81. package/dist/apps/control-plane/providers/worker-provider-factory.js.map +1 -0
  82. package/dist/apps/control-plane/supervisor/build-wave-executor.d.ts +13 -0
  83. package/dist/apps/control-plane/supervisor/build-wave-executor.js +92 -3
  84. package/dist/apps/control-plane/supervisor/build-wave-executor.js.map +1 -1
  85. package/dist/apps/control-plane/supervisor/planning-wave-executor.d.ts +12 -0
  86. package/dist/apps/control-plane/supervisor/planning-wave-executor.js +83 -5
  87. package/dist/apps/control-plane/supervisor/planning-wave-executor.js.map +1 -1
  88. package/dist/apps/control-plane/supervisor/qa-wave-executor.d.ts +13 -0
  89. package/dist/apps/control-plane/supervisor/qa-wave-executor.js +91 -2
  90. package/dist/apps/control-plane/supervisor/qa-wave-executor.js.map +1 -1
  91. package/dist/apps/control-plane/supervisor/runtime.js +19 -0
  92. package/dist/apps/control-plane/supervisor/runtime.js.map +1 -1
  93. package/dist/apps/control-plane/supervisor/worker-decision-loop.d.ts +10 -0
  94. package/dist/apps/control-plane/supervisor/worker-decision-loop.js +113 -12
  95. package/dist/apps/control-plane/supervisor/worker-decision-loop.js.map +1 -1
  96. package/package.json +2 -2
  97. package/packages/web-dashboard/next-env.d.ts +2 -1
  98. package/packages/web-dashboard/src/app/api/features/[id]/checkout/route.ts +4 -3
  99. package/packages/web-dashboard/src/app/api/features/[id]/diff/route.ts +6 -2
  100. package/packages/web-dashboard/src/app/api/features/[id]/evidence/[artifact]/route.ts +6 -5
  101. package/packages/web-dashboard/src/app/api/features/[id]/review/route.ts +5 -4
  102. package/packages/web-dashboard/src/app/api/features/[id]/route.ts +7 -3
  103. package/packages/web-dashboard/src/lib/aop-client.ts +2 -2
  104. package/packages/web-dashboard/src/lib/orchestrator-tools.ts +1 -1
  105. package/packages/web-dashboard/tsconfig.json +1 -0
  106. package/spec-files/outstanding/agentic_orchestrator_human_input_interaction_protocol_spec.md +590 -0
  107. package/spec-files/outstanding/agentic_orchestrator_real_worker_provider_execution_spec.md +616 -0
  108. package/spec-files/progress.md +91 -0
@@ -0,0 +1,440 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import { ERROR_CODES } from '../src/core/error-codes.js';
3
+ import { ApiWorkerProvider } from '../src/providers/api-worker-provider.js';
4
+ import { CliWorkerProvider } from '../src/providers/cli-worker-provider.js';
5
+ import type { ProviderCommandResult, ProviderSelection } from '../src/providers/providers.js';
6
+ import type { ProviderOutputParser } from '../src/providers/output-parsers/types.js';
7
+ import type { WorkerOutputEnvelope } from '../src/providers/output-parsers/types.js';
8
+ import { GenericCliOutputParser } from '../src/providers/output-parsers/generic-output-parser.js';
9
+
10
+ const parserContext = {
11
+ sessionId: 'session-1',
12
+ role: 'builder',
13
+ featureId: 'feature-1',
14
+ provider: 'codex',
15
+ model: 'local-default',
16
+ };
17
+
18
+ function makeSelection(
19
+ provider: string,
20
+ overrides: Partial<ProviderSelection> = {},
21
+ ): ProviderSelection {
22
+ return {
23
+ provider,
24
+ model: `${provider}-model`,
25
+ provider_config_env: null,
26
+ provider_config_ref: null,
27
+ agent_config: null,
28
+ ...overrides,
29
+ };
30
+ }
31
+
32
+ describe('GenericCliOutputParser', () => {
33
+ it('GIVEN_empty_output_WHEN_parse_THEN_throws_provider_output_invalid', () => {
34
+ const parser = new GenericCliOutputParser();
35
+ try {
36
+ parser.parse(' ', parserContext);
37
+ throw new Error('expected parse to throw');
38
+ } catch (error) {
39
+ expect(error).toMatchObject({ code: ERROR_CODES.PROVIDER_OUTPUT_INVALID });
40
+ }
41
+ });
42
+
43
+ it('GIVEN_invalid_json_WHEN_parse_THEN_throws_provider_output_invalid', () => {
44
+ const parser = new GenericCliOutputParser();
45
+ try {
46
+ parser.parse('{not-json', parserContext);
47
+ throw new Error('expected parse to throw');
48
+ } catch (error) {
49
+ expect(error).toMatchObject({ code: ERROR_CODES.PROVIDER_OUTPUT_INVALID });
50
+ }
51
+ });
52
+
53
+ it('GIVEN_object_without_outputs_or_type_WHEN_parse_THEN_throws_provider_output_invalid', () => {
54
+ const parser = new GenericCliOutputParser();
55
+ try {
56
+ parser.parse(JSON.stringify({ session_id: 's-1' }), parserContext);
57
+ throw new Error('expected parse to throw');
58
+ } catch (error) {
59
+ expect(error).toMatchObject({ code: ERROR_CODES.PROVIDER_OUTPUT_INVALID });
60
+ }
61
+ });
62
+
63
+ it('GIVEN_output_array_WHEN_parse_THEN_filters_non_record_items_and_uses_context_fallbacks', () => {
64
+ const parser = new GenericCliOutputParser();
65
+ const parsed = parser.parse(
66
+ JSON.stringify({
67
+ outputs: [{ type: 'PATCH', unified_diff: 'diff --git a b' }, 'bad-entry', 12, null],
68
+ }),
69
+ parserContext,
70
+ );
71
+
72
+ expect(parsed.session_id).toBe(parserContext.sessionId);
73
+ expect(parsed.role).toBe(parserContext.role);
74
+ expect(parsed.feature_id).toBe(parserContext.featureId);
75
+ expect(parsed.outputs).toEqual([{ type: 'PATCH', unified_diff: 'diff --git a b' }]);
76
+ expect(parsed.provider_meta).toEqual({
77
+ provider: parserContext.provider,
78
+ model: parserContext.model,
79
+ });
80
+ });
81
+
82
+ it('GIVEN_single_output_shape_WHEN_parse_THEN_wraps_it_as_outputs_array', () => {
83
+ const parser = new GenericCliOutputParser();
84
+ const parsed = parser.parse(
85
+ JSON.stringify({
86
+ session_id: 'session-explicit',
87
+ role: 'qa',
88
+ feature_id: 'feature-explicit',
89
+ type: 'NOTE',
90
+ content: 'done',
91
+ }),
92
+ parserContext,
93
+ );
94
+ expect(parsed.session_id).toBe('session-explicit');
95
+ expect(parsed.role).toBe('qa');
96
+ expect(parsed.feature_id).toBe('feature-explicit');
97
+ expect(parsed.outputs).toEqual([
98
+ {
99
+ session_id: 'session-explicit',
100
+ role: 'qa',
101
+ feature_id: 'feature-explicit',
102
+ type: 'NOTE',
103
+ content: 'done',
104
+ },
105
+ ]);
106
+ });
107
+ });
108
+
109
+ describe('ApiWorkerProvider', () => {
110
+ it('GIVEN_missing_provider_config_ref_WHEN_runWorker_THEN_throws_runtime_unavailable', async () => {
111
+ const provider = new ApiWorkerProvider(makeSelection('gemini'), {
112
+ outputParser: new GenericCliOutputParser(),
113
+ workerResponseTimeoutMs: 1000,
114
+ });
115
+ try {
116
+ await provider.runWorker({
117
+ role: 'builder',
118
+ feature_id: 'feature-a',
119
+ });
120
+ throw new Error('expected runWorker to throw');
121
+ } catch (error) {
122
+ expect(error).toMatchObject({
123
+ code: ERROR_CODES.PROVIDER_RUNTIME_UNAVAILABLE,
124
+ details: { reason: 'missing_provider_config_ref' },
125
+ });
126
+ }
127
+ });
128
+
129
+ it('GIVEN_no_mock_response_WHEN_runWorker_THEN_throws_runtime_unavailable', async () => {
130
+ const provider = new ApiWorkerProvider(
131
+ makeSelection('gemini', {
132
+ provider_config_ref: 'token',
133
+ agent_config: {},
134
+ }),
135
+ {
136
+ outputParser: new GenericCliOutputParser(),
137
+ workerResponseTimeoutMs: 1000,
138
+ },
139
+ );
140
+ try {
141
+ await provider.runWorker({
142
+ role: 'builder',
143
+ feature_id: 'feature-a',
144
+ });
145
+ throw new Error('expected runWorker to throw');
146
+ } catch (error) {
147
+ expect(error).toMatchObject({
148
+ code: ERROR_CODES.PROVIDER_RUNTIME_UNAVAILABLE,
149
+ details: { reason: 'missing_api_adapter_configuration' },
150
+ });
151
+ }
152
+ });
153
+
154
+ it('GIVEN_mock_response_WHEN_runWorker_THEN_parses_and_returns_envelope', async () => {
155
+ const parse = vi.fn(
156
+ (): WorkerOutputEnvelope => ({
157
+ session_id: 'builder-feature-a-api',
158
+ role: 'builder',
159
+ feature_id: 'feature-a',
160
+ outputs: [{ type: 'NOTE', content: 'ok' }],
161
+ provider_meta: { provider: 'gemini', model: 'gemini-model' },
162
+ }),
163
+ );
164
+ const parser: ProviderOutputParser = { parse };
165
+ const provider = new ApiWorkerProvider(
166
+ makeSelection('gemini', {
167
+ provider_config_ref: 'token',
168
+ agent_config: {
169
+ mock_response: {
170
+ outputs: [{ type: 'NOTE', content: 'ok' }],
171
+ },
172
+ },
173
+ }),
174
+ {
175
+ outputParser: parser,
176
+ workerResponseTimeoutMs: 1000,
177
+ },
178
+ );
179
+
180
+ const result = await provider.runWorker({
181
+ role: 'builder',
182
+ feature_id: 'feature-a',
183
+ });
184
+
185
+ expect(parse).toHaveBeenCalledTimes(1);
186
+ expect(result).toMatchObject({
187
+ session_id: 'builder-feature-a-api',
188
+ role: 'builder',
189
+ feature_id: 'feature-a',
190
+ });
191
+ });
192
+
193
+ it('GIVEN_session_methods_WHEN_called_THEN_behave_deterministically', async () => {
194
+ const provider = new ApiWorkerProvider(makeSelection('gemini'), {
195
+ outputParser: new GenericCliOutputParser(),
196
+ workerResponseTimeoutMs: 1000,
197
+ });
198
+ const created = await provider.createSession('planner', 'feature-a', 'prompt');
199
+ expect(created.system_prompt_loaded).toBe(true);
200
+ expect(await provider.reattachSession('unknown')).toBeNull();
201
+ expect(await provider.reattachSession('session-2')).toMatchObject({ session_id: 'session-2' });
202
+ expect(await provider.closeSession('session-2')).toEqual({ closed: true });
203
+ });
204
+ });
205
+
206
+ describe('CliWorkerProvider', () => {
207
+ it('GIVEN_missing_run_template_WHEN_runWorker_THEN_throws_runtime_unavailable', async () => {
208
+ const commandRunner = {
209
+ run: vi.fn(),
210
+ };
211
+ const provider = new CliWorkerProvider(makeSelection('custom'), {
212
+ outputParser: new GenericCliOutputParser(),
213
+ commandRunner,
214
+ workerResponseTimeoutMs: 1000,
215
+ });
216
+ await expect(
217
+ provider.runWorker({
218
+ role: 'builder',
219
+ feature_id: 'feature-a',
220
+ }),
221
+ ).rejects.toMatchObject({
222
+ code: ERROR_CODES.PROVIDER_RUNTIME_UNAVAILABLE,
223
+ details: { reason: 'missing_run_command_template' },
224
+ });
225
+ expect(commandRunner.run).not.toHaveBeenCalled();
226
+ });
227
+
228
+ it('GIVEN_codex_selection_WHEN_runWorker_THEN_uses_default_template_and_env_and_parser', async () => {
229
+ const run = vi.fn(
230
+ async (
231
+ _command: string,
232
+ _args: string[],
233
+ _options?: Record<string, unknown>,
234
+ ): Promise<ProviderCommandResult> => ({
235
+ exitCode: 0,
236
+ signal: null,
237
+ stdout: JSON.stringify({
238
+ outputs: [{ type: 'NOTE', content: 'ok' }],
239
+ }),
240
+ }),
241
+ );
242
+ const parse = vi.fn(
243
+ (): WorkerOutputEnvelope => ({
244
+ session_id: 'planner-feature-a-session',
245
+ role: 'planner',
246
+ feature_id: 'feature-a',
247
+ outputs: [{ type: 'NOTE', content: 'ok' }],
248
+ provider_meta: { provider: 'codex', model: 'codex-model' },
249
+ }),
250
+ );
251
+ const provider = new CliWorkerProvider(
252
+ makeSelection('codex', {
253
+ provider_config_env: 'CODEX_TOKEN',
254
+ provider_config_ref: 'secret',
255
+ }),
256
+ {
257
+ outputParser: { parse },
258
+ commandRunner: { run },
259
+ workerResponseTimeoutMs: 2222,
260
+ },
261
+ );
262
+
263
+ const session = await provider.createSession('planner', 'feature-a', 'prompt');
264
+ const result = await provider.runWorker({
265
+ role: 'planner',
266
+ feature_id: 'feature-a',
267
+ instructions: 'do work',
268
+ });
269
+
270
+ expect(result).toMatchObject({
271
+ role: 'planner',
272
+ feature_id: 'feature-a',
273
+ });
274
+ expect(run).toHaveBeenCalledTimes(1);
275
+ const firstCall = run.mock.calls.at(0);
276
+ expect(firstCall).toBeDefined();
277
+ expect(firstCall?.[0]).toBe('codex');
278
+ expect(firstCall?.[1]).toContain(session.session_id);
279
+ const options = firstCall?.[2] as
280
+ | { stdin?: string; timeoutMs?: number; env?: NodeJS.ProcessEnv }
281
+ | undefined;
282
+ expect(options.timeoutMs).toBe(2222);
283
+ expect(options.env?.CODEX_TOKEN).toBe('secret');
284
+ expect(parse).toHaveBeenCalledTimes(1);
285
+ });
286
+
287
+ it('GIVEN_nonzero_run_exit_WHEN_runWorker_THEN_throws_runtime_unavailable', async () => {
288
+ const provider = new CliWorkerProvider(makeSelection('codex'), {
289
+ outputParser: new GenericCliOutputParser(),
290
+ commandRunner: {
291
+ run: vi.fn(async () => ({
292
+ exitCode: 2,
293
+ signal: null,
294
+ stderr: 'failed',
295
+ })),
296
+ },
297
+ workerResponseTimeoutMs: 1000,
298
+ });
299
+ await expect(
300
+ provider.runWorker({
301
+ role: 'builder',
302
+ feature_id: 'feature-a',
303
+ }),
304
+ ).rejects.toMatchObject({
305
+ code: ERROR_CODES.PROVIDER_RUNTIME_UNAVAILABLE,
306
+ details: { exit_code: 2 },
307
+ });
308
+ });
309
+
310
+ it('GIVEN_attach_and_send_templates_WHEN_commands_succeed_THEN_methods_are_available', async () => {
311
+ const run = vi.fn(
312
+ async (
313
+ _command: string,
314
+ _args: string[],
315
+ _options?: Record<string, unknown>,
316
+ ): Promise<ProviderCommandResult> => ({
317
+ exitCode: 0,
318
+ signal: null,
319
+ stdout: '{}',
320
+ }),
321
+ );
322
+ const provider = new CliWorkerProvider(
323
+ makeSelection('custom', {
324
+ agent_config: {
325
+ run: {
326
+ command: 'worker-cli',
327
+ args: ['run', '{session_id}', '{prompt}'],
328
+ },
329
+ attach_command: 'worker-cli',
330
+ attach_args: ['attach', '{session_id}'],
331
+ send: {
332
+ command: 'worker-cli',
333
+ args: ['send', '{session_id}', '{message}'],
334
+ },
335
+ },
336
+ }),
337
+ {
338
+ outputParser: new GenericCliOutputParser(),
339
+ commandRunner: { run },
340
+ workerResponseTimeoutMs: 1000,
341
+ },
342
+ );
343
+
344
+ expect(provider.attachToSession).toBeTypeOf('function');
345
+ expect(provider.sendMessage).toBeTypeOf('function');
346
+ expect(provider.getSessionInfo).toBeTypeOf('function');
347
+
348
+ await provider.attachToSession?.('session-a');
349
+ await provider.sendMessage?.('session-a', 'hello');
350
+ const info = await provider.getSessionInfo?.('session-a');
351
+ const unknownInfo = await provider.getSessionInfo?.('unknown');
352
+
353
+ expect(info).toEqual({ active: true, provider: 'custom' });
354
+ expect(unknownInfo).toEqual({ active: false, provider: 'custom' });
355
+
356
+ const attachCall = run.mock.calls.at(0);
357
+ const attachOptions = attachCall?.[2] as
358
+ | { interactive?: boolean; timeoutMs?: number }
359
+ | undefined;
360
+ expect(attachOptions?.interactive).toBe(true);
361
+ const sendCall = run.mock.calls.at(1);
362
+ const sendOptions = sendCall?.[2] as { interactive?: boolean; timeoutMs?: number } | undefined;
363
+ expect(sendOptions?.timeoutMs).toBe(15_000);
364
+ });
365
+
366
+ it('GIVEN_attach_command_not_found_WHEN_attach_called_THEN_throws_unsupported_provider', async () => {
367
+ const provider = new CliWorkerProvider(
368
+ makeSelection('custom', {
369
+ agent_config: {
370
+ run: { command: 'worker-cli', args: ['run', '{session_id}', '{prompt}'] },
371
+ attach: { command: 'worker-cli', args: ['attach', '{session_id}'] },
372
+ },
373
+ }),
374
+ {
375
+ outputParser: new GenericCliOutputParser(),
376
+ commandRunner: {
377
+ run: vi.fn(async () => ({
378
+ exitCode: 127,
379
+ signal: null,
380
+ errorCode: 'ENOENT',
381
+ })),
382
+ },
383
+ workerResponseTimeoutMs: 1000,
384
+ },
385
+ );
386
+
387
+ await expect(provider.attachToSession?.('session-a')).rejects.toMatchObject({
388
+ code: ERROR_CODES.UNSUPPORTED_AGENT_PROVIDER,
389
+ });
390
+ });
391
+
392
+ it('GIVEN_send_command_general_failure_WHEN_send_called_THEN_throws_internal_error', async () => {
393
+ const provider = new CliWorkerProvider(
394
+ makeSelection('custom', {
395
+ agent_config: {
396
+ run: { command: 'worker-cli', args: ['run', '{session_id}', '{prompt}'] },
397
+ send_command: 'worker-cli',
398
+ send_args: ['send', '{session_id}', '{message}'],
399
+ },
400
+ }),
401
+ {
402
+ outputParser: new GenericCliOutputParser(),
403
+ commandRunner: {
404
+ run: vi.fn(async () => ({
405
+ exitCode: 1,
406
+ signal: null,
407
+ errorCode: 'EFAIL',
408
+ })),
409
+ },
410
+ workerResponseTimeoutMs: 1000,
411
+ },
412
+ );
413
+
414
+ await expect(provider.sendMessage?.('session-a', 'msg')).rejects.toMatchObject({
415
+ code: ERROR_CODES.INTERNAL_ERROR,
416
+ });
417
+ });
418
+
419
+ it('GIVEN_session_lifecycle_WHEN_created_reattached_closed_THEN_session_state_is_consistent', async () => {
420
+ const provider = new CliWorkerProvider(makeSelection('codex'), {
421
+ outputParser: new GenericCliOutputParser(),
422
+ commandRunner: {
423
+ run: vi.fn(async () => ({
424
+ exitCode: 0,
425
+ signal: null,
426
+ stdout: JSON.stringify({
427
+ outputs: [{ type: 'NOTE', content: 'ok' }],
428
+ }),
429
+ })),
430
+ },
431
+ workerResponseTimeoutMs: 1000,
432
+ });
433
+
434
+ const created = await provider.createSession('builder', 'feature-a', null);
435
+ expect(created.system_prompt_loaded).toBe(false);
436
+ expect(await provider.reattachSession('unknown')).toBeNull();
437
+ expect(await provider.reattachSession('session-b')).toMatchObject({ session_id: 'session-b' });
438
+ expect(await provider.closeSession(created.session_id)).toEqual({ closed: true });
439
+ });
440
+ });
@@ -0,0 +1,151 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { ERROR_CODES } from '../src/core/error-codes.js';
3
+ import { ApiWorkerProvider } from '../src/providers/api-worker-provider.js';
4
+ import { CliWorkerProvider } from '../src/providers/cli-worker-provider.js';
5
+ import { NullWorkerProvider, type ProviderSelection } from '../src/providers/providers.js';
6
+ import {
7
+ DefaultWorkerProviderFactory,
8
+ resolveMalformedWorkerOutputAction,
9
+ resolveNoProgressAction,
10
+ resolveWorkerProviderMode,
11
+ resolveWorkerProviderPolicy,
12
+ resolveWorkerProviderRuntime,
13
+ } from '../src/providers/worker-provider-factory.js';
14
+
15
+ function selection(provider: string): ProviderSelection {
16
+ return {
17
+ provider,
18
+ model: `${provider}-model`,
19
+ provider_config_env: null,
20
+ provider_config_ref: null,
21
+ agent_config: null,
22
+ };
23
+ }
24
+
25
+ describe('worker-provider-factory resolvers', () => {
26
+ it('GIVEN_cli_and_config_modes_WHEN_resolving_mode_THEN_cli_wins_then_config_then_fallback', () => {
27
+ expect(resolveWorkerProviderMode('live', 'stub', 'stub')).toBe('live');
28
+ expect(resolveWorkerProviderMode(undefined, 'stub', 'live')).toBe('stub');
29
+ expect(resolveWorkerProviderMode('invalid', 'invalid', 'stub')).toBe('stub');
30
+ });
31
+
32
+ it('GIVEN_invalid_runtime_values_WHEN_resolving_runtime_THEN_defaults_are_used', () => {
33
+ const runtime = resolveWorkerProviderRuntime({
34
+ worker_response_timeout_ms: 0,
35
+ max_consecutive_no_progress_iterations: -2,
36
+ });
37
+ expect(runtime.worker_response_timeout_ms).toBe(120_000);
38
+ expect(runtime.max_consecutive_no_progress_iterations).toBe(2);
39
+ });
40
+
41
+ it('GIVEN_numeric_runtime_values_WHEN_resolving_runtime_THEN_values_are_floored', () => {
42
+ const runtime = resolveWorkerProviderRuntime({
43
+ worker_response_timeout_ms: 4500.9,
44
+ max_consecutive_no_progress_iterations: 3.8,
45
+ });
46
+ expect(runtime.worker_response_timeout_ms).toBe(4500);
47
+ expect(runtime.max_consecutive_no_progress_iterations).toBe(3);
48
+ });
49
+
50
+ it('GIVEN_policy_input_WHEN_resolving_policy_and_actions_THEN_defaults_and_fail_run_are_supported', () => {
51
+ expect(resolveWorkerProviderPolicy(undefined).require_live_provider_for_run).toBe(true);
52
+ expect(
53
+ resolveWorkerProviderPolicy({ require_live_provider_for_run: false })
54
+ .require_live_provider_for_run,
55
+ ).toBe(false);
56
+ expect(resolveMalformedWorkerOutputAction(undefined)).toBe('block_feature');
57
+ expect(resolveMalformedWorkerOutputAction({ malformed_worker_output_action: 'fail_run' })).toBe(
58
+ 'fail_run',
59
+ );
60
+ expect(resolveNoProgressAction(undefined)).toBe('block_feature');
61
+ expect(resolveNoProgressAction({ no_progress_action: 'fail_run' })).toBe('fail_run');
62
+ });
63
+ });
64
+
65
+ describe('DefaultWorkerProviderFactory', () => {
66
+ const factory = new DefaultWorkerProviderFactory();
67
+ const runtime = {
68
+ worker_response_timeout_ms: 2000,
69
+ max_consecutive_no_progress_iterations: 2,
70
+ };
71
+ const policy = { require_live_provider_for_run: true };
72
+
73
+ it('GIVEN_unsupported_provider_WHEN_create_called_THEN_throws_unsupported_provider', () => {
74
+ try {
75
+ factory.create({
76
+ selection: selection('bogus-provider'),
77
+ mode: 'live',
78
+ context: 'run',
79
+ policy,
80
+ runtime,
81
+ });
82
+ throw new Error('expected factory to throw');
83
+ } catch (error) {
84
+ expect(error).toMatchObject({ code: ERROR_CODES.UNSUPPORTED_AGENT_PROVIDER });
85
+ }
86
+ });
87
+
88
+ it('GIVEN_stub_mode_for_run_with_live_required_WHEN_create_called_THEN_throws_stub_disallowed', () => {
89
+ try {
90
+ factory.create({
91
+ selection: selection('custom'),
92
+ mode: 'stub',
93
+ context: 'run',
94
+ policy: { require_live_provider_for_run: true },
95
+ runtime,
96
+ });
97
+ throw new Error('expected factory to throw');
98
+ } catch (error) {
99
+ expect(error).toMatchObject({ code: ERROR_CODES.PROVIDER_STUB_DISALLOWED });
100
+ }
101
+ });
102
+
103
+ it('GIVEN_stub_mode_for_attach_WHEN_create_called_THEN_returns_null_worker_provider', () => {
104
+ const provider = factory.create({
105
+ selection: selection('custom'),
106
+ mode: 'stub',
107
+ context: 'attach',
108
+ policy: { require_live_provider_for_run: true },
109
+ runtime,
110
+ });
111
+ expect(provider).toBeInstanceOf(NullWorkerProvider);
112
+ expect(provider.mode).toBe('stub');
113
+ });
114
+
115
+ it('GIVEN_live_gemini_provider_WHEN_create_called_THEN_returns_api_worker_provider', () => {
116
+ const provider = factory.create({
117
+ selection: {
118
+ ...selection('gemini'),
119
+ provider_config_ref: 'token',
120
+ },
121
+ mode: 'live',
122
+ context: 'run',
123
+ policy,
124
+ runtime,
125
+ });
126
+ expect(provider).toBeInstanceOf(ApiWorkerProvider);
127
+ expect(provider.mode).toBe('live');
128
+ });
129
+
130
+ it('GIVEN_live_codex_provider_WHEN_create_called_THEN_returns_cli_worker_provider', () => {
131
+ const provider = factory.create({
132
+ selection: selection('codex'),
133
+ mode: 'live',
134
+ context: 'run',
135
+ policy,
136
+ runtime,
137
+ });
138
+ expect(provider).toBeInstanceOf(CliWorkerProvider);
139
+ });
140
+
141
+ it('GIVEN_live_custom_provider_WHEN_create_called_THEN_returns_cli_worker_provider', () => {
142
+ const provider = factory.create({
143
+ selection: selection('custom'),
144
+ mode: 'live',
145
+ context: 'send',
146
+ policy,
147
+ runtime,
148
+ });
149
+ expect(provider).toBeInstanceOf(CliWorkerProvider);
150
+ });
151
+ });
@@ -10,4 +10,7 @@ missing_prompt_behavior: ignore
10
10
  runtime:
11
11
  default_provider: claude
12
12
  default_model: local-default
13
+ worker_provider_mode: live
14
+ worker_response_timeout_ms: 120000
15
+ max_consecutive_no_progress_iterations: 2
13
16
  role_provider_overrides: {}
@@ -94,6 +94,13 @@ export class CliArgumentParser {
94
94
  index += 1;
95
95
  continue;
96
96
  }
97
+ if (token === '--worker-provider-mode') {
98
+ if (next === 'live' || next === 'stub') {
99
+ options.worker_provider_mode = next;
100
+ index += 1;
101
+ }
102
+ continue;
103
+ }
97
104
  if (token === '--transport') {
98
105
  options.transport = next;
99
106
  index += 1;
@@ -1 +1 @@
1
- {"version":3,"file":"cli-argument-parser.js","sourceRoot":"","sources":["../../../../apps/control-plane/src/cli/cli-argument-parser.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli-argument-parser.js","sourceRoot":"","sources":["../../../../apps/control-plane/src/cli/cli-argument-parser.ts"],"names":[],"mappings":"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"}
@@ -20,6 +20,10 @@ const COMMAND_HELP = {
20
20
  flag: '--provider-config-env <var>',
21
21
  description: 'Env var name used for API-backed provider auth/config',
22
22
  },
23
+ {
24
+ flag: '--worker-provider-mode <live|stub>',
25
+ description: 'Worker execution mode override (default: live for run/resume)',
26
+ },
23
27
  { flag: '--transport <inprocess|mcp>', description: 'Tool transport layer (default: mcp)' },
24
28
  { flag: '--takeover-stale-run', description: 'Take over a stale run lease' },
25
29
  { flag: '--project <name>', description: 'Select project from multi-project.yaml' },
@@ -40,6 +44,10 @@ const COMMAND_HELP = {
40
44
  flags: [
41
45
  { flag: '--feature-id <id>', description: 'Resume a specific feature' },
42
46
  { flag: '--force', description: 'Force-resume even if the feature is not blocked' },
47
+ {
48
+ flag: '--worker-provider-mode <live|stub>',
49
+ description: 'Worker execution mode override (default: live)',
50
+ },
43
51
  { flag: '--transport <inprocess|mcp>', description: 'Tool transport layer (default: mcp)' },
44
52
  ],
45
53
  },