nolo-cli 0.1.30 → 0.1.31

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 (308) hide show
  1. package/agent-runtime/agentRecordConfig.ts +0 -2
  2. package/agent-runtime/hostAdapter.ts +0 -1
  3. package/agent-runtime/hostRuntimeCapabilities.ts +7 -0
  4. package/agent-runtime/hostRuntimeConfig.ts +86 -0
  5. package/agent-runtime/index.ts +13 -0
  6. package/agent-runtime/localToolPolicy.ts +13 -6
  7. package/agent-runtime/localWorkspaceTools.ts +333 -30
  8. package/agent-runtime/platformChatProvider.ts +4 -1
  9. package/agent-runtime/runtimeToolPolicy.ts +32 -47
  10. package/agent-runtime/shellCommandPolicy.ts +117 -0
  11. package/agent-runtime/toolGate.ts +38 -0
  12. package/agentRecordCommands.ts +1 -1
  13. package/agentRecordHelpers.ts +35 -20
  14. package/agentRunParsing.ts +18 -5
  15. package/agentRuntimeLocal.ts +10 -0
  16. package/ai/agent/agentRunDialogLineage.ts +56 -0
  17. package/ai/agent/agentSlice.ts +45 -10
  18. package/ai/agent/avatarUtils.ts +1 -1
  19. package/ai/agent/buildSystemPrompt.ts +1 -2
  20. package/ai/agent/cliExecutor.ts +330 -19
  21. package/ai/agent/createAgentSchema.ts +22 -0
  22. package/ai/agent/hooks/fetchPublicAgents.ts +14 -39
  23. package/ai/agent/hooks/usePublicAgents.ts +90 -192
  24. package/ai/agent/publicAgentCatalog.ts +359 -0
  25. package/ai/agent/publicAgentIdentity.ts +76 -0
  26. package/ai/agent/server/fetchPublicAgents.ts +21 -46
  27. package/ai/agent/serverOrigin.ts +7 -0
  28. package/ai/agent/streamAgentChatTurn.ts +23 -21
  29. package/ai/agent/streamAgentChatTurnUtils.ts +292 -6
  30. package/ai/agent/types.ts +2 -0
  31. package/ai/agent/web/agentDisplayUtils.ts +171 -0
  32. package/ai/agent/web/useAgentModelAvatarComponent.ts +32 -0
  33. package/ai/ai.locale.ts +8 -0
  34. package/ai/chat/sendOpenAICompletionsRequest.native.ts +15 -0
  35. package/ai/chat/sendOpenAICompletionsRequest.ts +93 -1
  36. package/ai/chat/sendOpenAIResponseRequest.ts +86 -9
  37. package/ai/chat/updateTotalUsage.ts +7 -0
  38. package/ai/llm/deepinfra.ts +30 -15
  39. package/ai/llm/mistral.ts +3 -4
  40. package/ai/llm/providers.ts +2 -0
  41. package/ai/llm/types.ts +15 -0
  42. package/ai/memory/capture.ts +3 -3
  43. package/ai/memory/consolidate.ts +2 -2
  44. package/ai/memory/delete.ts +4 -3
  45. package/ai/memory/query.ts +3 -3
  46. package/ai/memory/remember.ts +2 -2
  47. package/ai/memory/store.ts +3 -3
  48. package/ai/memory/storeShared.ts +3 -2
  49. package/ai/policy/commercialMultiplier.ts +16 -0
  50. package/ai/token/billingAdminAuditEvent.ts +68 -0
  51. package/ai/token/billingAdminAuditEventWriter.ts +41 -0
  52. package/ai/token/billingAnomaly.ts +90 -0
  53. package/ai/token/billingAnomalyLifecycle.ts +54 -0
  54. package/ai/token/billingAnomalyLifecycleWriter.ts +44 -0
  55. package/ai/token/billingAnomalyWriter.ts +41 -0
  56. package/ai/token/calculatePrice.ts +3 -2
  57. package/ai/token/deepinfraReconciliation.ts +153 -0
  58. package/ai/token/deepinfraRequestIdQuery.ts +92 -0
  59. package/ai/token/externalToolCost.ts +54 -41
  60. package/ai/token/missingUsageEstimate.ts +12 -3
  61. package/ai/token/normalizeUsage.ts +45 -5
  62. package/ai/token/openaiReconciliation.ts +188 -0
  63. package/ai/token/providerBillableEvent.ts +84 -0
  64. package/ai/token/providerBillableEventWriter.ts +36 -0
  65. package/ai/token/providerBillingAnomalyDrilldown.ts +308 -0
  66. package/ai/token/providerBillingDrilldown.ts +361 -0
  67. package/ai/token/providerBillingHealthReport.ts +366 -0
  68. package/ai/token/providerCall.ts +144 -0
  69. package/ai/token/providerCallSweeper.ts +168 -0
  70. package/ai/token/providerCallWriter.ts +33 -0
  71. package/ai/token/providerCredential.ts +89 -0
  72. package/ai/token/providerCredentialAnomaly.ts +154 -0
  73. package/ai/token/providerCredentialLifecycle.ts +59 -0
  74. package/ai/token/providerCredentialLifecycleWriter.ts +44 -0
  75. package/ai/token/providerCredentialRegistry.ts +83 -0
  76. package/ai/token/providerCredentialRegistryCommand.ts +97 -0
  77. package/ai/token/providerCredentialRegistryList.ts +124 -0
  78. package/ai/token/providerCredentialRegistryResolver.ts +150 -0
  79. package/ai/token/providerCredentialRegistryWriter.ts +41 -0
  80. package/ai/token/providerCredentialRotationCommand.ts +102 -0
  81. package/ai/token/providerCredentialRuntime.ts +56 -0
  82. package/ai/token/providerDispatchIntent.ts +67 -0
  83. package/ai/token/providerDispatchIntentWriter.ts +36 -0
  84. package/ai/token/providerGateway.ts +260 -0
  85. package/ai/token/providerReconciliation.ts +148 -0
  86. package/ai/token/providerReconciliationLocal.ts +97 -0
  87. package/ai/token/providerReconciliationRunner.ts +165 -0
  88. package/ai/token/providerReconciliationWriter.ts +41 -0
  89. package/ai/token/ratingResult.ts +202 -0
  90. package/ai/token/ratingResultWriter.ts +33 -0
  91. package/ai/token/serverDialogProjection.ts +5 -3
  92. package/ai/token/serverTokenWriter.ts +11 -3
  93. package/ai/token/types.ts +10 -0
  94. package/ai/tools/agent/callAgentTool.ts +3 -4
  95. package/ai/tools/agent/presets/appBuilderPreset.ts +5 -7
  96. package/ai/tools/agent/runStreamingAgentTool.ts +1 -2
  97. package/ai/tools/agent/streamParallelAgentsTool.ts +2 -3
  98. package/ai/tools/readXPostTool.ts +1 -5
  99. package/app/admin/adminPages.ts +9 -0
  100. package/app/i18n/i18n.config.ts +5 -0
  101. package/app/i18n/translations/pricing.locale.ts +397 -0
  102. package/app/utils/desktopAgentRuntimeStatusClient.ts +5 -4
  103. package/app/utils/desktopAgentRuntimeTurnClient.ts +4 -1
  104. package/app/utils/imageUtils.ts +64 -34
  105. package/auth/adminPermissions.ts +18 -0
  106. package/auth/authSlice.ts +26 -12
  107. package/auth/hooks/useFetchUsers.ts +3 -0
  108. package/auth/routes.ts +46 -0
  109. package/auth/server/accessActivity.ts +4 -3
  110. package/auth/server/adminPermissions.ts +43 -0
  111. package/auth/server/adminUsageReport.ts +375 -0
  112. package/auth/server/billingAnomalies.ts +235 -0
  113. package/auth/server/billingUsageReport.ts +41 -2
  114. package/auth/server/creatorEarningCreditConversion.ts +10 -2
  115. package/auth/server/deduct.ts +14 -7
  116. package/auth/server/delete.ts +10 -2
  117. package/auth/server/disable.ts +4 -3
  118. package/auth/server/emailAutomation.ts +7 -5
  119. package/auth/server/emailDbConfig.ts +4 -2
  120. package/auth/server/emailDelivery.ts +24 -20
  121. package/auth/server/emailDeliveryGuards.ts +10 -7
  122. package/auth/server/emailPreferences.ts +6 -4
  123. package/auth/server/emailReport.ts +6 -4
  124. package/auth/server/emailRuntimeConfig.ts +3 -3
  125. package/auth/server/emailScenarioNotifications.ts +9 -8
  126. package/auth/server/enable.ts +4 -3
  127. package/auth/server/getRechargeHistory.ts +3 -2
  128. package/auth/server/getUser.ts +3 -2
  129. package/auth/server/gptProAccess.ts +44 -0
  130. package/auth/server/inviteReward.ts +10 -7
  131. package/auth/server/listusers.ts +6 -4
  132. package/auth/server/login.ts +2 -2
  133. package/auth/server/productEntitlements.ts +7 -4
  134. package/auth/server/productPurchase.ts +10 -2
  135. package/auth/server/providerBillingDrilldown.ts +47 -0
  136. package/auth/server/providerBillingHealth.ts +71 -0
  137. package/auth/server/providerCredentials.ts +136 -0
  138. package/auth/server/recharge.ts +14 -8
  139. package/auth/server/revokeSessions.ts +4 -3
  140. package/auth/server/route.ts +77 -0
  141. package/auth/server/sendEmail.ts +5 -4
  142. package/auth/server/signup.ts +10 -3
  143. package/auth/server/token.ts +53 -55
  144. package/auth/server/tokenUsageBilling.ts +18 -7
  145. package/auth/server/usageManagementAccess.ts +43 -0
  146. package/auth/server/usageReport.ts +59 -0
  147. package/auth/types.ts +12 -0
  148. package/auth/utils.ts +24 -22
  149. package/authCommands.ts +36 -2
  150. package/buildPublish.ts +3 -1
  151. package/buildPublishArtifactAssembly.ts +62 -1
  152. package/buildPublishImportAnalysis.ts +21 -16
  153. package/chat/dialog/dialogLaunchScope.ts +32 -0
  154. package/chat/dialog/objectAssistantRegistry.ts +2 -2
  155. package/chat/dialog/useCreateDialog.ts +1 -1
  156. package/chat/hooks/useChatInput.ts +41 -10
  157. package/chat/messages/messageSlice.ts +5 -1
  158. package/chat/messages/pendingAttachmentParts.ts +28 -2
  159. package/chat/messages/sendFirstMessage.ts +76 -79
  160. package/chat/messages/types.ts +9 -0
  161. package/chat/messages/web/streamingMarkdownModel.ts +41 -0
  162. package/chat/messages/web/useStreamingReveal.ts +91 -0
  163. package/chat/web/messageInputAgentUi.ts +94 -6
  164. package/cliEnvHelpers.ts +8 -0
  165. package/cliRuntimeDoctorReport.ts +193 -0
  166. package/client/agentConfigResolver.test.ts +0 -2
  167. package/client/agentRun.test.ts +171 -10
  168. package/client/agentRun.ts +44 -637
  169. package/client/agentRunInput.ts +10 -0
  170. package/client/agentRunLocalExecutor.ts +179 -0
  171. package/client/agentRunServerTransport.ts +394 -0
  172. package/client/agentRunTaskRunRecorder.ts +176 -0
  173. package/client/localRuntimeAdapter.test.ts +236 -9
  174. package/client/localRuntimeAdapter.ts +221 -23
  175. package/client/localToolPolicy.test.ts +28 -4
  176. package/connector-experimental/daemonLauncher.ts +38 -4
  177. package/connectorRunArtifact.ts +34 -10
  178. package/connectorWebSocketTarget.ts +9 -5
  179. package/core/builtinAgents.ts +155 -11
  180. package/create/space/contentLabels.ts +1 -1
  181. package/create/space/contentTypeMeta.ts +3 -2
  182. package/create/space/sidebarVisibleTypes.ts +27 -0
  183. package/create/space/space.locale.ts +76 -4
  184. package/database/actions/agentReadResolution.ts +2 -8
  185. package/database/actions/read.ts +11 -9
  186. package/database/actions/readAndWait.ts +10 -5
  187. package/database/server/agentDelegation.ts +3 -2
  188. package/database/server/authorityStoreConformance.ts +209 -0
  189. package/database/server/authorityStoreTypes.ts +31 -0
  190. package/database/server/coreDataProxy.ts +1 -1
  191. package/database/server/dataHandlers.ts +13 -5
  192. package/database/server/db.ts +15 -34
  193. package/database/server/delete.ts +88 -71
  194. package/database/server/emailRepository.ts +11 -9
  195. package/database/server/fileService.ts +2 -1
  196. package/database/server/legacyServerDb.ts +58 -0
  197. package/database/server/levelAuthorityStore.ts +75 -0
  198. package/database/server/memoryAuthorityStore.ts +133 -0
  199. package/database/server/patch.ts +13 -12
  200. package/database/server/query.ts +3 -2
  201. package/database/server/read.ts +33 -30
  202. package/database/server/resourceAccess.ts +7 -5
  203. package/database/server/serverStoreFactory.ts +124 -0
  204. package/database/server/spaceMemberAuthority.ts +3 -2
  205. package/database/server/storeBatchCompat.ts +37 -0
  206. package/database/server/testAuthorityStore.ts +76 -0
  207. package/database/server/write.ts +29 -27
  208. package/integrations/anthropic/anthropicModels.ts +12 -12
  209. package/integrations/deepseek/models.ts +67 -67
  210. package/integrations/google/models.ts +111 -53
  211. package/integrations/openai/models.ts +22 -22
  212. package/integrations/xai/models.ts +1 -1
  213. package/localRuntimeDb.ts +39 -2
  214. package/machineCommandPrompts.ts +2 -0
  215. package/machineCommands.ts +193 -63
  216. package/machineWsRunDispatch.ts +80 -15
  217. package/machineWsSession.ts +39 -2
  218. package/noloReadBridgePrompt.ts +16 -0
  219. package/package.json +99 -6
  220. package/render/layout/mainLayoutViewMode.ts +25 -0
  221. package/render/page/server/createPage.ts +3 -1
  222. package/render/page/server/handleCreatePage.ts +2 -11
  223. package/runtimeDoctorCommands.ts +15 -66
  224. package/server/api/methods.ts +34 -12
  225. package/server/api/tableHandlers.ts +6 -3
  226. package/server/authenticateToken.ts +47 -2
  227. package/server/billingLedgerRoutes.ts +15 -0
  228. package/server/buildManifest.ts +54 -0
  229. package/server/coreReadiness.ts +34 -25
  230. package/server/coreRuntime.ts +15 -10
  231. package/server/handlers/activityStatsHandler.ts +5 -2
  232. package/server/handlers/agentEmailRegistrationE2EHandler.ts +25 -23
  233. package/server/handlers/agentRun/agentLookup.ts +1 -7
  234. package/server/handlers/agentRun/autonomousRuntime.ts +11 -10
  235. package/server/handlers/agentRun/builtinAgents.ts +12 -88
  236. package/server/handlers/agentRun/continueDialogContext.ts +15 -3
  237. package/server/handlers/agentRun/{inheritedDialogPrompt.ts → conversationReference.ts} +3 -3
  238. package/server/handlers/agentRun/dialogLookup.ts +4 -3
  239. package/server/handlers/agentRun/index.ts +864 -404
  240. package/server/handlers/agentRun/localRuntimeBootstrap.ts +17 -1
  241. package/server/handlers/agentRun/loop.ts +920 -508
  242. package/server/handlers/agentRun/machineConnector.ts +56 -8
  243. package/server/handlers/agentRun/machineRunAudit.ts +3 -2
  244. package/server/handlers/agentRun/modelUsageToolHandlers.ts +13 -10
  245. package/server/handlers/agentRun/requestContext.ts +12 -8
  246. package/server/handlers/agentRun/runtimeExecutionContext.ts +15 -3
  247. package/server/handlers/agentRun/runtimePreparation.ts +26 -24
  248. package/server/handlers/agentRun/runtimeRouting.ts +25 -40
  249. package/server/handlers/agentRun/runtimeSystemMessages.ts +65 -0
  250. package/server/handlers/agentRun/saveDialog.ts +97 -87
  251. package/server/handlers/agentRun/taskRunToolHandler.ts +9 -7
  252. package/server/handlers/agentRun/toolExecutor.ts +42 -78
  253. package/server/handlers/agentRun/types.ts +2 -1
  254. package/server/handlers/appDeployStatusStore.ts +17 -10
  255. package/server/handlers/appDomainHandler.ts +21 -15
  256. package/server/handlers/appLegacyInfraCleanup.ts +5 -2
  257. package/server/handlers/appSandboxHandler.ts +29 -8
  258. package/server/handlers/appSpaceAccess.ts +15 -8
  259. package/server/handlers/chatHandler.ts +22 -2
  260. package/server/handlers/chatUpstreamRetry.ts +225 -2
  261. package/server/handlers/connector/connectorConnectionRegistry.ts +55 -7
  262. package/server/handlers/connector/connectorWebSocket.ts +14 -10
  263. package/server/handlers/desktopAgentRuntimeAdapter.ts +4 -4
  264. package/server/handlers/desktopAgentRuntimeHostCapabilities.ts +25 -0
  265. package/server/handlers/desktopAgentRuntimeReadiness.ts +62 -0
  266. package/server/handlers/desktopAgentRuntimeStatusHandler.ts +38 -30
  267. package/server/handlers/desktopAgentRuntimeTurnHandler.ts +7 -3
  268. package/server/handlers/desktopAgentRuntimeTurnService.ts +39 -45
  269. package/server/handlers/desktopLlamaRuntimeHandler.ts +85 -51
  270. package/server/handlers/desktopUpdaterHandler.ts +132 -24
  271. package/server/handlers/favoriteHandlers.ts +8 -2
  272. package/server/handlers/getDialogBillingHandler.ts +4 -3
  273. package/server/handlers/getTransactionsHandler.ts +5 -2
  274. package/server/handlers/machines/machineBinding.ts +1 -0
  275. package/server/handlers/machines/machineHandlers.ts +0 -14
  276. package/server/handlers/machines/machineInstallAssets.ts +4 -2
  277. package/server/handlers/notificationEmitter.ts +5 -3
  278. package/server/handlers/notificationsHandler.ts +5 -2
  279. package/server/handlers/providerCallsRecentHandler.ts +234 -0
  280. package/server/handlers/providerReconciliationRunHandler.ts +180 -0
  281. package/server/handlers/providerRequestIdsHandler.ts +105 -0
  282. package/server/handlers/tableAccess.ts +6 -2
  283. package/server/handlers/tableToolHandlers.ts +28 -14
  284. package/server/handlers/userSecretsHandler.ts +17 -6
  285. package/server/handlers/versionHandler.ts +9 -4
  286. package/server/handlers/versionStore.ts +18 -10
  287. package/server/html/ssrPreload.ts +5 -3
  288. package/server/payments/crypto/cryptoUsdcBasePaymentProvider.ts +11 -8
  289. package/server/payments/crypto/cryptoUsdcBaseScanner.ts +12 -7
  290. package/server/payments/crypto/cryptoUsdtTronPaymentProvider.ts +11 -8
  291. package/server/payments/crypto/cryptoUsdtTronScanner.ts +9 -7
  292. package/server/payments/waffo/waffoPaymentProvider.ts +12 -9
  293. package/server/runtimeRole.ts +15 -0
  294. package/server/scheduler/scheduledTaskRuntime.ts +4 -2
  295. package/server/scheduler/schedulerService.ts +2 -2
  296. package/server/taskRunBridgeRoutes.ts +8 -5
  297. package/share/server/fetchCommunityShares.ts +1 -1
  298. package/share/server/helpers.ts +19 -17
  299. package/share/server/importShare.ts +9 -13
  300. package/share/server/listCommunityShares.ts +4 -4
  301. package/share/server/purchaseDoc.ts +8 -16
  302. package/share/server/readCommunityShareCover.ts +3 -2
  303. package/share/server/readSharedTable.ts +14 -13
  304. package/share/server/tableReplication.ts +42 -39
  305. package/spaceAttachCommands.ts +135 -0
  306. package/spaceInternalCommandEntries.ts +2 -0
  307. package/ai/agent/runtimeServerBase.ts +0 -37
  308. package/server/handlers/desktopAgentRuntimeHostFacts.ts +0 -40
