nolo-cli 0.15.0 → 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-QDO62EZA.js → agentDeleteCommand-PBIUC4FT.js} +18 -17
  6. package/{agentEmailCommands-UZ5BKX3P.js → agentEmailCommands-KNZY4HXV.js} +35 -34
  7. package/{agentListCommands-ZC33UDWT.js → agentListCommands-N64PHBXM.js} +20 -19
  8. package/{agentMachineCommands-RZGZEZRL.js → agentMachineCommands-2AIPJKFM.js} +18 -17
  9. package/{agentRecordCommands-DGDXE2VH.js → agentRecordCommands-TB4N7YSB.js} +34 -33
  10. package/{agentRunCommand-SRZWFOPH.js → agentRunCommand-UVW2ZLKT.js} +34 -33
  11. package/{agentRuntimeLocal-4YCF6IRF.js → agentRuntimeLocal-T6YECTNF.js} +15 -16
  12. package/{agentSlice-IVE735EV.js → agentSlice-533PEM4O.js} +3 -3
  13. package/{appDeleteCommands-7I26L64I.js → appDeleteCommands-D6B6Z4ZQ.js} +19 -18
  14. package/{appDeployCommands-TZLZNTJN.js → appDeployCommands-YMO5FK4T.js} +19 -18
  15. package/{appDeployStatusCommands-OPPTLHRW.js → appDeployStatusCommands-EO5DWWPQ.js} +19 -18
  16. package/{appGetCommands-N2S4HYKY.js → appGetCommands-6SMZ3URQ.js} +19 -18
  17. package/{appListCommands-OBTPPKUM.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-JBKVPAYK.js → chunk-6KBBMW4D.js} +2 -2
  22. package/{chunk-U7LEGLEB.js → chunk-6N4KODMN.js} +1 -1
  23. package/{chunk-IZ2QRVEU.js → chunk-A7O4KKLZ.js} +3 -3
  24. package/{chunk-WA6KZL5V.js → chunk-AAODAAUQ.js} +23 -20
  25. package/{chunk-K53477EY.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-XGQZFBO5.js → chunk-DBLHEQH7.js} +148 -175
  29. package/{chunk-TTGAVETO.js → chunk-EABWT43X.js} +2 -2
  30. package/{chunk-OKSYPTDZ.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-P4MJQWWF.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-UXKQQ2MR.js → chunk-LO6JNGCT.js} +3 -3
  43. package/{chunk-472E5RMQ.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-IOQ7IBPU.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-5VMYGIIL.js → chunk-VHXXRWNL.js} +23 -9
  57. package/{chunk-OOIN7HSO.js → chunk-XJITGCTM.js} +10 -1
  58. package/{chunk-AWDOJBHW.js → chunk-XJYXSTBK.js} +883 -174
  59. package/{chunk-V2J635L5.js → chunk-XOIF2TNF.js} +2 -2
  60. package/{chunk-VPTJB4HM.js → chunk-XPC5C7BK.js} +0 -3
  61. package/{chunk-NTC6I2FN.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-3GEPXHFB.js → dialogCommands-DFY5HJ6M.js} +19 -18
  70. package/{dialogSlice-FAWUQDJW.js → dialogSlice-MS7OYWHW.js} +13 -13
  71. package/{docCreateCommands-ZE3S6BCP.js → docCreateCommands-5L76YTI2.js} +18 -17
  72. package/{docDeleteCommands-TW6PGTRT.js → docDeleteCommands-3GASP3VR.js} +19 -18
  73. package/{docReadCommands-LDXL3B6J.js → docReadCommands-ALA77AZM.js} +18 -17
  74. package/{docStore-2UHVWLTV.js → docStore-KYTKNGMU.js} +14 -14
  75. package/{docUpdateCommands-GYD6XI5O.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-OKNDYS3M.js → machineCommands-RDQQBA72.js} +33 -32
  80. package/{machineWsRunDispatch-ZX5AJ6FJ.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-MB3ANKHM.js → readlineWorkspace-BTONC7NW.js} +177 -76
  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-O3KJNCON.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-IOQ7IBPU.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-5VMYGIIL.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"
