funolio-agent 1.0.7 → 1.0.47

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 (155) hide show
  1. package/dist/approval.d.ts +1 -0
  2. package/dist/approval.d.ts.map +1 -1
  3. package/dist/approval.js +12 -0
  4. package/dist/approval.js.map +1 -1
  5. package/dist/auth/auto-detect.d.ts +11 -3
  6. package/dist/auth/auto-detect.d.ts.map +1 -1
  7. package/dist/auth/auto-detect.js +136 -168
  8. package/dist/auth/auto-detect.js.map +1 -1
  9. package/dist/auth/subscription-runtime.js +1 -1
  10. package/dist/auth/subscription-runtime.js.map +1 -1
  11. package/dist/backfill.d.ts.map +1 -1
  12. package/dist/backfill.js +31 -28
  13. package/dist/backfill.js.map +1 -1
  14. package/dist/bot-manager.d.ts +16 -4
  15. package/dist/bot-manager.d.ts.map +1 -1
  16. package/dist/bot-manager.js +280 -73
  17. package/dist/bot-manager.js.map +1 -1
  18. package/dist/clerk-model.d.ts +10 -6
  19. package/dist/clerk-model.d.ts.map +1 -1
  20. package/dist/clerk-model.js +39 -16
  21. package/dist/clerk-model.js.map +1 -1
  22. package/dist/cli.js +7 -2
  23. package/dist/cli.js.map +1 -1
  24. package/dist/commands/import-history.js +5 -1
  25. package/dist/commands/import-history.js.map +1 -1
  26. package/dist/commands/start.d.ts.map +1 -1
  27. package/dist/commands/start.js +57 -225
  28. package/dist/commands/start.js.map +1 -1
  29. package/dist/config.d.ts.map +1 -1
  30. package/dist/config.js +13 -2
  31. package/dist/config.js.map +1 -1
  32. package/dist/context-window.js +1 -1
  33. package/dist/context-window.js.map +1 -1
  34. package/dist/import-parser-core.d.ts.map +1 -1
  35. package/dist/import-parser-core.js +74 -8
  36. package/dist/import-parser-core.js.map +1 -1
  37. package/dist/local-data.d.ts +59 -6
  38. package/dist/local-data.d.ts.map +1 -1
  39. package/dist/local-data.js +544 -62
  40. package/dist/local-data.js.map +1 -1
  41. package/dist/local-db.d.ts.map +1 -1
  42. package/dist/local-db.js +21 -1
  43. package/dist/local-db.js.map +1 -1
  44. package/dist/local-funnel.d.ts +0 -7
  45. package/dist/local-funnel.d.ts.map +1 -1
  46. package/dist/local-funnel.js +19 -28
  47. package/dist/local-funnel.js.map +1 -1
  48. package/dist/local-import-worker.d.ts.map +1 -1
  49. package/dist/local-import-worker.js +49 -4
  50. package/dist/local-import-worker.js.map +1 -1
  51. package/dist/local-memory-search.d.ts.map +1 -1
  52. package/dist/local-memory-search.js +6 -3
  53. package/dist/local-memory-search.js.map +1 -1
  54. package/dist/local-server.d.ts +37 -0
  55. package/dist/local-server.d.ts.map +1 -1
  56. package/dist/local-server.js +731 -227
  57. package/dist/local-server.js.map +1 -1
  58. package/dist/mcp/local-memory-server.d.ts +1 -1
  59. package/dist/mcp/local-memory-server.d.ts.map +1 -1
  60. package/dist/mcp/local-memory-server.js +23 -11
  61. package/dist/mcp/local-memory-server.js.map +1 -1
  62. package/dist/mcp/manager.d.ts.map +1 -1
  63. package/dist/mcp/manager.js +86 -18
  64. package/dist/mcp/manager.js.map +1 -1
  65. package/dist/message-loop.d.ts +5 -10
  66. package/dist/message-loop.d.ts.map +1 -1
  67. package/dist/message-loop.js +393 -289
  68. package/dist/message-loop.js.map +1 -1
  69. package/dist/mqtt-client.d.ts +4 -1
  70. package/dist/mqtt-client.d.ts.map +1 -1
  71. package/dist/mqtt-client.js.map +1 -1
  72. package/dist/orchestration/orchestrator-blocked-prompt.d.ts +2 -1
  73. package/dist/orchestration/orchestrator-blocked-prompt.d.ts.map +1 -1
  74. package/dist/orchestration/orchestrator-blocked-prompt.js +11 -0
  75. package/dist/orchestration/orchestrator-blocked-prompt.js.map +1 -1
  76. package/dist/orchestration/orchestrator-final-response-prompt.d.ts +4 -1
  77. package/dist/orchestration/orchestrator-final-response-prompt.d.ts.map +1 -1
  78. package/dist/orchestration/orchestrator-final-response-prompt.js +8 -6
  79. package/dist/orchestration/orchestrator-final-response-prompt.js.map +1 -1
  80. package/dist/orchestration/worker-operating-prompt.d.ts +2 -0
  81. package/dist/orchestration/worker-operating-prompt.d.ts.map +1 -1
  82. package/dist/orchestration/worker-operating-prompt.js +39 -0
  83. package/dist/orchestration/worker-operating-prompt.js.map +1 -1
  84. package/dist/orchestrator.d.ts +13 -0
  85. package/dist/orchestrator.d.ts.map +1 -1
  86. package/dist/orchestrator.js +235 -133
  87. package/dist/orchestrator.js.map +1 -1
  88. package/dist/providers/anthropic.d.ts +0 -5
  89. package/dist/providers/anthropic.d.ts.map +1 -1
  90. package/dist/providers/anthropic.js +29 -75
  91. package/dist/providers/anthropic.js.map +1 -1
  92. package/dist/providers/claude-cli.d.ts.map +1 -1
  93. package/dist/providers/claude-cli.js +16 -140
  94. package/dist/providers/claude-cli.js.map +1 -1
  95. package/dist/providers/codex-cli.d.ts.map +1 -1
  96. package/dist/providers/codex-cli.js +78 -59
  97. package/dist/providers/codex-cli.js.map +1 -1
  98. package/dist/providers/google.d.ts.map +1 -1
  99. package/dist/providers/google.js +4 -2
  100. package/dist/providers/google.js.map +1 -1
  101. package/dist/providers/index.d.ts +2 -0
  102. package/dist/providers/index.d.ts.map +1 -1
  103. package/dist/providers/index.js.map +1 -1
  104. package/dist/providers/openai.d.ts.map +1 -1
  105. package/dist/providers/openai.js +27 -2
  106. package/dist/providers/openai.js.map +1 -1
  107. package/dist/storage-mode.d.ts +5 -0
  108. package/dist/storage-mode.d.ts.map +1 -0
  109. package/dist/storage-mode.js +21 -0
  110. package/dist/storage-mode.js.map +1 -0
  111. package/dist/summarization-pipeline.d.ts +9 -0
  112. package/dist/summarization-pipeline.d.ts.map +1 -1
  113. package/dist/summarization-pipeline.js +61 -17
  114. package/dist/summarization-pipeline.js.map +1 -1
  115. package/dist/tools/analyze-image.js +2 -2
  116. package/dist/tools/analyze-image.js.map +1 -1
  117. package/dist/tools/edit-file.js +3 -3
  118. package/dist/tools/edit-file.js.map +1 -1
  119. package/dist/tools/index.d.ts.map +1 -1
  120. package/dist/tools/index.js +36 -0
  121. package/dist/tools/index.js.map +1 -1
  122. package/dist/tools/list-directory.js +7 -4
  123. package/dist/tools/list-directory.js.map +1 -1
  124. package/dist/tools/read-file.js +3 -3
  125. package/dist/tools/read-file.js.map +1 -1
  126. package/dist/tools/run-command.js +3 -3
  127. package/dist/tools/run-command.js.map +1 -1
  128. package/dist/tools/sandbox.d.ts +10 -5
  129. package/dist/tools/sandbox.d.ts.map +1 -1
  130. package/dist/tools/sandbox.js +41 -13
  131. package/dist/tools/sandbox.js.map +1 -1
  132. package/dist/tools/search-codebase.js +2 -2
  133. package/dist/tools/search-codebase.js.map +1 -1
  134. package/dist/tools/search-local-memory.d.ts.map +1 -1
  135. package/dist/tools/search-local-memory.js +19 -8
  136. package/dist/tools/search-local-memory.js.map +1 -1
  137. package/dist/tools/spawn-subagent.js.map +1 -1
  138. package/dist/tools/write-file.js +3 -3
  139. package/dist/tools/write-file.js.map +1 -1
  140. package/dist/types.d.ts +2 -0
  141. package/dist/types.d.ts.map +1 -1
  142. package/dist/verification/index.js +2 -2
  143. package/dist/verification/index.js.map +1 -1
  144. package/dist/wizard-state.d.ts.map +1 -1
  145. package/dist/wizard-state.js +16 -2
  146. package/dist/wizard-state.js.map +1 -1
  147. package/dist/wizard-support.d.ts +2 -2
  148. package/dist/wizard-support.d.ts.map +1 -1
  149. package/dist/wizard-support.js +80 -93
  150. package/dist/wizard-support.js.map +1 -1
  151. package/dist/workflow-engine.d.ts +3 -1
  152. package/dist/workflow-engine.d.ts.map +1 -1
  153. package/dist/workflow-engine.js +131 -12
  154. package/dist/workflow-engine.js.map +1 -1
  155. package/package.json +1 -1
