@the-open-engine/zeroshot 6.18.0 → 6.20.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.
Files changed (34) hide show
  1. package/cli/index.js +2 -1
  2. package/lib/agent-cli-provider/omp-release.d.ts +15 -0
  3. package/lib/agent-cli-provider/omp-release.d.ts.map +1 -0
  4. package/lib/agent-cli-provider/omp-release.js +50 -0
  5. package/lib/agent-cli-provider/omp-release.js.map +1 -0
  6. package/lib/agent-cli-provider/omp-rpc-protocol.d.ts +38 -0
  7. package/lib/agent-cli-provider/omp-rpc-protocol.d.ts.map +1 -0
  8. package/lib/agent-cli-provider/omp-rpc-protocol.js +267 -0
  9. package/lib/agent-cli-provider/omp-rpc-protocol.js.map +1 -0
  10. package/lib/agent-cli-provider/provider-registry.d.ts +16 -1
  11. package/lib/agent-cli-provider/provider-registry.d.ts.map +1 -1
  12. package/lib/agent-cli-provider/provider-registry.js +25 -1
  13. package/lib/agent-cli-provider/provider-registry.js.map +1 -1
  14. package/lib/agent-cli-provider/single-agent-runtime.d.ts.map +1 -1
  15. package/lib/agent-cli-provider/single-agent-runtime.js +1 -1
  16. package/lib/agent-cli-provider/single-agent-runtime.js.map +1 -1
  17. package/lib/provider-names.js +5 -0
  18. package/lib/settings.js +6 -3
  19. package/lib/setup-plan.js +5 -5
  20. package/lib/start-cluster.js +3 -3
  21. package/package.json +1 -1
  22. package/src/agent/agent-lifecycle.js +4 -4
  23. package/src/agent/agent-task-executor.js +7 -6
  24. package/src/agent/pr-verification.js +4 -1
  25. package/src/agent-cli-provider/omp-release.ts +63 -0
  26. package/src/agent-cli-provider/omp-rpc-protocol.ts +396 -0
  27. package/src/agent-cli-provider/provider-registry.ts +29 -1
  28. package/src/agent-cli-provider/single-agent-runtime.ts +2 -1
  29. package/src/agent-wrapper.js +3 -3
  30. package/src/claude-task-runner.js +5 -3
  31. package/src/config-validator.js +3 -2
  32. package/src/isolation-manager.js +6 -2
  33. package/src/orchestrator.js +3 -3
  34. package/src/preflight.js +2 -1