@@ -764,8 +776,8 @@ Use /switch, /switch list, /switch minimax-m3, or a full agent key.`,
764
776
  },
765
777
  themeCurrent: { en: "Current theme: {0} \xB7 {1}", zh: "\u5F53\u524D\u4E3B\u9898\uFF1A{0} \xB7 {1}" },
766
778
  themeUsage: {
767
- en: "Usage: /theme <name> | /theme light | /theme dark",
768
- zh: "\u7528\u6CD5\uFF1A/theme <name> | /theme light | /theme dark"
779
+ en: "Usage: /theme <name> | /theme light | /theme dark | /theme refresh",
780
+ zh: "\u7528\u6CD5\uFF1A/theme <name> | /theme light | /theme dark | /theme refresh"
769
781
  },
770
782
  themeAvailable: { en: "Available themes: {0}", zh: "\u53EF\u7528\u4E3B\u9898\uFF1A{0}" },
771
783
  themeBrightnessSwitched: { en: "Switched to {0} background colors.", zh: "\u5DF2\u5207\u6362\u5230 {0} \u80CC\u666F\u8272\u3002" },
@@ -773,6 +785,14 @@ Use /switch, /switch list, /switch minimax-m3, or a full agent key.`,
773
785
  en: "Background colors follow terminal detection (now: {0}).",
774
786
  zh: "\u80CC\u666F\u8272\u8DDF\u968F\u7EC8\u7AEF\u81EA\u52A8\u68C0\u6D4B\uFF08\u5F53\u524D\uFF1A{0}\uFF09\u3002"
775
787
  },
788
+ themeRefreshed: {
789
+ en: "Re-detected terminal background: {0}.",
790
+ zh: "\u5DF2\u91CD\u65B0\u68C0\u6D4B\u7EC8\u7AEF\u80CC\u666F\uFF1A{0}\u3002"
791
+ },
792
+ themeRefreshFailed: {
793
+ en: "Could not detect terminal background (not a TTY or no response).",
794
+ zh: "\u65E0\u6CD5\u68C0\u6D4B\u7EC8\u7AEF\u80CC\u666F\uFF08\u975E TTY \u6216\u7EC8\u7AEF\u65E0\u54CD\u5E94\uFF09\u3002"
795
+ },
776
796
  themeSwitched: { en: "Switched to theme: {0}", zh: "\u5DF2\u5207\u6362\u5230\u4E3B\u9898\uFF1A{0}" },
777
797
  themeUnknown: { en: "Unknown theme: {0}. Available themes: {1}", zh: "\u672A\u77E5\u4E3B\u9898\uFF1A{0}\u3002\u53EF\u7528\u4E3B\u9898\uFF1A{1}" },
778
798
  densityCurrent: {
@@ -920,6 +940,7 @@ function agentRunCardLabels() {
920
940
  runStatus: t("runStatusLabel"),
921
941
  runStarted: t("runStartedLabel"),
922
942
  runStopped: t("runStoppedLabel"),
943
+ runFinished: t("runFinishedLabel"),
923
944
  logTail: t("runLogTailLabel"),
924
945
  runs: (count) => t("runsListLabel", String(count))
925
946
  };
@@ -1115,6 +1136,11 @@ async function fetchWithTransientRetry(fetchImpl, input, init, options = {}) {
1115
1136
  const attemptBudget = coreDraining ? coreDrainingMaxAttempts : maxAttempts;
1116
1137
  if (attempt < attemptBudget) {
1117
1138
  const delayMs = await resolveRetryAfterMs(response, attempt);
1139
+ options.onRetry?.({
1140
+ attempt: attempt + 1,
1141
+ maxAttempts: attemptBudget,
1142
+ delayMs
1143
+ });
1118
1144
  await (options.sleep ?? defaultSleep)(delayMs);
1119
1145
  continue;
1120
1146
  }
@@ -1128,7 +1154,13 @@ async function fetchWithTransientRetry(fetchImpl, input, init, options = {}) {
1128
1154
  if (!isTransientFetchError(error)) throw error;
1129
1155
  lastError = error;
1130
1156
  if (attempt < maxAttempts) {
1131
- 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);
1132
1164
  }
1133
1165
  }
1134
1166
  }
