nolo-cli 0.16.0-alpha.1 → 0.16.0-alpha.11

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 (97) hide show
  1. package/{_executeModel-QAUS6B7J.js → _executeModel-LGHYA5XS.js} +29 -28
  2. package/{action-GUOZYYGN.js → action-F5JACQBG.js} +4 -4
  3. package/{addContentAction-QDGHGUBH.js → addContentAction-AQXEYRBE.js} +3 -3
  4. package/{addDialogAgentAction-Z4YCYZIV.js → addDialogAgentAction-EJHHJZWW.js} +2 -2
  5. package/{agentDeleteCommand-365DMKHW.js → agentDeleteCommand-PBIUC4FT.js} +18 -17
  6. package/{agentEmailCommands-TQMXL36I.js → agentEmailCommands-KC2QCPQV.js} +35 -34
  7. package/{agentListCommands-6B5X4RC6.js → agentListCommands-N64PHBXM.js} +20 -19
  8. package/{agentMachineCommands-LOEARB6V.js → agentMachineCommands-P7S5WAVA.js} +18 -17
  9. package/{agentRecordCommands-DCH2WBL2.js → agentRecordCommands-JKZR2TZJ.js} +34 -33
  10. package/{agentRunCommand-SGMH67WT.js → agentRunCommand-2ELKCBWR.js} +34 -33
  11. package/{agentRuntimeLocal-YSYZ33ER.js → agentRuntimeLocal-T6YECTNF.js} +15 -16
  12. package/{agentSlice-IVE735EV.js → agentSlice-NXLMDKR7.js} +3 -3
  13. package/{appDeleteCommands-6QYOO3JB.js → appDeleteCommands-D6B6Z4ZQ.js} +19 -18
  14. package/{appDeployCommands-WTCT6XO6.js → appDeployCommands-YMO5FK4T.js} +19 -18
  15. package/{appDeployStatusCommands-CGWGZJKB.js → appDeployStatusCommands-EO5DWWPQ.js} +19 -18
  16. package/{appGetCommands-O4OCAMRW.js → appGetCommands-6SMZ3URQ.js} +19 -18
  17. package/{appListCommands-UENFP4XY.js → appListCommands-RZXSWR2G.js} +19 -18
  18. package/{authCommand-YFTR3347.js → authCommand-MSSBXCQ6.js} +8 -2
  19. package/{chunk-EMXI3N3Z.js → chunk-22NGXGN3.js} +2 -2
  20. package/{chunk-WPN6RMDF.js → chunk-2WXMU64E.js} +3 -3
  21. package/{chunk-SFXYKGK2.js → chunk-3S2VOMIF.js} +3 -3
  22. package/{chunk-WRN5EQT7.js → chunk-47QUPRHO.js} +3 -3
  23. package/{chunk-YNHQIXX5.js → chunk-4LXOVZ4W.js} +21 -21
  24. package/{chunk-O53CP2QR.js → chunk-6CRACQXW.js} +3 -3
  25. package/{chunk-E237VE6U.js → chunk-6KBBMW4D.js} +2 -2
  26. package/{chunk-U7LEGLEB.js → chunk-6N4KODMN.js} +1 -1
  27. package/{chunk-GRTFNYLR.js → chunk-A7O4KKLZ.js} +3 -3
  28. package/{chunk-WA6KZL5V.js → chunk-AAODAAUQ.js} +23 -20
  29. package/{chunk-Z24FGIU2.js → chunk-BXXECNBU.js} +3 -3
  30. package/{chunk-4NLUNENX.js → chunk-C4MMO7W4.js} +1 -1
  31. package/{chunk-JKWWVF2I.js → chunk-D3HVJJIA.js} +1 -1
  32. package/{chunk-VE6XMVKG.js → chunk-D4NCEGGR.js} +167 -53
  33. package/{chunk-TTGAVETO.js → chunk-EABWT43X.js} +2 -2
  34. package/{chunk-YYIRR6QC.js → chunk-EQTZPEID.js} +140 -175
  35. package/{chunk-RSYUDGGZ.js → chunk-F3UOACU4.js} +1 -1
  36. package/{chunk-RKM3K52F.js → chunk-GPELDE6I.js} +2 -2
  37. package/{chunk-OGGHETUE.js → chunk-HQPG2PIV.js} +62 -19
  38. package/{chunk-BFRVXJJJ.js → chunk-HSASSW4L.js} +27 -11
  39. package/{chunk-XVP3C2KY.js → chunk-IWLUTMYX.js} +1 -1
  40. package/{chunk-B4KT7RN2.js → chunk-JTMNCCWF.js} +2 -2
  41. package/chunk-KFEVY3ST.js +255 -0
  42. package/{chunk-WNLPAOIT.js → chunk-KFHN5NGJ.js} +1 -1
  43. package/{chunk-ISYE6GZB.js → chunk-L6NVTGI7.js} +1 -1
  44. package/{chunk-J55UHASN.js → chunk-MSA4JAOZ.js} +1 -1
  45. package/{chunk-HRQCKQA5.js → chunk-MUCU6ATG.js} +8 -257
  46. package/{chunk-524BDL33.js → chunk-O6W2O2DA.js} +1 -15
  47. package/{chunk-4QQFLN5C.js → chunk-OVBVEXZ7.js} +4 -4
  48. package/{chunk-QZVGMD5F.js → chunk-PU4LXVAC.js} +1 -1
  49. package/{chunk-4IJYA27C.js → chunk-RG2U2MTJ.js} +1 -1
  50. package/{chunk-6MHDWKOT.js → chunk-RIF3XLXK.js} +9 -5
  51. package/{chunk-IKXL2HZ3.js → chunk-RK5NYQEL.js} +1 -1
  52. package/{chunk-JS33TCQ3.js → chunk-RPDGJO4D.js} +2 -2
  53. package/{chunk-EHLHSX7R.js → chunk-UB4RYYNQ.js} +9 -2
  54. package/{chunk-YC3DJILJ.js → chunk-VHXXRWNL.js} +22 -8
  55. package/{chunk-G2MKOQCB.js → chunk-WBA6SIBB.js} +1 -1
  56. package/{chunk-6565R2TI.js → chunk-XEWUC53Z.js} +38 -20
  57. package/{chunk-OOIN7HSO.js → chunk-XJITGCTM.js} +10 -1
  58. package/{chunk-V2J635L5.js → chunk-XOIF2TNF.js} +2 -2
  59. package/{chunk-VPTJB4HM.js → chunk-XPC5C7BK.js} +0 -3
  60. package/{chunk-I66RU7P7.js → chunk-XRSPI6CP.js} +1 -1
  61. package/{chunk-N5424GSW.js → chunk-YJKXGHJ6.js} +1 -1
  62. package/{chunk-QLFCNUVQ.js → chunk-ZH62XNZE.js} +877 -172
  63. package/chunk-ZHXJ6M7T.js +27 -0
  64. package/{chunk-OQMPU2ML.js → chunk-ZXQ52OY2.js} +4 -4
  65. package/{createAgentAutomationAction-TS6NNZ4X.js → createAgentAutomationAction-RKWIMKHW.js} +13 -13
  66. package/{createDialogAction-5HVQ33EX.js → createDialogAction-VN7MEBS3.js} +14 -14
  67. package/{createPageAction-4F3ZGQJD.js → createPageAction-JBUWBHHC.js} +13 -13
  68. package/{dbSlice-OP6UPXKA.js → dbSlice-7KQH6GOU.js} +2 -2
  69. package/{dialogCommands-ZL6L24BS.js → dialogCommands-DFY5HJ6M.js} +19 -18
  70. package/{dialogSlice-FAWUQDJW.js → dialogSlice-NNYBU35K.js} +13 -13
  71. package/{docCreateCommands-LYROQTFH.js → docCreateCommands-5L76YTI2.js} +18 -17
  72. package/{docDeleteCommands-6TWGTZNR.js → docDeleteCommands-3GASP3VR.js} +19 -18
  73. package/{docReadCommands-PRULNF26.js → docReadCommands-ALA77AZM.js} +18 -17
  74. package/{docStore-2UHVWLTV.js → docStore-DR22GGF3.js} +14 -14
  75. package/{docUpdateCommands-NNYYWJBI.js → docUpdateCommands-6AZGXE5M.js} +18 -17
  76. package/{getPricing-UGDJHI7M.js → getPricing-RYY6OBA4.js} +4 -4
  77. package/{handleSendMessageAction-LJPUYNOH.js → handleSendMessageAction-FHITDM7H.js} +201 -15
  78. package/index.js +47 -47
  79. package/{machineCommands-JQPEQFSE.js → machineCommands-3B4IHHVK.js} +33 -32
  80. package/{machineWsRunDispatch-FFFNWVEW.js → machineWsRunDispatch-AXZ6OL3V.js} +33 -32
  81. package/{models-LSCRJJ6P.js → models-5K5G2CZI.js} +2 -2
  82. package/package.json +1 -1
  83. package/{read-HXHAZBKH.js → read-CN3TNXIP.js} +1 -1
  84. package/{readDocTool-VPBDTO4G.js → readDocTool-WF3675ED.js} +1 -1
  85. package/{readlineWorkspace-QSXHSBHA.js → readlineWorkspace-DBZCXS7Y.js} +145 -92
  86. package/{removeDialogAgentAction-HUFVN35S.js → removeDialogAgentAction-YDHBFEGI.js} +5 -5
  87. package/{runAgentClientLoop-A75BUU6D.js → runAgentClientLoop-AB7PQ3TB.js} +26 -25
  88. package/{setDialogExtraReferencesAction-2VLGWQKG.js → setDialogExtraReferencesAction-LR6MSIXO.js} +2 -2
  89. package/{setPrimaryDialogAgentAction-VB4UV2CC.js → setPrimaryDialogAgentAction-IIVDCY5C.js} +5 -5
  90. package/{settingSlice-7JYPQNAC.js → settingSlice-O23YDK2O.js} +3 -3
  91. package/{spaceCommands-4LE45GB7.js → spaceCommands-AB2D7A2R.js} +18 -17
  92. package/{spaceSlice-444MFUP6.js → spaceSlice-TEJDCU6A.js} +13 -13
  93. package/{streamAgentChatTurn-DJAE7USZ.js → streamAgentChatTurn-NZ3HLAXS.js} +30 -32
  94. package/{tools-YB6LXSVN.js → tools-M4USUF3R.js} +20 -20
  95. package/{tuiSummaryLlmCaller-QQL3JA5I.js → tuiSummaryLlmCaller-VUNVBRX3.js} +7 -6
  96. package/{updateDialogTitleAction-6HGFBM64.js → updateDialogTitleAction-SMPQVKWT.js} +13 -13
  97. package/chunk-BYXBJQAS.js +0 -0