@@ -0,0 +1,396 @@
1
+ import { getNumber, getString, isRecord } from './json';
2
+ import { OMP_SUPPORTED_VERSION } from './omp-release';
3
+
4
+ // Purely for traceability/doc; no runtime coupling to omp-release's spawn/install concerns.
5
+ export const OMP_RPC_CONTRACT_RELEASE = OMP_SUPPORTED_VERSION;
6
+
7
+ export interface OmpRpcDecoderLimits {
8
+ readonly maxPhysicalFrameBytes: number;
9
+ readonly maxReassembledFrameBytes: number;
10
+ readonly maxConcurrentReassemblies: number;
11
+ readonly maxChunksPerFrame: number;
12
+ readonly maxInflightReassemblyBytes: number;
13
+ }
14
+
15
+ // Verified against the pinned OMP release's rpc-frame.ts: MAX_RPC_FRAME_BYTES=1MiB, MAX_RPC_REASSEMBLED_BYTES=64MiB,
16
+ // RPC_CHUNK_PAYLOAD_BYTES=256KiB -> ceil(64MiB/256KiB)=256 chunks max. The real decoder tracks exactly one
17
+ // pending sequence at a time, so maxConcurrentReassemblies/maxInflightReassemblyBytes mirror that ceiling.
18
+ export const DEFAULT_OMP_RPC_DECODER_LIMITS: OmpRpcDecoderLimits = {
19
+ maxPhysicalFrameBytes: 1024 * 1024,
20
+ maxReassembledFrameBytes: 64 * 1024 * 1024,
21
+ maxConcurrentReassemblies: 1,
22
+ maxChunksPerFrame: 256,
23
+ maxInflightReassemblyBytes: 64 * 1024 * 1024,
24
+ };
25
+
26
+ export interface OmpRpcInboundFrame {
27
+ readonly type: string;
28
+ readonly [key: string]: unknown;
29
+ }
30
+
31
+ export interface OmpRpcCommand {
32
+ readonly id?: string;
33
+ readonly type: string;
34
+ readonly [key: string]: unknown;
35
+ }
36
+
37
+ export class OmpRpcProtocolError extends Error {
38
+ readonly code: string;
39
+
40
+ constructor(code: string, message: string) {
41
+ super(message);
42
+ this.name = 'OmpRpcProtocolError';
43
+ this.code = code;
44
+ }
45
+ }
46
+
47
+ const KNOWN_PRE_NEGOTIATION_FRAME_TYPES: ReadonlySet<string> = new Set([
48
+ 'ready',
49
+ 'available_commands_update',
50
+ 'response',
51
+ 'extension_error',
52
+ 'agent_start',
53
+ 'agent_end',
54
+ 'turn_start',
55
+ 'turn_end',
56
+ 'message_start',
57
+ 'message_update',
58
+ 'message_end',
59
+ 'tool_execution_start',
60
+ 'tool_execution_update',
61
+ 'tool_execution_end',
62
+ 'auto_compaction_start',
63
+ 'auto_compaction_end',
64
+ 'auto_retry_start',
65
+ 'auto_retry_end',
66
+ 'ttsr_triggered',
67
+ 'todo_reminder',
68
+ 'todo_auto_clear',
69
+ 'extension_ui_request',
70
+ 'host_tool_call',
71
+ 'host_tool_cancel',
72
+ 'host_uri_request',
73
+ 'host_uri_cancel',
74
+ 'prompt_result',
75
+ 'command_output',
76
+ 'session_info_update',
77
+ 'config_update',
78
+ 'subagent_lifecycle',
79
+ 'subagent_progress',
80
+ 'subagent_event',
81
+ ]);
82
+
83
+ export function classifyOmpRpcFrameType(
84
+ type: string
85
+ ): 'known-pre-negotiation' | 'v2-only' | 'unknown' {
86
+ if (type === 'rpc_chunk') return 'v2-only';
87
+ if (KNOWN_PRE_NEGOTIATION_FRAME_TYPES.has(type)) return 'known-pre-negotiation';
88
+ return 'unknown';
89
+ }
90
+
91
+ export function assertNoPreNegotiationRpcChunk(frameType: string, negotiatedV2: boolean): void {
92
+ if (frameType === 'rpc_chunk' && !negotiatedV2) {
93
+ throw new OmpRpcProtocolError(
94
+ 'pre-negotiation-rpc-chunk',
95
+ 'rpc_chunk frame received before protocol v2 negotiation succeeded.'
96
+ );
97
+ }
98
+ }
99
+
100
+ const STRICT_BASE64_PATTERN = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
101
+
102
+ function decodeStrictBase64(data: unknown): Buffer {
103
+ if (typeof data !== 'string' || data.length === 0 || !STRICT_BASE64_PATTERN.test(data)) {
104
+ throw new OmpRpcProtocolError(
105
+ 'invalid-chunk-data',
106
+ "rpc_chunk 'data' must be a non-empty, canonically-padded base64 string."
107
+ );
108
+ }
109
+ const bytes = Buffer.from(data, 'base64');
110
+ if (bytes.toString('base64') !== data) {
111
+ throw new OmpRpcProtocolError(
112
+ 'invalid-chunk-data',
113
+ "rpc_chunk 'data' failed a base64 round-trip check (non-canonical encoding)."
114
+ );
115
+ }
116
+ return bytes;
117
+ }
118
+
119
+ function decodeStrictUtf8(bytes: Buffer): string {
120
+ try {
121
+ return new TextDecoder('utf-8', { fatal: true }).decode(bytes);
122
+ } catch {
123
+ throw new OmpRpcProtocolError(
124
+ 'invalid-utf8-in-reassembled-frame',
125
+ 'Reassembled rpc_chunk sequence is not valid UTF-8.'
126
+ );
127
+ }
128
+ }
129
+
130
+ function toPhysicalFrame(record: Record<string, unknown>): OmpRpcInboundFrame {
131
+ const type = getString(record, 'type');
132
+ if (type === null) {
133
+ throw new OmpRpcProtocolError(
134
+ 'malformed-physical-frame',
135
+ "Physical frame is missing a string 'type' field."
136
+ );
137
+ }
138
+ return { ...record, type };
139
+ }
140
+
141
+ function toReassembledFrame(record: Record<string, unknown>, chunkId: string): OmpRpcInboundFrame {
142
+ const type = getString(record, 'type');
143
+ if (type === null) {
144
+ throw new OmpRpcProtocolError(
145
+ 'malformed-json-in-reassembled-frame',
146
+ `rpc_chunk sequence "${chunkId}" reassembled into an object missing a string 'type' field.`
147
+ );
148
+ }
149
+ return { ...record, type };
150
+ }
151
+
152
+ interface ChunkMetadata {
153
+ readonly chunkId: string;
154
+ readonly index: number;
155
+ readonly count: number;
156
+ readonly byteLength: number;
157
+ }
158
+
159
+ function readChunkMetadata(
160
+ parsed: Record<string, unknown>,
161
+ limits: OmpRpcDecoderLimits
162
+ ): ChunkMetadata {
163
+ const chunkId = getString(parsed, 'chunkId');
164
+ if (chunkId === null || chunkId.length === 0 || chunkId.length > 128) {
165
+ throw new OmpRpcProtocolError(
166
+ 'invalid-chunk-metadata',
167
+ "rpc_chunk 'chunkId' must be a non-empty string of at most 128 characters."
168
+ );
169
+ }
170
+
171
+ const index = getNumber(parsed, 'index');
172
+ const count = getNumber(parsed, 'count');
173
+ const byteLength = getNumber(parsed, 'byteLength');
174
+ if (
175
+ index === null ||
176
+ !Number.isSafeInteger(index) ||
177
+ index < 0 ||
178
+ count === null ||
179
+ !Number.isSafeInteger(count) ||
180
+ count < 2 ||
181
+ count > limits.maxChunksPerFrame ||
182
+ index >= count ||
183
+ byteLength === null ||
184
+ !Number.isSafeInteger(byteLength) ||
185
+ byteLength <= 0 ||
186
+ byteLength > limits.maxReassembledFrameBytes
187
+ ) {
188
+ throw new OmpRpcProtocolError(
189
+ 'invalid-chunk-metadata',
190
+ "rpc_chunk has invalid 'index'/'count'/'byteLength' metadata."
191
+ );
192
+ }
193
+
194
+ return { chunkId, index, count, byteLength };
195
+ }
196
+
197
+ interface PendingReassembly {
198
+ readonly chunkId: string;
199
+ readonly count: number;
200
+ readonly byteLength: number;
201
+ nextIndex: number;
202
+ readonly chunks: Buffer[];
203
+ receivedBytes: number;
204
+ }
205
+
206
+ export class OmpRpcFrameDecoder {
207
+ private readonly limits: OmpRpcDecoderLimits;
208
+ private buffer: Buffer;
209
+ private finished: boolean;
210
+ private readonly pendingReassemblies: Map<string, PendingReassembly>;
211
+ private inflightReassemblyBytes: number;
212
+
213
+ constructor(limits: OmpRpcDecoderLimits) {
214
+ this.limits = limits;
215
+ this.buffer = Buffer.alloc(0);
216
+ this.finished = false;
217
+ this.pendingReassemblies = new Map();
218
+ this.inflightReassemblyBytes = 0;
219
+ }
220
+
221
+ push(chunk: Uint8Array): readonly OmpRpcInboundFrame[] {
222
+ if (this.finished) {
223
+ throw new OmpRpcProtocolError('decoder-finished', 'push() called after finish().');
224
+ }
225
+
226
+ this.buffer = Buffer.concat([this.buffer, Buffer.from(chunk)]);
227
+ const frames: OmpRpcInboundFrame[] = [];
228
+
229
+ for (;;) {
230
+ const newlineIndex = this.buffer.indexOf(0x0a);
231
+ if (newlineIndex === -1) {
232
+ if (this.buffer.byteLength > this.limits.maxPhysicalFrameBytes) {
233
+ throw new OmpRpcProtocolError(
234
+ 'physical-frame-too-large',
235
+ `Buffered physical frame exceeds the ${this.limits.maxPhysicalFrameBytes}-byte limit without a terminating newline.`
236
+ );
237
+ }
238
+ break;
239
+ }
240
+
241
+ const lineBytes = this.buffer.subarray(0, newlineIndex);
242
+ this.buffer = this.buffer.subarray(newlineIndex + 1);
243
+ if (lineBytes.byteLength + 1 > this.limits.maxPhysicalFrameBytes) {
244
+ throw new OmpRpcProtocolError(
245
+ 'physical-frame-too-large',
246
+ `Physical frame of ${lineBytes.byteLength + 1} bytes exceeds the ${this.limits.maxPhysicalFrameBytes}-byte limit.`
247
+ );
248
+ }
249
+
250
+ const frame = this.consumeLine(lineBytes);
251
+ if (frame !== null) frames.push(frame);
252
+ }
253
+
254
+ return frames;
255
+ }
256
+
257
+ finish(): void {
258
+ this.finished = true;
259
+ if (this.buffer.byteLength > 0) {
260
+ throw new OmpRpcProtocolError(
261
+ 'incomplete-physical-frame',
262
+ 'Stream ended with an unterminated physical frame (no trailing newline).'
263
+ );
264
+ }
265
+ if (this.pendingReassemblies.size > 0) {
266
+ throw new OmpRpcProtocolError(
267
+ 'incomplete-chunk-sequence',
268
+ 'Stream ended with an incomplete rpc_chunk sequence still pending.'
269
+ );
270
+ }
271
+ }
272
+
273
+ private consumeLine(lineBytes: Buffer): OmpRpcInboundFrame | null {
274
+ let value: unknown;
275
+ try {
276
+ value = JSON.parse(lineBytes.toString('utf8'));
277
+ } catch {
278
+ throw new OmpRpcProtocolError('malformed-physical-frame', 'Physical frame is not valid JSON.');
279
+ }
280
+ if (!isRecord(value)) {
281
+ throw new OmpRpcProtocolError(
282
+ 'malformed-physical-frame',
283
+ 'Physical frame must be a JSON object.'
284
+ );
285
+ }
286
+
287
+ const type = getString(value, 'type');
288
+ if (type !== 'rpc_chunk') {
289
+ if (this.pendingReassemblies.size > 0) {
290
+ throw new OmpRpcProtocolError(
291
+ 'interrupted-chunk-sequence',
292
+ 'A non-chunk frame arrived while an rpc_chunk sequence was pending.'
293
+ );
294
+ }
295
+ return toPhysicalFrame(value);
296
+ }
297
+
298
+ return this.consumeChunk(value);
299
+ }
300
+
301
+ private consumeChunk(parsed: Record<string, unknown>): OmpRpcInboundFrame | null {
302
+ const metadata = readChunkMetadata(parsed, this.limits);
303
+ const bytes = decodeStrictBase64(parsed.data);
304
+
305
+ let pending = this.pendingReassemblies.get(metadata.chunkId);
306
+ if (pending === undefined) {
307
+ if (metadata.index !== 0) {
308
+ throw new OmpRpcProtocolError(
309
+ 'chunk-sequence-must-start-at-zero',
310
+ `rpc_chunk sequence "${metadata.chunkId}" must begin at index 0.`
311
+ );
312
+ }
313
+ if (this.pendingReassemblies.size >= this.limits.maxConcurrentReassemblies) {
314
+ throw new OmpRpcProtocolError(
315
+ 'interleaved-chunk-sequence',
316
+ `Starting rpc_chunk sequence "${metadata.chunkId}" would exceed the concurrent-reassembly limit of ${this.limits.maxConcurrentReassemblies}.`
317
+ );
318
+ }
319
+ pending = {
320
+ chunkId: metadata.chunkId,
321
+ count: metadata.count,
322
+ byteLength: metadata.byteLength,
323
+ nextIndex: 0,
324
+ chunks: [],
325
+ receivedBytes: 0,
326
+ };
327
+ this.pendingReassemblies.set(metadata.chunkId, pending);
328
+ } else if (
329
+ pending.count !== metadata.count ||
330
+ pending.byteLength !== metadata.byteLength ||
331
+ pending.nextIndex !== metadata.index
332
+ ) {
333
+ throw new OmpRpcProtocolError(
334
+ 'chunk-sequence-mismatch',
335
+ `rpc_chunk sequence "${metadata.chunkId}" metadata or ordering does not match the tracked sequence.`
336
+ );
337
+ }
338
+
339
+ pending.chunks.push(bytes);
340
+ pending.receivedBytes += bytes.byteLength;
341
+ this.inflightReassemblyBytes += bytes.byteLength;
342
+ if (this.inflightReassemblyBytes > this.limits.maxInflightReassemblyBytes) {
343
+ throw new OmpRpcProtocolError(
344
+ 'inflight-reassembly-bytes-exceeded',
345
+ `Total in-flight rpc_chunk reassembly bytes exceed the ${this.limits.maxInflightReassemblyBytes}-byte limit.`
346
+ );
347
+ }
348
+ if (pending.receivedBytes > pending.byteLength) {
349
+ throw new OmpRpcProtocolError(
350
+ 'chunk-sequence-exceeds-declared-length',
351
+ `rpc_chunk sequence "${metadata.chunkId}" received more bytes than its declared byteLength.`
352
+ );
353
+ }
354
+ pending.nextIndex += 1;
355
+ if (pending.nextIndex < pending.count) return null;
356
+
357
+ this.pendingReassemblies.delete(metadata.chunkId);
358
+ this.inflightReassemblyBytes -= pending.receivedBytes;
359
+ if (pending.receivedBytes !== pending.byteLength) {
360
+ throw new OmpRpcProtocolError(
361
+ 'chunk-sequence-length-mismatch',
362
+ `rpc_chunk sequence "${metadata.chunkId}" completed with ${pending.receivedBytes} bytes but declared ${pending.byteLength}.`
363
+ );
364
+ }
365
+
366
+ const decodedText = decodeStrictUtf8(Buffer.concat(pending.chunks));
367
+ let reassembled: unknown;
368
+ try {
369
+ reassembled = JSON.parse(decodedText);
370
+ } catch {
371
+ throw new OmpRpcProtocolError(
372
+ 'malformed-json-in-reassembled-frame',
373
+ `rpc_chunk sequence "${metadata.chunkId}" reassembled into invalid JSON.`
374
+ );
375
+ }
376
+ if (!isRecord(reassembled)) {
377
+ throw new OmpRpcProtocolError(
378
+ 'non-object-reassembled-frame',
379
+ `rpc_chunk sequence "${metadata.chunkId}" reassembled into a non-object JSON value.`
380
+ );
381
+ }
382
+ return toReassembledFrame(reassembled, metadata.chunkId);
383
+ }
384
+ }
385
+
386
+ export function encodeOmpRpcCommand(command: OmpRpcCommand, maxFrameBytes: number): Buffer {
387
+ const line = `${JSON.stringify(command)}\n`;
388
+ const byteLength = Buffer.byteLength(line, 'utf8');
389
+ if (byteLength > maxFrameBytes) {
390
+ throw new OmpRpcProtocolError(
391
+ 'outbound-frame-too-large',
392
+ `Outbound command of ${byteLength} bytes exceeds the ${maxFrameBytes}-byte limit.`
393
+ );
394
+ }
395
+ return Buffer.from(line, 'utf8');
396
+ }
@@ -8,6 +8,7 @@ import { opencodeAdapter } from './adapters/opencode';
8
8
  import { ompAdapter } from './adapters/omp';