@@ -1458,14 +1490,14 @@ var BUILTIN_PLATFORM_AGENT_CONFIGS = {
1458
1490
  [PUBLIC_DEEPSEEK_V4_PRO_AGENT_KEY]: {
1459
1491
  key: PUBLIC_DEEPSEEK_V4_PRO_AGENT_KEY,
1460
1492
  name: "DeepSeek V4 Pro",
1461
- provider: "deepseek",
1493
+ provider: "nolo",
1462
1494
  model: "deepseek-v4-pro",
1463
1495
  apiSource: "platform",
1464
1496
  useServerProxy: true,
1465
1497
  rawRecord: {
1466
1498
  dbKey: PUBLIC_DEEPSEEK_V4_PRO_AGENT_KEY,
1467
1499
  isPublic: true,
1468
- provider: "deepseek",
1500
+ provider: "nolo",
1469
1501
  model: "deepseek-v4-pro",
1470
1502
  apiSource: "platform",
1471
1503
  useServerProxy: true
@@ -1503,22 +1535,6 @@ var BUILTIN_PLATFORM_AGENT_CONFIGS = {
1503
1535
  useServerProxy: true
1504
1536
  }
1505
1537
  },
1506
- [PUBLIC_KIMI_K27_CODING_AGENT_KEY]: {
1507
- key: PUBLIC_KIMI_K27_CODING_AGENT_KEY,
1508
- name: "Kimi K2.7 Coding",
1509
- provider: "nolo",
1510
- model: "kimi-k2.7-code",
1511
- apiSource: "platform",
1512
- useServerProxy: true,
1513
- rawRecord: {
1514
- dbKey: PUBLIC_KIMI_K27_CODING_AGENT_KEY,
1515
- isPublic: true,
1516
- provider: "nolo",
1517
- model: "kimi-k2.7-code",
1518
- apiSource: "platform",
1519
- useServerProxy: true
1520
- }
1521
- },
1522
1538
  [BUILTIN_NOLO_AGENT_KEY]: {
1523
1539
  key: BUILTIN_NOLO_AGENT_KEY,
1524
1540
  name: "Nolo",
@@ -2029,6 +2045,93 @@ function buildServerPlatformToolExecutors(args) {
2029
2045
 
2030
2046
  // packages/cli/client/cliAgentRunToolExecutors.ts
2031
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
2032
2135
  var noopOutput = { write: () => {
2033
2136
  } };
2034
2137
  var parseCallArgs = (call) => {
@@ -2061,7 +2164,16 @@ function createCliStartAgentRunExecutor(deps = {}) {
2061
2164
 
2062
2165
  --- \u9644\u52A0\u8F93\u5165 ---
2063
2166
  ${JSON.stringify(args.input)}`;
2064
- 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
+ ];
2065
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;
2066
2178
  const { runId } = await spawnLocalBackgroundRun(
2067
2179
  {
@@ -2076,16 +2188,22 @@ ${JSON.stringify(args.input)}`;
2076
2188
  },
2077
2189
  deps
2078
2190
  );
2079
- const displayName = agentName ?? "agent";
2191
+ const displayName = resolveRunLabel({ agentName, agentKey, runId });
2080
2192
  const labels = agentRunCardLabels();
2193
+ const taskPreview = typeof args.task === "string" ? args.task.replace(/\s+/g, " ").trim().slice(0, TASK_PREVIEW_MAX) : "";
2081
2194
  return {
2082
2195
  content: JSON.stringify({
2083
2196
  runId,
2084
2197
  status: "running",
2085
- ...agentName ? { agentName } : {}
2198
+ ...agentName ? { agentName } : {},
2199
+ ...taskPreview ? { taskPreview } : {}
2086
2200
  }),
2087
2201
  metadata: {
2088
- displayData: formatStartRunCard(displayName, "running", labels)
2202
+ displayData: formatStartRunCard(displayName, "running", {
2203
+ task: taskPreview,
2204
+ runId,
2205
+ labels
2206
+ })
2089
2207
  }
2090
2208
  };
2091
2209
  };
@@ -2131,7 +2249,7 @@ function createCliControlAgentRunExecutor(deps = {}) {
2131
2249
  if (action === "status") {
2132
2250
  const reconciled = checkStaleRun(record.runId, deps) ?? record;
2133
2251
  const logTail = tailLines > 0 ? tailFile(record.logPath, tailLines, resolveFs(deps)) : void 0;
2134
- const name = reconciled.agentName || "agent";
2252
+ const name = resolveRunLabel(reconciled);
2135
2253
  const logLines = logTail ? logTail.split("\n") : void 0;
2136
2254
  const labels2 = agentRunCardLabels();
2137
2255
  return {
@@ -2158,7 +2276,15 @@ function createCliControlAgentRunExecutor(deps = {}) {
2158
2276
  ...logLines ? { logLines } : {}
2159
2277
  }),
2160
2278
  metadata: {
2161
- 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
+ })
2162
2288
  }
2163
2289
  };
2164
2290
  }
@@ -2440,19 +2566,22 @@ function resolveAntigravityWireModel(logicalModelId) {
2440
2566
  return { wireModelId: id };
2441
2567
  }
2442
2568
 
2443
- // packages/agent-runtime/antigravityCloudCodeProvider.ts
2444
- var STREAM_PATH = "/v1internal:streamGenerateContent?alt=sse";
2569
+ // packages/agent-runtime/geminiNativeShared.ts
2445
2570
  var SKIP_THOUGHT_SIGNATURE = "skip_thought_signature_validator";
2446
- function isGemini3WireModel(modelId) {
2571
+ function isGemini3Model(modelId) {
2447
2572
  return modelId.includes("gemini-3");
2448
2573
  }
2449
2574
  function messageText(content) {
2450
2575
  if (typeof content === "string") return content;
2451
2576
  if (!Array.isArray(content)) return "";
2452
- 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();
2453
2580
  }
2454
2581
  function parseDataUrlToInlineData(url) {
2455
- 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
+ );
2456
2585
  if (!match) return null;
2457
2586
  return { mimeType: match[1], data: match[2] };
2458
2587
  }
@@ -2469,7 +2598,7 @@ function extractInlineDataParts(content) {
2469
2598
  }
2470
2599
  return parts;
2471
2600
  }
