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

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-6BR65FSI.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-KNZY4HXV.js} +35 -34
  7. package/{agentListCommands-6B5X4RC6.js → agentListCommands-N64PHBXM.js} +20 -19
  8. package/{agentMachineCommands-LOEARB6V.js → agentMachineCommands-2AIPJKFM.js} +18 -17
  9. package/{agentRecordCommands-DCH2WBL2.js → agentRecordCommands-TB4N7YSB.js} +34 -33
  10. package/{agentRunCommand-SGMH67WT.js → agentRunCommand-UVW2ZLKT.js} +34 -33
  11. package/{agentRuntimeLocal-YSYZ33ER.js → agentRuntimeLocal-T6YECTNF.js} +15 -16
  12. package/{agentSlice-IVE735EV.js → agentSlice-533PEM4O.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-OQMPU2ML.js → chunk-2OUI4TLC.js} +4 -4
  20. package/{chunk-SFXYKGK2.js → chunk-3S2VOMIF.js} +3 -3
  21. package/{chunk-E237VE6U.js → chunk-6KBBMW4D.js} +2 -2
  22. package/{chunk-U7LEGLEB.js → chunk-6N4KODMN.js} +1 -1
  23. package/{chunk-GRTFNYLR.js → chunk-A7O4KKLZ.js} +3 -3
  24. package/{chunk-WA6KZL5V.js → chunk-AAODAAUQ.js} +23 -20
  25. package/{chunk-4NLUNENX.js → chunk-C4MMO7W4.js} +1 -1
  26. package/{chunk-YNHQIXX5.js → chunk-CXM4IIUF.js} +21 -21
  27. package/{chunk-JKWWVF2I.js → chunk-D3HVJJIA.js} +1 -1
  28. package/{chunk-YYIRR6QC.js → chunk-DBLHEQH7.js} +140 -175
  29. package/{chunk-TTGAVETO.js → chunk-EABWT43X.js} +2 -2
  30. package/{chunk-RSYUDGGZ.js → chunk-F3UOACU4.js} +1 -1
  31. package/{chunk-VE6XMVKG.js → chunk-G2IQGDQZ.js} +163 -53
  32. package/{chunk-RKM3K52F.js → chunk-GPELDE6I.js} +2 -2
  33. package/{chunk-OGGHETUE.js → chunk-HQPG2PIV.js} +62 -19
  34. package/{chunk-XVP3C2KY.js → chunk-IWLUTMYX.js} +1 -1
  35. package/{chunk-B4KT7RN2.js → chunk-JTMNCCWF.js} +2 -2
  36. package/chunk-KFEVY3ST.js +255 -0
  37. package/{chunk-WNLPAOIT.js → chunk-KFHN5NGJ.js} +1 -1
  38. package/{chunk-EMXI3N3Z.js → chunk-KPD4CEQD.js} +2 -2
  39. package/{chunk-G2MKOQCB.js → chunk-KPJWHHG4.js} +1 -1
  40. package/{chunk-ISYE6GZB.js → chunk-L6NVTGI7.js} +1 -1
  41. package/{chunk-O53CP2QR.js → chunk-LCMAJFAD.js} +3 -3
  42. package/{chunk-WPN6RMDF.js → chunk-LO6JNGCT.js} +3 -3
  43. package/{chunk-J55UHASN.js → chunk-MSA4JAOZ.js} +1 -1
  44. package/{chunk-HRQCKQA5.js → chunk-MUCU6ATG.js} +8 -257
  45. package/{chunk-524BDL33.js → chunk-O6W2O2DA.js} +1 -15
  46. package/{chunk-4QQFLN5C.js → chunk-OVBVEXZ7.js} +4 -4
  47. package/{chunk-QZVGMD5F.js → chunk-PU4LXVAC.js} +1 -1
  48. package/{chunk-Z24FGIU2.js → chunk-R4L524UB.js} +3 -3
  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-BFRVXJJJ.js → chunk-SI73WO7P.js} +10 -10
  54. package/{chunk-WRN5EQT7.js → chunk-T26DWCH5.js} +3 -3
  55. package/{chunk-EHLHSX7R.js → chunk-UB4RYYNQ.js} +9 -2
  56. package/{chunk-YC3DJILJ.js → chunk-VHXXRWNL.js} +22 -8
  57. package/{chunk-OOIN7HSO.js → chunk-XJITGCTM.js} +10 -1
  58. package/{chunk-QLFCNUVQ.js → chunk-XJYXSTBK.js} +873 -172
  59. package/{chunk-V2J635L5.js → chunk-XOIF2TNF.js} +2 -2
  60. package/{chunk-VPTJB4HM.js → chunk-XPC5C7BK.js} +0 -3
  61. package/{chunk-I66RU7P7.js → chunk-XRSPI6CP.js} +1 -1
  62. package/{chunk-N5424GSW.js → chunk-YJKXGHJ6.js} +1 -1
  63. package/chunk-ZHXJ6M7T.js +27 -0
  64. package/{chunk-6565R2TI.js → chunk-ZOQNJXMS.js} +23 -18
  65. package/{createAgentAutomationAction-TS6NNZ4X.js → createAgentAutomationAction-OARFMDWU.js} +13 -13
  66. package/{createDialogAction-5HVQ33EX.js → createDialogAction-4E6ALCDK.js} +14 -14
  67. package/{createPageAction-4F3ZGQJD.js → createPageAction-RS65DDRX.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-MS7OYWHW.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-KYTKNGMU.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-LHTGYRMN.js} +201 -15
  78. package/index.js +47 -47
  79. package/{machineCommands-JQPEQFSE.js → machineCommands-RDQQBA72.js} +33 -32
  80. package/{machineWsRunDispatch-FFFNWVEW.js → machineWsRunDispatch-27RCTQQF.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-BTONC7NW.js} +89 -74
  86. package/{removeDialogAgentAction-HUFVN35S.js → removeDialogAgentAction-YDHBFEGI.js} +5 -5
  87. package/{runAgentClientLoop-A75BUU6D.js → runAgentClientLoop-Q4CL22BP.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-XLJ4DRG6.js} +13 -13
  93. package/{streamAgentChatTurn-DJAE7USZ.js → streamAgentChatTurn-YYAAGLZL.js} +30 -32
  94. package/{tools-YB6LXSVN.js → tools-5UKY65R3.js} +20 -20
  95. package/{tuiSummaryLlmCaller-QQL3JA5I.js → tuiSummaryLlmCaller-VUNVBRX3.js} +7 -6
  96. package/{updateDialogTitleAction-6HGFBM64.js → updateDialogTitleAction-VNSUVPUZ.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-T26DWCH5.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-G2IQGDQZ.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-CXM4IIUF.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-2OUI4TLC.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"
@@ -928,6 +940,7 @@ function agentRunCardLabels() {
928
940
  runStatus: t("runStatusLabel"),
929
941
  runStarted: t("runStartedLabel"),
930
942
  runStopped: t("runStoppedLabel"),
943
+ runFinished: t("runFinishedLabel"),
931
944
  logTail: t("runLogTailLabel"),
932
945
  runs: (count) => t("runsListLabel", String(count))
933
946
  };
@@ -1123,6 +1136,11 @@ async function fetchWithTransientRetry(fetchImpl, input, init, options = {}) {
1123
1136
  const attemptBudget = coreDraining ? coreDrainingMaxAttempts : maxAttempts;
1124
1137
  if (attempt < attemptBudget) {
1125
1138
  const delayMs = await resolveRetryAfterMs(response, attempt);
1139
+ options.onRetry?.({
1140
+ attempt: attempt + 1,
1141
+ maxAttempts: attemptBudget,
1142
+ delayMs
1143
+ });
1126
1144
  await (options.sleep ?? defaultSleep)(delayMs);
1127
1145
  continue;
1128
1146
  }
@@ -1136,7 +1154,13 @@ async function fetchWithTransientRetry(fetchImpl, input, init, options = {}) {
1136
1154
  if (!isTransientFetchError(error)) throw error;
1137
1155
  lastError = error;
1138
1156
  if (attempt < maxAttempts) {
1139
- await (options.sleep ?? defaultSleep)(transientFetchRetryDelayMs(attempt));
1157
+ const delayMs = transientFetchRetryDelayMs(attempt);
1158
+ options.onRetry?.({
1159
+ attempt: attempt + 1,
1160
+ maxAttempts,
1161
+ delayMs
1162
+ });
1163
+ await (options.sleep ?? defaultSleep)(delayMs);
1140
1164
  }
1141
1165
  }
1142
1166
  }
@@ -1466,14 +1490,14 @@ var BUILTIN_PLATFORM_AGENT_CONFIGS = {
1466
1490
  [PUBLIC_DEEPSEEK_V4_PRO_AGENT_KEY]: {
1467
1491
  key: PUBLIC_DEEPSEEK_V4_PRO_AGENT_KEY,
1468
1492
  name: "DeepSeek V4 Pro",
1469
- provider: "deepseek",
1493
+ provider: "nolo",
1470
1494
  model: "deepseek-v4-pro",
1471
1495
  apiSource: "platform",
1472
1496
  useServerProxy: true,
1473
1497
  rawRecord: {
1474
1498
  dbKey: PUBLIC_DEEPSEEK_V4_PRO_AGENT_KEY,
1475
1499
  isPublic: true,
1476
- provider: "deepseek",
1500
+ provider: "nolo",
1477
1501
  model: "deepseek-v4-pro",
1478
1502
  apiSource: "platform",
1479
1503
  useServerProxy: true
@@ -1511,22 +1535,6 @@ var BUILTIN_PLATFORM_AGENT_CONFIGS = {
1511
1535
  useServerProxy: true
1512
1536
  }
1513
1537
  },
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
1538
  [BUILTIN_NOLO_AGENT_KEY]: {
1531
1539
  key: BUILTIN_NOLO_AGENT_KEY,
1532
1540
  name: "Nolo",
@@ -2037,6 +2045,93 @@ function buildServerPlatformToolExecutors(args) {
2037
2045
 
2038
2046
  // packages/cli/client/cliAgentRunToolExecutors.ts
2039
2047
  import { existsSync, readFileSync } from "node:fs";
2048
+
2049
+ // packages/cli/client/agentRunSnapshot.ts
2050
+ function readString(value) {
2051
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
2052
+ }
2053
+ function readLogLines(parsed) {
2054
+ if (Array.isArray(parsed.logLines)) return parsed.logLines;
2055
+ const tail = readString(parsed.logTail);
2056
+ return tail ? tail.split("\n") : void 0;
2057
+ }
2058
+ function readTimestamp(value) {
2059
+ if (typeof value === "number" && Number.isFinite(value) && value > 0) return value;
2060
+ if (typeof value === "string" && value.trim()) {
2061
+ const parsed = Date.parse(value);
2062
+ if (Number.isFinite(parsed) && parsed > 0) return parsed;
2063
+ }
2064
+ return void 0;
2065
+ }
2066
+ function readToolNames(value) {
2067
+ if (!Array.isArray(value)) return void 0;
2068
+ const names = value.filter((n) => typeof n === "string" && Boolean(n.trim()));
2069
+ return names.length > 0 ? names : void 0;
2070
+ }
2071
+ function buildSnapshot(parsed, event) {
2072
+ const runId = readString(parsed.runId) ?? readString(event.metadata?.runId) ?? "";
2073
+ const label = resolveRunLabel({
2074
+ agentName: parsed.agentName,
2075
+ name: parsed.name,
2076
+ agentKey: parsed.agentKey
2077
+ });
2078
+ const logLines = readLogLines(parsed);
2079
+ const taskPreview = readString(parsed.taskPreview);
2080
+ const lastToolNames = readToolNames(parsed.lastToolNames);
2081
+ const lastAssistantText = readString(parsed.lastAssistantText);
2082
+ const errorMessage = readString(parsed.errorMessage);
2083
+ const startedAt = readTimestamp(parsed.startedAt);
2084
+ const finishedAt = readTimestamp(parsed.finishedAt) ?? readTimestamp(parsed.endedAt);
2085
+ return {
2086
+ runId,
2087
+ status: readString(parsed.status) ?? "running",
2088
+ // The literal `agent` fallback is dropped here rather than at each render
2089
+ // site: an unnamed run should render no name row, not the word "agent".
2090
+ ...isAgentNameFallback(label) ? {} : { agentName: label },
2091
+ ...taskPreview ? { taskPreview } : {},
2092
+ ...typeof parsed.toolCallCount === "number" && Number.isFinite(parsed.toolCallCount) ? { toolCallCount: parsed.toolCallCount } : {},
2093
+ ...lastToolNames ? { lastToolNames } : {},
2094
+ ...lastAssistantText ? { lastAssistantText } : {},
2095
+ ...errorMessage ? { errorMessage } : {},
2096
+ ...startedAt !== void 0 ? { startedAt } : {},
2097
+ ...finishedAt !== void 0 ? { finishedAt } : {},
2098
+ ...logLines ? { logLines } : {},
2099
+ logKey: logLines && logLines.length > 0 ? logLines.join("\n") : ""
2100
+ };
2101
+ }
2102
+ var STOP_STATUSES = /* @__PURE__ */ new Set(["killed", "cancelled", "cancelling"]);
2103
+ function parseAgentRunEvent(event) {
2104
+ if (event.type !== "tool-result") return null;
2105
+ if (event.toolName !== "startAgentRun" && event.toolName !== "controlAgentRun") {
2106
+ return null;
2107
+ }
2108
+ const raw = typeof event.content === "string" ? event.content.trim() : "";
2109
+ if (!raw.startsWith("{")) return null;
2110
+ let parsed;
2111
+ try {
2112
+ parsed = JSON.parse(raw);
2113
+ } catch {
2114
+ return null;
2115
+ }
2116
+ if (Array.isArray(parsed.runs)) return null;
2117
+ const snapshot = buildSnapshot(parsed, event);
2118
+ const status = readString(parsed.status);
2119
+ if (event.toolName === "startAgentRun") {
2120
+ if (!snapshot.runId) return null;
2121
+ return { kind: "start", snapshot };
2122
+ }
2123
+ if (parsed.found === false || status === "not_found") {
2124
+ return { kind: "gone", snapshot: { ...snapshot, status: "not_found" } };
2125
+ }
2126
+ if (status && STOP_STATUSES.has(status)) {
2127
+ return { kind: "stop", snapshot };
2128
+ }
2129
+ if (!status) return null;
2130
+ if (!snapshot.runId) return null;
2131
+ return { kind: "status", snapshot };
2132
+ }
2133
+
2134
+ // packages/cli/client/cliAgentRunToolExecutors.ts
2040
2135
  var noopOutput = { write: () => {
2041
2136
  } };
2042
2137
  var parseCallArgs = (call) => {
@@ -2069,7 +2164,16 @@ function createCliStartAgentRunExecutor(deps = {}) {
2069
2164
 
2070
2165
  --- \u9644\u52A0\u8F93\u5165 ---
2071
2166
  ${JSON.stringify(args.input)}`;
2072
- const rawArgs = ["--agent", agentKey, "--msg-file", "PLACEHOLDER", "--bg"];
2167
+ const rawArgs = [
2168
+ "--agent",
2169
+ agentKey,
2170
+ "--msg-file",
2171
+ "PLACEHOLDER",
2172
+ "--bg",
2173
+ // 非持久化派发(review 等一次性任务):透传 --ephemeral,run 完成后不留
2174
+ // dialog 记录。与 web 端 runAgentBackground 的 ephemeral: true 对齐。
2175
+ ...args.ephemeral === true ? ["--ephemeral"] : []
2176
+ ];
2073
2177
  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
2178
  const { runId } = await spawnLocalBackgroundRun(
2075
2179
  {
@@ -2084,16 +2188,22 @@ ${JSON.stringify(args.input)}`;
2084
2188
  },
2085
2189
  deps
2086
2190
  );
2087
- const displayName = agentName ?? "agent";
2191
+ const displayName = resolveRunLabel({ agentName, agentKey, runId });
2088
2192
  const labels = agentRunCardLabels();
2193
+ const taskPreview = typeof args.task === "string" ? args.task.replace(/\s+/g, " ").trim().slice(0, TASK_PREVIEW_MAX) : "";
2089
2194
  return {
2090
2195
  content: JSON.stringify({
2091
2196
  runId,
2092
2197
  status: "running",
2093
- ...agentName ? { agentName } : {}
2198
+ ...agentName ? { agentName } : {},
2199
+ ...taskPreview ? { taskPreview } : {}
2094
2200
  }),
2095
2201
  metadata: {
2096
- displayData: formatStartRunCard(displayName, "running", labels)
2202
+ displayData: formatStartRunCard(displayName, "running", {
2203
+ task: taskPreview,
2204
+ runId,
2205
+ labels
2206
+ })
2097
2207
  }
2098
2208
  };
2099
2209
  };
@@ -2139,7 +2249,7 @@ function createCliControlAgentRunExecutor(deps = {}) {
2139
2249
  if (action === "status") {
2140
2250
  const reconciled = checkStaleRun(record.runId, deps) ?? record;
2141
2251
  const logTail = tailLines > 0 ? tailFile(record.logPath, tailLines, resolveFs(deps)) : void 0;
2142
- const name = reconciled.agentName || "agent";
2252
+ const name = resolveRunLabel(reconciled);
2143
2253
  const logLines = logTail ? logTail.split("\n") : void 0;
2144
2254
  const labels2 = agentRunCardLabels();
2145
2255
  return {
@@ -2166,7 +2276,15 @@ function createCliControlAgentRunExecutor(deps = {}) {
2166
2276
  ...logLines ? { logLines } : {}
2167
2277
  }),
2168
2278
  metadata: {
2169
- displayData: formatStatusRunCard(name, reconciled.status, { logLines, labels: labels2 })
2279
+ displayData: formatStatusRunCard(name, reconciled.status, {
2280
+ runId: reconciled.runId,
2281
+ timing: {
2282
+ startedAt: readTimestamp(reconciled.startedAt),
2283
+ finishedAt: readTimestamp(reconciled.endedAt)
2284
+ },
2285
+ logLines,
2286
+ labels: labels2
2287
+ })
2170
2288
  }
2171
2289
  };
2172
2290
  }
@@ -2448,19 +2566,22 @@ function resolveAntigravityWireModel(logicalModelId) {
2448
2566
  return { wireModelId: id };
2449
2567
  }
2450
2568
 
2451
- // packages/agent-runtime/antigravityCloudCodeProvider.ts
2452
- var STREAM_PATH = "/v1internal:streamGenerateContent?alt=sse";
2569
+ // packages/agent-runtime/geminiNativeShared.ts
2453
2570
  var SKIP_THOUGHT_SIGNATURE = "skip_thought_signature_validator";
2454
- function isGemini3WireModel(modelId) {
2571
+ function isGemini3Model(modelId) {
2455
2572
  return modelId.includes("gemini-3");
2456
2573
  }
2457
2574
  function messageText(content) {
2458
2575
  if (typeof content === "string") return content;
2459
2576
  if (!Array.isArray(content)) return "";
2460
- return content.filter((part) => part?.type === "text").map((part) => part.text).join("\n").trim();
2577
+ return content.filter(
2578
+ (part) => part?.type === "text"
2579
+ ).map((part) => part.text).join("\n").trim();
2461
2580
  }
2462
2581
  function parseDataUrlToInlineData(url) {
2463
- const match = /^data:([A-Za-z0-9.+-]+\/[A-Za-z0-9.+-]+);base64,([A-Za-z0-9+/=]*)$/.exec(url);
2582
+ const match = /^data:([A-Za-z0-9.+-]+\/[A-Za-z0-9.+-]+);base64,([A-Za-z0-9+/=]*)$/.exec(
2583
+ url
2584
+ );
2464
2585
  if (!match) return null;
2465
2586
  return { mimeType: match[1], data: match[2] };
2466
2587
  }
@@ -2477,7 +2598,7 @@ function extractInlineDataParts(content) {
2477
2598
  }
2478
2599
  return parts;
2479
2600
  }
2480
- function convertOpenAiMessagesToCca(messages, options) {
2601
+ function convertOpenAiMessagesToGemini(messages, options) {
2481
2602
  const contents = [];
2482
2603
  const systemTexts = [];
2483
2604
  const toolNamesById = /* @__PURE__ */ new Map();
@@ -2493,9 +2614,11 @@ function convertOpenAiMessagesToCca(messages, options) {
2493
2614
  };
2494
2615
  const flushPendingFunctionCalls = () => {
2495
2616
  if (pendingFunctionCalls.length === 0) return;
2496
- const dummyResponses = pendingFunctionCalls.map(({ name }) => ({
2497
- functionResponse: { name, response: { output: "{}" } }
2498
- }));
2617
+ const dummyResponses = pendingFunctionCalls.map(
2618
+ ({ name }) => ({
2619
+ functionResponse: { name, response: { output: "{}" } }
2620
+ })
2621
+ );
2499
2622
  pendingFunctionCalls = [];
2500
2623
  pushOrMergeContent("user", dummyResponses);
2501
2624
  };
@@ -2504,13 +2627,17 @@ function convertOpenAiMessagesToCca(messages, options) {
2504
2627
  const role = String(raw.role);
2505
2628
  const content = "content" in raw ? raw.content : null;
2506
2629
  if (role === "system") {
2507
- const text = messageText(content);
2630
+ const text = messageText(
2631
+ content
2632
+ );
2508
2633
  if (text) systemTexts.push(text);
2509
2634
  continue;
2510
2635
  }
2511
2636
  if (role === "user") {
2512
2637
  flushPendingFunctionCalls();
2513
- const text = messageText(content);
2638
+ const text = messageText(
2639
+ content
2640
+ );
2514
2641
  const imageParts = extractInlineDataParts(
2515
2642
  content
2516
2643
  );
@@ -2524,7 +2651,9 @@ function convertOpenAiMessagesToCca(messages, options) {
2524
2651
  if (role === "assistant") {
2525
2652
  flushPendingFunctionCalls();
2526
2653
  const parts = [];
2527
- const text = messageText(content);
2654
+ const text = messageText(
2655
+ content
2656
+ );
2528
2657
  if (text) parts.push({ text });
2529
2658
  const toolCalls = "tool_calls" in raw && Array.isArray(raw.tool_calls) ? raw.tool_calls ?? [] : [];
2530
2659
  for (const call of toolCalls) {
@@ -2534,17 +2663,20 @@ function convertOpenAiMessagesToCca(messages, options) {
2534
2663
  toolNamesById.set(id, name);
2535
2664
  pendingFunctionCalls.push({ name, id });
2536
2665
  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({
2666
+ const isFirstFunctionCallPart = !parts.some(
2667
+ (p) => "functionCall" in p
2668
+ );
2669
+ const signature = realSignature ?? (options.attachSkipThoughtSignature && isFirstFunctionCallPart ? SKIP_THOUGHT_SIGNATURE : void 0);
2670
+ const part = {
2539
2671
  functionCall: {
2540
2672
  name,
2541
- args: parseToolArgumentsJson(call.function?.arguments),
2542
- id
2673
+ args: parseToolArgs(call.function?.arguments),
2674
+ ...id ? { id } : {}
2543
2675
  },
2544
- ...realSignature ? { thoughtSignature: realSignature } : options.attachSkipThoughtSignature && isFirstFunctionCallPart ? { thoughtSignature: SKIP_THOUGHT_SIGNATURE } : {}
2545
- });
2676
+ ...signature ? { thoughtSignature: signature } : {}
2677
+ };
2678
+ parts.push(part);
2546
2679
  }
2547
- if (parts.length === 0) continue;
2548
2680
  pushOrMergeContent("model", parts);
2549
2681
  continue;
2550
2682
  }
@@ -2562,14 +2694,39 @@ function convertOpenAiMessagesToCca(messages, options) {
2562
2694
  }
2563
2695
  const output = messageText(content) || "{}";
2564
2696
  pushOrMergeContent("user", [
2565
- { functionResponse: { name, response: { output } } }
2697
+ {
2698
+ functionResponse: {
2699
+ name,
2700
+ response: { output },
2701
+ // 保留 OpenAI tool_call_id:antigravity Cloud Code Assist 网关把
2702
+ // Gemini contents 转成 Claude messages 时需要 functionResponse →
2703
+ // tool_result 的 tool_use_id;缺 id 时网关报
2704
+ // "tool_result.tool_use_id: Field required"(HTTP 400)。
2705
+ ...toolCallId ? { id: toolCallId } : {}
2706
+ }
2707
+ }
2566
2708
  ]);
2567
2709
  }
2568
2710
  }
2569
2711
  flushPendingFunctionCalls();
2570
2712
  return { contents, systemTexts };
2571
2713
  }
2572
- function convertOpenAiTools(tools) {
2714
+ function parseToolArgs(raw) {
2715
+ if (typeof raw === "string") {
2716
+ try {
2717
+ const parsed = JSON.parse(raw);
2718
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
2719
+ return parsed;
2720
+ }
2721
+ } catch {
2722
+ }
2723
+ }
2724
+ if (raw && typeof raw === "object" && !Array.isArray(raw)) {
2725
+ return raw;
2726
+ }
2727
+ return {};
2728
+ }
2729
+ function convertOpenAiToolsToGemini(tools) {
2573
2730
  if (!Array.isArray(tools) || tools.length === 0) return void 0;
2574
2731
  const declarations = [];
2575
2732
  for (const tool of tools) {
@@ -2586,6 +2743,97 @@ function convertOpenAiTools(tools) {
2586
2743
  if (declarations.length === 0) return void 0;
2587
2744
  return [{ functionDeclarations: declarations }];
2588
2745
  }
2746
+ function accumulateGeminiChunks(chunks) {
2747
+ let text = "";
2748
+ const toolCalls = [];
2749
+ let usage;
2750
+ let pendingThoughtSignature;
2751
+ for (const chunk of chunks) {
2752
+ if (!chunk || typeof chunk !== "object") continue;
2753
+ const response = "response" in chunk && chunk.response && typeof chunk.response === "object" ? chunk.response : chunk;
2754
+ if ("usageMetadata" in response && response.usageMetadata && typeof response.usageMetadata === "object") {
2755
+ const meta = response.usageMetadata;
2756
+ const prompt = typeof meta.promptTokenCount === "number" ? meta.promptTokenCount : 0;
2757
+ const candidates2 = typeof meta.candidatesTokenCount === "number" ? meta.candidatesTokenCount : 0;
2758
+ const total = typeof meta.totalTokenCount === "number" ? meta.totalTokenCount : prompt + candidates2;
2759
+ usage = {
2760
+ prompt_tokens: prompt,
2761
+ completion_tokens: candidates2,
2762
+ total_tokens: total
2763
+ };
2764
+ }
2765
+ const candidates = Array.isArray(response.candidates) ? response.candidates : [];
2766
+ for (const candidate of candidates) {
2767
+ if (!candidate || typeof candidate !== "object") continue;
2768
+ const parts = Array.isArray(
2769
+ candidate.content?.parts
2770
+ ) ? candidate.content.parts : [];
2771
+ for (const part of parts) {
2772
+ if (!part || typeof part !== "object") continue;
2773
+ const partSignature = part.thoughtSignature;
2774
+ if ("text" in part && typeof part.text === "string") {
2775
+ const piece = part.text;
2776
+ if (!part.thought) {
2777
+ text += piece;
2778
+ }
2779
+ }
2780
+ if (part.thought && typeof partSignature === "string" && partSignature) {
2781
+ pendingThoughtSignature = partSignature;
2782
+ }
2783
+ if ("functionCall" in part && part.functionCall) {
2784
+ const call = part.functionCall;
2785
+ const name = typeof call.name === "string" ? call.name : "tool";
2786
+ const id = typeof call.id === "string" ? call.id : `${name}_${toolCalls.length}`;
2787
+ const argsObj = call.args && typeof call.args === "object" ? call.args : {};
2788
+ const resolvedSignature = typeof partSignature === "string" && partSignature ? partSignature : pendingThoughtSignature;
2789
+ pendingThoughtSignature = void 0;
2790
+ toolCalls.push({
2791
+ id,
2792
+ type: "function",
2793
+ function: { name, arguments: JSON.stringify(argsObj) },
2794
+ ...typeof resolvedSignature === "string" && resolvedSignature ? { thought_signature: resolvedSignature } : {}
2795
+ });
2796
+ }
2797
+ }
2798
+ }
2799
+ }
2800
+ return { text, toolCalls, usage };
2801
+ }
2802
+ function shouldUseGeminiNativeToolRoute(provider, model, tools, isImageModel) {
2803
+ return provider === "google" && !isImageModel(model) && isGemini3Model(model) && Array.isArray(tools) && tools.length > 0;
2804
+ }
2805
+ function buildGeminiGenerateContentRequest(args) {
2806
+ const { contents, systemTexts } = convertOpenAiMessagesToGemini(
2807
+ args.messages,
2808
+ { attachSkipThoughtSignature: args.attachSkipThoughtSignature }
2809
+ );
2810
+ const request = { contents };
2811
+ if (systemTexts.length > 0) {
2812
+ request.systemInstruction = {
2813
+ role: "user",
2814
+ parts: systemTexts.map((text) => ({ text }))
2815
+ };
2816
+ }
2817
+ const toolsResult = convertOpenAiToolsToGemini(args.tools);
2818
+ if (toolsResult) {
2819
+ request.tools = toolsResult;
2820
+ request.toolConfig = { functionCallingConfig: { mode: "VALIDATED" } };
2821
+ }
2822
+ const generationConfig = {};
2823
+ if (typeof args.maxTokens === "number" && args.maxTokens > 0) {
2824
+ generationConfig.maxOutputTokens = args.maxTokens;
2825
+ }
2826
+ if (typeof args.temperature === "number") {
2827
+ generationConfig.temperature = args.temperature;
2828
+ }
2829
+ if (Object.keys(generationConfig).length > 0) {
2830
+ request.generationConfig = generationConfig;
2831
+ }
2832
+ return request;
2833
+ }
2834
+
2835
+ // packages/agent-runtime/antigravityCloudCodeProvider.ts
2836
+ var STREAM_PATH = "/v1internal:streamGenerateContent?alt=sse";
2589
2837
  function buildCloudCodeAssistPayload(args) {
2590
2838
  const projectId = readAntigravityProjectId(args.metadata);
2591
2839
  if (!projectId) {
@@ -2596,8 +2844,9 @@ function buildCloudCodeAssistPayload(args) {
2596
2844
  const logicalModel = asOptionalTrimmedString(args.openAiBody.model) ?? asOptionalTrimmedString(args.agentConfig.model) ?? "gemini-3.1-pro";
2597
2845
  const { wireModelId: model, profile } = resolveAntigravityWireModel(logicalModel);
2598
2846
  const rawMessages = Array.isArray(args.openAiBody.messages) ? args.openAiBody.messages : [];
2599
- const { contents, systemTexts } = convertOpenAiMessagesToCca(rawMessages, {
2600
- attachSkipThoughtSignature: isGemini3WireModel(model)
2847
+ const isClaude = model.toLowerCase().includes("claude");
2848
+ const { contents, systemTexts } = convertOpenAiMessagesToGemini(rawMessages, {
2849
+ attachSkipThoughtSignature: isGemini3Model(model)
2601
2850
  });
2602
2851
  if (contents.length === 0) {
2603
2852
  throw new Error("Antigravity Cloud Code Assist request has no user/model contents.");
@@ -2611,7 +2860,7 @@ function buildCloudCodeAssistPayload(args) {
2611
2860
  parts: systemTexts.map((text) => ({ text }))
2612
2861
  };
2613
2862
  }
2614
- const tools = convertOpenAiTools(
2863
+ const tools = convertOpenAiToolsToGemini(
2615
2864
  Array.isArray(args.openAiBody.tools) ? args.openAiBody.tools : void 0
2616
2865
  );
2617
2866
  if (tools) {
@@ -2634,7 +2883,6 @@ function buildCloudCodeAssistPayload(args) {
2634
2883
  const trajectoryId = randomUUID();
2635
2884
  const step = 2;
2636
2885
  const requestId = `agent/${agentId}/${Date.now()}/${trajectoryId}/${step}`;
2637
- const isClaude = model.toLowerCase().includes("claude");
2638
2886
  const labels = {
2639
2887
  trajectory_id: trajectoryId,
2640
2888
  last_step_index: String(step - 1),
@@ -2658,57 +2906,6 @@ function buildCloudCodeAssistPayload(args) {
2658
2906
  }
2659
2907
  };
2660
2908
  }
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
2909
  async function readSseJsonChunks(response) {
2713
2910
  return readSseDataValues(response, parseSseDataLineJson);
2714
2911
  }
@@ -2733,7 +2930,7 @@ async function fetchAntigravityCloudCodeCompletion(args) {
2733
2930
  };
2734
2931
  }
2735
2932
  const chunks = await readSseJsonChunks(response);
2736
- const { text, toolCalls, usage } = accumulateCcaChunks(chunks);
2933
+ const { text, toolCalls, usage } = accumulateGeminiChunks(chunks);
2737
2934
  const message = {
2738
2935
  role: "assistant",
2739
2936
  content: text || null
@@ -2769,28 +2966,94 @@ var CLAUDE_CODE_IDENTITY_PATTERNS = [
2769
2966
  CLAUDE_CODE_SYSTEM_INSTRUCTION,
2770
2967
  "You are Claude Code"
2771
2968
  ];
2969
+ var REASONING_EFFORT_TO_BUDGET = {
2970
+ minimal: 2048,
2971
+ low: 4096,
2972
+ medium: 8192,
2973
+ high: 16384,
2974
+ xhigh: 32e3,
2975
+ max: 32e3
2976
+ };
2977
+ function resolveThinkingBudget(effort) {
2978
+ if (!effort) return void 0;
2979
+ const normalized = effort.toLowerCase();
2980
+ if (normalized === "none" || normalized === "off") return void 0;
2981
+ return REASONING_EFFORT_TO_BUDGET[normalized];
2982
+ }
2983
+ var DEFAULT_THINKING_EFFORT = "medium";
2984
+ var DEFAULT_ENABLED_BUDGET = 8192;
2985
+ var DEFAULT_ENABLE_THINKING_BUDGET = 8e3;
2986
+ var ANTHROPIC_EFFORT_ALIASES = { minimal: "low" };
2987
+ function resolveThinkingSpec(input) {
2988
+ const { model, maxTokens } = input;
2989
+ const normalizedEffort = input.reasoningEffort?.toLowerCase();
2990
+ const effortDisabled = normalizedEffort === "none" || normalizedEffort === "off";
2991
+ const effectiveEffort = normalizedEffort !== void 0 && !effortDisabled ? ANTHROPIC_EFFORT_ALIASES[normalizedEffort] ?? normalizedEffort : DEFAULT_THINKING_EFFORT;
2992
+ let thinkingBlock;
2993
+ let outputConfig;
2994
+ let finalMaxTokens = maxTokens;
2995
+ let finalTemperature = input.temperature;
2996
+ if (isAdaptiveThinkingModelId(model)) {
2997
+ if (effortDisabled) {
2998
+ thinkingBlock = { type: "disabled" };
2999
+ } else {
3000
+ thinkingBlock = { type: "adaptive", display: "summarized" };
3001
+ outputConfig = { effort: effectiveEffort };
3002
+ }
3003
+ } else {
3004
+ const injected = input.injectedThinking;
3005
+ const injectedBudget = injected?.type === "enabled" && typeof injected.budget_tokens === "number" ? injected.budget_tokens : void 0;
3006
+ const effortBudget = resolveThinkingBudget(input.reasoningEffort);
3007
+ 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;
3008
+ const thinkingBudget = effortBudget ?? fallbackBudget;
3009
+ if (thinkingBudget !== void 0) {
3010
+ thinkingBlock = { type: "enabled", budget_tokens: thinkingBudget };
3011
+ finalMaxTokens = Math.max(maxTokens, thinkingBudget + 1);
3012
+ finalTemperature = 1;
3013
+ }
3014
+ }
3015
+ return {
3016
+ thinkingBlock,
3017
+ outputConfig,
3018
+ maxTokens: finalMaxTokens,
3019
+ temperature: finalTemperature
3020
+ };
3021
+ }
2772
3022
  function stringValue(value) {
2773
3023
  return typeof value === "string" && value.length > 0 ? value : void 0;
2774
3024
  }
3025
+ function isCacheControl(value) {
3026
+ return Boolean(
3027
+ value && typeof value === "object" && !Array.isArray(value) && typeof value.type === "string"
3028
+ );
3029
+ }
2775
3030
  function toAnthropicContent(content) {
2776
- if (typeof content === "string") return [{ type: "text", text: content }];
3031
+ if (typeof content === "string") {
3032
+ return content.length > 0 ? [{ type: "text", text: content }] : [];
3033
+ }
2777
3034
  if (!Array.isArray(content)) return [];
2778
3035
  const blocks = [];
2779
3036
  for (const raw of content) {
2780
3037
  if (!raw || typeof raw !== "object") continue;
2781
3038
  const part = raw;
2782
3039
  if ((part.type === "text" || part.type === "input_text") && typeof part.text === "string") {
2783
- blocks.push({ type: "text", text: part.text });
3040
+ if (part.text.length > 0) {
3041
+ const block2 = { type: "text", text: part.text };
3042
+ if (isCacheControl(part.cache_control)) block2.cache_control = part.cache_control;
3043
+ blocks.push(block2);
3044
+ }
2784
3045
  continue;
2785
3046
  }
2786
3047
  if (part.type !== "image_url") continue;
2787
3048
  const imageUrl = typeof part.image_url === "string" ? part.image_url : stringValue(part.image_url?.url);
2788
3049
  if (!imageUrl) continue;
2789
3050
  const dataMatch = imageUrl.match(/^data:([^;,]+);base64,(.+)$/s);
2790
- blocks.push({
3051
+ const block = {
2791
3052
  type: "image",
2792
3053
  source: dataMatch ? { type: "base64", media_type: dataMatch[1], data: dataMatch[2] } : { type: "url", url: imageUrl }
2793
- });
3054
+ };
3055
+ if (isCacheControl(part.cache_control)) block.cache_control = part.cache_control;
3056
+ blocks.push(block);
2794
3057
  }
2795
3058
  return blocks;
2796
3059
  }
@@ -2824,7 +3087,15 @@ function buildAnthropicMessagesBody(args) {
2824
3087
  const message = raw;
2825
3088
  const role = String(message.role ?? "");
2826
3089
  if (role === "system" || role === "developer") {
2827
- system.push(...toAnthropicContent(message.content));
3090
+ const stablePrefixChars = Number(message.stable_prefix_chars);
3091
+ if (typeof message.content === "string" && Number.isFinite(stablePrefixChars) && stablePrefixChars > 0 && stablePrefixChars <= message.content.length) {
3092
+ const stable = message.content.slice(0, stablePrefixChars);
3093
+ const dynamic = message.content.slice(stablePrefixChars);
3094
+ system.push({ type: "text", text: stable, cache_control: { type: "ephemeral" } });
3095
+ if (dynamic) system.push({ type: "text", text: dynamic });
3096
+ } else {
3097
+ system.push(...toAnthropicContent(message.content));
3098
+ }
2828
3099
  continue;
2829
3100
  }
2830
3101
  if (role === "tool") {
@@ -2866,6 +3137,9 @@ function buildAnthropicMessagesBody(args) {
2866
3137
  if (!hasClaudeCodeIdentity(system)) {
2867
3138
  system.unshift({ type: "text", text: CLAUDE_CODE_SYSTEM_INSTRUCTION });
2868
3139
  }
3140
+ if (system.length > 0 && !system.some((block) => isCacheControl(block.cache_control))) {
3141
+ system[system.length - 1].cache_control = { type: "ephemeral" };
3142
+ }
2869
3143
  const tools = Array.isArray(args.openAiBody.tools) ? args.openAiBody.tools.flatMap((raw) => {
2870
3144
  if (!raw || typeof raw !== "object") return [];
2871
3145
  const fn = raw.function;
@@ -2880,14 +3154,39 @@ function buildAnthropicMessagesBody(args) {
2880
3154
  const model = stringValue(args.openAiBody.model) ?? args.agentConfig.model ?? "claude-sonnet-5";
2881
3155
  const maxTokensRaw = args.openAiBody.max_completion_tokens ?? args.openAiBody.max_tokens ?? args.agentConfig.max_tokens;
2882
3156
  const maxTokens = typeof maxTokensRaw === "number" && Number.isFinite(maxTokensRaw) ? Math.max(1, Math.floor(maxTokensRaw)) : 8192;
3157
+ const reasoningEffort = stringValue(args.openAiBody.reasoning_effort) ?? stringValue(args.agentConfig.reasoning_effort);
3158
+ const spec = resolveThinkingSpec({
3159
+ model,
3160
+ reasoningEffort,
3161
+ maxTokens,
3162
+ temperature: typeof args.openAiBody.temperature === "number" ? args.openAiBody.temperature : args.agentConfig.temperature,
3163
+ injectedThinking: args.openAiBody.thinking,
3164
+ enableThinking: args.agentConfig.enableThinking,
3165
+ thinkingBudget: args.agentConfig.thinkingBudget
3166
+ });
3167
+ const { thinkingBlock, outputConfig } = spec;
3168
+ const finalMaxTokens = spec.maxTokens;
3169
+ const finalTemperature = spec.temperature;
3170
+ if (messages.length > 0) {
3171
+ const lastMessage = messages[messages.length - 1];
3172
+ const content = Array.isArray(lastMessage.content) ? lastMessage.content : [];
3173
+ if (content.length > 0) {
3174
+ const lastBlock = content[content.length - 1];
3175
+ if (!isCacheControl(lastBlock.cache_control)) {
3176
+ lastBlock.cache_control = { type: "ephemeral" };
3177
+ }
3178
+ }
3179
+ }
2883
3180
  return {
2884
3181
  model,
2885
3182
  messages,
2886
- max_tokens: maxTokens,
3183
+ max_tokens: finalMaxTokens,
2887
3184
  stream: false,
3185
+ ...thinkingBlock ? { thinking: thinkingBlock } : {},
3186
+ ...outputConfig ? { output_config: outputConfig } : {},
2888
3187
  ...system.length > 0 ? { system } : {},
2889
3188
  ...tools.length > 0 ? { tools } : {},
2890
- ...typeof args.openAiBody.temperature === "number" ? { temperature: args.openAiBody.temperature } : typeof args.agentConfig.temperature === "number" ? { temperature: args.agentConfig.temperature } : {},
3189
+ ...typeof finalTemperature === "number" ? { temperature: finalTemperature } : {},
2891
3190
  ...typeof args.openAiBody.top_p === "number" ? { top_p: args.openAiBody.top_p } : {}
2892
3191
  };
2893
3192
  }
@@ -2911,6 +3210,8 @@ function mapAnthropicMessageToOpenAi(payload) {
2911
3210
  }
2912
3211
  const usage = payload.usage ?? {};
2913
3212
  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);
3213
+ const cacheCreationInputTokens = typeof usage.cache_creation_input_tokens === "number" ? usage.cache_creation_input_tokens : 0;
3214
+ const cacheReadInputTokens = typeof usage.cache_read_input_tokens === "number" ? usage.cache_read_input_tokens : 0;
2914
3215
  const outputTokens = typeof usage.output_tokens === "number" ? usage.output_tokens : 0;
2915
3216
  const stopReason = String(payload.stop_reason ?? "");
2916
3217
  const message = { role: "assistant", content: text || null };
@@ -2926,9 +3227,16 @@ function mapAnthropicMessageToOpenAi(payload) {
2926
3227
  finish_reason: toolCalls.length > 0 || stopReason === "tool_use" ? "tool_calls" : stopReason === "max_tokens" ? "length" : "stop"
2927
3228
  }],
2928
3229
  usage: {
3230
+ // prompt_tokens/input_tokens are total input, including cache read/write.
3231
+ // Preserve Anthropic's components so normalization and billing can apply
3232
+ // the correct cache prices without double-counting them.
2929
3233
  prompt_tokens: inputTokens,
3234
+ input_tokens: inputTokens,
2930
3235
  completion_tokens: outputTokens,
2931
- total_tokens: inputTokens + outputTokens
3236
+ output_tokens: outputTokens,
3237
+ total_tokens: inputTokens + outputTokens,
3238
+ cache_creation_input_tokens: cacheCreationInputTokens,
3239
+ cache_read_input_tokens: cacheReadInputTokens
2932
3240
  }
2933
3241
  };
2934
3242
  }
@@ -9003,6 +9311,262 @@ function isCursorOAuthAgent(agent) {
9003
9311
  return agent.apiKeyRef?.trim().toLowerCase() === "cursor";
9004
9312
  }
9005
9313
 
9314
+ // packages/agent-runtime/codexResponsesProvider.ts
9315
+ import { randomUUID as randomUUID4 } from "node:crypto";
9316
+ var CODEX_RESPONSES_URL = "https://chatgpt.com/backend-api/codex/responses";
9317
+ var CODEX_CLIENT_VERSION = "0.144.1";
9318
+ var CODEX_ORIGINATOR = "codex_cli_rs";
9319
+ var CODEX_OPENAI_BETA = "responses=experimental";
9320
+ var OPENAI_AUTH_CLAIM = "https://api.openai.com/auth";
9321
+ var CODEX_INSTALLATION_ID = randomUUID4();
9322
+ function decodeCodexAccountId(accessToken) {
9323
+ const parts = accessToken.split(".");
9324
+ if (parts.length < 2) return void 0;
9325
+ try {
9326
+ const payload = JSON.parse(
9327
+ Buffer.from(parts[1], "base64").toString("utf8")
9328
+ );
9329
+ const claim = payload[OPENAI_AUTH_CLAIM];
9330
+ const value = claim && typeof claim === "object" ? claim.chatgpt_account_id : void 0;
9331
+ return typeof value === "string" && value ? value : void 0;
9332
+ } catch {
9333
+ return void 0;
9334
+ }
9335
+ }
9336
+ function createCodexRequestIdentity(installationId = CODEX_INSTALLATION_ID) {
9337
+ const sessionId = randomUUID4();
9338
+ const threadId = randomUUID4();
9339
+ const windowId = randomUUID4();
9340
+ const turnId = randomUUID4();
9341
+ const turnMetadata = {
9342
+ installation_id: installationId,
9343
+ session_id: sessionId,
9344
+ thread_id: threadId,
9345
+ turn_id: turnId,
9346
+ window_id: windowId,
9347
+ request_kind: "turn",
9348
+ turn_started_at_unix_ms: Date.now()
9349
+ };
9350
+ const turnMetadataJson = JSON.stringify(turnMetadata);
9351
+ return {
9352
+ sessionId,
9353
+ threadId,
9354
+ windowId,
9355
+ turnId,
9356
+ turnMetadataJson,
9357
+ clientMetadata: {
9358
+ "x-codex-installation-id": installationId,
9359
+ session_id: sessionId,
9360
+ thread_id: threadId,
9361
+ "x-codex-window-id": windowId,
9362
+ turn_id: turnId,
9363
+ "x-codex-turn-metadata": turnMetadataJson
9364
+ }
9365
+ };
9366
+ }
9367
+ function buildCodexCompatibilityHeaders(identity, accountId) {
9368
+ return {
9369
+ Authorization: "",
9370
+ // filled by caller with bearer token
9371
+ "Content-Type": "application/json",
9372
+ Accept: "text/event-stream",
9373
+ "chatgpt-account-id": accountId,
9374
+ "OpenAI-Beta": CODEX_OPENAI_BETA,
9375
+ originator: CODEX_ORIGINATOR,
9376
+ version: CODEX_CLIENT_VERSION,
9377
+ session_id: identity.sessionId,
9378
+ conversation_id: identity.sessionId,
9379
+ "x-client-request-id": identity.sessionId,
9380
+ "session-id": identity.sessionId,
9381
+ "thread-id": identity.threadId,
9382
+ "x-codex-window-id": identity.windowId,
9383
+ "x-codex-turn-metadata": identity.turnMetadataJson
9384
+ };
9385
+ }
9386
+ function collectInstructions(messages, agentPrompt) {
9387
+ const systemTexts = [];
9388
+ const prompt = agentPrompt?.trim();
9389
+ if (prompt) systemTexts.push(prompt);
9390
+ for (const raw of messages) {
9391
+ if (!raw || typeof raw !== "object") continue;
9392
+ const role = String(raw.role ?? "");
9393
+ if (role !== "system" && role !== "developer") continue;
9394
+ const content = raw.content;
9395
+ const stringContent = asOptionalTrimmedString(content);
9396
+ if (stringContent) {
9397
+ systemTexts.push(stringContent);
9398
+ } else if (Array.isArray(content)) {
9399
+ const text = content.filter(
9400
+ (p) => !!p && p.type === "text"
9401
+ ).map((p) => p.text).join("\n").trim();
9402
+ if (text) systemTexts.push(text);
9403
+ }
9404
+ }
9405
+ return systemTexts.join("\n\n");
9406
+ }
9407
+ function collectStableInstructions(messages, fallbackPrompt) {
9408
+ const systemTexts = [];
9409
+ if (fallbackPrompt?.trim()) systemTexts.push(fallbackPrompt.trim());
9410
+ for (const raw of messages) {
9411
+ if (!raw || typeof raw !== "object") continue;
9412
+ const message = raw;
9413
+ const role = String(message.role ?? "");
9414
+ if (role !== "system" && role !== "developer") continue;
9415
+ if (typeof message.content === "string") {
9416
+ const boundary = Number(message.stable_prefix_chars);
9417
+ const text = Number.isFinite(boundary) && boundary > 0 ? message.content.slice(0, boundary) : message.content;
9418
+ if (text.trim()) systemTexts.push(text.trim());
9419
+ }
9420
+ }
9421
+ return systemTexts.join("\n\n");
9422
+ }
9423
+ function stablePromptCacheKey(parts) {
9424
+ const value = JSON.stringify(parts);
9425
+ let hash = 2166136261;
9426
+ for (let index = 0; index < value.length; index += 1) {
9427
+ hash ^= value.charCodeAt(index);
9428
+ hash = Math.imul(hash, 16777619) >>> 0;
9429
+ }
9430
+ return `nolo-codex-${hash.toString(16).padStart(8, "0")}`;
9431
+ }
9432
+ function buildCodexRequestBody(args, identity = createCodexRequestIdentity()) {
9433
+ const rawMessages = Array.isArray(args.openAiBody.messages) ? args.openAiBody.messages : [];
9434
+ const nonSystem = rawMessages.filter((m) => {
9435
+ const role = m && typeof m === "object" ? String(m.role) : "";
9436
+ return role !== "system" && role !== "developer";
9437
+ });
9438
+ const input = convertMessagesToResponsesInput(nonSystem);
9439
+ const instructions = collectInstructions(rawMessages, args.agentConfig.prompt);
9440
+ const stableInstructions = collectStableInstructions(rawMessages, args.agentConfig.prompt);
9441
+ const model = asOptionalTrimmedString(args.openAiBody.model) ?? asOptionalTrimmedString(args.agentConfig.model) ?? "gpt-5.5";
9442
+ const tools = toResponsesTools(
9443
+ Array.isArray(args.openAiBody.tools) ? args.openAiBody.tools : void 0
9444
+ );
9445
+ const body = {
9446
+ model,
9447
+ input,
9448
+ stream: true,
9449
+ store: false,
9450
+ // Keep routing stable across turns and request UUIDs. Growing input/history
9451
+ // is intentionally excluded; only stable request-prefix material belongs.
9452
+ prompt_cache_key: stablePromptCacheKey([model, stableInstructions, tools ?? []]),
9453
+ client_metadata: identity.clientMetadata
9454
+ };
9455
+ if (instructions) body.instructions = instructions;
9456
+ if (tools && tools.length > 0) {
9457
+ body.tools = tools;
9458
+ body.tool_choice = "auto";
9459
+ body.parallel_tool_calls = true;
9460
+ }
9461
+ return body;
9462
+ }
9463
+ function aggregateResponsesStream(events) {
9464
+ let text = "";
9465
+ const toolCalls = [];
9466
+ let usage;
9467
+ for (const ev of events) {
9468
+ const type = String(ev.type ?? "");
9469
+ if (type === "response.output_text.delta" && typeof ev.delta === "string") {
9470
+ text += ev.delta;
9471
+ continue;
9472
+ }
9473
+ if (type === "response.output_item.done") {
9474
+ const item = ev.item;
9475
+ if (item && item.type === "function_call") {
9476
+ const name = typeof item.name === "string" ? item.name : "";
9477
+ if (name) {
9478
+ toolCalls.push({
9479
+ id: typeof item.call_id === "string" && item.call_id ? item.call_id : `${name}_${toolCalls.length}`,
9480
+ type: "function",
9481
+ function: {
9482
+ name,
9483
+ arguments: typeof item.arguments === "string" ? item.arguments : "{}"
9484
+ }
9485
+ });
9486
+ }
9487
+ }
9488
+ continue;
9489
+ }
9490
+ if (type === "response.completed") {
9491
+ const response = ev.response;
9492
+ const u = response?.usage;
9493
+ if (u) {
9494
+ const prompt = typeof u.input_tokens === "number" ? u.input_tokens : 0;
9495
+ const completion = typeof u.output_tokens === "number" ? u.output_tokens : 0;
9496
+ const total = typeof u.total_tokens === "number" ? u.total_tokens : prompt + completion;
9497
+ usage = {
9498
+ prompt_tokens: prompt,
9499
+ completion_tokens: completion,
9500
+ total_tokens: total
9501
+ };
9502
+ }
9503
+ }
9504
+ }
9505
+ return { text, toolCalls, usage };
9506
+ }
9507
+ async function readSseEvents(response) {
9508
+ return readSseDataValues(response, (line) => {
9509
+ const ev = parseSseDataLineObject(line);
9510
+ return ev && !Array.isArray(ev) ? ev : null;
9511
+ });
9512
+ }
9513
+ async function fetchCodexResponsesCompletion(args) {
9514
+ const fetchImpl = args.fetchImpl ?? fetch;
9515
+ const accountId = args.accountId?.trim() || decodeCodexAccountId(args.accessToken);
9516
+ if (!accountId) {
9517
+ return {
9518
+ status: 401,
9519
+ body: {
9520
+ error: {
9521
+ message: "ChatGPT Codex credential is missing chatgpt_account_id. Re-run `nolo auth chatgpt`."
9522
+ }
9523
+ }
9524
+ };
9525
+ }
9526
+ const identity = createCodexRequestIdentity();
9527
+ const body = buildCodexRequestBody(args, identity);
9528
+ const headers = buildCodexCompatibilityHeaders(identity, accountId);
9529
+ headers.Authorization = `Bearer ${args.accessToken}`;
9530
+ const response = await fetchImpl(CODEX_RESPONSES_URL, {
9531
+ method: "POST",
9532
+ headers,
9533
+ body: JSON.stringify(body),
9534
+ signal: args.signal
9535
+ });
9536
+ if (!response.ok) {
9537
+ const errorText = await response.text();
9538
+ return {
9539
+ status: response.status,
9540
+ body: { error: { message: errorText || response.statusText } }
9541
+ };
9542
+ }
9543
+ const events = await readSseEvents(response);
9544
+ const { text, toolCalls, usage } = aggregateResponsesStream(events);
9545
+ const message = {
9546
+ role: "assistant",
9547
+ content: text || null
9548
+ };
9549
+ if (toolCalls.length > 0) message.tool_calls = toolCalls;
9550
+ return {
9551
+ status: 200,
9552
+ body: {
9553
+ choices: [
9554
+ {
9555
+ index: 0,
9556
+ message,
9557
+ finish_reason: toolCalls.length > 0 ? "tool_calls" : "stop"
9558
+ }
9559
+ ],
9560
+ ...usage ? { usage } : {}
9561
+ }
9562
+ };
9563
+ }
9564
+ function isCodexOAuthAgent(agentConfig) {
9565
+ if (!agentConfig) return false;
9566
+ const apiKeyRef = asTrimmedLowercaseString(agentConfig.apiKeyRef);
9567
+ return apiKeyRef === "chatgpt";
9568
+ }
9569
+
9006
9570
  // packages/agent-runtime/oauthProviders.ts
9007
9571
  var XAI_ACCESS_TOKEN_CLIENT_SKEW_MS = 5 * 60 * 1e3;
9008
9572
  var decodeBase64 = (s) => Buffer.from(s, "base64").toString("utf8");
@@ -10200,6 +10764,74 @@ function createCliLocalRuntimeAdapter(deps) {
10200
10764
  }
10201
10765
  };
10202
10766
  }
10767
+ if (isCodexOAuthAgent(agentConfig)) {
10768
+ const accessToken = await apiKeyRefResolver("chatgpt");
10769
+ if (!accessToken) {
10770
+ throw new Error(
10771
+ 'OAuth credential for "chatgpt" not found locally. Run `nolo auth chatgpt`.'
10772
+ );
10773
+ }
10774
+ const credential = readOAuthCredential("chatgpt");
10775
+ const accountId = credential?.accountId;
10776
+ const { requestedToolNames: requestedToolNames2, tools: tools2 } = resolveProviderOpenAiToolBundle(
10777
+ agentConfig,
10778
+ deps.env,
10779
+ buildProviderOpenAiTools,
10780
+ additionalToolNames,
10781
+ { hasUserChoice: Boolean(deps.requestUserChoice) }
10782
+ );
10783
+ logLocalRuntimeDiagnostic("provider.selected", {
10784
+ agentKey: agentConfig.key,
10785
+ transport: "codex-responses",
10786
+ provider: "openai",
10787
+ model: agentConfig.model ?? "gpt-5.6-sol",
10788
+ hasApiKey: true
10789
+ });
10790
+ return {
10791
+ model: agentConfig.model || "gpt-5.6-sol",
10792
+ complete: async (messages, options) => {
10793
+ const result = await fetchCodexResponsesCompletion({
10794
+ agentConfig,
10795
+ accessToken,
10796
+ ...accountId ? { accountId } : {},
10797
+ openAiBody: {
10798
+ model: agentConfig.model || "gpt-5.6-sol",
10799
+ messages,
10800
+ stream: false,
10801
+ ...tools2.length > 0 ? { tools: tools2 } : {}
10802
+ },
10803
+ fetchImpl: (url, init) => fetchWithTransientRetry(fetchImpl, url, init, {
10804
+ sleep: deps.sleep,
10805
+ loopbackRequest
10806
+ })
10807
+ });
10808
+ if (result.status < 200 || result.status >= 300) {
10809
+ const errMsg = result.body?.error && typeof result.body.error === "object" && typeof result.body.error.message === "string" ? result.body.error.message : JSON.stringify(result.body);
10810
+ throw new Error(
10811
+ `local Codex OAuth provider failed: HTTP ${result.status} ${errMsg}`
10812
+ );
10813
+ }
10814
+ const choice = Array.isArray(result.body.choices) ? result.body.choices[0] : void 0;
10815
+ const message = choice?.message ?? {};
10816
+ const content = typeof message.content === "string" ? message.content : "";
10817
+ const tool_calls = Array.isArray(message.tool_calls) ? message.tool_calls : void 0;
10818
+ if (content && options?.onTextDelta) options.onTextDelta(content);
10819
+ logLocalRuntimeDiagnostic("provider.request.result", {
10820
+ agentKey: agentConfig.key,
10821
+ transport: "codex-responses",
10822
+ ok: true,
10823
+ contentChars: content.length,
10824
+ toolCallCount: tool_calls?.length ?? 0,
10825
+ requestedToolNames: requestedToolNames2
10826
+ });
10827
+ return {
10828
+ content,
10829
+ ...tool_calls ? { tool_calls } : {},
10830
+ trace: messages
10831
+ };
10832
+ }
10833
+ };
10834
+ }
10203
10835
  if (isCursorOAuthAgent(agentConfig)) {
10204
10836
  const accessToken = await apiKeyRefResolver("cursor");
10205
10837
  if (!accessToken) {
@@ -10269,6 +10901,101 @@ function createCliLocalRuntimeAdapter(deps) {
10269
10901
  }
10270
10902
  };
10271
10903
  }
10904
+ if (shouldUsePlatformChatProvider(deps.env, agentConfig) && isGemini3Model(agentConfig.model ?? "") && agentConfig.provider === "google") {
10905
+ const providerConfig2 = await resolvePlatformChatProviderConfig({
10906
+ agentConfig,
10907
+ env: deps.env,
10908
+ apiKeyRefResolver,
10909
+ credentialBroker,
10910
+ syncFetcher
10911
+ });
10912
+ const { requestedToolNames: requestedToolNames2, tools: tools2 } = resolveProviderOpenAiToolBundle(
10913
+ agentConfig,
10914
+ deps.env,
10915
+ buildProviderOpenAiTools,
10916
+ additionalToolNames,
10917
+ { hasUserChoice: Boolean(deps.requestUserChoice) }
10918
+ );
10919
+ if (tools2.length > 0 && providerConfig2.apiKey && shouldUseGeminiNativeToolRoute(
10920
+ agentConfig.provider ?? "",
10921
+ agentConfig.model ?? "",
10922
+ tools2,
10923
+ () => false
10924
+ // CLI 端不区分 image 模型
10925
+ )) {
10926
+ logLocalRuntimeDiagnostic("provider.selected", {
10927
+ agentKey: agentConfig.key,
10928
+ transport: "gemini-native-tool",
10929
+ apiSource: agentConfig.apiSource ?? null,
10930
+ provider: providerConfig2.provider,
10931
+ model: providerConfig2.model,
10932
+ hasApiKey: Boolean(providerConfig2.apiKey)
10933
+ });
10934
+ return {
10935
+ model: providerConfig2.model,
10936
+ complete: async (messages, options) => {
10937
+ const requestBody = buildGeminiGenerateContentRequest({
10938
+ messages,
10939
+ tools: tools2,
10940
+ maxTokens: typeof agentConfig.max_tokens === "number" ? agentConfig.max_tokens : void 0,
10941
+ temperature: typeof agentConfig.temperature === "number" ? agentConfig.temperature : void 0,
10942
+ attachSkipThoughtSignature: true
10943
+ });
10944
+ const model = providerConfig2.model;
10945
+ const url = `https://generativelanguage.googleapis.com/v1beta/models/${model}:streamGenerateContent?alt=sse`;
10946
+ logLocalRuntimeDiagnostic("provider.request.start", {
10947
+ agentKey: agentConfig.key,
10948
+ transport: "gemini-native-tool",
10949
+ model,
10950
+ messageCount: messages.length,
10951
+ toolCount: tools2.length,
10952
+ requestedToolNames: requestedToolNames2
10953
+ });
10954
+ const res = await fetchImpl(url, {
10955
+ method: "POST",
10956
+ headers: {
10957
+ "Content-Type": "application/json",
10958
+ "x-goog-api-key": providerConfig2.apiKey ?? ""
10959
+ },
10960
+ body: JSON.stringify(requestBody),
10961
+ signal: AbortSignal.timeout(12e4)
10962
+ });
10963
+ if (!res.ok) {
10964
+ const errText = await res.text();
10965
+ logLocalRuntimeDiagnostic("provider.request.failed", {
10966
+ agentKey: agentConfig.key,
10967
+ transport: "gemini-native-tool",
10968
+ status: res.status,
10969
+ error: errText.slice(0, 200)
10970
+ });
10971
+ throw new Error(
10972
+ `gemini native tool provider failed: HTTP ${res.status} ${errText.slice(0, 500)}`
10973
+ );
10974
+ }
10975
+ const chunks = await readSseDataValues(res, parseSseDataLineJson);
10976
+ const { text, toolCalls, usage } = accumulateGeminiChunks(chunks);
10977
+ if (text && options?.onTextDelta) {
10978
+ options.onTextDelta(text);
10979
+ }
10980
+ const result = {
10981
+ content: text,
10982
+ model,
10983
+ tool_calls: toolCalls.length > 0 ? toolCalls : void 0,
10984
+ ...usage ? { usage } : {},
10985
+ trace: messages
10986
+ };
10987
+ logLocalRuntimeDiagnostic("provider.request.result", {
10988
+ agentKey: agentConfig.key,
10989
+ transport: "gemini-native-tool",
10990
+ ok: true,
10991
+ contentChars: text.length,
10992
+ toolCallCount: toolCalls.length
10993
+ });
10994
+ return result;
10995
+ }
10996
+ };
10997
+ }
10998
+ }
10272
10999
  if (shouldUsePlatformChatProvider(deps.env, agentConfig)) {
10273
11000
  const providerConfig2 = await resolvePlatformChatProviderConfig({
10274
11001
  agentConfig,
@@ -10329,47 +11056,20 @@ function createCliLocalRuntimeAdapter(deps) {
10329
11056
  },
10330
11057
  {
10331
11058
  sleep: deps.sleep,
10332
- loopbackRequest
11059
+ loopbackRequest,
11060
+ // auto 档位转发 nolo.chat 时,网关层 502(server: Caddy、空 body)
11061
+ // 意味着请求根本没到 Bun 上游,provider 未受理,重试安全。
11062
+ // 与 429/503 同口径:不会重复计费/重复生成。
11063
+ retryableStatuses: /* @__PURE__ */ new Set([429, 502, 503]),
11064
+ onRetry: deps.activityReporter ? ({ attempt, maxAttempts, delayMs }) => {
11065
+ deps.activityReporter(
11066
+ `\u81EA\u52A8\u91CD\u8BD5 ${attempt}/${maxAttempts} \xB7 ${Math.ceil(delayMs / 1e3)}s`
11067
+ );
11068
+ } : void 0
10333
11069
  }
10334
11070
  );
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
11071
  if (!res.ok) {
10372
- const raw2 = firstErrorRaw ?? await res.text().catch(() => "");
11072
+ const raw2 = await res.text().catch(() => "");
10373
11073
  const data2 = parsePlatformChatCompletionData(raw2);
10374
11074
  const rawPreview = raw2.length > 200 ? `${raw2.slice(0, 200)}\u2026(${raw2.length}b)` : raw2;
10375
11075
  const gatewayHeaders = [
@@ -10420,7 +11120,7 @@ function createCliLocalRuntimeAdapter(deps) {
10420
11120
  });
10421
11121
  const data = parsePlatformChatCompletionData(raw);
10422
11122
  return parsePlatformChatCompletionResponse({
10423
- providerConfig: responseProviderConfig,
11123
+ providerConfig: providerConfig2,
10424
11124
  data,
10425
11125
  trace: messages
10426
11126
  });
@@ -10550,6 +11250,7 @@ function createCliLocalRuntimeAdapter(deps) {
10550
11250
  export {
10551
11251
  summarizeEndpoint,
10552
11252
  isBuiltinNoloAgentRef,
11253
+ parseAgentRunEvent,
10553
11254
  parseCliLocale,
10554
11255
  getCliLocale,
10555
11256
  setCliLocale,