9
9
  import { piAdapter } from './adapters/pi';
10
10
  import { resolveClaudeCommand } from './claude-command';
11
+ import { OMP_INSTALL_COMMAND } from './omp-release';
11
12
  import type { ModelLevel, ProviderAdapter, StructuredOutputRecoveryAdapter } from './types';
12
13
 
13
14
  export type ProviderCapabilityState = boolean | 'experimental';
@@ -71,6 +72,7 @@ export interface ProviderDockerMetadata {
71
72
 
72
73
  interface ProviderRegistryEntryBase {
73
74
  readonly id: string;
75
+ readonly default: boolean;
74
76
  readonly aliases: readonly string[];
75
77
  readonly displayName: string;
76
78
  readonly binary: string;
@@ -176,6 +178,7 @@ const kiroAdapter = createAcpAdapter({
176
178
  export const providerRegistry = [
177
179
  {
178
180
  id: 'claude',
181
+ default: true,
179
182
  aliases: ['anthropic'],
180
183
  displayName: 'Claude',
181
184
  binary: 'claude',
@@ -214,6 +217,7 @@ export const providerRegistry = [
214
217
  },
215
218
  {
216
219
  id: 'codex',
220
+ default: false,
217
221
  aliases: ['openai'],
218
222
  displayName: 'Codex',
219
223
  binary: 'codex',
@@ -255,6 +259,7 @@ export const providerRegistry = [
255
259
  },
256
260
  {
257
261
  id: 'gateway',
262
+ default: false,
258
263
  aliases: [],
259
264
  displayName: 'Gateway',
260
265
  binary: 'node',
@@ -303,6 +308,7 @@ export const providerRegistry = [
303
308
  },
304
309
  {
305
310
  id: 'gemini',
311
+ default: false,
306
312
  aliases: ['google'],
307
313
  displayName: 'Gemini',
308
314
  binary: 'gemini',
@@ -340,6 +346,7 @@ export const providerRegistry = [
340
346
  },
341
347
  {
342
348
  id: 'opencode',
349
+ default: false,
343
350
  aliases: [],
344
351
  displayName: 'Opencode',
345
352
  binary: 'opencode',
@@ -380,6 +387,7 @@ export const providerRegistry = [
380
387
  },
381
388
  {
382
389
  id: 'pi',
390
+ default: false,
383
391
  aliases: [],
384
392
  displayName: 'Pi',
385
393
  binary: 'pi',
@@ -419,12 +427,13 @@ export const providerRegistry = [
419
427
  },
420
428
  {
421
429
  id: 'omp',
430
+ default: false,
422
431
  aliases: [],
423
432
  displayName: 'OMP',
424
433
  binary: 'omp',
425
434
  command: { kind: 'fixed', command: 'omp', args: [] },
426
435
  invoke: SPAWN_INVOKE,
427
- installInstructions: 'npm install -g --ignore-scripts @oh-my-pi/pi-coding-agent',
436
+ installInstructions: OMP_INSTALL_COMMAND,
428
437
  authInstructions: 'omp\n/login',
429
438
  credentialPaths: ['~/.omp'],
430
439
  credentialEnvKeys: ompAdapter.credentialEnvKeys,
@@ -457,6 +466,7 @@ export const providerRegistry = [
457
466
  },
458
467
  {
459
468
  id: 'kiro',
469
+ default: false,
460
470
  aliases: [],
461
471
  displayName: 'Kiro',
462
472
  binary: 'kiro-cli',
@@ -494,6 +504,7 @@ export const providerRegistry = [
494
504
  },
495
505
  {
496
506
  id: 'copilot',
507
+ default: false,
497
508
  aliases: [],
498
509
  displayName: 'Copilot',
499
510
  binary: 'copilot',
@@ -565,6 +576,23 @@ export const providerAliasMap: Readonly<Record<string, RegistryProviderId>> = Ob
565
576
  }, {})
566
577
  );
567
578
 
579
+ export function assertExactlyOneDefaultProvider<T extends { id: string; default: boolean }>(
580
+ entries: readonly T[]
581
+ ): T['id'] {
582
+ const defaults = entries.filter((e) => e.default);
583
+ const [onlyDefault, ...rest] = defaults;
584
+ if (!onlyDefault || rest.length > 0) {
585
+ throw new Error(
586
+ `Provider registry must declare exactly one default provider; found ${defaults.length}${defaults.length ? ' (' + defaults.map((e) => e.id).join(', ') + ')' : ''}`
587
+ );
588
+ }
589
+ return onlyDefault.id;
590
+ }
591
+ const DEFAULT_PROVIDER_ID = assertExactlyOneDefaultProvider(providerRegistry);
592
+ export function getDefaultProviderId(): RegistryProviderId {
593
+ return DEFAULT_PROVIDER_ID;
594
+ }
595
+
568
596
  export function normalizeProviderName(name: string): RegistryProviderId | string {
569
597
  const normalized = name.toLowerCase();
570
598
  return providerAliasMap[normalized] ?? name;
@@ -3,6 +3,7 @@ import { UnsupportedProviderCapabilityError } from './errors';
3
3
  import { normalizeGatewayBuildOptions, resolveGatewayConfiguration } from './gateway-tools';
4
4
  import { isRecord } from './json';
5
5
  import {
6
+ getDefaultProviderId,
6
7
  getProviderRegistryEntry,
7
8
  resolveProviderCommand,
8
9
  supportsProviderCapability,
@@ -414,7 +415,7 @@ function adapterForRuntimeInput(
414
415
  ): ProviderAdapter {
415
416
  const configured =
416
417
  provider ?? optionalString(settings.defaultProvider, 'settings.defaultProvider');
417
- return getProviderAdapter(configured ?? 'claude');
418
+ return getProviderAdapter(configured ?? getDefaultProviderId());
418
419
  }
419
420
 
420
421
  function runtimeProviderSettings(
@@ -13,7 +13,7 @@
13
13
  const LogicEngine = require('./logic-engine');
14
14
  const { validateAgentConfig } = require('./agent/agent-config');
15
15
  const { loadSettings, validateModelAgainstMax, VALID_MODELS } = require('../lib/settings');
16
- const { normalizeProviderName } = require('../lib/provider-names');
16
+ const { normalizeProviderName, getDefaultProviderId } = require('../lib/provider-names');
17
17
  const { getProvider } = require('./providers');
18
18
  const { buildContext } = require('./agent/agent-context-builder');
19
19
  const { collectQueuedGuidance } = require('./agent/guidance-queue');
@@ -160,9 +160,9 @@ class AgentWrapper {
160
160
  this.config.provider ||
161
161
  clusterConfig.defaultProvider ||
162
162
  settings.defaultProvider ||
163
- 'claude';
163
+ getDefaultProviderId();
164
164
 
165
- return normalizeProviderName(resolved) || 'claude';
165
+ return normalizeProviderName(resolved) || getDefaultProviderId();
166
166
  }
167
167
 
168
168
  _resolveModelSpec() {
@@ -9,7 +9,7 @@ const { spawn, spawnSync } = require('child_process');
9
9
  const fs = require('fs');
10
10
  const TaskRunner = require('./task-runner');
11
11
  const { loadSettings } = require('../lib/settings');
12
- const { normalizeProviderName } = require('../lib/provider-names');
12
+ const { normalizeProviderName, getDefaultProviderId } = require('../lib/provider-names');
13
13
  const { getProvider } = require('./providers');
14
14
  const { prependWorktreeToolBinToEnv } = require('./worktree-tooling-env');
15
15
  const { applyDarwinKeychainBoundaryToEnv } = require('./darwin-keychain-boundary');
@@ -200,7 +200,9 @@ class ClaudeTaskRunner extends TaskRunner {
200
200
  } = options;
201
201
 
202
202
  const settings = loadSettings();
203
- const providerName = normalizeProviderName(provider || settings.defaultProvider || 'claude');
203
+ const providerName = normalizeProviderName(
204
+ provider || settings.defaultProvider || getDefaultProviderId()
205
+ );
204
206
  const { providerModule, providerSettings, levelOverrides } = this._getProviderContext(
205
207
  providerName,
206
208
  settings
@@ -736,7 +738,7 @@ class ClaudeTaskRunner extends TaskRunner {
736
738
  rejectCallerSuppliedModelProvenance(options);
737
739
  const {
738
740
  agentId = 'unknown',
739
- provider = 'claude',
741
+ provider = getDefaultProviderId(),
740
742
  model = null,
741
743
  modelLevel = null,
742
744
  modelSpec: explicitModelSpec = null,
@@ -14,6 +14,7 @@
14
14
  const { loadSettings } = require('../lib/settings');
15
15
  const {
16
16
  VALID_PROVIDERS,
17
+ getDefaultProviderId,
17
18
  normalizeProviderName,
18
19
  providerSupportsCapability,
19
20
  } = require('../lib/provider-names');
@@ -1987,8 +1988,8 @@ function resolveProviderName(agent, config, settings) {
1987
1988
  agent.provider ||
1988
1989
  config.defaultProvider ||
1989
1990
  settings.defaultProvider ||
1990
- 'claude';
1991
- return normalizeProviderName(resolved) || 'claude';
1991
+ getDefaultProviderId();
1992
+ return normalizeProviderName(resolved) || getDefaultProviderId();
1992
1993
  }
1993
1994
 
1994
1995
  function validateProviderLevel(provider, requestedLevel, minLevel, maxLevel) {
@@ -16,7 +16,11 @@ const os = require('os');
16
16
  const fs = require('fs');
17
17
  const { loadSettings } = require('../lib/settings');
18
18
  const { CLAUDE_AUTH_ENV_VARS, resolveClaudeAuth } = require('../lib/settings/claude-auth');
19
- const { normalizeProviderName, getProviderMetadata } = require('../lib/provider-names');
19
+ const {
20
+ normalizeProviderName,
21
+ getProviderMetadata,
22
+ getDefaultProviderId,
23
+ } = require('../lib/provider-names');
20
24
  const {
21
25
  MOUNT_PRESETS,
22
26
  resolveMounts,
@@ -236,7 +240,7 @@ class IsolationManager {
236
240
 
237
241
  const settings = loadSettings();
238
242
  const providerName = normalizeProviderName(
239
- config.provider || settings.defaultProvider || 'claude'
243
+ config.provider || settings.defaultProvider || getDefaultProviderId()
240
244
  );
241
245
  const containerHome = config.containerHome || settings.dockerContainerHome || '/root';
242
246
 
@@ -46,7 +46,7 @@ const { generateName } = require('./name-generator');
46
46
  const configValidator = require('./config-validator');
47
47
  const TemplateResolver = require('./template-resolver');
48
48
  const { loadSettings } = require('../lib/settings');
49
- const { normalizeProviderName } = require('../lib/provider-names');
49
+ const { normalizeProviderName, getDefaultProviderId } = require('../lib/provider-names');
50
50
  const { resolveRunPlan } = require('../lib/run-plan');
51
51
  const { isProcessRunning } = require('../lib/process-liveness');
52
52
  const { getProvider } = require('./providers');
@@ -313,8 +313,8 @@ class Orchestrator {
313
313
  clusterConfig.forceProvider ||
314
314
  clusterConfig.defaultProvider ||
315
315
  settings.defaultProvider ||
316
- 'claude';
317
- return normalizeProviderName(resolved) || 'claude';
316
+ getDefaultProviderId();
317
+ return normalizeProviderName(resolved) || getDefaultProviderId();
318
318
  }
319
319
 
320
320
  /**
package/src/preflight.js CHANGED
@@ -21,6 +21,7 @@ const {
21
21
  const { loadSettings, getClaudeCommand } = require('../lib/settings.js');
22
22
  const {
23
23
  VALID_PROVIDERS,
24
+ getDefaultProviderId,
24
25
  getProviderMetadata,
25
26
  normalizeProviderName,
26
27
  resolveProviderCommand,
@@ -597,7 +598,7 @@ async function runPreflight(options = {}) {
597
598
  };
598
599
  }
599
600
  const providerName = normalizeProviderName(
600
- options.provider || settings.defaultProvider || 'claude'
601
+ options.provider || settings.defaultProvider || getDefaultProviderId()
601
602
  );
602
603
 
603
604
  const providerResult = validateProvider(providerName, options);