2472
- function convertOpenAiMessagesToCca(messages, options) {
2601
+ function convertOpenAiMessagesToGemini(messages, options) {
2473
2602
  const contents = [];
2474
2603
  const systemTexts = [];
2475
2604
  const toolNamesById = /* @__PURE__ */ new Map();
@@ -2485,9 +2614,11 @@ function convertOpenAiMessagesToCca(messages, options) {
2485
2614
  };
2486
2615
  const flushPendingFunctionCalls = () => {
2487
2616
  if (pendingFunctionCalls.length === 0) return;
2488
- const dummyResponses = pendingFunctionCalls.map(({ name }) => ({
2489
- functionResponse: { name, response: { output: "{}" } }
2490
- }));
2617
+ const dummyResponses = pendingFunctionCalls.map(
2618
+ ({ name }) => ({
2619
+ functionResponse: { name, response: { output: "{}" } }
2620
+ })
2621
+ );
2491
2622
  pendingFunctionCalls = [];
2492
2623
  pushOrMergeContent("user", dummyResponses);
2493
2624
  };
@@ -2496,13 +2627,17 @@ function convertOpenAiMessagesToCca(messages, options) {
2496
2627
  const role = String(raw.role);
2497
2628
  const content = "content" in raw ? raw.content : null;
2498
2629
  if (role === "system") {
2499
- const text = messageText(content);
2630
+ const text = messageText(
2631
+ content
2632
+ );
2500
2633
  if (text) systemTexts.push(text);
2501
2634
  continue;
2502
2635
  }
2503
2636
  if (role === "user") {
2504
2637
  flushPendingFunctionCalls();
2505
- const text = messageText(content);
2638
+ const text = messageText(
2639
+ content
2640
+ );
2506
2641
  const imageParts = extractInlineDataParts(
2507
2642
  content
2508
2643
  );
@@ -2516,7 +2651,9 @@ function convertOpenAiMessagesToCca(messages, options) {
2516
2651
  if (role === "assistant") {
2517
2652
  flushPendingFunctionCalls();
2518
2653
  const parts = [];
2519
- const text = messageText(content);
2654
+ const text = messageText(
2655
+ content
2656
+ );
2520
2657
  if (text) parts.push({ text });
2521
2658
  const toolCalls = "tool_calls" in raw && Array.isArray(raw.tool_calls) ? raw.tool_calls ?? [] : [];
2522
2659
  for (const call of toolCalls) {
@@ -2526,17 +2663,20 @@ function convertOpenAiMessagesToCca(messages, options) {
2526
2663
  toolNamesById.set(id, name);
2527
2664
  pendingFunctionCalls.push({ name, id });
2528
2665
  const realSignature = typeof call.thought_signature === "string" && call.thought_signature ? call.thought_signature : void 0;
2529
- const isFirstFunctionCallPart = !parts.some((p) => "functionCall" in p);
2530
- 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 = {
2531
2671
  functionCall: {
2532
2672
  name,
2533
- args: parseToolArgumentsJson(call.function?.arguments),
2534
- id
2673
+ args: parseToolArgs(call.function?.arguments),
2674
+ ...id ? { id } : {}
2535
2675
  },
2536
- ...realSignature ? { thoughtSignature: realSignature } : options.attachSkipThoughtSignature && isFirstFunctionCallPart ? { thoughtSignature: SKIP_THOUGHT_SIGNATURE } : {}
2537
- });
2676
+ ...signature ? { thoughtSignature: signature } : {}
2677
+ };
2678
+ parts.push(part);
2538
2679
  }
2539
- if (parts.length === 0) continue;
2540
2680
  pushOrMergeContent("model", parts);
2541
2681
  continue;
2542
2682
  }
@@ -2554,14 +2694,39 @@ function convertOpenAiMessagesToCca(messages, options) {
2554
2694
  }
2555
2695
  const output = messageText(content) || "{}";
2556
2696
  pushOrMergeContent("user", [
2557
- { 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
+ }
2558
2708
  ]);
2559
2709
  }
2560
2710
  }
2561
2711
  flushPendingFunctionCalls();
2562
2712
  return { contents, systemTexts };
2563
2713
  }
2564
- 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) {
2565
2730
  if (!Array.isArray(tools) || tools.length === 0) return void 0;
2566
2731
  const declarations = [];
2567
2732
  for (const tool of tools) {
@@ -2578,6 +2743,97 @@ function convertOpenAiTools(tools) {
2578
2743
  if (declarations.length === 0) return void 0;
2579
2744
  return [{ functionDeclarations: declarations }];
2580
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";
2581
2837
  function buildCloudCodeAssistPayload(args) {
2582
2838
  const projectId = readAntigravityProjectId(args.metadata);
2583
2839
  if (!projectId) {
@@ -2588,8 +2844,9 @@ function buildCloudCodeAssistPayload(args) {
2588
2844
  const logicalModel = asOptionalTrimmedString(args.openAiBody.model) ?? asOptionalTrimmedString(args.agentConfig.model) ?? "gemini-3.1-pro";
2589
2845
  const { wireModelId: model, profile } = resolveAntigravityWireModel(logicalModel);
2590
2846
  const rawMessages = Array.isArray(args.openAiBody.messages) ? args.openAiBody.messages : [];
2591
- const { contents, systemTexts } = convertOpenAiMessagesToCca(rawMessages, {
2592
- attachSkipThoughtSignature: isGemini3WireModel(model)
2847
+ const isClaude = model.toLowerCase().includes("claude");
2848
+ const { contents, systemTexts } = convertOpenAiMessagesToGemini(rawMessages, {
2849
+ attachSkipThoughtSignature: isGemini3Model(model)
2593
2850
  });
2594
2851
  if (contents.length === 0) {
2595
2852
  throw new Error("Antigravity Cloud Code Assist request has no user/model contents.");
@@ -2603,7 +2860,7 @@ function buildCloudCodeAssistPayload(args) {
2603
2860
  parts: systemTexts.map((text) => ({ text }))
2604
2861
  };
2605
2862
  }
2606
- const tools = convertOpenAiTools(
2863
+ const tools = convertOpenAiToolsToGemini(
2607
2864
  Array.isArray(args.openAiBody.tools) ? args.openAiBody.tools : void 0
2608
2865
  );
2609
2866
  if (tools) {
@@ -2626,7 +2883,6 @@ function buildCloudCodeAssistPayload(args) {
2626
2883
  const trajectoryId = randomUUID();
2627
2884
  const step = 2;
2628
2885
  const requestId = `agent/${agentId}/${Date.now()}/${trajectoryId}/${step}`;
2629
- const isClaude = model.toLowerCase().includes("claude");
2630
2886
  const labels = {
2631
2887
  trajectory_id: trajectoryId,
2632
2888
  last_step_index: String(step - 1),
@@ -2650,57 +2906,6 @@ function buildCloudCodeAssistPayload(args) {
2650
2906
  }
2651
2907
  };
2652
2908
  }
2653
- function accumulateCcaChunks(chunks) {
2654
- let text = "";
2655
- const toolCalls = [];
2656
- let usage;
2657
- for (const chunk of chunks) {
2658
- if (!chunk || typeof chunk !== "object") continue;
2659
- const response = "response" in chunk && chunk.response && typeof chunk.response === "object" ? chunk.response : chunk;
2660
- if ("usageMetadata" in response && response.usageMetadata && typeof response.usageMetadata === "object") {
2661
- const meta = response.usageMetadata;
2662
- const prompt = typeof meta.promptTokenCount === "number" ? meta.promptTokenCount : 0;
2663
- const candidates2 = typeof meta.candidatesTokenCount === "number" ? meta.candidatesTokenCount : 0;
2664
- const total = typeof meta.totalTokenCount === "number" ? meta.totalTokenCount : prompt + candidates2;
2665
- usage = {
2666
- prompt_tokens: prompt,
2667
- completion_tokens: candidates2,
2668
- total_tokens: total
2669
- };
2670
- }
2671
- const candidates = Array.isArray(response.candidates) ? response.candidates : [];
2672
- for (const candidate of candidates) {
2673
- if (!candidate || typeof candidate !== "object" || !("content" in candidate)) continue;
2674
- const content = candidate.content;
2675
- if (!content || typeof content !== "object" || !("parts" in content)) continue;
2676
- const parts = content.parts;
2677
- if (!Array.isArray(parts)) continue;
2678
- for (const part of parts) {
2679
- if (!part || typeof part !== "object") continue;
2680
- const partSignature = part.thoughtSignature;
2681
- if ("text" in part && typeof part.text === "string") {
2682
- const piece = part.text;
2683
- if (!part.thought) {
2684
- text += piece;
2685
- }
2686
- }
2687
- if ("functionCall" in part && part.functionCall) {
2688
- const call = part.functionCall;
2689
- const name = typeof call.name === "string" ? call.name : "tool";
2690
- const id = typeof call.id === "string" ? call.id : `${name}_${toolCalls.length}`;
2691
- const argsObj = asRecordOrEmpty(call.args);
2692
- toolCalls.push({
2693
- id,
2694
- type: "function",
2695
- function: { name, arguments: JSON.stringify(argsObj) },
2696
- ...typeof partSignature === "string" && partSignature ? { thought_signature: partSignature } : {}
2697
- });
2698
- }
2699
- }
2700
- }
2701
- }
2702
- return { text, toolCalls, usage };
2703
- }
2704
2909
  async function readSseJsonChunks(response) {
2705
2910
  return readSseDataValues(response, parseSseDataLineJson);
2706
2911
  }
@@ -2725,7 +2930,7 @@ async function fetchAntigravityCloudCodeCompletion(args) {
2725
2930
  };
2726
2931
  }
2727
2932
  const chunks = await readSseJsonChunks(response);
2728
- const { text, toolCalls, usage } = accumulateCcaChunks(chunks);
2933
+ const { text, toolCalls, usage } = accumulateGeminiChunks(chunks);
2729
2934
  const message = {
2730
2935
  role: "assistant",
2731
2936
  content: text || null
@@ -2761,28 +2966,94 @@ var CLAUDE_CODE_IDENTITY_PATTERNS = [
2761
2966
  CLAUDE_CODE_SYSTEM_INSTRUCTION,
2762
2967
  "You are Claude Code"
2763
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
+ }
2764
3022
  function stringValue(value) {
2765
3023
  return typeof value === "string" && value.length > 0 ? value : void 0;
2766
3024
  }
3025
+ function isCacheControl(value) {
3026
+ return Boolean(
3027
+ value && typeof value === "object" && !Array.isArray(value) && typeof value.type === "string"
3028
+ );
3029
+ }
2767
3030
  function toAnthropicContent(content) {
2768
- if (typeof content === "string") return [{ type: "text", text: content }];
3031
+ if (typeof content === "string") {
3032
+ return content.length > 0 ? [{ type: "text", text: content }] : [];
3033
+ }
2769
3034
  if (!Array.isArray(content)) return [];
2770
3035
  const blocks = [];
2771
3036
  for (const raw of content) {
2772
3037
  if (!raw || typeof raw !== "object") continue;
2773
3038
  const part = raw;
2774
3039
  if ((part.type === "text" || part.type === "input_text") && typeof part.text === "string") {
2775
- 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
+ }
2776
3045
  continue;
2777
3046
  }
2778
3047
  if (part.type !== "image_url") continue;
2779
3048
  const imageUrl = typeof part.image_url === "string" ? part.image_url : stringValue(part.image_url?.url);
2780
3049
  if (!imageUrl) continue;
2781
3050
  const dataMatch = imageUrl.match(/^data:([^;,]+);base64,(.+)$/s);
2782
- blocks.push({
3051
+ const block = {
2783
3052
  type: "image",
2784
3053
  source: dataMatch ? { type: "base64", media_type: dataMatch[1], data: dataMatch[2] } : { type: "url", url: imageUrl }
2785
- });
3054
+ };
3055
+ if (isCacheControl(part.cache_control)) block.cache_control = part.cache_control;
3056
+ blocks.push(block);
2786
3057
  }
2787
3058
  return blocks;
2788
3059
  }
@@ -2816,7 +3087,15 @@ function buildAnthropicMessagesBody(args) {
2816
3087
  const message = raw;
2817
3088
  const role = String(message.role ?? "");
2818
3089
  if (role === "system" || role === "developer") {
2819
- 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
+ }
2820
3099
  continue;
2821
3100
  }
2822
3101
  if (role === "tool") {
@@ -2858,6 +3137,9 @@ function buildAnthropicMessagesBody(args) {
2858
3137
  if (!hasClaudeCodeIdentity(system)) {
2859
3138
  system.unshift({ type: "text", text: CLAUDE_CODE_SYSTEM_INSTRUCTION });
2860
3139
  }
3140
+ if (system.length > 0 && !system.some((block) => isCacheControl(block.cache_control))) {
3141
+ system[system.length - 1].cache_control = { type: "ephemeral" };
3142
+ }
2861
3143
  const tools = Array.isArray(args.openAiBody.tools) ? args.openAiBody.tools.flatMap((raw) => {
2862
3144
  if (!raw || typeof raw !== "object") return [];
2863
3145
  const fn = raw.function;
@@ -2872,14 +3154,39 @@ function buildAnthropicMessagesBody(args) {
2872
3154
  const model = stringValue(args.openAiBody.model) ?? args.agentConfig.model ?? "claude-sonnet-5";
2873
3155
  const maxTokensRaw = args.openAiBody.max_completion_tokens ?? args.openAiBody.max_tokens ?? args.agentConfig.max_tokens;
2874
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
+ }
2875
3180
  return {
2876
3181
  model,
2877
3182
  messages,
2878
- max_tokens: maxTokens,
3183
+ max_tokens: finalMaxTokens,
2879
3184
  stream: false,
3185
+ ...thinkingBlock ? { thinking: thinkingBlock } : {},
3186
+ ...outputConfig ? { output_config: outputConfig } : {},
2880
3187
  ...system.length > 0 ? { system } : {},
2881
3188
  ...tools.length > 0 ? { tools } : {},
2882
- ...typeof args.openAiBody.temperature === "number" ? { temperature: args.openAiBody.temperature } : typeof args.agentConfig.temperature === "number" ? { temperature: args.agentConfig.temperature } : {},
3189
+ ...typeof finalTemperature === "number" ? { temperature: finalTemperature } : {},
2883
3190
  ...typeof args.openAiBody.top_p === "number" ? { top_p: args.openAiBody.top_p } : {}
2884
3191
  };
2885
3192
  }
@@ -2903,6 +3210,8 @@ function mapAnthropicMessageToOpenAi(payload) {
2903
3210
  }
2904
3211
  const usage = payload.usage ?? {};
2905
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;
2906
3215
  const outputTokens = typeof usage.output_tokens === "number" ? usage.output_tokens : 0;
2907
3216
  const stopReason = String(payload.stop_reason ?? "");
2908
3217
  const message = { role: "assistant", content: text || null };
@@ -2918,9 +3227,16 @@ function mapAnthropicMessageToOpenAi(payload) {
2918
3227
  finish_reason: toolCalls.length > 0 || stopReason === "tool_use" ? "tool_calls" : stopReason === "max_tokens" ? "length" : "stop"
2919
3228
  }],
2920
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.
2921
3233
  prompt_tokens: inputTokens,
3234
+ input_tokens: inputTokens,
2922
3235
  completion_tokens: outputTokens,
2923
- 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
2924
3240
  }
2925
3241
  };
2926
3242
  }
@@ -8995,6 +9311,262 @@ function isCursorOAuthAgent(agent) {
8995
9311
  return agent.apiKeyRef?.trim().toLowerCase() === "cursor";
8996
9312
  }
8997
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
+
8998
9570
  // packages/agent-runtime/oauthProviders.ts
8999
9571
  var XAI_ACCESS_TOKEN_CLIENT_SKEW_MS = 5 * 60 * 1e3;
9000
9572
  var decodeBase64 = (s) => Buffer.from(s, "base64").toString("utf8");
@@ -10192,6 +10764,74 @@ function createCliLocalRuntimeAdapter(deps) {
10192
10764
  }
10193
10765
  };
10194
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
+ }
10195
10835
  if (isCursorOAuthAgent(agentConfig)) {
10196
10836
  const accessToken = await apiKeyRefResolver("cursor");
10197
10837
  if (!accessToken) {
@@ -10261,6 +10901,101 @@ function createCliLocalRuntimeAdapter(deps) {
10261
10901
  }
10262
10902
  };
10263
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
+ }
10264
10999
  if (shouldUsePlatformChatProvider(deps.env, agentConfig)) {
10265
11000
  const providerConfig2 = await resolvePlatformChatProviderConfig({
10266
11001
  agentConfig,
@@ -10321,47 +11056,20 @@ function createCliLocalRuntimeAdapter(deps) {
10321
11056
  },
10322
11057
  {
10323
11058
  sleep: deps.sleep,
10324
- 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
10325
11069
  }
10326
11070
  );
10327
- let responseProviderConfig = providerConfig2;
10328
- let firstErrorRaw;
10329
- if (!res.ok) {
10330
- firstErrorRaw = await res.text().catch(() => "");
10331
- const fallbackProviderConfig = resolveLegacyDeepSeekProxyChatFallback({
10332
- providerConfig: providerConfig2,
10333
- status: res.status,
10334
- raw: firstErrorRaw
10335
- });
10336
- if (fallbackProviderConfig) {
10337
- responseProviderConfig = fallbackProviderConfig;
10338
- const fallbackRequest = buildPlatformChatCompletionRequest({
10339
- providerConfig: fallbackProviderConfig,
10340
- messages,
10341
- tools: tools2,
10342
- stream: false
10343
- });
10344
- logLocalRuntimeDiagnostic("provider.request.compatibility-fallback", {
10345
- agentKey: agentConfig.key,
10346
- provider: providerConfig2.provider,
10347
- fromEndpoint: summarizeEndpoint(providerConfig2.endpoint) ?? null,
10348
- toEndpoint: summarizeEndpoint(fallbackProviderConfig.endpoint) ?? null,
10349
- reason: "legacy-proxy-responses-schema"
10350
- });
10351
- res = await fetchWithTransientRetry(
10352
- fetchImpl,
10353
- fallbackRequest.url,
10354
- { ...fallbackRequest.init },
10355
- {
10356
- sleep: deps.sleep,
10357
- loopbackRequest
10358
- }
10359
- );
10360
- firstErrorRaw = void 0;
10361
- }
10362
- }
10363
11071
  if (!res.ok) {
10364
- const raw2 = firstErrorRaw ?? await res.text().catch(() => "");
11072
+ const raw2 = await res.text().catch(() => "");
10365
11073
  const data2 = parsePlatformChatCompletionData(raw2);
10366
11074
  const rawPreview = raw2.length > 200 ? `${raw2.slice(0, 200)}\u2026(${raw2.length}b)` : raw2;
10367
11075
  const gatewayHeaders = [
@@ -10412,7 +11120,7 @@ function createCliLocalRuntimeAdapter(deps) {
10412
11120
  });
10413
11121
  const data = parsePlatformChatCompletionData(raw);
10414
11122
  return parsePlatformChatCompletionResponse({
10415
- providerConfig: responseProviderConfig,
11123
+ providerConfig: providerConfig2,
10416
11124
  data,
10417
11125
  trace: messages
10418
11126
  });
@@ -10542,6 +11250,7 @@ function createCliLocalRuntimeAdapter(deps) {
10542
11250
  export {
10543
11251
  summarizeEndpoint,
10544
11252
  isBuiltinNoloAgentRef,
11253
+ parseAgentRunEvent,
10545
11254
  parseCliLocale,
10546
11255
  getCliLocale,
10547
11256
  setCliLocale,