@@ -14,8 +14,8 @@
14
14
  */
15
15
 
16
16
  import { exec, execSync, spawn } from "child_process";
17
- import { randomUUID } from "node:crypto";
18
- import { mkdtempSync, readFileSync, rmSync } from "node:fs";
17
+ import { createHash, randomUUID } from "node:crypto";
18
+ import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
19
19
  import { join } from "node:path";
20
20
  import { tmpdir } from "node:os";
21
21
  import { resolveLaunchableCodexCommand } from "../../connector-experimental/codexBinary";
@@ -50,6 +50,25 @@ export interface CliExecuteResult {
50
50
  warnings?: string[];
51
51
  }
52
52
 
53
+ type AgyDebugArtifact = {
54
+ dir: string;
55
+ promptHash: string;
56
+ promptBytes: number;
57
+ writeResult: (args: {
58
+ startedAt: string;
59
+ finishedAt: string;
60
+ elapsedMs: number;
61
+ cwd: string;
62
+ timeoutMs: number;
63
+ args: string[];
64
+ stdout: string;
65
+ stderr: string;
66
+ exitCode: number | null;
67
+ outcome: "succeeded" | "timed_out" | "spawn_error" | "failed";
68
+ errorMessage?: string;
69
+ }) => void;
70
+ };
71
+
53
72
  type CliSessionMessage = {
54
73
  role: "user" | "assistant";
55
74
  content: string;
@@ -171,6 +190,8 @@ function supportsNativeSystemPrompt(provider: CliProvider): boolean {
171
190
  }
172
191
 
173
192
  function supportsModel(provider: CliProvider): boolean {
193
+ // Antigravity CLI does not expose a model selection flag.
194
+ // Codex is handled separately so explicit opt-in can still pass --model through.
174
195
  return provider !== "agy";
175
196
  }
176
197
 
@@ -178,6 +199,13 @@ function supportsReasoningEffort(provider: CliProvider): boolean {
178
199
  return provider === "claude" || provider === "copilot";
179
200
  }
180
201
 
202
+ function shouldPassCodexModel(options: CliExecuteOptions): boolean {
203
+ return (options.env?.NOLO_CODEX_CLI_ALLOW_MODEL ?? process.env.NOLO_CODEX_CLI_ALLOW_MODEL) === "1";
204
+ }
205
+ function shouldPassClaudeModel(options: CliExecuteOptions): boolean {
206
+ return (options.env?.NOLO_CLAUDE_CLI_ALLOW_MODEL ?? process.env.NOLO_CLAUDE_CLI_ALLOW_MODEL) === "1";
207
+ }
208
+
181
209
  function collectCliCapabilityWarnings(
182
210
  provider: CliProvider,
183
211
  options: CliExecuteOptions
@@ -189,7 +217,15 @@ function collectCliCapabilityWarnings(
189
217
  warnings.push(`${label} does not support reasoning_effort; ignored.`);
190
218
  }
191
219
 
192
- if (options.model !== undefined && !supportsModel(provider)) {
220
+ if (provider === "codex" && options.model !== undefined && !shouldPassCodexModel(options)) {
221
+ warnings.push(
222
+ "Codex CLI model selection is disabled by default because real Codex installs can reject --model with subscription/plan errors; set NOLO_CODEX_CLI_ALLOW_MODEL=1 to pass it through."
223
+ );
224
+ } else if (provider === "claude" && options.model !== undefined && !shouldPassClaudeModel(options)) {
225
+ warnings.push(
226
+ "Claude CLI model selection is disabled by default because current installs can reject --model; set NOLO_CLAUDE_CLI_ALLOW_MODEL=1 to pass it through."
227
+ );
228
+ } else if (options.model !== undefined && !supportsModel(provider)) {
193
229
  warnings.push(`${label} does not support model selection; ignored.`);
194
230
  }
195
231
 
@@ -218,16 +254,121 @@ function resolveCliExecution(
218
254
  options: CliExecuteOptions
219
255
  ): { prompt: string; options: CliExecuteOptions; warnings: string[] } {
220
256
  const warnings = collectCliCapabilityWarnings(provider, options);
221
- if (supportsNativeSystemPrompt(provider) || !options.systemPrompt?.trim()) {
222
- return { prompt, options, warnings };
257
+ const resolvedPrompt =
258
+ supportsNativeSystemPrompt(provider) || !options.systemPrompt?.trim()
259
+ ? prompt
260
+ : buildCliPrompt(options.systemPrompt, prompt);
261
+ const resolvedOptions =
262
+ supportsNativeSystemPrompt(provider) || !options.systemPrompt?.trim()
263
+ ? options
264
+ : {
265
+ ...options,
266
+ systemPrompt: undefined,
267
+ };
268
+ const agyPrompt = provider === "agy" ? compactAgyPrompt(resolvedPrompt) : null;
269
+ return {
270
+ prompt: agyPrompt?.prompt ?? resolvedPrompt,
271
+ options: resolvedOptions,
272
+ warnings: [...warnings, ...(agyPrompt?.warnings ?? [])],
273
+ };
274
+ }
275
+
276
+ const AGY_PRESERVED_PROMPT_BLOCK_HEADERS = [
277
+ "--- Nolo read-only CLI bridge ---",
278
+ "--- Nolo task-run tool bridge ---",
279
+ ] as const;
280
+ const AGY_OPTIONAL_TASKRUN_GUIDANCE_HEADERS = [
281
+ "## TaskRun tool guidance (2026-05-17)",
282
+ "## TaskRun tool strictness (2026-05-17)",
283
+ "## TaskRun delegation boundary (2026-05-17)",
284
+ ] as const;
285
+
286
+ function escapeRegExp(value: string) {
287
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
288
+ }
289
+
290
+ function extractPromptBlock(source: string, header: string) {
291
+ const pattern = new RegExp(
292
+ `(?:^|\\n)(${escapeRegExp(header)}\\n[\\s\\S]*?)(?=\\n{2,}--- [^\\n]+ ---|\\n{2,}User task:|\\n{2,}--- User task ---|$)`,
293
+ );
294
+ const match = source.match(pattern);
295
+ if (!match) return null;
296
+ return {
297
+ block: match[1].trim(),
298
+ remaining: source.replace(pattern, "\n\n"),
299
+ };
300
+ }
301
+
302
+ function stripMarkdownSection(source: string, header: string) {
303
+ const pattern = new RegExp(
304
+ `(?:^|\\n)${escapeRegExp(header)}\\n[\\s\\S]*?(?=\\n{2,}## [^\\n]+|\\n{2,}--- [^\\n]+ ---|\\n{2,}User task:|\\n{2,}--- User task ---|$)`,
305
+ );
306
+ return source.replace(pattern, "\n\n");
307
+ }
308
+
309
+ function compactAgyPrompt(prompt: string): { prompt: string; warnings: string[] } {
310
+ let next = prompt;
311
+ let changed = false;
312
+ const preservedBlocks: string[] = [];
313
+
314
+ const stripBlock = (pattern: RegExp) => {
315
+ const updated = next.replace(pattern, "\n\n");
316
+ if (updated !== next) {
317
+ next = updated;
318
+ changed = true;
319
+ }
320
+ };
321
+
322
+ for (const header of AGY_PRESERVED_PROMPT_BLOCK_HEADERS) {
323
+ const extracted = extractPromptBlock(next, header);
324
+ if (!extracted) continue;
325
+ next = extracted.remaining;
326
+ preservedBlocks.push(extracted.block);
327
+ changed = true;
328
+ }
329
+
330
+ // Antigravity intermittently stalls on long runtime metadata tails. The
331
+ // connector already enforces permissions and owns dialog context, so trim
332
+ // these blocks before handing the prompt to agy.
333
+ stripBlock(/(?:^|\n)Conversation Reference:\n[\s\S]*?(?=\n{2,}--- Machine permission policy ---|\n{2,}--- User task ---|\n{2,}User task:|$)/);
334
+ stripBlock(/(?:^|\n)--- Machine permission policy ---\n[\s\S]*?(?=\n{2,}--- User task ---|\n{2,}User task:|$)/);
335
+ if (!preservedBlocks.some((block) => block.startsWith("--- Nolo task-run tool bridge ---"))) {
336
+ for (const header of AGY_OPTIONAL_TASKRUN_GUIDANCE_HEADERS) {
337
+ const updated = stripMarkdownSection(next, header);
338
+ if (updated !== next) {
339
+ next = updated;
340
+ changed = true;
341
+ }
342
+ }
343
+ }
344
+
345
+ let normalized = next
346
+ .replace(/\n\n--- User task ---\n/g, "\n\nUser task:\n")
347
+ .replace(/\n{3,}/g, "\n\n")
348
+ .trim();
349
+ if (preservedBlocks.length > 0) {
350
+ const reinjected = preservedBlocks.join("\n\n");
351
+ if (/^User task:\n/.test(normalized)) {
352
+ normalized = `${reinjected}\n\n${normalized}`;
353
+ } else if (/\n\nUser task:\n/.test(normalized)) {
354
+ normalized = normalized.replace(/\n\nUser task:\n/, `\n\n${reinjected}\n\nUser task:\n`);
355
+ } else {
356
+ normalized = `${normalized}\n\n${reinjected}`.trim();
357
+ }
223
358
  }
359
+ if (normalized !== prompt) {
360
+ changed = true;
361
+ }
362
+
363
+ if (!changed) {
364
+ return { prompt, warnings: [] };
365
+ }
366
+
224
367
  return {
225
- prompt: buildCliPrompt(options.systemPrompt, prompt),
226
- options: {
227
- ...options,
228
- systemPrompt: undefined,
229
- },
230
- warnings,
368
+ prompt: normalized,
369
+ warnings: [
370
+ "Antigravity CLI prompt was compacted to avoid known timeout patterns in conversation-reference and machine-permission runtime blocks.",
371
+ ],
231
372
  };
232
373
  }
233
374
 
@@ -416,7 +557,9 @@ function executeCodex(
416
557
  "--cd",
417
558
  cwd,
418
559
  ];
419
- if (model) {
560
+ // Codex CLI accepts --model syntactically, but real desktop/subscription
561
+ // installs can fail with plan-gating errors. Keep default execution stable.
562
+ if (model && shouldPassCodexModel(options)) {
420
563
  args.push("--model");
421
564
  args.push(model);
422
565
  }
@@ -496,8 +639,8 @@ function executeClaude(
496
639
  } = options;
497
640
 
498
641
  return new Promise((resolve, reject) => {
499
- const args = ["-p", prompt];
500
- if (model) {
642
+ const args = ["--add-dir", cwd, "-p", prompt];
643
+ if (model && shouldPassClaudeModel(options)) {
501
644
  args.push("--model");
502
645
  args.push(model);
503
646
  }
@@ -564,9 +707,82 @@ function formatCliTimeout(timeoutMs: number) {
564
707
  return `${Math.max(1, Math.ceil(timeoutMs / 1000))}s`;
565
708
  }
566
709
 
567
- function executeAgy(
710
+ function shortHash(value: string) {
711
+ return createHash("sha256").update(value).digest("hex").slice(0, 12);
712
+ }
713
+
714
+ function resolveAgyDebugDir(env?: Record<string, string | undefined>) {
715
+ const raw = env?.NOLO_AGY_DEBUG_DIR ?? process.env.NOLO_AGY_DEBUG_DIR ?? "";
716
+ return raw.trim();
717
+ }
718
+
719
+ function createAgyDebugArtifact(args: {
720
+ prompt: string;
721
+ attempt: number;
722
+ timeoutMs: number;
723
+ cwd: string;
724
+ env?: Record<string, string | undefined>;
725
+ }): AgyDebugArtifact | null {
726
+ const debugRoot = resolveAgyDebugDir(args.env);
727
+ if (!debugRoot) return null;
728
+
729
+ const promptHash = shortHash(args.prompt);
730
+ const promptBytes = Buffer.byteLength(args.prompt, "utf8");
731
+ const dir = join(debugRoot, `${Date.now()}-agy-${promptHash}-attempt-${args.attempt + 1}`);
732
+ mkdirSync(dir, { recursive: true });
733
+ writeFileSync(join(dir, "prompt.txt"), args.prompt, "utf8");
734
+
735
+ return {
736
+ dir,
737
+ promptHash,
738
+ promptBytes,
739
+ writeResult: (result) => {
740
+ writeFileSync(join(dir, "stdout.txt"), result.stdout, "utf8");
741
+ writeFileSync(join(dir, "stderr.txt"), result.stderr, "utf8");
742
+ writeFileSync(
743
+ join(dir, "meta.json"),
744
+ `${JSON.stringify({
745
+ promptHash,
746
+ promptBytes,
747
+ attempt: args.attempt + 1,
748
+ startedAt: result.startedAt,
749
+ finishedAt: result.finishedAt,
750
+ elapsedMs: result.elapsedMs,
751
+ cwd: result.cwd,
752
+ timeoutMs: result.timeoutMs,
753
+ args: result.args,
754
+ exitCode: result.exitCode,
755
+ outcome: result.outcome,
756
+ errorMessage: result.errorMessage ?? null,
757
+ stdoutBytes: Buffer.byteLength(result.stdout, "utf8"),
758
+ stderrBytes: Buffer.byteLength(result.stderr, "utf8"),
759
+ }, null, 2)}\n`,
760
+ "utf8"
761
+ );
762
+ },
763
+ };
764
+ }
765
+
766
+ function isAgyTimeoutError(error: unknown) {
767
+ return error instanceof Error && /Antigravity CLI timed out after \d+ms/.test(error.message);
768
+ }
769
+
770
+ function resolveAgyTimeoutRetryCount(env?: Record<string, string | undefined>) {
771
+ const raw = env?.NOLO_AGY_TIMEOUT_RETRIES ?? process.env.NOLO_AGY_TIMEOUT_RETRIES ?? "2";
772
+ const parsed = Number.parseInt(raw, 10);
773
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : 2;
774
+ }
775
+
776
+ const AGY_PROCESS_TIMEOUT_BUFFER_MS = 10_000;
777
+
778
+ function isAgyUpstreamTimeoutText(stdout: string) {
779
+ return /^Error:\s+timed out waiting for response\b/i.test(stdout.trim());
780
+ }
781
+
782
+ function executeAgyOnce(
568
783
  prompt: string,
569
- options: CliExecuteOptions
784
+ options: CliExecuteOptions,
785
+ attempt = 0
570
786
  ): Promise<CliExecuteResult> {
571
787
  const {
572
788
  timeout = 120_000,
@@ -576,6 +792,8 @@ function executeAgy(
576
792
 
577
793
  return new Promise((resolve, reject) => {
578
794
  const args = [
795
+ "--add-dir",
796
+ cwd,
579
797
  "--print",
580
798
  prompt,
581
799
  "--print-timeout",
@@ -586,6 +804,14 @@ function executeAgy(
586
804
  }
587
805
 
588
806
  const start = Date.now();
807
+ const startedAt = new Date(start).toISOString();
808
+ const debugArtifact = createAgyDebugArtifact({
809
+ prompt,
810
+ attempt,
811
+ timeoutMs: timeout,
812
+ cwd,
813
+ env: options.env,
814
+ });
589
815
  const proc = spawn("agy", args, {
590
816
  cwd,
591
817
  env: buildCliProcessEnv(options.env),
@@ -594,12 +820,40 @@ function executeAgy(
594
820
  let stdout = "";
595
821
  let stderr = "";
596
822
  let timer: ReturnType<typeof setTimeout> | undefined;
823
+ let timedOut = false;
824
+
825
+ const flushDebug = (result: {
826
+ exitCode: number | null;
827
+ outcome: "succeeded" | "timed_out" | "spawn_error" | "failed";
828
+ errorMessage?: string;
829
+ }) => {
830
+ debugArtifact?.writeResult({
831
+ startedAt,
832
+ finishedAt: new Date().toISOString(),
833
+ elapsedMs: Date.now() - start,
834
+ cwd,
835
+ timeoutMs: timeout,
836
+ args,
837
+ stdout,
838
+ stderr,
839
+ exitCode: result.exitCode,
840
+ outcome: result.outcome,
841
+ ...(result.errorMessage ? { errorMessage: result.errorMessage } : {}),
842
+ });
843
+ };
597
844
 
598
845
  if (timeout > 0) {
599
846
  timer = setTimeout(() => {
847
+ timedOut = true;
600
848
  proc.kill("SIGTERM");
601
- reject(new Error(`Antigravity CLI timed out after ${timeout}ms`));
602
- }, timeout + 1_000);
849
+ const error = new Error(`Antigravity CLI timed out after ${timeout}ms`);
850
+ flushDebug({
851
+ exitCode: null,
852
+ outcome: "timed_out",
853
+ errorMessage: error.message,
854
+ });
855
+ reject(error);
856
+ }, timeout + AGY_PROCESS_TIMEOUT_BUFFER_MS);
603
857
  }
604
858
 
605
859
  proc.stdout.on("data", (data: Buffer) => {
@@ -612,11 +866,32 @@ function executeAgy(
612
866
 
613
867
  proc.on("close", (code) => {
614
868
  if (timer) clearTimeout(timer);
869
+ if (timedOut) return;
615
870
  if (code !== 0 && code !== null) {
616
- reject(new Error(`Antigravity CLI exited with code ${code}\nstderr: ${stderr}`));
871
+ const error = new Error(`Antigravity CLI exited with code ${code}\nstderr: ${stderr}`);
872
+ flushDebug({
873
+ exitCode: code,
874
+ outcome: "failed",
875
+ errorMessage: error.message,
876
+ });
877
+ reject(error);
878
+ return;
879
+ }
880
+ if (isAgyUpstreamTimeoutText(stdout)) {
881
+ const error = new Error(`Antigravity CLI timed out after ${timeout}ms`);
882
+ flushDebug({
883
+ exitCode: code,
884
+ outcome: "timed_out",
885
+ errorMessage: error.message,
886
+ });
887
+ reject(error);
617
888
  return;
618
889
  }
619
890
 
891
+ flushDebug({
892
+ exitCode: code,
893
+ outcome: "succeeded",
894
+ });
620
895
  resolve({
621
896
  text: stdout.trim(),
622
897
  raw: stdout,
@@ -626,11 +901,47 @@ function executeAgy(
626
901
 
627
902
  proc.on("error", (err) => {
628
903
  if (timer) clearTimeout(timer);
904
+ flushDebug({
905
+ exitCode: null,
906
+ outcome: "spawn_error",
907
+ errorMessage: err instanceof Error ? err.message : String(err),
908
+ });
629
909
  reject(err);
630
910
  });
631
911
  });
632
912
  }
633
913
 
914
+ async function executeAgy(
915
+ prompt: string,
916
+ options: CliExecuteOptions
917
+ ): Promise<CliExecuteResult> {
918
+ const maxRetries = resolveAgyTimeoutRetryCount(options.env);
919
+ let attempt = 0;
920
+ let lastError: unknown;
921
+
922
+ while (attempt <= maxRetries) {
923
+ try {
924
+ const result = await executeAgyOnce(prompt, options, attempt);
925
+ if (attempt === 0) return result;
926
+ return {
927
+ ...result,
928
+ warnings: [
929
+ ...(result.warnings ?? []),
930
+ `Antigravity CLI succeeded after ${attempt} timeout retr${attempt === 1 ? "y" : "ies"}.`,
931
+ ],
932
+ };
933
+ } catch (error) {
934
+ lastError = error;
935
+ if (!isAgyTimeoutError(error) || attempt >= maxRetries) {
936
+ throw error;
937
+ }
938
+ attempt += 1;
939
+ }
940
+ }
941
+
942
+ throw lastError instanceof Error ? lastError : new Error(String(lastError));
943
+ }
944
+
634
945
  // ── 注册表(新增 CLI 工具时在这里加) ────────────────────────────────────────
635
946
 
636
947
  const EXECUTORS: Record<
@@ -35,6 +35,17 @@ const referenceItemSchema = z
35
35
  type: data.type === "page" ? "knowledge" : data.type,
36
36
  }));
37
37
 
38
+ const isLocalProviderUrl = (value?: string | null) => {
39
+ const normalized = typeof value === "string" ? value.trim() : "";
40
+ if (!normalized) return false;
41
+ try {
42
+ const hostname = new URL(normalized).hostname.toLowerCase();
43
+ return hostname === "127.0.0.1" || hostname === "localhost" || hostname === "::1";
44
+ } catch {
45
+ return false;
46
+ }
47
+ };
48
+
38
49
  // --- 核心 schema ---
39
50
  export const getCreateAgentSchema = (t: TFunction) =>
40
51
  z
@@ -222,6 +233,17 @@ export const getCreateAgentSchema = (t: TFunction) =>
222
233
  message: t("validation.modelRequired"),
223
234
  path: ["model"],
224
235
  }
236
+ )
237
+ .refine(
238
+ (data) => {
239
+ if (!data.machineId?.trim()) return true;
240
+ if (data.apiSource === "cli") return true;
241
+ return data.apiSource === "custom" && isLocalProviderUrl(data.customProviderUrl);
242
+ },
243
+ {
244
+ message: t("validation.machineBindingRequiresCliOrLocalCustom"),
245
+ path: ["machineId"],
246
+ }
225
247
  );
226
248
 
227
249
  export type FormData = z.infer<ReturnType<typeof getCreateAgentSchema>>;
@@ -2,27 +2,18 @@ import { getDb } from "../../../database/client/db";
2
2
  import { pino } from "pino";
3
3
  import { pubAgentKeys } from "../../../database/keys";
4
4
  import { Agent } from "../../../app/types";
5
- import { supportsImageGeneration } from "../../agent/utils/imageOutput";
6
5
  import { getRecordTimestamp, isTombstoneRecord } from "../../../database/tombstones";
6
+ import {
7
+ filterPublicAgentRecords,
8
+ preparePublicAgentCatalogRecords,
9
+ type PublicAgentFilterOptions,
10
+ type PublicAgentListOptions,
11
+ } from "../../agent/publicAgentCatalog";
7
12
  import { buildSortMeta, sortAgents } from "../../agent/utils/sortUtils";
8
13
 
9
14
  const logger = pino({ name: "fetchPublicAgents" });
10
15
 
11
- interface FetchPublicAgentsOptions {
12
- limit?: number;
13
- sortBy?:
14
- | "recommended"
15
- | "newest"
16
- | "popular"
17
- | "rating"
18
- | "outputPriceAsc"
19
- | "outputPriceDesc"
20
- | "favorite";
21
- searchName?: string;
22
- userId?: string;
23
- imageOutputOnly?: boolean;
24
- toolName?: string;
25
- }
16
+ interface FetchPublicAgentsOptions extends PublicAgentFilterOptions, PublicAgentListOptions {}
26
17
 
27
18
  interface PublicAgentTombstone {
28
19
  id?: string;
@@ -57,7 +48,7 @@ export async function fetchPublicAgents(
57
48
  let tombstones: PublicAgentTombstone[] = [];
58
49
 
59
50
  const db = getDb();
60
- if (!db) return { data: [], total: 0, hasMore: false };
51
+ if (!db) return { data: [], total: 0, hasMore: false, tombstones: [] };
61
52
 
62
53
  for (const { start, end } of ranges) {
63
54
  const iterator = await db.iterator({
@@ -73,28 +64,12 @@ export async function fetchPublicAgents(
73
64
  results.push(value as Agent);
74
65
  }
75
66
  }
76
-
77
- if (searchName) {
78
- const kw = searchName.toLowerCase();
79
- results = results.filter((agent) =>
80
- agent.name?.toLowerCase().includes(kw)
81
- );
82
- }
83
-
84
- if (userId) {
85
- results = results.filter((agent) => agent.userId === userId);
86
- }
87
-
88
- if (imageOutputOnly) {
89
- results = results.filter((agent) => supportsImageGeneration(agent));
90
- }
91
-
92
- if (toolName) {
93
- const kw = toolName.toLowerCase();
94
- results = results.filter((agent) =>
95
- agent.tools?.some((t) => t.toLowerCase().includes(kw))
96
- );
97
- }
67
+ results = filterPublicAgentRecords(preparePublicAgentCatalogRecords(results), {
68
+ searchName,
69
+ userId,
70
+ imageOutputOnly,
71
+ toolName,
72
+ });
98
73
 
99
74
  results = sortAgents(
100
75
  results.map((agent) => ({