@@ -100,10 +100,12 @@ class WorkflowEngine extends events_1.EventEmitter {
100
100
  }
101
101
  else {
102
102
  // Single agent, single step
103
+ const stepDescription = opts?.stepDescription?.trim()
104
+ || prompt.slice(0, 100);
103
105
  steps = [{
104
106
  id: `${workflowId}-0`,
105
107
  index: 0,
106
- description: prompt.slice(0, 100),
108
+ description: stepDescription,
107
109
  prompt,
108
110
  agentId: profile.id,
109
111
  agentName: profile.name,
@@ -902,6 +904,53 @@ class WorkflowEngine extends events_1.EventEmitter {
902
904
  loopCount: step.loopCount,
903
905
  };
904
906
  const result = await this.executeStep(step, fullPrompt, conversationId, opts, opts?.apiKey, wfContext);
907
+ if (opts?.isOrchestrated && opts.taskId) {
908
+ const completedTodo = data.getTodoTask(opts.taskId, 'completed');
909
+ if (completedTodo) {
910
+ step.status = 'completed';
911
+ step.result = completedTodo.output_summary || completedTodo.handoff_prompt || result;
912
+ step.completedAt = Date.now();
913
+ completed.add(step.index);
914
+ this.emitProgress(workflowId, step, steps, 'step-completed', opts?.onProgress, undefined, opts?.onWorkerChunk);
915
+ try {
916
+ const execId = step._execId;
917
+ if (execId) {
918
+ data.updateStepExecution(execId, {
919
+ status: 'completed',
920
+ attempts: step.attempts,
921
+ resultSummary: step.result.length > 200 ? step.result.slice(0, 200) + '...' : step.result,
922
+ completedAt: new Date().toISOString().replace('T', ' ').replace('Z', ''),
923
+ });
924
+ data.updateWorkflowExecution(workflowId, { completedSteps: completed.size });
925
+ }
926
+ }
927
+ catch { /* best effort */ }
928
+ return;
929
+ }
930
+ const blockedTodo = data.getTodoTask(opts.taskId, 'active');
931
+ if (blockedTodo?.blocker_summary) {
932
+ step.status = 'failed';
933
+ step.result = blockedTodo.blocker_summary;
934
+ step.error = blockedTodo.blocker_summary;
935
+ step.completedAt = Date.now();
936
+ failed.add(step.index);
937
+ this.emitProgress(workflowId, step, steps, 'step-failed', opts?.onProgress, undefined, opts?.onWorkerChunk);
938
+ try {
939
+ const execId = step._execId;
940
+ if (execId) {
941
+ data.updateStepExecution(execId, {
942
+ status: 'failed',
943
+ attempts: step.attempts,
944
+ error: step.error,
945
+ resultSummary: blockedTodo.blocker_summary.slice(0, 200),
946
+ completedAt: new Date().toISOString().replace('T', ' ').replace('Z', ''),
947
+ });
948
+ }
949
+ }
950
+ catch { /* best effort */ }
951
+ return;
952
+ }
953
+ }
905
954
  const footer = (0, status_parser_1.parseStructuredFooter)(result);
906
955
  const stepRole = this.inferRoleForStep(step);
907
956
  if (stepRole !== 'qa' && (footer.status === 'PASS' || footer.status === 'FAIL')) {
@@ -1279,7 +1328,7 @@ class WorkflowEngine extends events_1.EventEmitter {
1279
1328
  */
1280
1329
  async executeStep(step, prompt, conversationId, opts, apiKey, workflowContext) {
1281
1330
  const profile = data.getAgentProfile(step.agentId);
1282
- const runtime = await this.resolveStepRuntime(step, profile, apiKey);
1331
+ const runtime = await this.resolveStepRuntime(step, profile, apiKey, opts);
1283
1332
  let activeRuntime = runtime;
1284
1333
  let llm = (0, index_1.createProvider)(activeRuntime.providerName, {
1285
1334
  apiKey: activeRuntime.apiKey,
@@ -1298,11 +1347,13 @@ class WorkflowEngine extends events_1.EventEmitter {
1298
1347
  const toolDefs = (0, index_2.getAllToolDefinitions)();
1299
1348
  const workspacePath = opts?.workspacePath?.trim();
1300
1349
  const effectiveProjectDir = workspacePath || this.projectDir;
1350
+ const unrestrictedCliProvider = index_1.CLI_PROVIDERS.has(step.provider);
1301
1351
  const toolCtx = (0, index_2.createToolContext)(effectiveProjectDir, {
1302
1352
  projectId: opts?.projectId ?? null,
1303
1353
  currentTodoTaskId: opts?.taskId,
1304
1354
  actorType: 'llm',
1305
1355
  actorId: step.agentName || step.agentId,
1356
+ restrictFileAccessToProject: unrestrictedCliProvider ? false : undefined,
1306
1357
  });
1307
1358
  const isWorkflowWorker = opts?.workerMode !== false;
1308
1359
  let systemPrompt = profile?.soul_md
@@ -1348,6 +1399,9 @@ class WorkflowEngine extends events_1.EventEmitter {
1348
1399
  const MAX_ITERATIONS = safeguards_1.SAFEGUARDS.MAX_WORKFLOW_ITERATIONS;
1349
1400
  let incompleteExecutionRecoveries = 0;
1350
1401
  while (iteration < MAX_ITERATIONS) {
1402
+ if (opts?.isOrchestrated && this.orchestratedTodoHandled(opts.taskId)) {
1403
+ return this.buildOrchestratedTodoHandledResult(opts.taskId);
1404
+ }
1351
1405
  iteration++;
1352
1406
  let streamedContent = '';
1353
1407
  let lastChunkProgressAt = 0;
@@ -1377,7 +1431,7 @@ class WorkflowEngine extends events_1.EventEmitter {
1377
1431
  const now2 = Date.now();
1378
1432
  if (chunkBuffer.length >= 80 || now2 - lastChunkForwardAt >= 150) {
1379
1433
  opts.onWorkerChunk({
1380
- type: 'chunk',
1434
+ type: opts?.isOrchestrated ? 'worker_chunk' : 'chunk',
1381
1435
  stepId: step.id,
1382
1436
  agentName: step.agentName,
1383
1437
  description: step.description,
@@ -1410,7 +1464,7 @@ class WorkflowEngine extends events_1.EventEmitter {
1410
1464
  // Flush remaining chunk buffer
1411
1465
  if (opts?.onWorkerChunk && chunkBuffer) {
1412
1466
  opts.onWorkerChunk({
1413
- type: 'chunk',
1467
+ type: opts?.isOrchestrated ? 'worker_chunk' : 'chunk',
1414
1468
  stepId: step.id,
1415
1469
  agentName: step.agentName,
1416
1470
  description: step.description,
@@ -1452,7 +1506,9 @@ class WorkflowEngine extends events_1.EventEmitter {
1452
1506
  toolCalls: response.toolCalls,
1453
1507
  });
1454
1508
  for (const tc of response.toolCalls) {
1455
- const permMode = (profile?.permission_mode || 'autopilot');
1509
+ const permMode = unrestrictedCliProvider
1510
+ ? 'autopilot'
1511
+ : (profile?.permission_mode || 'autopilot');
1456
1512
  const approval = (0, approval_1.checkPermission)(tc.name, permMode);
1457
1513
  if (!approval.approved) {
1458
1514
  throw new Error(`APPROVAL_REQUIRED: ${approval.reason}`);
@@ -1460,7 +1516,7 @@ class WorkflowEngine extends events_1.EventEmitter {
1460
1516
  // Emit tool_call event so UI can show what's happening
1461
1517
  if (opts?.onWorkerChunk) {
1462
1518
  opts.onWorkerChunk({
1463
- type: 'tool_call',
1519
+ type: opts?.isOrchestrated ? 'worker_tool_call' : 'tool_call',
1464
1520
  stepId: step.id,
1465
1521
  agentName: step.agentName,
1466
1522
  description: step.description,
@@ -1477,7 +1533,7 @@ class WorkflowEngine extends events_1.EventEmitter {
1477
1533
  // Emit tool_result event
1478
1534
  if (opts?.onWorkerChunk) {
1479
1535
  opts.onWorkerChunk({
1480
- type: 'tool_result',
1536
+ type: opts?.isOrchestrated ? 'worker_tool_result' : 'tool_result',
1481
1537
  stepId: step.id,
1482
1538
  agentName: step.agentName,
1483
1539
  description: step.description,
@@ -1489,6 +1545,9 @@ class WorkflowEngine extends events_1.EventEmitter {
1489
1545
  toolIsError: !result.success,
1490
1546
  });
1491
1547
  }
1548
+ if (opts?.isOrchestrated && this.orchestratedTodoHandled(opts.taskId)) {
1549
+ return this.buildOrchestratedTodoHandledResult(opts.taskId);
1550
+ }
1492
1551
  }
1493
1552
  if (opts?.isOrchestrated && this.orchestratedTodoHandled(opts.taskId)) {
1494
1553
  return this.buildOrchestratedTodoHandledResult(opts.taskId);
@@ -1687,12 +1746,12 @@ class WorkflowEngine extends events_1.EventEmitter {
1687
1746
  default: return undefined;
1688
1747
  }
1689
1748
  }
1690
- async resolveStepRuntime(step, profile, apiKey) {
1749
+ async resolveStepRuntime(step, profile, apiKey, opts) {
1691
1750
  if (step.provider === 'claude-cli') {
1692
- return this.resolveClaudeWorkflowRuntime(step, profile);
1751
+ return this.resolveClaudeWorkflowRuntime(step, profile, opts?.disallowCliRuntime === true);
1693
1752
  }
1694
1753
  if (step.provider === 'codex-cli') {
1695
- return this.resolveCodexWorkflowRuntime(step, profile);
1754
+ return this.resolveCodexWorkflowRuntime(step, profile, opts?.disallowCliRuntime === true);
1696
1755
  }
1697
1756
  const profileConnection = profile?.provider_connection_id
1698
1757
  ? data.getProviderConnection(profile.provider_connection_id)
@@ -1701,6 +1760,22 @@ class WorkflowEngine extends events_1.EventEmitter {
1701
1760
  || profileConnection?.api_key_enc
1702
1761
  || apiKey
1703
1762
  || this.resolveApiKey(step.provider);
1763
+ if (!resolvedKey && step.provider === 'openai') {
1764
+ const preferredModel = (0, subscription_runtime_1.resolveSubscriptionApiModel)(step.model || profile?.model, data.findProviderConnection('openai')?.default_model || undefined) || (step.model || profile?.model || 'default').trim() || 'default';
1765
+ const subscriptionRuntime = await (0, subscription_runtime_1.resolveCodexSubscriptionRuntime)({
1766
+ preferredModel,
1767
+ });
1768
+ if (subscriptionRuntime) {
1769
+ return {
1770
+ providerName: subscriptionRuntime.providerName,
1771
+ apiKey: subscriptionRuntime.apiKey,
1772
+ model: subscriptionRuntime.model,
1773
+ runtimeLabel: 'Subscription API (Token)',
1774
+ ...(subscriptionRuntime.baseUrl ? { baseUrl: subscriptionRuntime.baseUrl } : {}),
1775
+ ...(subscriptionRuntime.apiStyle ? { apiStyle: subscriptionRuntime.apiStyle } : {}),
1776
+ };
1777
+ }
1778
+ }
1704
1779
  if (!resolvedKey) {
1705
1780
  throw new Error(`No API key for provider ${step.provider}`);
1706
1781
  }
@@ -1711,7 +1786,7 @@ class WorkflowEngine extends events_1.EventEmitter {
1711
1786
  runtimeLabel: 'API Key',
1712
1787
  };
1713
1788
  }
1714
- async resolveClaudeWorkflowRuntime(step, profile) {
1789
+ async resolveClaudeWorkflowRuntime(step, profile, disallowCliRuntime = false) {
1715
1790
  const preferredModel = (0, subscription_runtime_1.resolveSubscriptionApiModel)(step.model || profile?.model, data.findProviderConnection('anthropic')?.default_model || data.findProviderConnection('claude-cli')?.default_model || undefined) || (step.model || profile?.model || 'default').trim() || 'default';
1716
1791
  const apiKeyFallback = data.findProviderConnection('anthropic')?.api_key_enc || process.env.ANTHROPIC_API_KEY;
1717
1792
  const apiFallbackConfig = apiKeyFallback
@@ -1722,6 +1797,26 @@ class WorkflowEngine extends events_1.EventEmitter {
1722
1797
  runtimeLabel: 'API Key',
1723
1798
  }
1724
1799
  : undefined;
1800
+ if (disallowCliRuntime) {
1801
+ const subscriptionRuntime = await (0, subscription_runtime_1.resolveClaudeSubscriptionRuntime)({
1802
+ preferredModel,
1803
+ });
1804
+ if (subscriptionRuntime) {
1805
+ return {
1806
+ providerName: subscriptionRuntime.providerName,
1807
+ apiKey: subscriptionRuntime.apiKey,
1808
+ model: subscriptionRuntime.model,
1809
+ runtimeLabel: 'Subscription API (Token)',
1810
+ ...(subscriptionRuntime.authMode ? { authMode: subscriptionRuntime.authMode } : {}),
1811
+ ...(subscriptionRuntime.baseUrl ? { baseUrl: subscriptionRuntime.baseUrl } : {}),
1812
+ ...(subscriptionRuntime.apiQuery ? { apiQuery: subscriptionRuntime.apiQuery } : {}),
1813
+ ...(subscriptionRuntime.extraHeaders ? { extraHeaders: subscriptionRuntime.extraHeaders } : {}),
1814
+ };
1815
+ }
1816
+ if (apiFallbackConfig)
1817
+ return apiFallbackConfig;
1818
+ throw new Error('No non-CLI Anthropic runtime is available for this workflow step.');
1819
+ }
1725
1820
  const cliFallbackConfig = {
1726
1821
  providerName: 'claude-cli',
1727
1822
  apiKey: 'cli-auth',
@@ -1731,11 +1826,35 @@ class WorkflowEngine extends events_1.EventEmitter {
1731
1826
  };
1732
1827
  return cliFallbackConfig;
1733
1828
  }
1734
- async resolveCodexWorkflowRuntime(step, profile) {
1829
+ async resolveCodexWorkflowRuntime(step, profile, disallowCliRuntime = false) {
1735
1830
  const preferredModel = (0, subscription_runtime_1.resolveSubscriptionApiModel)(step.model || profile?.model, data.findProviderConnection('openai')?.default_model || data.findProviderConnection('codex-cli')?.default_model || undefined)
1736
1831
  || (step.model || profile?.model || 'default').trim()
1737
1832
  || 'default';
1833
+ const subscriptionRuntime = await (0, subscription_runtime_1.resolveCodexSubscriptionRuntime)({
1834
+ preferredModel,
1835
+ });
1836
+ if (subscriptionRuntime) {
1837
+ return {
1838
+ providerName: subscriptionRuntime.providerName,
1839
+ apiKey: subscriptionRuntime.apiKey,
1840
+ model: subscriptionRuntime.model,
1841
+ runtimeLabel: 'Subscription API (Token)',
1842
+ ...(subscriptionRuntime.baseUrl ? { baseUrl: subscriptionRuntime.baseUrl } : {}),
1843
+ ...(subscriptionRuntime.apiStyle ? { apiStyle: subscriptionRuntime.apiStyle } : {}),
1844
+ };
1845
+ }
1738
1846
  const apiKeyFallback = data.findProviderConnection('openai')?.api_key_enc || process.env.OPENAI_API_KEY;
1847
+ if (disallowCliRuntime) {
1848
+ if (apiKeyFallback) {
1849
+ return {
1850
+ providerName: 'openai',
1851
+ apiKey: apiKeyFallback,
1852
+ model: preferredModel,
1853
+ runtimeLabel: 'API Key',
1854
+ };
1855
+ }
1856
+ throw new Error('No non-CLI OpenAI runtime is available for this workflow step.');
1857
+ }
1739
1858
  return {
1740
1859
  providerName: 'codex-cli',
1741
1860
  apiKey: 'cli-auth',