@@ -3,12 +3,12 @@ import {
3
3
  refreshAntigravityOAuthToken,
4
4
  refreshOpenAiCodexToken,
5
5
  refreshXaiOAuthToken
6
- } from "./chunk-EHLHSX7R.js";
6
+ } from "./chunk-UB4RYYNQ.js";
7
7
  import {
8
8
  buildLocalAgentLookupKeys,
9
9
  normalizeAgentHandle,
10
10
  shouldReadAgentKeyRemotely
11
- } from "./chunk-QZVGMD5F.js";
11
+ } from "./chunk-PU4LXVAC.js";
12
12
  import {
13
13
  LOCAL_CODEX_AGENT_ID,
14
14
  LOCAL_CODEX_AGENT_KEY,
@@ -17,19 +17,20 @@ import {
17
17
  } from "./chunk-VHBWHNVT.js";
18
18
  import {
19
19
  inferCaptureIntent
20
- } from "./chunk-WNLPAOIT.js";
20
+ } from "./chunk-KFHN5NGJ.js";
21
21
  import {
22
22
  inlineImageUrlsForCustomProvider,
23
23
  prepareTools
24
- } from "./chunk-WRN5EQT7.js";
24
+ } from "./chunk-47QUPRHO.js";
25
25
  import {
26
26
  getAntigravityUserAgent,
27
27
  isAntigravityOAuthAgent,
28
28
  readAntigravityProjectId,
29
29
  resolveAntigravityCloudCodeBaseUrl
30
- } from "./chunk-ISYE6GZB.js";
30
+ } from "./chunk-L6NVTGI7.js";
31
31
  import {
32
32
  FORCED_TOOLS,
33
+ TASK_PREVIEW_MAX,
33
34
  addDefaultLightWebToolsForConfiguredAgents,
34
35
  addDefaultSystemCapabilityTools,
35
36
  appendEnabledPackPromptPatches,
@@ -41,13 +42,15 @@ import {
41
42
  formatStartRunCard,
42
43
  formatStatusRunCard,
43
44
  formatStopRunCard,
45
+ isAgentNameFallback,
44
46
  readXPostFunc,
45
47
  readXPostFunctionSchema,
46
48
  readXhsProfileFunc,
47
49
  readXhsProfileFunctionSchema,
48
50
  rememberMemoryFunctionSchema,
49
- resolveEffectiveEnabledPacks
50
- } from "./chunk-VE6XMVKG.js";
51
+ resolveEffectiveEnabledPacks,
52
+ resolveRunLabel
53
+ } from "./chunk-D4NCEGGR.js";
51
54
  import {
52
55
  createDrainExhaustedResponse,
53
56
  isCoreDrainingBody,
@@ -59,13 +62,13 @@ import {
59
62
  } from "./chunk-OWOHNGCN.js";
60
63
  import {
61
64
  prepareTokenUsageData
62
- } from "./chunk-YNHQIXX5.js";
65
+ } from "./chunk-4LXOVZ4W.js";
63
66
  import {
64
67
  BUILTIN_TITLE_LLM_CONFIG
65
- } from "./chunk-V2J635L5.js";
68
+ } from "./chunk-XOIF2TNF.js";
66
69
  import {
67
70
  fetchServerSyncedCredential
68
- } from "./chunk-OQMPU2ML.js";
71
+ } from "./chunk-ZXQ52OY2.js";
69
72
  import {
70
73
  buildAgentRuntimeDialogWritePlan,
71
74
  buildLocalWorkspaceOpenAiTools,
@@ -76,29 +79,32 @@ import {
76
79
  executeLocalToolWithPolicy,
77
80
  executeOpenAiCompatibleChatCompletion,
78
81
  parseSseDataLineJson,
82
+ parseSseDataLineObject,
79
83
  readOpenAiCompatibleSseCompletion,
80
84
  resolveOpenAiCompatibleProviderConfig
81
- } from "./chunk-YC3DJILJ.js";
85
+ } from "./chunk-VHXXRWNL.js";
82
86
  import {
83
87
  buildPlatformChatCompletionRequest,
84
88
  canUsePlatformChatProvider,
85
89
  parsePlatformChatCompletionData,
86
90
  parsePlatformChatCompletionResponse,
87
91
  readSseDataValues,
88
- resolveLegacyDeepSeekProxyChatFallback,
89
92
  resolvePlatformChatProviderConfig,
90
93
  shouldUsePlatformChatProvider
91
- } from "./chunk-WA6KZL5V.js";
94
+ } from "./chunk-AAODAAUQ.js";
92
95
  import {
93
96
  resolveAgentRuntimeConfigFromRecord
94
97
  } from "./chunk-OIQPORYI.js";
95
98
  import {
96
- parseToolArgumentsJson,
97
99
  summarizeToolArguments
98
- } from "./chunk-6MHDWKOT.js";
100
+ } from "./chunk-RIF3XLXK.js";
101
+ import {
102
+ convertMessagesToResponsesInput,
103
+ toResponsesTools
104
+ } from "./chunk-KFEVY3ST.js";
99
105
  import {
100
106
  resolvePlatformAuthToken
101
- } from "./chunk-HRQCKQA5.js";
107
+ } from "./chunk-MUCU6ATG.js";
102
108
  import {
103
109
  buildLoadSkillExecutor,
104
110
  buildNoloWorkspaceCliToolExecutors,
@@ -106,10 +112,13 @@ import {
106
112
  canonicalizeToolNames,
107
113
  parseNoloWorkspaceToolArguments,
108
114
  resolveRuntimeToolSurfaceForAgent
109
- } from "./chunk-B4KT7RN2.js";
115
+ } from "./chunk-JTMNCCWF.js";
110
116
  import {
111
117
  clipCompactText
112
118
  } from "./chunk-5MMAK75Q.js";
119
+ import {
120
+ isAdaptiveThinkingModelId
121
+ } from "./chunk-HQPG2PIV.js";
113
122
  import {
114
123
  createFileCredentialBroker,
115
124
  resolveCurrentRunRuntimeToolPolicy,
@@ -152,9 +161,6 @@ import {
152
161
  import {
153
162
  DEFAULT_NOLO_SERVER_URL
154
163
  } from "./chunk-OLZBQWZU.js";
155
- import {
156
- asRecordOrEmpty
157
- } from "./chunk-KX6YBIHG.js";
158
164
  import {
159
165
  createTokenKey,
160
166
  createUserKey,
@@ -166,14 +172,16 @@ import {
166
172
  import {
167
173
  asOptionalFiniteNumber
168
174
  } from "./chunk-WWC7I6TA.js";
175
+ import {
176
+ asTrimmedLowercaseString
177
+ } from "./chunk-QSJ3HFEF.js";
169
178
  import {
170
179
  BUILTIN_NOLO_AGENT_KEY,
171
180
  PUBLIC_DEEPSEEK_V4_FLASH_AGENT_KEY,
172
181
  PUBLIC_DEEPSEEK_V4_PRO_AGENT_KEY,
173
182
  PUBLIC_GLM_52_AGENT_KEY,
174
- PUBLIC_KIMI_K26_IMAGE_AGENT_KEY,
175
- PUBLIC_KIMI_K27_CODING_AGENT_KEY
176
- } from "./chunk-VPTJB4HM.js";
183
+ PUBLIC_KIMI_K26_IMAGE_AGENT_KEY
184
+ } from "./chunk-XPC5C7BK.js";
177
185
  import {
178
186
  asTrimmedString
179
187
  } from "./chunk-3EUW3WEO.js";
@@ -463,6 +471,10 @@ var STRINGS = {
463
471
  en: "Run stopped",
464
472
  zh: "\u8FD0\u884C\u5DF2\u505C\u6B62"
465
473
  },
474
+ runFinishedLabel: {
475
+ en: "Run finished",
476
+ zh: "\u8FD0\u884C\u5DF2\u7ED3\u675F"
477
+ },
466
478
  runLogTailLabel: {
467
479
  en: "Log tail:",
468
480
  zh: "\u65E5\u5FD7\u5C3E\u90E8\uFF1A"
@@ -497,6 +509,10 @@ var STRINGS = {
497
509
  en: "selected",
498
510
  zh: "\u5DF2\u9009"
499
511
  },
512
+ dialogMultiSelectRequired: {
513
+ en: "Pick at least one option to submit",
514
+ zh: "\u81F3\u5C11\u9009\u62E9\u4E00\u9879\u624D\u80FD\u63D0\u4EA4"
515
+ },
500
516
  dialogConfirmHint: {
501
517
  en: "(\u2191\u2193 move \xB7 Enter choose \xB7 Esc cancel)",
502
518
  zh: "\uFF08\u2191\u2193 \u79FB\u52A8 \xB7 Enter \u9009\u62E9 \xB7 Esc \u53D6\u6D88\uFF09"
@@ -928,6 +944,7 @@ function agentRunCardLabels() {
928
944
  runStatus: t("runStatusLabel"),
929
945
  runStarted: t("runStartedLabel"),
930
946
  runStopped: t("runStoppedLabel"),
947
+ runFinished: t("runFinishedLabel"),
931
948
  logTail: t("runLogTailLabel"),
932
949
  runs: (count) => t("runsListLabel", String(count))
933
950
  };
@@ -1123,6 +1140,11 @@ async function fetchWithTransientRetry(fetchImpl, input, init, options = {}) {
1123
1140
  const attemptBudget = coreDraining ? coreDrainingMaxAttempts : maxAttempts;
1124
1141
  if (attempt < attemptBudget) {
1125
1142
  const delayMs = await resolveRetryAfterMs(response, attempt);
1143
+ options.onRetry?.({
1144
+ attempt: attempt + 1,
1145
+ maxAttempts: attemptBudget,
1146
+ delayMs
1147
+ });
1126
1148
  await (options.sleep ?? defaultSleep)(delayMs);
1127
1149
  continue;
1128
1150
  }
@@ -1136,7 +1158,13 @@ async function fetchWithTransientRetry(fetchImpl, input, init, options = {}) {
1136
1158
  if (!isTransientFetchError(error)) throw error;
1137
1159
  lastError = error;
1138
1160
  if (attempt < maxAttempts) {
1139
- await (options.sleep ?? defaultSleep)(transientFetchRetryDelayMs(attempt));
1161
+ const delayMs = transientFetchRetryDelayMs(attempt);
1162
+ options.onRetry?.({
1163
+ attempt: attempt + 1,
1164
+ maxAttempts,
1165
+ delayMs
1166
+ });
1167
+ await (options.sleep ?? defaultSleep)(delayMs);
1140
1168
  }
1141
1169
  }
1142
1170
  }
@@ -1466,14 +1494,14 @@ var BUILTIN_PLATFORM_AGENT_CONFIGS = {
1466
1494
  [PUBLIC_DEEPSEEK_V4_PRO_AGENT_KEY]: {
1467
1495
  key: PUBLIC_DEEPSEEK_V4_PRO_AGENT_KEY,
1468
1496
  name: "DeepSeek V4 Pro",
1469
- provider: "deepseek",
1497
+ provider: "nolo",
1470
1498
  model: "deepseek-v4-pro",
1471
1499
  apiSource: "platform",
1472
1500
  useServerProxy: true,
1473
1501
  rawRecord: {
1474
1502
  dbKey: PUBLIC_DEEPSEEK_V4_PRO_AGENT_KEY,
1475
1503
  isPublic: true,
1476
- provider: "deepseek",
1504
+ provider: "nolo",
1477
1505
  model: "deepseek-v4-pro",
1478
1506
  apiSource: "platform",
1479
1507
  useServerProxy: true
@@ -1511,22 +1539,6 @@ var BUILTIN_PLATFORM_AGENT_CONFIGS = {
1511
1539
  useServerProxy: true
1512
1540
  }
1513
1541
  },
1514
- [PUBLIC_KIMI_K27_CODING_AGENT_KEY]: {
1515
- key: PUBLIC_KIMI_K27_CODING_AGENT_KEY,
1516
- name: "Kimi K2.7 Coding",
1517
- provider: "nolo",
1518
- model: "kimi-k2.7-code",
1519
- apiSource: "platform",
1520
- useServerProxy: true,
1521
- rawRecord: {
1522
- dbKey: PUBLIC_KIMI_K27_CODING_AGENT_KEY,
1523
- isPublic: true,
1524
- provider: "nolo",
1525
- model: "kimi-k2.7-code",
1526
- apiSource: "platform",
1527
- useServerProxy: true
1528
- }
1529
- },
1530
1542
  [BUILTIN_NOLO_AGENT_KEY]: {
1531
1543
  key: BUILTIN_NOLO_AGENT_KEY,
1532
1544
  name: "Nolo",
@@ -2037,6 +2049,93 @@ function buildServerPlatformToolExecutors(args) {
2037
2049
 
2038
2050
  // packages/cli/client/cliAgentRunToolExecutors.ts
2039
2051
  import { existsSync, readFileSync } from "node:fs";
2052
+
2053
+ // packages/cli/client/agentRunSnapshot.ts
2054
+ function readString(value) {
2055
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
2056
+ }
2057
+ function readLogLines(parsed) {
2058
+ if (Array.isArray(parsed.logLines)) return parsed.logLines;
2059
+ const tail = readString(parsed.logTail);
2060
+ return tail ? tail.split("\n") : void 0;
2061
+ }
2062
+ function readTimestamp(value) {
2063
+ if (typeof value === "number" && Number.isFinite(value) && value > 0) return value;
2064
+ if (typeof value === "string" && value.trim()) {
2065
+ const parsed = Date.parse(value);
2066
+ if (Number.isFinite(parsed) && parsed > 0) return parsed;
2067
+ }
2068
+ return void 0;
2069
+ }
2070
+ function readToolNames(value) {
2071
+ if (!Array.isArray(value)) return void 0;
2072
+ const names = value.filter((n) => typeof n === "string" && Boolean(n.trim()));
2073
+ return names.length > 0 ? names : void 0;
2074
+ }
2075
+ function buildSnapshot(parsed, event) {
2076
+ const runId = readString(parsed.runId) ?? readString(event.metadata?.runId) ?? "";
2077
+ const label = resolveRunLabel({
2078
+ agentName: parsed.agentName,
2079
+ name: parsed.name,
2080
+ agentKey: parsed.agentKey
2081
+ });
2082
+ const logLines = readLogLines(parsed);
2083
+ const taskPreview = readString(parsed.taskPreview);
2084
+ const lastToolNames = readToolNames(parsed.lastToolNames);
2085
+ const lastAssistantText = readString(parsed.lastAssistantText);
2086
+ const errorMessage = readString(parsed.errorMessage);
2087
+ const startedAt = readTimestamp(parsed.startedAt);
2088
+ const finishedAt = readTimestamp(parsed.finishedAt) ?? readTimestamp(parsed.endedAt);
2089
+ return {
2090
+ runId,
2091
+ status: readString(parsed.status) ?? "running",
2092
+ // The literal `agent` fallback is dropped here rather than at each render
2093
+ // site: an unnamed run should render no name row, not the word "agent".
2094
+ ...isAgentNameFallback(label) ? {} : { agentName: label },
2095
+ ...taskPreview ? { taskPreview } : {},
2096
+ ...typeof parsed.toolCallCount === "number" && Number.isFinite(parsed.toolCallCount) ? { toolCallCount: parsed.toolCallCount } : {},
2097
+ ...lastToolNames ? { lastToolNames } : {},
2098
+ ...lastAssistantText ? { lastAssistantText } : {},
2099
+ ...errorMessage ? { errorMessage } : {},
2100
+ ...startedAt !== void 0 ? { startedAt } : {},
2101
+ ...finishedAt !== void 0 ? { finishedAt } : {},
2102
+ ...logLines ? { logLines } : {},
2103
+ logKey: logLines && logLines.length > 0 ? logLines.join("\n") : ""
2104
+ };
2105
+ }
2106
+ var STOP_STATUSES = /* @__PURE__ */ new Set(["killed", "cancelled", "cancelling"]);
2107
+ function parseAgentRunEvent(event) {
2108
+ if (event.type !== "tool-result") return null;
2109
+ if (event.toolName !== "startAgentRun" && event.toolName !== "controlAgentRun") {
2110
+ return null;
2111
+ }
2112
+ const raw = typeof event.content === "string" ? event.content.trim() : "";
2113
+ if (!raw.startsWith("{")) return null;
2114
+ let parsed;
2115
+ try {
2116
+ parsed = JSON.parse(raw);
2117
+ } catch {
2118
+ return null;
2119
+ }
2120
+ if (Array.isArray(parsed.runs)) return null;
2121
+ const snapshot = buildSnapshot(parsed, event);
2122
+ const status = readString(parsed.status);
2123
+ if (event.toolName === "startAgentRun") {
2124
+ if (!snapshot.runId) return null;
2125
+ return { kind: "start", snapshot };
2126
+ }
2127
+ if (parsed.found === false || status === "not_found") {
2128
+ return { kind: "gone", snapshot: { ...snapshot, status: "not_found" } };
2129
+ }
2130
+ if (status && STOP_STATUSES.has(status)) {
2131
+ return { kind: "stop", snapshot };
2132
+ }
2133
+ if (!status) return null;
2134
+ if (!snapshot.runId) return null;
2135
+ return { kind: "status", snapshot };
2136
+ }
2137
+
2138
+ // packages/cli/client/cliAgentRunToolExecutors.ts
2040
2139
  var noopOutput = { write: () => {
2041
2140
  } };
2042
2141
  var parseCallArgs = (call) => {
@@ -2069,7 +2168,16 @@ function createCliStartAgentRunExecutor(deps = {}) {
2069
2168
 
2070
2169
  --- \u9644\u52A0\u8F93\u5165 ---
2071
2170
  ${JSON.stringify(args.input)}`;
2072
- const rawArgs = ["--agent", agentKey, "--msg-file", "PLACEHOLDER", "--bg"];
2171
+ const rawArgs = [
2172
+ "--agent",
2173
+ agentKey,
2174
+ "--msg-file",
2175
+ "PLACEHOLDER",
2176
+ "--bg",
2177
+ // 非持久化派发(review 等一次性任务):透传 --ephemeral,run 完成后不留
2178
+ // dialog 记录。与 web 端 runAgentBackground 的 ephemeral: true 对齐。
2179
+ ...args.ephemeral === true ? ["--ephemeral"] : []
2180
+ ];
2073
2181
  const agentName = typeof args.agentName === "string" && args.agentName.trim() ? args.agentName.trim() : typeof args.name === "string" && args.name.trim() ? args.name.trim() : void 0;
2074
2182
  const { runId } = await spawnLocalBackgroundRun(
2075
2183
  {
@@ -2084,16 +2192,22 @@ ${JSON.stringify(args.input)}`;
2084
2192
  },
2085
2193
  deps
2086
2194
  );
2087
- const displayName = agentName ?? "agent";
2195
+ const displayName = resolveRunLabel({ agentName, agentKey, runId });
2088
2196
  const labels = agentRunCardLabels();
2197
+ const taskPreview = typeof args.task === "string" ? args.task.replace(/\s+/g, " ").trim().slice(0, TASK_PREVIEW_MAX) : "";
2089
2198
  return {
2090
2199
  content: JSON.stringify({
2091
2200
  runId,
2092
2201
  status: "running",
2093
- ...agentName ? { agentName } : {}
2202
+ ...agentName ? { agentName } : {},
2203
+ ...taskPreview ? { taskPreview } : {}
2094
2204
  }),
2095
2205
  metadata: {
2096
- displayData: formatStartRunCard(displayName, "running", labels)
2206
+ displayData: formatStartRunCard(displayName, "running", {
2207
+ task: taskPreview,
2208
+ runId,
2209
+ labels
2210
+ })
2097
2211
  }
2098
2212
  };
2099
2213
  };
@@ -2139,7 +2253,7 @@ function createCliControlAgentRunExecutor(deps = {}) {
2139
2253
  if (action === "status") {
2140
2254
  const reconciled = checkStaleRun(record.runId, deps) ?? record;
2141
2255
  const logTail = tailLines > 0 ? tailFile(record.logPath, tailLines, resolveFs(deps)) : void 0;
2142
- const name = reconciled.agentName || "agent";
2256
+ const name = resolveRunLabel(reconciled);
2143
2257
  const logLines = logTail ? logTail.split("\n") : void 0;
2144
2258
  const labels2 = agentRunCardLabels();
2145
2259
  return {
@@ -2166,7 +2280,15 @@ function createCliControlAgentRunExecutor(deps = {}) {
2166
2280
  ...logLines ? { logLines } : {}
2167
2281
  }),
2168
2282
  metadata: {
2169
- displayData: formatStatusRunCard(name, reconciled.status, { logLines, labels: labels2 })
2283
+ displayData: formatStatusRunCard(name, reconciled.status, {
2284
+ runId: reconciled.runId,
2285
+ timing: {
2286
+ startedAt: readTimestamp(reconciled.startedAt),
2287
+ finishedAt: readTimestamp(reconciled.endedAt)
2288
+ },
2289
+ logLines,
2290
+ labels: labels2
2291
+ })
2170
2292
  }
2171
2293
  };
2172
2294
  }
@@ -2448,19 +2570,22 @@ function resolveAntigravityWireModel(logicalModelId) {
2448
2570
  return { wireModelId: id };
2449
2571
  }
2450
2572
 
2451
- // packages/agent-runtime/antigravityCloudCodeProvider.ts
2452
- var STREAM_PATH = "/v1internal:streamGenerateContent?alt=sse";
2573
+ // packages/agent-runtime/geminiNativeShared.ts
2453
2574
  var SKIP_THOUGHT_SIGNATURE = "skip_thought_signature_validator";
2454
- function isGemini3WireModel(modelId) {
2575
+ function isGemini3Model(modelId) {
2455
2576
  return modelId.includes("gemini-3");
2456
2577
  }
2457
2578
  function messageText(content) {
2458
2579
  if (typeof content === "string") return content;
2459
2580
  if (!Array.isArray(content)) return "";
2460
- return content.filter((part) => part?.type === "text").map((part) => part.text).join("\n").trim();
2581
+ return content.filter(
2582
+ (part) => part?.type === "text"
2583
+ ).map((part) => part.text).join("\n").trim();
2461
2584
  }
2462
2585
  function parseDataUrlToInlineData(url) {
2463
- const match = /^data:([A-Za-z0-9.+-]+\/[A-Za-z0-9.+-]+);base64,([A-Za-z0-9+/=]*)$/.exec(url);
2586
+ const match = /^data:([A-Za-z0-9.+-]+\/[A-Za-z0-9.+-]+);base64,([A-Za-z0-9+/=]*)$/.exec(
2587
+ url
2588
+ );
2464
2589
  if (!match) return null;
2465
2590
  return { mimeType: match[1], data: match[2] };
2466
2591
  }
@@ -2477,7 +2602,7 @@ function extractInlineDataParts(content) {
2477
2602
  }
2478
2603
  return parts;
2479
2604
  }
2480
- function convertOpenAiMessagesToCca(messages, options) {
2605
+ function convertOpenAiMessagesToGemini(messages, options) {
2481
2606
  const contents = [];
2482
2607
  const systemTexts = [];
2483
2608
  const toolNamesById = /* @__PURE__ */ new Map();
@@ -2493,9 +2618,11 @@ function convertOpenAiMessagesToCca(messages, options) {
2493
2618
  };
2494
2619
  const flushPendingFunctionCalls = () => {
2495
2620
  if (pendingFunctionCalls.length === 0) return;
2496
- const dummyResponses = pendingFunctionCalls.map(({ name }) => ({
2497
- functionResponse: { name, response: { output: "{}" } }
2498
- }));
2621
+ const dummyResponses = pendingFunctionCalls.map(
2622
+ ({ name }) => ({
2623
+ functionResponse: { name, response: { output: "{}" } }
2624
+ })
2625
+ );
2499
2626
  pendingFunctionCalls = [];
2500
2627
  pushOrMergeContent("user", dummyResponses);
2501
2628
  };
@@ -2504,13 +2631,17 @@ function convertOpenAiMessagesToCca(messages, options) {
2504
2631
  const role = String(raw.role);
2505
2632
  const content = "content" in raw ? raw.content : null;
2506
2633
  if (role === "system") {
2507
- const text = messageText(content);
2634
+ const text = messageText(
2635
+ content
2636
+ );
2508
2637
  if (text) systemTexts.push(text);
2509
2638
  continue;
2510
2639
  }
2511
2640
  if (role === "user") {
2512
2641
  flushPendingFunctionCalls();
2513
- const text = messageText(content);
2642
+ const text = messageText(
2643
+ content
2644
+ );
2514
2645
  const imageParts = extractInlineDataParts(
2515
2646
  content
2516
2647
  );
@@ -2524,7 +2655,9 @@ function convertOpenAiMessagesToCca(messages, options) {
2524
2655
  if (role === "assistant") {
2525
2656
  flushPendingFunctionCalls();
2526
2657
  const parts = [];
2527
- const text = messageText(content);
2658
+ const text = messageText(
2659
+ content
2660
+ );
2528
2661
  if (text) parts.push({ text });
2529
2662
  const toolCalls = "tool_calls" in raw && Array.isArray(raw.tool_calls) ? raw.tool_calls ?? [] : [];
2530
2663
  for (const call of toolCalls) {
@@ -2534,17 +2667,20 @@ function convertOpenAiMessagesToCca(messages, options) {
2534
2667
  toolNamesById.set(id, name);
2535
2668
  pendingFunctionCalls.push({ name, id });
2536
2669
  const realSignature = typeof call.thought_signature === "string" && call.thought_signature ? call.thought_signature : void 0;
2537
- const isFirstFunctionCallPart = !parts.some((p) => "functionCall" in p);
2538
- parts.push({
2670
+ const isFirstFunctionCallPart = !parts.some(
2671
+ (p) => "functionCall" in p
2672
+ );
2673
+ const signature = realSignature ?? (options.attachSkipThoughtSignature && isFirstFunctionCallPart ? SKIP_THOUGHT_SIGNATURE : void 0);
2674
+ const part = {
2539
2675
  functionCall: {
2540
2676
  name,
2541
- args: parseToolArgumentsJson(call.function?.arguments),
2542
- id
2677
+ args: parseToolArgs(call.function?.arguments),
2678
+ ...id ? { id } : {}
2543
2679
  },
2544
- ...realSignature ? { thoughtSignature: realSignature } : options.attachSkipThoughtSignature && isFirstFunctionCallPart ? { thoughtSignature: SKIP_THOUGHT_SIGNATURE } : {}
2545
- });
2680
+ ...signature ? { thoughtSignature: signature } : {}
2681
+ };
2682
+ parts.push(part);
2546
2683
  }
2547
- if (parts.length === 0) continue;
2548
2684
  pushOrMergeContent("model", parts);
2549
2685
  continue;
2550
2686
  }
@@ -2562,14 +2698,39 @@ function convertOpenAiMessagesToCca(messages, options) {
2562
2698
  }
2563
2699
  const output = messageText(content) || "{}";
2564
2700
  pushOrMergeContent("user", [
2565
- { functionResponse: { name, response: { output } } }
2701
+ {
2702
+ functionResponse: {
2703
+ name,
2704
+ response: { output },
2705
+ // 保留 OpenAI tool_call_id:antigravity Cloud Code Assist 网关把
2706
+ // Gemini contents 转成 Claude messages 时需要 functionResponse →
2707
+ // tool_result 的 tool_use_id;缺 id 时网关报
2708
+ // "tool_result.tool_use_id: Field required"(HTTP 400)。
2709
+ ...toolCallId ? { id: toolCallId } : {}
2710
+ }
2711
+ }
2566
2712
  ]);
2567
2713
  }
2568
2714
  }
2569
2715
  flushPendingFunctionCalls();
2570
2716
  return { contents, systemTexts };
2571
2717
  }
2572
- function convertOpenAiTools(tools) {
2718
+ function parseToolArgs(raw) {
2719
+ if (typeof raw === "string") {
2720
+ try {
2721
+ const parsed = JSON.parse(raw);
2722
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
2723
+ return parsed;
2724
+ }
2725
+ } catch {
2726
+ }
2727
+ }
2728
+ if (raw && typeof raw === "object" && !Array.isArray(raw)) {
2729
+ return raw;
2730
+ }
2731
+ return {};
2732
+ }
2733
+ function convertOpenAiToolsToGemini(tools) {
2573
2734
  if (!Array.isArray(tools) || tools.length === 0) return void 0;
2574
2735
  const declarations = [];
2575
2736
  for (const tool of tools) {
@@ -2586,6 +2747,97 @@ function convertOpenAiTools(tools) {
2586
2747
  if (declarations.length === 0) return void 0;
2587
2748
  return [{ functionDeclarations: declarations }];
2588
2749
  }
2750
+ function accumulateGeminiChunks(chunks) {
2751
+ let text = "";
2752
+ const toolCalls = [];
2753
+ let usage;
2754
+ let pendingThoughtSignature;
2755
+ for (const chunk of chunks) {
2756
+ if (!chunk || typeof chunk !== "object") continue;
2757
+ const response = "response" in chunk && chunk.response && typeof chunk.response === "object" ? chunk.response : chunk;
2758
+ if ("usageMetadata" in response && response.usageMetadata && typeof response.usageMetadata === "object") {
2759
+ const meta = response.usageMetadata;
2760
+ const prompt = typeof meta.promptTokenCount === "number" ? meta.promptTokenCount : 0;
2761
+ const candidates2 = typeof meta.candidatesTokenCount === "number" ? meta.candidatesTokenCount : 0;
2762
+ const total = typeof meta.totalTokenCount === "number" ? meta.totalTokenCount : prompt + candidates2;
2763
+ usage = {
2764
+ prompt_tokens: prompt,
2765
+ completion_tokens: candidates2,
2766
+ total_tokens: total
2767
+ };
2768
+ }
2769
+ const candidates = Array.isArray(response.candidates) ? response.candidates : [];
2770
+ for (const candidate of candidates) {
2771
+ if (!candidate || typeof candidate !== "object") continue;
2772
+ const parts = Array.isArray(
2773
+ candidate.content?.parts
2774
+ ) ? candidate.content.parts : [];
2775
+ for (const part of parts) {
2776
+ if (!part || typeof part !== "object") continue;
2777
+ const partSignature = part.thoughtSignature;
2778
+ if ("text" in part && typeof part.text === "string") {
2779
+ const piece = part.text;
2780
+ if (!part.thought) {
2781
+ text += piece;
2782
+ }
2783
+ }
2784
+ if (part.thought && typeof partSignature === "string" && partSignature) {
2785
+ pendingThoughtSignature = partSignature;
2786
+ }
2787
+ if ("functionCall" in part && part.functionCall) {
2788
+ const call = part.functionCall;
2789
+ const name = typeof call.name === "string" ? call.name : "tool";
2790
+ const id = typeof call.id === "string" ? call.id : `${name}_${toolCalls.length}`;
2791
+ const argsObj = call.args && typeof call.args === "object" ? call.args : {};
2792
+ const resolvedSignature = typeof partSignature === "string" && partSignature ? partSignature : pendingThoughtSignature;
2793
+ pendingThoughtSignature = void 0;
2794
+ toolCalls.push({
2795
+ id,
2796
+ type: "function",
2797
+ function: { name, arguments: JSON.stringify(argsObj) },
2798
+ ...typeof resolvedSignature === "string" && resolvedSignature ? { thought_signature: resolvedSignature } : {}
2799
+ });
2800
+ }
2801
+ }
2802
+ }
2803
+ }
2804
+ return { text, toolCalls, usage };
2805
+ }
2806
+ function shouldUseGeminiNativeToolRoute(provider, model, tools, isImageModel) {
2807
+ return provider === "google" && !isImageModel(model) && isGemini3Model(model) && Array.isArray(tools) && tools.length > 0;
2808
+ }
2809
+ function buildGeminiGenerateContentRequest(args) {
2810
+ const { contents, systemTexts } = convertOpenAiMessagesToGemini(
2811
+ args.messages,
2812
+ { attachSkipThoughtSignature: args.attachSkipThoughtSignature }
2813
+ );
2814
+ const request = { contents };
2815
+ if (systemTexts.length > 0) {
2816
+ request.systemInstruction = {
2817
+ role: "user",
2818
+ parts: systemTexts.map((text) => ({ text }))
2819
+ };
2820
+ }
2821
+ const toolsResult = convertOpenAiToolsToGemini(args.tools);
2822
+ if (toolsResult) {
2823
+ request.tools = toolsResult;
2824
+ request.toolConfig = { functionCallingConfig: { mode: "VALIDATED" } };
2825
+ }
2826
+ const generationConfig = {};
2827
+ if (typeof args.maxTokens === "number" && args.maxTokens > 0) {
2828
+ generationConfig.maxOutputTokens = args.maxTokens;
2829
+ }
2830
+ if (typeof args.temperature === "number") {
2831
+ generationConfig.temperature = args.temperature;
2832
+ }
2833
+ if (Object.keys(generationConfig).length > 0) {
2834
+ request.generationConfig = generationConfig;
2835
+ }
2836
+ return request;
2837
+ }
2838
+
2839
+ // packages/agent-runtime/antigravityCloudCodeProvider.ts
2840
+ var STREAM_PATH = "/v1internal:streamGenerateContent?alt=sse";
2589
2841
  function buildCloudCodeAssistPayload(args) {
2590
2842
  const projectId = readAntigravityProjectId(args.metadata);
2591
2843
  if (!projectId) {
@@ -2596,8 +2848,9 @@ function buildCloudCodeAssistPayload(args) {
2596
2848
  const logicalModel = asOptionalTrimmedString(args.openAiBody.model) ?? asOptionalTrimmedString(args.agentConfig.model) ?? "gemini-3.1-pro";
2597
2849
  const { wireModelId: model, profile } = resolveAntigravityWireModel(logicalModel);
2598
2850
  const rawMessages = Array.isArray(args.openAiBody.messages) ? args.openAiBody.messages : [];
2599
- const { contents, systemTexts } = convertOpenAiMessagesToCca(rawMessages, {
2600
- attachSkipThoughtSignature: isGemini3WireModel(model)
2851
+ const isClaude = model.toLowerCase().includes("claude");
2852
+ const { contents, systemTexts } = convertOpenAiMessagesToGemini(rawMessages, {
2853
+ attachSkipThoughtSignature: isGemini3Model(model)
2601
2854
  });
2602
2855
  if (contents.length === 0) {
2603
2856
  throw new Error("Antigravity Cloud Code Assist request has no user/model contents.");
@@ -2611,7 +2864,7 @@ function buildCloudCodeAssistPayload(args) {
2611
2864
  parts: systemTexts.map((text) => ({ text }))
2612
2865
  };
2613
2866
  }
2614
- const tools = convertOpenAiTools(
2867
+ const tools = convertOpenAiToolsToGemini(
2615
2868
  Array.isArray(args.openAiBody.tools) ? args.openAiBody.tools : void 0
2616
2869
  );
2617
2870
  if (tools) {
@@ -2634,7 +2887,6 @@ function buildCloudCodeAssistPayload(args) {
2634
2887
  const trajectoryId = randomUUID();
2635
2888
  const step = 2;
2636
2889
  const requestId = `agent/${agentId}/${Date.now()}/${trajectoryId}/${step}`;
2637
- const isClaude = model.toLowerCase().includes("claude");
2638
2890
  const labels = {
2639
2891
  trajectory_id: trajectoryId,
2640
2892
  last_step_index: String(step - 1),
@@ -2658,57 +2910,6 @@ function buildCloudCodeAssistPayload(args) {
2658
2910
  }
2659
2911
  };
2660
2912
  }
2661
- function accumulateCcaChunks(chunks) {
2662
- let text = "";
2663
- const toolCalls = [];
2664
- let usage;
2665
- for (const chunk of chunks) {
2666
- if (!chunk || typeof chunk !== "object") continue;
2667
- const response = "response" in chunk && chunk.response && typeof chunk.response === "object" ? chunk.response : chunk;
2668
- if ("usageMetadata" in response && response.usageMetadata && typeof response.usageMetadata === "object") {
2669
- const meta = response.usageMetadata;
2670
- const prompt = typeof meta.promptTokenCount === "number" ? meta.promptTokenCount : 0;
2671
- const candidates2 = typeof meta.candidatesTokenCount === "number" ? meta.candidatesTokenCount : 0;
2672
- const total = typeof meta.totalTokenCount === "number" ? meta.totalTokenCount : prompt + candidates2;
2673
- usage = {
2674
- prompt_tokens: prompt,
2675
- completion_tokens: candidates2,
2676
- total_tokens: total
2677
- };
2678
- }
2679
- const candidates = Array.isArray(response.candidates) ? response.candidates : [];
2680
- for (const candidate of candidates) {
2681
- if (!candidate || typeof candidate !== "object" || !("content" in candidate)) continue;
2682
- const content = candidate.content;
2683
- if (!content || typeof content !== "object" || !("parts" in content)) continue;
2684
- const parts = content.parts;
2685
- if (!Array.isArray(parts)) continue;
2686
- for (const part of parts) {
2687
- if (!part || typeof part !== "object") continue;
2688
- const partSignature = part.thoughtSignature;
2689
- if ("text" in part && typeof part.text === "string") {
2690
- const piece = part.text;
2691
- if (!part.thought) {
2692
- text += piece;
2693
- }
2694
- }
2695
- if ("functionCall" in part && part.functionCall) {
2696
- const call = part.functionCall;
2697
- const name = typeof call.name === "string" ? call.name : "tool";
2698
- const id = typeof call.id === "string" ? call.id : `${name}_${toolCalls.length}`;
2699
- const argsObj = asRecordOrEmpty(call.args);
2700
- toolCalls.push({
2701
- id,
2702
- type: "function",
2703
- function: { name, arguments: JSON.stringify(argsObj) },
2704
- ...typeof partSignature === "string" && partSignature ? { thought_signature: partSignature } : {}
2705
- });
2706
- }
2707
- }
2708
- }
2709
- }
2710
- return { text, toolCalls, usage };
2711
- }
2712
2913
  async function readSseJsonChunks(response) {
2713
2914
  return readSseDataValues(response, parseSseDataLineJson);
2714
2915
  }
@@ -2733,7 +2934,7 @@ async function fetchAntigravityCloudCodeCompletion(args) {
2733
2934
  };
2734
2935
  }
2735
2936
  const chunks = await readSseJsonChunks(response);
2736
- const { text, toolCalls, usage } = accumulateCcaChunks(chunks);
2937
+ const { text, toolCalls, usage } = accumulateGeminiChunks(chunks);
2737
2938
  const message = {
2738
2939
  role: "assistant",
2739
2940
  content: text || null
@@ -2769,28 +2970,94 @@ var CLAUDE_CODE_IDENTITY_PATTERNS = [
2769
2970
  CLAUDE_CODE_SYSTEM_INSTRUCTION,
2770
2971
  "You are Claude Code"
2771
2972
  ];
2973
+ var REASONING_EFFORT_TO_BUDGET = {
2974
+ minimal: 2048,
2975
+ low: 4096,
2976
+ medium: 8192,
2977
+ high: 16384,
2978
+ xhigh: 32e3,
2979
+ max: 32e3
2980
+ };
2981
+ function resolveThinkingBudget(effort) {
2982
+ if (!effort) return void 0;
2983
+ const normalized = effort.toLowerCase();
2984
+ if (normalized === "none" || normalized === "off") return void 0;
2985
+ return REASONING_EFFORT_TO_BUDGET[normalized];
2986
+ }
2987
+ var DEFAULT_THINKING_EFFORT = "medium";
2988
+ var DEFAULT_ENABLED_BUDGET = 8192;
2989
+ var DEFAULT_ENABLE_THINKING_BUDGET = 8e3;
2990
+ var ANTHROPIC_EFFORT_ALIASES = { minimal: "low" };
2991
+ function resolveThinkingSpec(input) {
2992
+ const { model, maxTokens } = input;
2993
+ const normalizedEffort = input.reasoningEffort?.toLowerCase();
2994
+ const effortDisabled = normalizedEffort === "none" || normalizedEffort === "off";
2995
+ const effectiveEffort = normalizedEffort !== void 0 && !effortDisabled ? ANTHROPIC_EFFORT_ALIASES[normalizedEffort] ?? normalizedEffort : DEFAULT_THINKING_EFFORT;
2996
+ let thinkingBlock;
2997
+ let outputConfig;
2998
+ let finalMaxTokens = maxTokens;
2999
+ let finalTemperature = input.temperature;
3000
+ if (isAdaptiveThinkingModelId(model)) {
3001
+ if (effortDisabled) {
3002
+ thinkingBlock = { type: "disabled" };
3003
+ } else {
3004
+ thinkingBlock = { type: "adaptive", display: "summarized" };
3005
+ outputConfig = { effort: effectiveEffort };
3006
+ }
3007
+ } else {
3008
+ const injected = input.injectedThinking;
3009
+ const injectedBudget = injected?.type === "enabled" && typeof injected.budget_tokens === "number" ? injected.budget_tokens : void 0;
3010
+ const effortBudget = resolveThinkingBudget(input.reasoningEffort);
3011
+ const fallbackBudget = input.reasoningEffort === void 0 ? injectedBudget ?? (input.enableThinking === true ? typeof input.thinkingBudget === "number" ? input.thinkingBudget : DEFAULT_ENABLE_THINKING_BUDGET : DEFAULT_ENABLED_BUDGET) : void 0;
3012
+ const thinkingBudget = effortBudget ?? fallbackBudget;
3013
+ if (thinkingBudget !== void 0) {
3014
+ thinkingBlock = { type: "enabled", budget_tokens: thinkingBudget };
3015
+ finalMaxTokens = Math.max(maxTokens, thinkingBudget + 1);
3016
+ finalTemperature = 1;
3017
+ }
3018
+ }
3019
+ return {
3020
+ thinkingBlock,
3021
+ outputConfig,
3022
+ maxTokens: finalMaxTokens,
3023
+ temperature: finalTemperature
3024
+ };
3025
+ }
2772
3026
  function stringValue(value) {
2773
3027
  return typeof value === "string" && value.length > 0 ? value : void 0;
2774
3028
  }
3029
+ function isCacheControl(value) {
3030
+ return Boolean(
3031
+ value && typeof value === "object" && !Array.isArray(value) && typeof value.type === "string"
3032
+ );
3033
+ }
2775
3034
  function toAnthropicContent(content) {
2776
- if (typeof content === "string") return [{ type: "text", text: content }];
3035
+ if (typeof content === "string") {
3036
+ return content.length > 0 ? [{ type: "text", text: content }] : [];
3037
+ }
2777
3038
  if (!Array.isArray(content)) return [];
2778
3039
  const blocks = [];
2779
3040
  for (const raw of content) {
2780
3041
  if (!raw || typeof raw !== "object") continue;
2781
3042
  const part = raw;
2782
3043
  if ((part.type === "text" || part.type === "input_text") && typeof part.text === "string") {
2783
- blocks.push({ type: "text", text: part.text });
3044
+ if (part.text.length > 0) {
3045
+ const block2 = { type: "text", text: part.text };
3046
+ if (isCacheControl(part.cache_control)) block2.cache_control = part.cache_control;
3047
+ blocks.push(block2);
3048
+ }
2784
3049
  continue;
2785
3050
  }
2786
3051
  if (part.type !== "image_url") continue;
2787
3052
  const imageUrl = typeof part.image_url === "string" ? part.image_url : stringValue(part.image_url?.url);
2788
3053
  if (!imageUrl) continue;
2789
3054
  const dataMatch = imageUrl.match(/^data:([^;,]+);base64,(.+)$/s);
2790
- blocks.push({
3055
+ const block = {
2791
3056
  type: "image",
2792
3057
  source: dataMatch ? { type: "base64", media_type: dataMatch[1], data: dataMatch[2] } : { type: "url", url: imageUrl }
2793
- });
3058
+ };
3059
+ if (isCacheControl(part.cache_control)) block.cache_control = part.cache_control;
3060
+ blocks.push(block);
2794
3061
  }
2795
3062
  return blocks;
2796
3063
  }
@@ -2824,7 +3091,15 @@ function buildAnthropicMessagesBody(args) {
2824
3091
  const message = raw;
2825
3092
  const role = String(message.role ?? "");
2826
3093
  if (role === "system" || role === "developer") {
2827
- system.push(...toAnthropicContent(message.content));
3094
+ const stablePrefixChars = Number(message.stable_prefix_chars);
3095
+ if (typeof message.content === "string" && Number.isFinite(stablePrefixChars) && stablePrefixChars > 0 && stablePrefixChars <= message.content.length) {
3096
+ const stable = message.content.slice(0, stablePrefixChars);
3097
+ const dynamic = message.content.slice(stablePrefixChars);
3098
+ system.push({ type: "text", text: stable, cache_control: { type: "ephemeral" } });
3099
+ if (dynamic) system.push({ type: "text", text: dynamic });
3100
+ } else {
3101
+ system.push(...toAnthropicContent(message.content));
3102
+ }
2828
3103
  continue;
2829
3104
  }
2830
3105
  if (role === "tool") {
@@ -2866,6 +3141,9 @@ function buildAnthropicMessagesBody(args) {
2866
3141
  if (!hasClaudeCodeIdentity(system)) {
2867
3142
  system.unshift({ type: "text", text: CLAUDE_CODE_SYSTEM_INSTRUCTION });
2868
3143
  }
3144
+ if (system.length > 0 && !system.some((block) => isCacheControl(block.cache_control))) {
3145
+ system[system.length - 1].cache_control = { type: "ephemeral" };
3146
+ }
2869
3147
  const tools = Array.isArray(args.openAiBody.tools) ? args.openAiBody.tools.flatMap((raw) => {
2870
3148
  if (!raw || typeof raw !== "object") return [];
2871
3149
  const fn = raw.function;
@@ -2880,14 +3158,39 @@ function buildAnthropicMessagesBody(args) {
2880
3158
  const model = stringValue(args.openAiBody.model) ?? args.agentConfig.model ?? "claude-sonnet-5";
2881
3159
  const maxTokensRaw = args.openAiBody.max_completion_tokens ?? args.openAiBody.max_tokens ?? args.agentConfig.max_tokens;
2882
3160
  const maxTokens = typeof maxTokensRaw === "number" && Number.isFinite(maxTokensRaw) ? Math.max(1, Math.floor(maxTokensRaw)) : 8192;
3161
+ const reasoningEffort = stringValue(args.openAiBody.reasoning_effort) ?? stringValue(args.agentConfig.reasoning_effort);
3162
+ const spec = resolveThinkingSpec({
3163
+ model,
3164
+ reasoningEffort,
3165
+ maxTokens,
3166
+ temperature: typeof args.openAiBody.temperature === "number" ? args.openAiBody.temperature : args.agentConfig.temperature,
3167
+ injectedThinking: args.openAiBody.thinking,
3168
+ enableThinking: args.agentConfig.enableThinking,
3169
+ thinkingBudget: args.agentConfig.thinkingBudget
3170
+ });
3171
+ const { thinkingBlock, outputConfig } = spec;
3172
+ const finalMaxTokens = spec.maxTokens;
3173
+ const finalTemperature = spec.temperature;
3174
+ if (messages.length > 0) {
3175
+ const lastMessage = messages[messages.length - 1];
3176
+ const content = Array.isArray(lastMessage.content) ? lastMessage.content : [];
3177
+ if (content.length > 0) {
3178
+ const lastBlock = content[content.length - 1];
3179
+ if (!isCacheControl(lastBlock.cache_control)) {
3180
+ lastBlock.cache_control = { type: "ephemeral" };
3181
+ }
3182
+ }
3183
+ }
2883
3184
  return {
2884
3185
  model,
2885
3186
  messages,
2886
- max_tokens: maxTokens,
3187
+ max_tokens: finalMaxTokens,
2887
3188
  stream: false,
3189
+ ...thinkingBlock ? { thinking: thinkingBlock } : {},
3190
+ ...outputConfig ? { output_config: outputConfig } : {},
2888
3191
  ...system.length > 0 ? { system } : {},
2889
3192
  ...tools.length > 0 ? { tools } : {},
2890
- ...typeof args.openAiBody.temperature === "number" ? { temperature: args.openAiBody.temperature } : typeof args.agentConfig.temperature === "number" ? { temperature: args.agentConfig.temperature } : {},
3193
+ ...typeof finalTemperature === "number" ? { temperature: finalTemperature } : {},
2891
3194
  ...typeof args.openAiBody.top_p === "number" ? { top_p: args.openAiBody.top_p } : {}
2892
3195
  };
2893
3196
  }
@@ -2911,6 +3214,8 @@ function mapAnthropicMessageToOpenAi(payload) {
2911
3214
  }
2912
3215
  const usage = payload.usage ?? {};
2913
3216
  const inputTokens = (typeof usage.input_tokens === "number" ? usage.input_tokens : 0) + (typeof usage.cache_creation_input_tokens === "number" ? usage.cache_creation_input_tokens : 0) + (typeof usage.cache_read_input_tokens === "number" ? usage.cache_read_input_tokens : 0);
3217
+ const cacheCreationInputTokens = typeof usage.cache_creation_input_tokens === "number" ? usage.cache_creation_input_tokens : 0;
3218
+ const cacheReadInputTokens = typeof usage.cache_read_input_tokens === "number" ? usage.cache_read_input_tokens : 0;
2914
3219
  const outputTokens = typeof usage.output_tokens === "number" ? usage.output_tokens : 0;
2915
3220
  const stopReason = String(payload.stop_reason ?? "");
2916
3221
  const message = { role: "assistant", content: text || null };
@@ -2926,9 +3231,16 @@ function mapAnthropicMessageToOpenAi(payload) {
2926
3231
  finish_reason: toolCalls.length > 0 || stopReason === "tool_use" ? "tool_calls" : stopReason === "max_tokens" ? "length" : "stop"
2927
3232
  }],
2928
3233
  usage: {
3234
+ // prompt_tokens/input_tokens are total input, including cache read/write.
3235
+ // Preserve Anthropic's components so normalization and billing can apply
3236
+ // the correct cache prices without double-counting them.
2929
3237
  prompt_tokens: inputTokens,
3238
+ input_tokens: inputTokens,
2930
3239
  completion_tokens: outputTokens,
2931
- total_tokens: inputTokens + outputTokens
3240
+ output_tokens: outputTokens,
3241
+ total_tokens: inputTokens + outputTokens,
3242
+ cache_creation_input_tokens: cacheCreationInputTokens,
3243
+ cache_read_input_tokens: cacheReadInputTokens
2932
3244
  }
2933
3245
  };
2934
3246
  }
@@ -9003,6 +9315,262 @@ function isCursorOAuthAgent(agent) {
9003
9315
  return agent.apiKeyRef?.trim().toLowerCase() === "cursor";
9004
9316
  }
9005
9317
 
9318
+ // packages/agent-runtime/codexResponsesProvider.ts
9319
+ import { randomUUID as randomUUID4 } from "node:crypto";
9320
+ var CODEX_RESPONSES_URL = "https://chatgpt.com/backend-api/codex/responses";
9321
+ var CODEX_CLIENT_VERSION = "0.144.1";
9322
+ var CODEX_ORIGINATOR = "codex_cli_rs";
9323
+ var CODEX_OPENAI_BETA = "responses=experimental";
9324
+ var OPENAI_AUTH_CLAIM = "https://api.openai.com/auth";
9325
+ var CODEX_INSTALLATION_ID = randomUUID4();
9326
+ function decodeCodexAccountId(accessToken) {
9327
+ const parts = accessToken.split(".");
9328
+ if (parts.length < 2) return void 0;
9329
+ try {
9330
+ const payload = JSON.parse(
9331
+ Buffer.from(parts[1], "base64").toString("utf8")
9332
+ );
9333
+ const claim = payload[OPENAI_AUTH_CLAIM];
9334
+ const value = claim && typeof claim === "object" ? claim.chatgpt_account_id : void 0;
9335
+ return typeof value === "string" && value ? value : void 0;
9336
+ } catch {
9337
+ return void 0;
9338
+ }
9339
+ }
9340
+ function createCodexRequestIdentity(installationId = CODEX_INSTALLATION_ID) {
9341
+ const sessionId = randomUUID4();
9342
+ const threadId = randomUUID4();
9343
+ const windowId = randomUUID4();
9344
+ const turnId = randomUUID4();
9345
+ const turnMetadata = {
9346
+ installation_id: installationId,
9347
+ session_id: sessionId,
9348
+ thread_id: threadId,
9349
+ turn_id: turnId,
9350
+ window_id: windowId,
9351
+ request_kind: "turn",
9352
+ turn_started_at_unix_ms: Date.now()
9353
+ };
9354
+ const turnMetadataJson = JSON.stringify(turnMetadata);
9355
+ return {
9356
+ sessionId,
9357
+ threadId,
9358
+ windowId,
9359
+ turnId,
9360
+ turnMetadataJson,
9361
+ clientMetadata: {
9362
+ "x-codex-installation-id": installationId,
9363
+ session_id: sessionId,
9364
+ thread_id: threadId,
9365
+ "x-codex-window-id": windowId,
9366
+ turn_id: turnId,
9367
+ "x-codex-turn-metadata": turnMetadataJson
9368
+ }
9369
+ };
9370
+ }
9371
+ function buildCodexCompatibilityHeaders(identity, accountId) {
9372
+ return {
9373
+ Authorization: "",
9374
+ // filled by caller with bearer token
9375
+ "Content-Type": "application/json",
9376
+ Accept: "text/event-stream",
9377
+ "chatgpt-account-id": accountId,
9378
+ "OpenAI-Beta": CODEX_OPENAI_BETA,
9379
+ originator: CODEX_ORIGINATOR,
9380
+ version: CODEX_CLIENT_VERSION,
9381
+ session_id: identity.sessionId,
9382
+ conversation_id: identity.sessionId,
9383
+ "x-client-request-id": identity.sessionId,
9384
+ "session-id": identity.sessionId,
9385
+ "thread-id": identity.threadId,
9386
+ "x-codex-window-id": identity.windowId,
9387
+ "x-codex-turn-metadata": identity.turnMetadataJson
9388
+ };
9389
+ }
9390
+ function collectInstructions(messages, agentPrompt) {
9391
+ const systemTexts = [];
9392
+ const prompt = agentPrompt?.trim();
9393
+ if (prompt) systemTexts.push(prompt);
9394
+ for (const raw of messages) {
9395
+ if (!raw || typeof raw !== "object") continue;
9396
+ const role = String(raw.role ?? "");
9397
+ if (role !== "system" && role !== "developer") continue;
9398
+ const content = raw.content;
9399
+ const stringContent = asOptionalTrimmedString(content);
9400
+ if (stringContent) {
9401
+ systemTexts.push(stringContent);
9402
+ } else if (Array.isArray(content)) {
9403
+ const text = content.filter(
9404
+ (p) => !!p && p.type === "text"
9405
+ ).map((p) => p.text).join("\n").trim();
9406
+ if (text) systemTexts.push(text);
9407
+ }
9408
+ }
9409
+ return systemTexts.join("\n\n");
9410
+ }
9411
+ function collectStableInstructions(messages, fallbackPrompt) {
9412
+ const systemTexts = [];
9413
+ if (fallbackPrompt?.trim()) systemTexts.push(fallbackPrompt.trim());
9414
+ for (const raw of messages) {
9415
+ if (!raw || typeof raw !== "object") continue;
9416
+ const message = raw;
9417
+ const role = String(message.role ?? "");
9418
+ if (role !== "system" && role !== "developer") continue;
9419
+ if (typeof message.content === "string") {
9420
+ const boundary = Number(message.stable_prefix_chars);
9421
+ const text = Number.isFinite(boundary) && boundary > 0 ? message.content.slice(0, boundary) : message.content;
9422
+ if (text.trim()) systemTexts.push(text.trim());
9423
+ }
9424
+ }
9425
+ return systemTexts.join("\n\n");
9426
+ }
9427
+ function stablePromptCacheKey(parts) {
9428
+ const value = JSON.stringify(parts);
9429
+ let hash = 2166136261;
9430
+ for (let index = 0; index < value.length; index += 1) {
9431
+ hash ^= value.charCodeAt(index);
9432
+ hash = Math.imul(hash, 16777619) >>> 0;
9433
+ }
9434
+ return `nolo-codex-${hash.toString(16).padStart(8, "0")}`;
9435
+ }
9436
+ function buildCodexRequestBody(args, identity = createCodexRequestIdentity()) {
9437
+ const rawMessages = Array.isArray(args.openAiBody.messages) ? args.openAiBody.messages : [];
9438
+ const nonSystem = rawMessages.filter((m) => {
9439
+ const role = m && typeof m === "object" ? String(m.role) : "";
9440
+ return role !== "system" && role !== "developer";
9441
+ });
9442
+ const input = convertMessagesToResponsesInput(nonSystem);
9443
+ const instructions = collectInstructions(rawMessages, args.agentConfig.prompt);
9444
+ const stableInstructions = collectStableInstructions(rawMessages, args.agentConfig.prompt);
9445
+ const model = asOptionalTrimmedString(args.openAiBody.model) ?? asOptionalTrimmedString(args.agentConfig.model) ?? "gpt-5.5";
9446
+ const tools = toResponsesTools(
9447
+ Array.isArray(args.openAiBody.tools) ? args.openAiBody.tools : void 0
9448
+ );
9449
+ const body = {
9450
+ model,
9451
+ input,
9452
+ stream: true,
9453
+ store: false,
9454
+ // Keep routing stable across turns and request UUIDs. Growing input/history
9455
+ // is intentionally excluded; only stable request-prefix material belongs.
9456
+ prompt_cache_key: stablePromptCacheKey([model, stableInstructions, tools ?? []]),
9457
+ client_metadata: identity.clientMetadata
9458
+ };
9459
+ if (instructions) body.instructions = instructions;
9460
+ if (tools && tools.length > 0) {
9461
+ body.tools = tools;
9462
+ body.tool_choice = "auto";
9463
+ body.parallel_tool_calls = true;
9464
+ }
9465
+ return body;
9466
+ }
9467
+ function aggregateResponsesStream(events) {
9468
+ let text = "";
9469
+ const toolCalls = [];
9470
+ let usage;
9471
+ for (const ev of events) {
9472
+ const type = String(ev.type ?? "");
9473
+ if (type === "response.output_text.delta" && typeof ev.delta === "string") {
9474
+ text += ev.delta;
9475
+ continue;
9476
+ }
9477
+ if (type === "response.output_item.done") {
9478
+ const item = ev.item;
9479
+ if (item && item.type === "function_call") {
9480
+ const name = typeof item.name === "string" ? item.name : "";
9481
+ if (name) {
9482
+ toolCalls.push({
9483
+ id: typeof item.call_id === "string" && item.call_id ? item.call_id : `${name}_${toolCalls.length}`,
9484
+ type: "function",
9485
+ function: {
9486
+ name,
9487
+ arguments: typeof item.arguments === "string" ? item.arguments : "{}"
9488
+ }
9489
+ });
9490
+ }
9491
+ }
9492
+ continue;
9493
+ }
9494
+ if (type === "response.completed") {
9495
+ const response = ev.response;
9496
+ const u = response?.usage;
9497
+ if (u) {
9498
+ const prompt = typeof u.input_tokens === "number" ? u.input_tokens : 0;
9499
+ const completion = typeof u.output_tokens === "number" ? u.output_tokens : 0;
9500
+ const total = typeof u.total_tokens === "number" ? u.total_tokens : prompt + completion;
9501
+ usage = {
9502
+ prompt_tokens: prompt,
9503
+ completion_tokens: completion,
9504
+ total_tokens: total
9505
+ };
9506
+ }
9507
+ }
9508
+ }
9509
+ return { text, toolCalls, usage };
9510
+ }
9511
+ async function readSseEvents(response) {
9512
+ return readSseDataValues(response, (line) => {
9513
+ const ev = parseSseDataLineObject(line);
9514
+ return ev && !Array.isArray(ev) ? ev : null;
9515
+ });
9516
+ }
9517
+ async function fetchCodexResponsesCompletion(args) {
9518
+ const fetchImpl = args.fetchImpl ?? fetch;
9519
+ const accountId = args.accountId?.trim() || decodeCodexAccountId(args.accessToken);
9520
+ if (!accountId) {
9521
+ return {
9522
+ status: 401,
9523
+ body: {
9524
+ error: {
9525
+ message: "ChatGPT Codex credential is missing chatgpt_account_id. Re-run `nolo auth chatgpt`."
9526
+ }
9527
+ }
9528
+ };
9529
+ }
9530
+ const identity = createCodexRequestIdentity();
9531
+ const body = buildCodexRequestBody(args, identity);
9532
+ const headers = buildCodexCompatibilityHeaders(identity, accountId);
9533
+ headers.Authorization = `Bearer ${args.accessToken}`;
9534
+ const response = await fetchImpl(CODEX_RESPONSES_URL, {
9535
+ method: "POST",
9536
+ headers,
9537
+ body: JSON.stringify(body),
9538
+ signal: args.signal
9539
+ });
9540
+ if (!response.ok) {
9541
+ const errorText = await response.text();
9542
+ return {
9543
+ status: response.status,
9544
+ body: { error: { message: errorText || response.statusText } }
9545
+ };
9546
+ }
9547
+ const events = await readSseEvents(response);
9548
+ const { text, toolCalls, usage } = aggregateResponsesStream(events);
9549
+ const message = {
9550
+ role: "assistant",
9551
+ content: text || null
9552
+ };
9553
+ if (toolCalls.length > 0) message.tool_calls = toolCalls;
9554
+ return {
9555
+ status: 200,
9556
+ body: {
9557
+ choices: [
9558
+ {
9559
+ index: 0,
9560
+ message,
9561
+ finish_reason: toolCalls.length > 0 ? "tool_calls" : "stop"
9562
+ }
9563
+ ],
9564
+ ...usage ? { usage } : {}
9565
+ }
9566
+ };
9567
+ }
9568
+ function isCodexOAuthAgent(agentConfig) {
9569
+ if (!agentConfig) return false;
9570
+ const apiKeyRef = asTrimmedLowercaseString(agentConfig.apiKeyRef);
9571
+ return apiKeyRef === "chatgpt";
9572
+ }
9573
+
9006
9574
  // packages/agent-runtime/oauthProviders.ts
9007
9575
  var XAI_ACCESS_TOKEN_CLIENT_SKEW_MS = 5 * 60 * 1e3;
9008
9576
  var decodeBase64 = (s) => Buffer.from(s, "base64").toString("utf8");
@@ -10200,6 +10768,74 @@ function createCliLocalRuntimeAdapter(deps) {
10200
10768
  }
10201
10769
  };
10202
10770
  }
10771
+ if (isCodexOAuthAgent(agentConfig)) {
10772
+ const accessToken = await apiKeyRefResolver("chatgpt");
10773
+ if (!accessToken) {
10774
+ throw new Error(
10775
+ 'OAuth credential for "chatgpt" not found locally. Run `nolo auth chatgpt`.'
10776
+ );
10777
+ }
10778
+ const credential = readOAuthCredential("chatgpt");
10779
+ const accountId = credential?.accountId;
10780
+ const { requestedToolNames: requestedToolNames2, tools: tools2 } = resolveProviderOpenAiToolBundle(
10781
+ agentConfig,
10782
+ deps.env,
10783
+ buildProviderOpenAiTools,
10784
+ additionalToolNames,
10785
+ { hasUserChoice: Boolean(deps.requestUserChoice) }
10786
+ );
10787
+ logLocalRuntimeDiagnostic("provider.selected", {
10788
+ agentKey: agentConfig.key,
10789
+ transport: "codex-responses",
10790
+ provider: "openai",
10791
+ model: agentConfig.model ?? "gpt-5.6-sol",
10792
+ hasApiKey: true
10793
+ });
10794
+ return {
10795
+ model: agentConfig.model || "gpt-5.6-sol",
10796
+ complete: async (messages, options) => {
10797
+ const result = await fetchCodexResponsesCompletion({
10798
+ agentConfig,
10799
+ accessToken,
10800
+ ...accountId ? { accountId } : {},
10801
+ openAiBody: {
10802
+ model: agentConfig.model || "gpt-5.6-sol",
10803
+ messages,
10804
+ stream: false,
10805
+ ...tools2.length > 0 ? { tools: tools2 } : {}
10806
+ },
10807
+ fetchImpl: (url, init) => fetchWithTransientRetry(fetchImpl, url, init, {
10808
+ sleep: deps.sleep,
10809
+ loopbackRequest
10810
+ })
10811
+ });
10812
+ if (result.status < 200 || result.status >= 300) {
10813
+ const errMsg = result.body?.error && typeof result.body.error === "object" && typeof result.body.error.message === "string" ? result.body.error.message : JSON.stringify(result.body);
10814
+ throw new Error(
10815
+ `local Codex OAuth provider failed: HTTP ${result.status} ${errMsg}`
10816
+ );
10817
+ }
10818
+ const choice = Array.isArray(result.body.choices) ? result.body.choices[0] : void 0;
10819
+ const message = choice?.message ?? {};
10820
+ const content = typeof message.content === "string" ? message.content : "";
10821
+ const tool_calls = Array.isArray(message.tool_calls) ? message.tool_calls : void 0;
10822
+ if (content && options?.onTextDelta) options.onTextDelta(content);
10823
+ logLocalRuntimeDiagnostic("provider.request.result", {
10824
+ agentKey: agentConfig.key,
10825
+ transport: "codex-responses",
10826
+ ok: true,
10827
+ contentChars: content.length,
10828
+ toolCallCount: tool_calls?.length ?? 0,
10829
+ requestedToolNames: requestedToolNames2
10830
+ });
10831
+ return {
10832
+ content,
10833
+ ...tool_calls ? { tool_calls } : {},
10834
+ trace: messages
10835
+ };
10836
+ }
10837
+ };
10838
+ }
10203
10839
  if (isCursorOAuthAgent(agentConfig)) {
10204
10840
  const accessToken = await apiKeyRefResolver("cursor");
10205
10841
  if (!accessToken) {
@@ -10269,6 +10905,101 @@ function createCliLocalRuntimeAdapter(deps) {
10269
10905
  }
10270
10906
  };
10271
10907
  }
10908
+ if (shouldUsePlatformChatProvider(deps.env, agentConfig) && isGemini3Model(agentConfig.model ?? "") && agentConfig.provider === "google") {
10909
+ const providerConfig2 = await resolvePlatformChatProviderConfig({
10910
+ agentConfig,
10911
+ env: deps.env,
10912
+ apiKeyRefResolver,
10913
+ credentialBroker,
10914
+ syncFetcher
10915
+ });
10916
+ const { requestedToolNames: requestedToolNames2, tools: tools2 } = resolveProviderOpenAiToolBundle(
10917
+ agentConfig,
10918
+ deps.env,
10919
+ buildProviderOpenAiTools,
10920
+ additionalToolNames,
10921
+ { hasUserChoice: Boolean(deps.requestUserChoice) }
10922
+ );
10923
+ if (tools2.length > 0 && providerConfig2.apiKey && shouldUseGeminiNativeToolRoute(
10924
+ agentConfig.provider ?? "",
10925
+ agentConfig.model ?? "",
10926
+ tools2,
10927
+ () => false
10928
+ // CLI 端不区分 image 模型
10929
+ )) {
10930
+ logLocalRuntimeDiagnostic("provider.selected", {
10931
+ agentKey: agentConfig.key,
10932
+ transport: "gemini-native-tool",
10933
+ apiSource: agentConfig.apiSource ?? null,
10934
+ provider: providerConfig2.provider,
10935
+ model: providerConfig2.model,
10936
+ hasApiKey: Boolean(providerConfig2.apiKey)
10937
+ });
10938
+ return {
10939
+ model: providerConfig2.model,
10940
+ complete: async (messages, options) => {
10941
+ const requestBody = buildGeminiGenerateContentRequest({
10942
+ messages,
10943
+ tools: tools2,
10944
+ maxTokens: typeof agentConfig.max_tokens === "number" ? agentConfig.max_tokens : void 0,
10945
+ temperature: typeof agentConfig.temperature === "number" ? agentConfig.temperature : void 0,
10946
+ attachSkipThoughtSignature: true
10947
+ });
10948
+ const model = providerConfig2.model;
10949
+ const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:streamGenerateContent?alt=sse`;
10950
+ logLocalRuntimeDiagnostic("provider.request.start", {
10951
+ agentKey: agentConfig.key,
10952
+ transport: "gemini-native-tool",
10953
+ model,
10954
+ messageCount: messages.length,
10955
+ toolCount: tools2.length,
10956
+ requestedToolNames: requestedToolNames2
10957
+ });
10958
+ const res = await fetchImpl(url, {
10959
+ method: "POST",
10960
+ headers: {
10961
+ "Content-Type": "application/json",
10962
+ "x-goog-api-key": providerConfig2.apiKey ?? ""
10963
+ },
10964
+ body: JSON.stringify(requestBody),
10965
+ signal: AbortSignal.timeout(12e4)
10966
+ });
10967
+ if (!res.ok) {
10968
+ const errText = await res.text();
10969
+ logLocalRuntimeDiagnostic("provider.request.failed", {
10970
+ agentKey: agentConfig.key,
10971
+ transport: "gemini-native-tool",
10972
+ status: res.status,
10973
+ error: errText.slice(0, 200)
10974
+ });
10975
+ throw new Error(
10976
+ `gemini native tool provider failed: HTTP ${res.status} ${errText.slice(0, 500)}`
10977
+ );
10978
+ }
10979
+ const chunks = await readSseDataValues(res, parseSseDataLineJson);
10980
+ const { text, toolCalls, usage } = accumulateGeminiChunks(chunks);
10981
+ if (text && options?.onTextDelta) {
10982
+ options.onTextDelta(text);
10983
+ }
10984
+ const result = {
10985
+ content: text,
10986
+ model,
10987
+ tool_calls: toolCalls.length > 0 ? toolCalls : void 0,
10988
+ ...usage ? { usage } : {},
10989
+ trace: messages
10990
+ };
10991
+ logLocalRuntimeDiagnostic("provider.request.result", {
10992
+ agentKey: agentConfig.key,
10993
+ transport: "gemini-native-tool",
10994
+ ok: true,
10995
+ contentChars: text.length,
10996
+ toolCallCount: toolCalls.length
10997
+ });
10998
+ return result;
10999
+ }
11000
+ };
11001
+ }
11002
+ }
10272
11003
  if (shouldUsePlatformChatProvider(deps.env, agentConfig)) {
10273
11004
  const providerConfig2 = await resolvePlatformChatProviderConfig({
10274
11005
  agentConfig,
@@ -10329,47 +11060,20 @@ function createCliLocalRuntimeAdapter(deps) {
10329
11060
  },
10330
11061
  {
10331
11062
  sleep: deps.sleep,
10332
- loopbackRequest
11063
+ loopbackRequest,
11064
+ // auto 档位转发 nolo.chat 时,网关层 502(server: Caddy、空 body)
11065
+ // 意味着请求根本没到 Bun 上游,provider 未受理,重试安全。
11066
+ // 与 429/503 同口径:不会重复计费/重复生成。
11067
+ retryableStatuses: /* @__PURE__ */ new Set([429, 502, 503]),
11068
+ onRetry: deps.activityReporter ? ({ attempt, maxAttempts, delayMs }) => {
11069
+ deps.activityReporter(
11070
+ `\u81EA\u52A8\u91CD\u8BD5 ${attempt}/${maxAttempts} \xB7 ${Math.ceil(delayMs / 1e3)}s`
11071
+ );
11072
+ } : void 0
10333
11073
  }
10334
11074
  );
10335
- let responseProviderConfig = providerConfig2;
10336
- let firstErrorRaw;
10337
- if (!res.ok) {
10338
- firstErrorRaw = await res.text().catch(() => "");
10339
- const fallbackProviderConfig = resolveLegacyDeepSeekProxyChatFallback({
10340
- providerConfig: providerConfig2,
10341
- status: res.status,
10342
- raw: firstErrorRaw
10343
- });
10344
- if (fallbackProviderConfig) {
10345
- responseProviderConfig = fallbackProviderConfig;
10346
- const fallbackRequest = buildPlatformChatCompletionRequest({
10347
- providerConfig: fallbackProviderConfig,
10348
- messages,
10349
- tools: tools2,
10350
- stream: false
10351
- });
10352
- logLocalRuntimeDiagnostic("provider.request.compatibility-fallback", {
10353
- agentKey: agentConfig.key,
10354
- provider: providerConfig2.provider,
10355
- fromEndpoint: summarizeEndpoint(providerConfig2.endpoint) ?? null,
10356
- toEndpoint: summarizeEndpoint(fallbackProviderConfig.endpoint) ?? null,
10357
- reason: "legacy-proxy-responses-schema"
10358
- });
10359
- res = await fetchWithTransientRetry(
10360
- fetchImpl,
10361
- fallbackRequest.url,
10362
- { ...fallbackRequest.init },
10363
- {
10364
- sleep: deps.sleep,
10365
- loopbackRequest
10366
- }
10367
- );
10368
- firstErrorRaw = void 0;
10369
- }
10370
- }
10371
11075
  if (!res.ok) {
10372
- const raw2 = firstErrorRaw ?? await res.text().catch(() => "");
11076
+ const raw2 = await res.text().catch(() => "");
10373
11077
  const data2 = parsePlatformChatCompletionData(raw2);
10374
11078
  const rawPreview = raw2.length > 200 ? `${raw2.slice(0, 200)}\u2026(${raw2.length}b)` : raw2;
10375
11079
  const gatewayHeaders = [
@@ -10420,7 +11124,7 @@ function createCliLocalRuntimeAdapter(deps) {
10420
11124
  });
10421
11125
  const data = parsePlatformChatCompletionData(raw);
10422
11126
  return parsePlatformChatCompletionResponse({
10423
- providerConfig: responseProviderConfig,
11127
+ providerConfig: providerConfig2,
10424
11128
  data,
10425
11129
  trace: messages
10426
11130
  });
@@ -10550,6 +11254,7 @@ function createCliLocalRuntimeAdapter(deps) {
10550
11254
  export {
10551
11255
  summarizeEndpoint,
10552
11256
  isBuiltinNoloAgentRef,
11257
+ parseAgentRunEvent,
10553
11258
  parseCliLocale,
10554
11259
  getCliLocale,
10555
11260
  setCliLocale,