nolo-cli 0.1.29 → 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 (329) 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/agentCreateCustomCommands.ts +9 -4
  13. package/agentDialogsCommands.ts +4 -3
  14. package/agentDoctorCommands.ts +3 -3
  15. package/agentListCommands.ts +3 -3
  16. package/agentMachineCommands.ts +6 -6
  17. package/agentPullCommand.ts +4 -12
  18. package/agentRecordCommands.ts +5 -3
  19. package/agentRecordHelpers.ts +42 -23
  20. package/agentRunCommand.ts +2 -6
  21. package/agentRunParsing.ts +18 -5
  22. package/agentRuntimeLocal.ts +10 -0
  23. package/agentUnpublishCommands.ts +3 -2
  24. package/ai/agent/agentRunDialogLineage.ts +56 -0
  25. package/ai/agent/agentSlice.ts +45 -10
  26. package/ai/agent/avatarUtils.ts +1 -1
  27. package/ai/agent/buildSystemPrompt.ts +1 -2
  28. package/ai/agent/cliExecutor.ts +330 -19
  29. package/ai/agent/createAgentSchema.ts +22 -0
  30. package/ai/agent/hooks/fetchPublicAgents.ts +14 -39
  31. package/ai/agent/hooks/usePublicAgents.ts +90 -192
  32. package/ai/agent/publicAgentCatalog.ts +359 -0
  33. package/ai/agent/publicAgentIdentity.ts +76 -0
  34. package/ai/agent/server/fetchPublicAgents.ts +21 -46
  35. package/ai/agent/serverOrigin.ts +7 -0
  36. package/ai/agent/streamAgentChatTurn.ts +23 -21
  37. package/ai/agent/streamAgentChatTurnUtils.ts +292 -6
  38. package/ai/agent/types.ts +2 -0
  39. package/ai/agent/web/agentDisplayUtils.ts +171 -0
  40. package/ai/agent/web/useAgentModelAvatarComponent.ts +32 -0
  41. package/ai/ai.locale.ts +8 -0
  42. package/ai/chat/sendOpenAICompletionsRequest.native.ts +15 -0
  43. package/ai/chat/sendOpenAICompletionsRequest.ts +93 -1
  44. package/ai/chat/sendOpenAIResponseRequest.ts +86 -9
  45. package/ai/chat/updateTotalUsage.ts +7 -0
  46. package/ai/llm/deepinfra.ts +30 -15
  47. package/ai/llm/mistral.ts +3 -4
  48. package/ai/llm/providers.ts +2 -0
  49. package/ai/llm/types.ts +15 -0
  50. package/ai/memory/capture.ts +3 -3
  51. package/ai/memory/consolidate.ts +2 -2
  52. package/ai/memory/delete.ts +4 -3
  53. package/ai/memory/query.ts +3 -3
  54. package/ai/memory/remember.ts +2 -2
  55. package/ai/memory/store.ts +3 -3
  56. package/ai/memory/storeShared.ts +3 -2
  57. package/ai/policy/commercialMultiplier.ts +16 -0
  58. package/ai/token/billingAdminAuditEvent.ts +68 -0
  59. package/ai/token/billingAdminAuditEventWriter.ts +41 -0
  60. package/ai/token/billingAnomaly.ts +90 -0
  61. package/ai/token/billingAnomalyLifecycle.ts +54 -0
  62. package/ai/token/billingAnomalyLifecycleWriter.ts +44 -0
  63. package/ai/token/billingAnomalyWriter.ts +41 -0
  64. package/ai/token/calculatePrice.ts +3 -2
  65. package/ai/token/deepinfraReconciliation.ts +153 -0
  66. package/ai/token/deepinfraRequestIdQuery.ts +92 -0
  67. package/ai/token/externalToolCost.ts +54 -41
  68. package/ai/token/missingUsageEstimate.ts +12 -3
  69. package/ai/token/normalizeUsage.ts +45 -5
  70. package/ai/token/openaiReconciliation.ts +188 -0
  71. package/ai/token/providerBillableEvent.ts +84 -0
  72. package/ai/token/providerBillableEventWriter.ts +36 -0
  73. package/ai/token/providerBillingAnomalyDrilldown.ts +308 -0
  74. package/ai/token/providerBillingDrilldown.ts +361 -0
  75. package/ai/token/providerBillingHealthReport.ts +366 -0
  76. package/ai/token/providerCall.ts +144 -0
  77. package/ai/token/providerCallSweeper.ts +168 -0
  78. package/ai/token/providerCallWriter.ts +33 -0
  79. package/ai/token/providerCredential.ts +89 -0
  80. package/ai/token/providerCredentialAnomaly.ts +154 -0
  81. package/ai/token/providerCredentialLifecycle.ts +59 -0
  82. package/ai/token/providerCredentialLifecycleWriter.ts +44 -0
  83. package/ai/token/providerCredentialRegistry.ts +83 -0
  84. package/ai/token/providerCredentialRegistryCommand.ts +97 -0
  85. package/ai/token/providerCredentialRegistryList.ts +124 -0
  86. package/ai/token/providerCredentialRegistryResolver.ts +150 -0
  87. package/ai/token/providerCredentialRegistryWriter.ts +41 -0
  88. package/ai/token/providerCredentialRotationCommand.ts +102 -0
  89. package/ai/token/providerCredentialRuntime.ts +56 -0
  90. package/ai/token/providerDispatchIntent.ts +67 -0
  91. package/ai/token/providerDispatchIntentWriter.ts +36 -0
  92. package/ai/token/providerGateway.ts +260 -0
  93. package/ai/token/providerReconciliation.ts +148 -0
  94. package/ai/token/providerReconciliationLocal.ts +97 -0
  95. package/ai/token/providerReconciliationRunner.ts +165 -0
  96. package/ai/token/providerReconciliationWriter.ts +41 -0
  97. package/ai/token/ratingResult.ts +202 -0
  98. package/ai/token/ratingResultWriter.ts +33 -0
  99. package/ai/token/serverDialogProjection.ts +5 -3
  100. package/ai/token/serverTokenWriter.ts +11 -3
  101. package/ai/token/types.ts +10 -0
  102. package/ai/tools/agent/callAgentTool.ts +3 -4
  103. package/ai/tools/agent/presets/appBuilderPreset.ts +5 -7
  104. package/ai/tools/agent/runStreamingAgentTool.ts +1 -2
  105. package/ai/tools/agent/streamParallelAgentsTool.ts +2 -3
  106. package/ai/tools/readXPostTool.ts +1 -5
  107. package/app/admin/adminPages.ts +9 -0
  108. package/app/i18n/i18n.config.ts +5 -0
  109. package/app/i18n/translations/pricing.locale.ts +397 -0
  110. package/app/utils/desktopAgentRuntimeStatusClient.ts +5 -4
  111. package/app/utils/desktopAgentRuntimeTurnClient.ts +4 -1
  112. package/app/utils/imageUtils.ts +64 -34
  113. package/auth/adminPermissions.ts +18 -0
  114. package/auth/authSlice.ts +26 -12
  115. package/auth/hooks/useFetchUsers.ts +3 -0
  116. package/auth/routes.ts +46 -0
  117. package/auth/server/accessActivity.ts +4 -3
  118. package/auth/server/adminPermissions.ts +43 -0
  119. package/auth/server/adminUsageReport.ts +375 -0
  120. package/auth/server/billingAnomalies.ts +235 -0
  121. package/auth/server/billingUsageReport.ts +41 -2
  122. package/auth/server/creatorEarningCreditConversion.ts +10 -2
  123. package/auth/server/deduct.ts +14 -7
  124. package/auth/server/delete.ts +10 -2
  125. package/auth/server/disable.ts +4 -3
  126. package/auth/server/emailAutomation.ts +7 -5
  127. package/auth/server/emailDbConfig.ts +4 -2
  128. package/auth/server/emailDelivery.ts +24 -20
  129. package/auth/server/emailDeliveryGuards.ts +10 -7
  130. package/auth/server/emailPreferences.ts +6 -4
  131. package/auth/server/emailReport.ts +6 -4
  132. package/auth/server/emailRuntimeConfig.ts +3 -3
  133. package/auth/server/emailScenarioNotifications.ts +9 -8
  134. package/auth/server/enable.ts +4 -3
  135. package/auth/server/getRechargeHistory.ts +3 -2
  136. package/auth/server/getUser.ts +3 -2
  137. package/auth/server/gptProAccess.ts +44 -0
  138. package/auth/server/inviteReward.ts +10 -7
  139. package/auth/server/listusers.ts +6 -4
  140. package/auth/server/login.ts +2 -2
  141. package/auth/server/productEntitlements.ts +7 -4
  142. package/auth/server/productPurchase.ts +10 -2
  143. package/auth/server/providerBillingDrilldown.ts +47 -0
  144. package/auth/server/providerBillingHealth.ts +71 -0
  145. package/auth/server/providerCredentials.ts +136 -0
  146. package/auth/server/recharge.ts +14 -8
  147. package/auth/server/revokeSessions.ts +4 -3
  148. package/auth/server/route.ts +77 -0
  149. package/auth/server/sendEmail.ts +5 -4
  150. package/auth/server/signup.ts +10 -3
  151. package/auth/server/token.ts +53 -55
  152. package/auth/server/tokenUsageBilling.ts +18 -7
  153. package/auth/server/usageManagementAccess.ts +43 -0
  154. package/auth/server/usageReport.ts +59 -0
  155. package/auth/types.ts +12 -0
  156. package/auth/utils.ts +24 -22
  157. package/authCommands.ts +36 -2
  158. package/buildPublish.ts +3 -1
  159. package/buildPublishArtifactAssembly.ts +62 -1
  160. package/buildPublishImportAnalysis.ts +21 -16
  161. package/chat/dialog/dialogLaunchScope.ts +32 -0
  162. package/chat/dialog/objectAssistantRegistry.ts +2 -2
  163. package/chat/dialog/useCreateDialog.ts +1 -1
  164. package/chat/hooks/useChatInput.ts +41 -10
  165. package/chat/messages/messageSlice.ts +5 -1
  166. package/chat/messages/pendingAttachmentParts.ts +28 -2
  167. package/chat/messages/sendFirstMessage.ts +76 -79
  168. package/chat/messages/types.ts +9 -0
  169. package/chat/messages/web/streamingMarkdownModel.ts +41 -0
  170. package/chat/messages/web/useStreamingReveal.ts +91 -0
  171. package/chat/web/messageInputAgentUi.ts +94 -6
  172. package/cliEnvHelpers.ts +68 -13
  173. package/cliRuntimeDoctorReport.ts +193 -0
  174. package/client/agentConfigResolver.test.ts +0 -2
  175. package/client/agentRun.test.ts +171 -10
  176. package/client/agentRun.ts +44 -637
  177. package/client/agentRunInput.ts +10 -0
  178. package/client/agentRunLocalExecutor.ts +179 -0
  179. package/client/agentRunServerTransport.ts +394 -0
  180. package/client/agentRunTaskRunRecorder.ts +176 -0
  181. package/client/localRuntimeAdapter.test.ts +236 -9
  182. package/client/localRuntimeAdapter.ts +221 -23
  183. package/client/localToolPolicy.test.ts +28 -4
  184. package/connector-experimental/daemonLauncher.ts +38 -4
  185. package/connectorRunArtifact.ts +34 -10
  186. package/connectorWebSocketTarget.ts +40 -15
  187. package/core/builtinAgents.ts +155 -11
  188. package/create/space/contentLabels.ts +1 -1
  189. package/create/space/contentTypeMeta.ts +3 -2
  190. package/create/space/sidebarVisibleTypes.ts +27 -0
  191. package/create/space/space.locale.ts +76 -4
  192. package/database/actions/agentReadResolution.ts +2 -8
  193. package/database/actions/read.ts +11 -9
  194. package/database/actions/readAndWait.ts +10 -5
  195. package/database/server/agentDelegation.ts +3 -2
  196. package/database/server/authorityStoreConformance.ts +209 -0
  197. package/database/server/authorityStoreTypes.ts +31 -0
  198. package/database/server/coreDataProxy.ts +1 -1
  199. package/database/server/dataHandlers.ts +13 -5
  200. package/database/server/db.ts +15 -34
  201. package/database/server/delete.ts +88 -71
  202. package/database/server/emailRepository.ts +11 -9
  203. package/database/server/fileService.ts +2 -1
  204. package/database/server/legacyServerDb.ts +58 -0
  205. package/database/server/levelAuthorityStore.ts +75 -0
  206. package/database/server/memoryAuthorityStore.ts +133 -0
  207. package/database/server/patch.ts +13 -12
  208. package/database/server/query.ts +3 -2
  209. package/database/server/read.ts +33 -30
  210. package/database/server/resourceAccess.ts +7 -5
  211. package/database/server/serverStoreFactory.ts +124 -0
  212. package/database/server/spaceMemberAuthority.ts +3 -2
  213. package/database/server/storeBatchCompat.ts +37 -0
  214. package/database/server/testAuthorityStore.ts +76 -0
  215. package/database/server/write.ts +29 -27
  216. package/dialogReadCommands.ts +2 -1
  217. package/dialogStatusCommands.ts +2 -1
  218. package/integrations/anthropic/anthropicModels.ts +12 -12
  219. package/integrations/deepseek/models.ts +67 -67
  220. package/integrations/google/models.ts +111 -53
  221. package/integrations/openai/models.ts +22 -22
  222. package/integrations/xai/models.ts +1 -1
  223. package/localRuntimeDb.ts +39 -2
  224. package/machineCommandPrompts.ts +2 -0
  225. package/machineCommands.ts +193 -62
  226. package/machineStatusCommands.ts +4 -12
  227. package/machineWsRunDispatch.ts +80 -15
  228. package/machineWsSession.ts +46 -2
  229. package/noloReadBridgePrompt.ts +16 -0
  230. package/package.json +114 -21
  231. package/pageCreateCommands.ts +2 -2
  232. package/pageDeleteCommands.ts +3 -3
  233. package/pageReadCommands.ts +3 -3
  234. package/pageUpdateCommands.ts +3 -3
  235. package/render/layout/mainLayoutViewMode.ts +25 -0
  236. package/render/page/server/createPage.ts +3 -1
  237. package/render/page/server/handleCreatePage.ts +2 -11
  238. package/runtimeDoctorCommands.ts +18 -69
  239. package/server/api/methods.ts +34 -12
  240. package/server/api/tableHandlers.ts +6 -3
  241. package/server/authenticateToken.ts +47 -2
  242. package/server/billingLedgerRoutes.ts +15 -0
  243. package/server/buildManifest.ts +54 -0
  244. package/server/coreReadiness.ts +34 -25
  245. package/server/coreRuntime.ts +15 -10
  246. package/server/handlers/activityStatsHandler.ts +5 -2
  247. package/server/handlers/agentEmailRegistrationE2EHandler.ts +25 -23
  248. package/server/handlers/agentRun/agentLookup.ts +1 -7
  249. package/server/handlers/agentRun/autonomousRuntime.ts +11 -10
  250. package/server/handlers/agentRun/builtinAgents.ts +12 -88
  251. package/server/handlers/agentRun/continueDialogContext.ts +15 -3
  252. package/server/handlers/agentRun/{inheritedDialogPrompt.ts → conversationReference.ts} +3 -3
  253. package/server/handlers/agentRun/dialogLookup.ts +4 -3
  254. package/server/handlers/agentRun/index.ts +864 -404
  255. package/server/handlers/agentRun/localRuntimeBootstrap.ts +17 -1
  256. package/server/handlers/agentRun/loop.ts +920 -508
  257. package/server/handlers/agentRun/machineConnector.ts +56 -8
  258. package/server/handlers/agentRun/machineRunAudit.ts +3 -2
  259. package/server/handlers/agentRun/modelUsageToolHandlers.ts +13 -10
  260. package/server/handlers/agentRun/requestContext.ts +12 -8
  261. package/server/handlers/agentRun/runtimeExecutionContext.ts +15 -3
  262. package/server/handlers/agentRun/runtimePreparation.ts +26 -24
  263. package/server/handlers/agentRun/runtimeRouting.ts +25 -40
  264. package/server/handlers/agentRun/runtimeSystemMessages.ts +65 -0
  265. package/server/handlers/agentRun/saveDialog.ts +97 -87
  266. package/server/handlers/agentRun/taskRunToolHandler.ts +9 -7
  267. package/server/handlers/agentRun/toolExecutor.ts +42 -78
  268. package/server/handlers/agentRun/types.ts +2 -1
  269. package/server/handlers/appDeployStatusStore.ts +17 -10
  270. package/server/handlers/appDomainHandler.ts +21 -15
  271. package/server/handlers/appLegacyInfraCleanup.ts +5 -2
  272. package/server/handlers/appSandboxHandler.ts +29 -8
  273. package/server/handlers/appSpaceAccess.ts +15 -8
  274. package/server/handlers/chatHandler.ts +22 -2
  275. package/server/handlers/chatUpstreamRetry.ts +225 -2
  276. package/server/handlers/connector/connectorConnectionRegistry.ts +55 -7
  277. package/server/handlers/connector/connectorWebSocket.ts +14 -10
  278. package/server/handlers/desktopAgentRuntimeAdapter.ts +4 -4
  279. package/server/handlers/desktopAgentRuntimeHostCapabilities.ts +25 -0
  280. package/server/handlers/desktopAgentRuntimeReadiness.ts +62 -0
  281. package/server/handlers/desktopAgentRuntimeStatusHandler.ts +38 -30
  282. package/server/handlers/desktopAgentRuntimeTurnHandler.ts +7 -3
  283. package/server/handlers/desktopAgentRuntimeTurnService.ts +39 -45
  284. package/server/handlers/desktopLlamaRuntimeHandler.ts +85 -51
  285. package/server/handlers/desktopUpdaterHandler.ts +132 -24
  286. package/server/handlers/favoriteHandlers.ts +8 -2
  287. package/server/handlers/getDialogBillingHandler.ts +4 -3
  288. package/server/handlers/getTransactionsHandler.ts +5 -2
  289. package/server/handlers/machines/machineBinding.ts +1 -0
  290. package/server/handlers/machines/machineHandlers.ts +0 -14
  291. package/server/handlers/machines/machineInstallAssets.ts +4 -2
  292. package/server/handlers/notificationEmitter.ts +5 -3
  293. package/server/handlers/notificationsHandler.ts +5 -2
  294. package/server/handlers/providerCallsRecentHandler.ts +234 -0
  295. package/server/handlers/providerReconciliationRunHandler.ts +180 -0
  296. package/server/handlers/providerRequestIdsHandler.ts +105 -0
  297. package/server/handlers/tableAccess.ts +6 -2
  298. package/server/handlers/tableToolHandlers.ts +28 -14
  299. package/server/handlers/userSecretsHandler.ts +17 -6
  300. package/server/handlers/versionHandler.ts +9 -4
  301. package/server/handlers/versionStore.ts +18 -10
  302. package/server/html/ssrPreload.ts +5 -3
  303. package/server/payments/crypto/cryptoUsdcBasePaymentProvider.ts +11 -8
  304. package/server/payments/crypto/cryptoUsdcBaseScanner.ts +12 -7
  305. package/server/payments/crypto/cryptoUsdtTronPaymentProvider.ts +11 -8
  306. package/server/payments/crypto/cryptoUsdtTronScanner.ts +9 -7
  307. package/server/payments/waffo/waffoPaymentProvider.ts +12 -9
  308. package/server/runtimeRole.ts +15 -0
  309. package/server/scheduler/scheduledTaskRuntime.ts +4 -2
  310. package/server/scheduler/schedulerService.ts +2 -2
  311. package/server/taskRunBridgeRoutes.ts +8 -5
  312. package/share/server/fetchCommunityShares.ts +1 -1
  313. package/share/server/helpers.ts +19 -17
  314. package/share/server/importShare.ts +9 -13
  315. package/share/server/listCommunityShares.ts +4 -4
  316. package/share/server/purchaseDoc.ts +8 -16
  317. package/share/server/readCommunityShareCover.ts +3 -2
  318. package/share/server/readSharedTable.ts +14 -13
  319. package/share/server/tableReplication.ts +42 -39
  320. package/spaceAttachCommands.ts +135 -0
  321. package/spaceCategoryCommands.ts +6 -6
  322. package/spaceCommands.ts +3 -3
  323. package/spaceDeleteCommands.ts +2 -2
  324. package/spaceInternalCommandEntries.ts +2 -0
  325. package/spaceReadCommands.ts +3 -3
  326. package/tableMetaCommands.ts +2 -2
  327. package/taskRunCommand.ts +11 -0
  328. package/ai/agent/runtimeServerBase.ts +0 -37
  329. package/server/handlers/desktopAgentRuntimeHostFacts.ts +0 -40
@@ -5,6 +5,7 @@ import type {
5
5
  AgentRuntimeToolCallInput,
6
6
  AgentRuntimeToolResult,
7
7
  } from "./types";
8
+ import type { HostRuntimeConfig } from "./hostRuntimeConfig";
8
9
 
9
10
  type LocalWorkspaceToolArgs = {
10
11
  workspaceRoot: string;
@@ -18,9 +19,13 @@ type WorkspaceFileArgs = {
18
19
  oldText?: unknown;
19
20
  newText?: unknown;
20
21
  expectedReplacements?: unknown;
22
+ edits?: unknown;
23
+ offset?: unknown;
24
+ limit?: unknown;
21
25
  query?: unknown;
22
26
  command?: unknown;
23
27
  cmd?: unknown;
28
+ timeout?: unknown;
24
29
  patch?: unknown;
25
30
  script?: unknown;
26
31
  args?: unknown;
@@ -74,6 +79,13 @@ const DEFAULT_LOCAL_CODING_TOOL_NAMES = [
74
79
  "searchFiles",
75
80
  ] as const;
76
81
 
82
+ const DEFAULT_LOCAL_CODING_TOOL_NAMES_WITH_SHELL = [
83
+ "readFile",
84
+ "writeFile",
85
+ "editFile",
86
+ "execShell",
87
+ ] as const;
88
+
77
89
  const SHELL_TOOL_NAMES = ["execShell"] as const;
78
90
  const WORKSPACE_TOOL_NAME_SET = new Set<string>(WORKSPACE_TOOL_NAMES);
79
91
  const REMOVED_WORKSPACE_TOOL_NAMES = new Set([
@@ -115,11 +127,19 @@ function buildReadWorkspaceFileTool(): OpenAiCompatibleTool {
115
127
  function: {
116
128
  name: "readWorkspaceFile",
117
129
  description:
118
- "Read a UTF-8 text file inside the workspace. Read before editing when you need the current content or exact text for replaceWorkspaceText; skip unnecessary reads for trivial known writes.",
130
+ "Read a UTF-8 text file inside the workspace. Read before editing when you need the current content or exact text for replaceWorkspaceText; skip unnecessary reads for trivial known writes. Use offset and limit to page large files by line range.",
119
131
  parameters: {
120
132
  type: "object",
121
133
  properties: {
122
134
  path: buildWorkspacePathProperty(),
135
+ offset: {
136
+ type: "integer",
137
+ description: "Optional zero-based starting line offset.",
138
+ },
139
+ limit: {
140
+ type: "integer",
141
+ description: "Optional maximum number of lines to return.",
142
+ },
123
143
  },
124
144
  required: ["path"],
125
145
  },
@@ -172,8 +192,26 @@ function buildReplaceWorkspaceTextTool(): OpenAiCompatibleTool {
172
192
  type: "integer",
173
193
  description: "Expected replacement count. Defaults to 1.",
174
194
  },
195
+ edits: {
196
+ type: "array",
197
+ description: "Optional batch exact-text replacements applied against the original file snapshot.",
198
+ items: {
199
+ type: "object",
200
+ properties: {
201
+ oldText: {
202
+ type: "string",
203
+ description: "Exact text currently present in the file.",
204
+ },
205
+ newText: {
206
+ type: "string",
207
+ description: "Replacement text to write in place of oldText.",
208
+ },
209
+ },
210
+ required: ["oldText", "newText"],
211
+ },
212
+ },
175
213
  },
176
- required: ["path", "oldText", "newText"],
214
+ required: ["path"],
177
215
  },
178
216
  },
179
217
  };
@@ -316,7 +354,7 @@ function buildExecShellTool(toolName: string): OpenAiCompatibleTool {
316
354
  function: {
317
355
  name: toolName,
318
356
  description:
319
- "Run a shell command in the local workspace. Commands already execute from the workspace root; do not cd into guessed paths such as /workspace, /repo, /home/user, or /home/user/workspace. Prefer one command that performs a complete verification or related git operation instead of many tiny commands. For branch setup, prefer idempotent commands such as git switch -C <branch> when replacing or recreating a benchmark branch is acceptable. Use portable POSIX commands for macOS/BSD shells; avoid GNU-only flags such as cat -A. Do not use cat -A. Do not use brittle byte-offset commands such as xxd -s -32. For separator lines, use echo or printf '%s\\n'. For text-file content or trailing-newline checks, prefer readFile over shell byte inspection when that tool is available. Do not run repeated git status, git log, git rev-parse, or branch checks after a successful command already returned the needed clean status and commit information; use one final verification command. If a command fails, use the error output to adjust the next command rather than repeating the same shape.",
357
+ "Run a shell command in the local workspace. Use execShell for ls, rg/grep, find, and git inspection when shell is available. Commands already execute from the workspace root; do not cd into guessed paths such as /workspace, /repo, /home/user, or /home/user/workspace. Prefer one command that performs a complete verification or related git operation instead of many tiny commands. For branch setup, prefer idempotent commands such as git switch -C <branch> when replacing or recreating a benchmark branch is acceptable. Use portable POSIX commands for macOS/BSD shells; avoid GNU-only flags such as cat -A. Do not use cat -A. Do not use brittle byte-offset commands such as xxd -s -32. For separator lines, use echo or printf '%s\\n'. For text-file content or trailing-newline checks, prefer readFile over shell byte inspection when that tool is available. Do not run repeated git status, git log, git rev-parse, or branch checks after a successful command already returned the needed clean status and commit information; use one final verification command. If a command fails, use the error output to adjust the next command rather than repeating the same shape. When output is truncated, the tool returns a workspace temp path for the full output.",
320
358
  parameters: {
321
359
  type: "object",
322
360
  properties: {
@@ -328,6 +366,10 @@ function buildExecShellTool(toolName: string): OpenAiCompatibleTool {
328
366
  type: "string",
329
367
  description: "Shell command to run.",
330
368
  },
369
+ timeout: {
370
+ type: "integer",
371
+ description: "Optional timeout in milliseconds. The runtime clamps values above its configured maximum.",
372
+ },
331
373
  },
332
374
  },
333
375
  },
@@ -452,18 +494,28 @@ function filterDeclaredWorkspaceToolNames(args: {
452
494
  return (args.toolNames ?? []).filter((toolName) =>
453
495
  WORKSPACE_TOOL_NAME_SET.has(toolName) &&
454
496
  !REMOVED_WORKSPACE_TOOL_NAMES.has(toolName) &&
455
- (args.exposeShellTools || !SHELL_TOOL_NAMES.includes(toolName as any))
497
+ (args.exposeShellTools || !SHELL_TOOL_NAMES.includes(toolName as any))
456
498
  );
457
499
  }
458
500
 
501
+ export function resolveLocalWorkspaceShellToolExposure(args: {
502
+ declaredToolNames?: string[];
503
+ hostRuntimeConfig?: Pick<HostRuntimeConfig, "capabilities">;
504
+ }) {
505
+ return args.hostRuntimeConfig?.capabilities.allowShell === true &&
506
+ (args.declaredToolNames ?? []).includes("execShell");
507
+ }
508
+
459
509
  export function buildLocalWorkspaceToolset(args: {
460
510
  declaredToolNames?: string[];
461
511
  exposeShellTools?: boolean;
462
512
  }) {
463
513
  const exposeShellTools = args.exposeShellTools === true;
514
+ const defaultToolNames = exposeShellTools
515
+ ? DEFAULT_LOCAL_CODING_TOOL_NAMES_WITH_SHELL
516
+ : DEFAULT_LOCAL_CODING_TOOL_NAMES;
464
517
  const toolNames = removeRedundantWorkspaceToolAliases(new Set([
465
- ...DEFAULT_LOCAL_CODING_TOOL_NAMES,
466
- ...(exposeShellTools ? SHELL_TOOL_NAMES : []),
518
+ ...defaultToolNames,
467
519
  ...filterDeclaredWorkspaceToolNames({
468
520
  toolNames: args.declaredToolNames,
469
521
  exposeShellTools,
@@ -538,6 +590,31 @@ function requireWorkspaceToolPath(args: WorkspaceFileArgs) {
538
590
  return requestedPath;
539
591
  }
540
592
 
593
+ function readOptionalNonNegativeIntegerArg(value: unknown, label: string) {
594
+ if (value === undefined) return undefined;
595
+ const number = Number(value);
596
+ if (!Number.isInteger(number) || number < 0) {
597
+ throw new Error(`${label} must be a non-negative integer.`);
598
+ }
599
+ return number;
600
+ }
601
+
602
+ function readOptionalPositiveIntegerArg(value: unknown, label: string) {
603
+ if (value === undefined) return undefined;
604
+ const number = Number(value);
605
+ if (!Number.isInteger(number) || number < 1) {
606
+ throw new Error(`${label} must be a positive integer.`);
607
+ }
608
+ return number;
609
+ }
610
+
611
+ function readWorkspaceReadWindow(args: WorkspaceFileArgs) {
612
+ return {
613
+ offset: readOptionalNonNegativeIntegerArg(args.offset, "readWorkspaceFile offset") ?? 0,
614
+ limit: readOptionalPositiveIntegerArg(args.limit, "readWorkspaceFile limit"),
615
+ };
616
+ }
617
+
541
618
  function requireWorkspaceFileContent(args: WorkspaceFileArgs) {
542
619
  if (typeof args.content !== "string") {
543
620
  throw new Error("writeWorkspaceFile requires string content.");
@@ -559,6 +636,37 @@ function requireWorkspaceNewText(args: WorkspaceFileArgs) {
559
636
  return args.newText;
560
637
  }
561
638
 
639
+ type WorkspaceStructuredEdit = {
640
+ oldText: string;
641
+ newText: string;
642
+ };
643
+
644
+ function readWorkspaceStructuredEdits(args: WorkspaceFileArgs) {
645
+ if (args.edits === undefined) return null;
646
+ if (!Array.isArray(args.edits) || args.edits.length === 0) {
647
+ throw new Error("editFile edits must be a non-empty array.");
648
+ }
649
+ return args.edits.map((entry, index) => {
650
+ if (!entry || typeof entry !== "object") {
651
+ throw new Error(`editFile edits[${index}] must be an object.`);
652
+ }
653
+ const oldText = typeof (entry as Record<string, unknown>).oldText === "string"
654
+ ? ((entry as Record<string, unknown>).oldText as string)
655
+ : "";
656
+ if (!oldText) {
657
+ throw new Error(`editFile edits[${index}] oldText must be a non-empty string.`);
658
+ }
659
+ const newTextValue = (entry as Record<string, unknown>).newText;
660
+ if (typeof newTextValue !== "string") {
661
+ throw new Error(`editFile edits[${index}] newText must be a string.`);
662
+ }
663
+ return {
664
+ oldText,
665
+ newText: newTextValue,
666
+ };
667
+ });
668
+ }
669
+
562
670
  function readExpectedReplacementCount(args: WorkspaceFileArgs) {
563
671
  if (args.expectedReplacements === undefined) return 1;
564
672
  const value = Number(args.expectedReplacements);
@@ -579,6 +687,79 @@ function pluralizeReplacement(count: number) {
579
687
  return count === 1 ? "replacement" : "replacements";
580
688
  }
581
689
 
690
+ function findUniqueEditRange(args: {
691
+ content: string;
692
+ oldText: string;
693
+ requestedPath: string;
694
+ index: number;
695
+ }) {
696
+ const start = args.content.indexOf(args.oldText);
697
+ if (start < 0) {
698
+ throw new Error(`editFile edits[${args.index}] oldText was not found in ${args.requestedPath}.`);
699
+ }
700
+ if (args.content.indexOf(args.oldText, start + 1) >= 0) {
701
+ throw new Error(
702
+ `editFile edits[${args.index}] oldText must match exactly once in ${args.requestedPath}.`
703
+ );
704
+ }
705
+ return {
706
+ start,
707
+ end: start + args.oldText.length,
708
+ };
709
+ }
710
+
711
+ function countLineNumberAtOffset(args: {
712
+ content: string;
713
+ offset: number;
714
+ }) {
715
+ let lineNumber = 1;
716
+ for (let index = 0; index < args.offset; index += 1) {
717
+ if (args.content[index] === "\n") {
718
+ lineNumber += 1;
719
+ }
720
+ }
721
+ return lineNumber;
722
+ }
723
+
724
+ function applyWorkspaceStructuredEdits(args: {
725
+ content: string;
726
+ edits: WorkspaceStructuredEdit[];
727
+ requestedPath: string;
728
+ }) {
729
+ const ranges = args.edits.map((edit, index) => ({
730
+ ...edit,
731
+ index,
732
+ ...findUniqueEditRange({
733
+ content: args.content,
734
+ oldText: edit.oldText,
735
+ requestedPath: args.requestedPath,
736
+ index,
737
+ }),
738
+ })).sort((left, right) => left.start - right.start);
739
+ for (let index = 1; index < ranges.length; index += 1) {
740
+ if (ranges[index]!.start < ranges[index - 1]!.end) {
741
+ throw new Error(`editFile edits overlap in ${args.requestedPath}.`);
742
+ }
743
+ }
744
+ let nextContent = args.content;
745
+ for (const range of [...ranges].sort((left, right) => right.start - left.start)) {
746
+ nextContent =
747
+ nextContent.slice(0, range.start) +
748
+ range.newText +
749
+ nextContent.slice(range.end);
750
+ }
751
+ return {
752
+ nextContent,
753
+ firstChangedLine: ranges.length > 0
754
+ ? countLineNumberAtOffset({
755
+ content: args.content,
756
+ offset: ranges[0]!.start,
757
+ })
758
+ : 1,
759
+ replacements: ranges.length,
760
+ };
761
+ }
762
+
582
763
  function requireWorkspaceSearchQuery(args: WorkspaceFileArgs) {
583
764
  const query = typeof args.query === "string" ? args.query.trim() : "";
584
765
  if (!query) throw new Error("searchWorkspace requires a non-empty query.");
@@ -607,6 +788,10 @@ function requirePackageScript(args: WorkspaceFileArgs) {
607
788
  return script;
608
789
  }
609
790
 
791
+ function readShellTimeoutMs(args: WorkspaceFileArgs) {
792
+ return readOptionalPositiveIntegerArg(args.timeout, "execShell timeout");
793
+ }
794
+
610
795
  function requireVisualWaitSelector(args: WorkspaceFileArgs) {
611
796
  const selector = typeof args.waitSelector === "string" ? args.waitSelector.trim() : "";
612
797
  if (!selector) throw new Error("captureVisualState requires a non-empty waitSelector.");
@@ -666,9 +851,38 @@ function formatAvailableScripts(scripts: string[]) {
666
851
  return scripts.length ? scripts.join(", ") : "(none)";
667
852
  }
668
853
 
854
+ function splitContentIntoLines(content: string) {
855
+ if (!content) return [];
856
+ const lines: string[] = [];
857
+ let start = 0;
858
+ for (let index = 0; index < content.length; index += 1) {
859
+ if (content[index] !== "\n") continue;
860
+ lines.push(content.slice(start, index + 1));
861
+ start = index + 1;
862
+ }
863
+ if (start < content.length) {
864
+ lines.push(content.slice(start));
865
+ }
866
+ return lines;
867
+ }
868
+
869
+ function appendReadContinuationHint(content: string, hint: string) {
870
+ if (!content) return hint;
871
+ return content.endsWith("\n") ? `${content}\n${hint}` : `${content}\n\n${hint}`;
872
+ }
873
+
669
874
  function truncateToolOutput(value: string, limit = 20_000) {
670
- if (value.length <= limit) return value;
671
- return `${value.slice(0, limit)}\n\n[truncated ${value.length - limit} chars]`;
875
+ if (value.length <= limit) {
876
+ return { content: value, truncated: false };
877
+ }
878
+ return {
879
+ content: `${value.slice(0, limit)}\n\n[truncated ${value.length - limit} chars]`,
880
+ truncated: true,
881
+ };
882
+ }
883
+
884
+ function sanitizeWorkspaceTempName(value: string) {
885
+ return value.replace(/[^a-zA-Z0-9._-]+/g, "_");
672
886
  }
673
887
 
674
888
  function parseLastJsonObject(text: string): Record<string, unknown> | null {
@@ -768,16 +982,20 @@ async function runWorkspaceCommand(args: {
768
982
  const stderr = timedOut
769
983
  ? `${rawStderr.trim() ? `${rawStderr.trim()}\n` : ""}command timed out after ${timeoutMs}ms\n`
770
984
  : rawStderr;
985
+ const fullContent = [
986
+ stdout.trim() ? `stdout:\n${stdout.trim()}` : "",
987
+ stderr.trim() ? `stderr:\n${stderr.trim()}` : "",
988
+ `exitCode: ${exitCode}`,
989
+ ].filter(Boolean).join("\n\n");
990
+ const summarizedContent = truncateToolOutput(fullContent);
771
991
  return {
772
992
  stdout,
773
993
  stderr,
774
994
  exitCode,
775
995
  timedOut,
776
- content: truncateToolOutput([
777
- stdout.trim() ? `stdout:\n${stdout.trim()}` : "",
778
- stderr.trim() ? `stderr:\n${stderr.trim()}` : "",
779
- `exitCode: ${exitCode}`,
780
- ].filter(Boolean).join("\n\n")),
996
+ fullContent,
997
+ outputTruncated: summarizedContent.truncated,
998
+ content: summarizedContent.content,
781
999
  };
782
1000
  }
783
1001
 
@@ -799,19 +1017,46 @@ async function readWorkspaceFileTool(args: {
799
1017
  }): Promise<AgentRuntimeToolResult> {
800
1018
  const parsed = parseWorkspaceToolArguments(args.call.arguments);
801
1019
  const requestedPath = requireWorkspaceToolPath(parsed);
1020
+ const readWindow = readWorkspaceReadWindow(parsed);
802
1021
  const absolutePath = resolveLocalWorkspaceToolPath({
803
1022
  workspaceRoot: args.workspaceRoot,
804
1023
  requestedPath,
805
1024
  });
806
1025
  const content = await readFile(absolutePath, "utf8");
1026
+ const lines = splitContentIntoLines(content);
1027
+ const lineOffset = Math.min(readWindow.offset, lines.length);
1028
+ const endLineIndex = readWindow.limit === undefined
1029
+ ? lines.length
1030
+ : Math.min(lineOffset + readWindow.limit, lines.length);
1031
+ const pagedContent = lines.slice(lineOffset, endLineIndex).join("");
1032
+ const returnedLineCount = endLineIndex - lineOffset;
1033
+ const truncated = readWindow.limit !== undefined && endLineIndex < lines.length;
1034
+ const toolContent = truncated && returnedLineCount > 0
1035
+ ? appendReadContinuationHint(
1036
+ pagedContent,
1037
+ `[readFile truncated: returned lines ${lineOffset + 1}-${endLineIndex} of ${lines.length}; ` +
1038
+ `call readFile again with offset ${endLineIndex}.]`
1039
+ )
1040
+ : pagedContent;
1041
+ const relativePath = normalizeWorkspaceRelativePath({
1042
+ workspaceRoot: resolve(args.workspaceRoot),
1043
+ targetPath: absolutePath,
1044
+ });
807
1045
  return {
808
- content,
1046
+ content: readWindow.offset === 0 && readWindow.limit === undefined ? content : toolContent,
809
1047
  metadata: {
810
- path: normalizeWorkspaceRelativePath({
811
- workspaceRoot: resolve(args.workspaceRoot),
812
- targetPath: absolutePath,
813
- }),
814
- bytes: Buffer.byteLength(content),
1048
+ path: relativePath,
1049
+ bytes: Buffer.byteLength(readWindow.offset === 0 && readWindow.limit === undefined ? content : pagedContent),
1050
+ ...(readWindow.offset !== 0 || readWindow.limit !== undefined
1051
+ ? {
1052
+ offset: readWindow.offset,
1053
+ ...(readWindow.limit !== undefined ? { limit: readWindow.limit } : {}),
1054
+ returnedLineCount,
1055
+ totalLineCount: lines.length,
1056
+ truncated,
1057
+ ...(truncated ? { nextOffset: endLineIndex } : {}),
1058
+ }
1059
+ : {}),
815
1060
  },
816
1061
  };
817
1062
  }
@@ -848,14 +1093,37 @@ async function replaceWorkspaceTextTool(args: {
848
1093
  }): Promise<AgentRuntimeToolResult> {
849
1094
  const parsed = parseWorkspaceToolArguments(args.call.arguments);
850
1095
  const requestedPath = requireWorkspaceToolPath(parsed);
851
- const oldText = requireWorkspaceOldText(parsed);
852
- const newText = requireWorkspaceNewText(parsed);
853
- const expectedReplacements = readExpectedReplacementCount(parsed);
1096
+ const structuredEdits = readWorkspaceStructuredEdits(parsed);
854
1097
  const absolutePath = resolveLocalWorkspaceToolPath({
855
1098
  workspaceRoot: args.workspaceRoot,
856
1099
  requestedPath,
857
1100
  });
858
1101
  const content = await readFile(absolutePath, "utf8");
1102
+ const relativePath = normalizeWorkspaceRelativePath({
1103
+ workspaceRoot: resolve(args.workspaceRoot),
1104
+ targetPath: absolutePath,
1105
+ });
1106
+ if (structuredEdits) {
1107
+ const result = applyWorkspaceStructuredEdits({
1108
+ content,
1109
+ edits: structuredEdits,
1110
+ requestedPath,
1111
+ });
1112
+ await writeFile(absolutePath, result.nextContent, "utf8");
1113
+ return {
1114
+ content: `applied ${result.replacements} edit${result.replacements === 1 ? "" : "s"} in ${relativePath}`,
1115
+ metadata: {
1116
+ path: relativePath,
1117
+ replacements: result.replacements,
1118
+ editCount: structuredEdits.length,
1119
+ bytes: Buffer.byteLength(result.nextContent),
1120
+ firstChangedLine: result.firstChangedLine,
1121
+ },
1122
+ };
1123
+ }
1124
+ const oldText = requireWorkspaceOldText(parsed);
1125
+ const newText = requireWorkspaceNewText(parsed);
1126
+ const expectedReplacements = readExpectedReplacementCount(parsed);
859
1127
  const replacementCount = countExactTextOccurrences({ content, oldText });
860
1128
  if (replacementCount !== expectedReplacements) {
861
1129
  throw new Error(
@@ -865,10 +1133,6 @@ async function replaceWorkspaceTextTool(args: {
865
1133
  }
866
1134
  const nextContent = content.split(oldText).join(newText);
867
1135
  await writeFile(absolutePath, nextContent, "utf8");
868
- const relativePath = normalizeWorkspaceRelativePath({
869
- workspaceRoot: resolve(args.workspaceRoot),
870
- targetPath: absolutePath,
871
- });
872
1136
  return {
873
1137
  content: `replaced ${replacementCount} occurrence${replacementCount === 1 ? "" : "s"} in ${relativePath}`,
874
1138
  metadata: {
@@ -1162,7 +1426,20 @@ async function previewLifecycleTool(args: {
1162
1426
  const summary = parseLastJsonObject(String(result.metadata?.stdoutTail ?? result.content)) ?? {};
1163
1427
  return {
1164
1428
  content: [
1165
- typeof summary.previewUrl === "string" ? `previewUrl: ${summary.previewUrl}` : "",
1429
+ typeof summary.preferredPreviewUrl === "string"
1430
+ ? `preferredPreviewUrl: ${summary.preferredPreviewUrl}`
1431
+ : "",
1432
+ typeof summary.assignedPreviewUrl === "string"
1433
+ ? `assignedPreviewUrl: ${summary.assignedPreviewUrl}`
1434
+ : typeof summary.previewUrl === "string"
1435
+ ? `assignedPreviewUrl: ${summary.previewUrl}`
1436
+ : "",
1437
+ typeof summary.previewUrlVerified === "boolean"
1438
+ ? `previewUrlVerified: ${String(summary.previewUrlVerified)}`
1439
+ : "",
1440
+ typeof summary.previewVerificationReason === "string"
1441
+ ? `previewVerificationReason: ${summary.previewVerificationReason}`
1442
+ : "",
1166
1443
  typeof summary.localApiOrigin === "string" ? `localApiOrigin: ${summary.localApiOrigin}` : "",
1167
1444
  typeof summary.serverDbPath === "string" ? `serverDbPath: ${summary.serverDbPath}` : "",
1168
1445
  "",
@@ -1184,6 +1461,13 @@ async function execShellTool(args: {
1184
1461
  }): Promise<AgentRuntimeToolResult> {
1185
1462
  const parsed = parseWorkspaceToolArguments(args.call.arguments);
1186
1463
  const command = requireShellCommand(parsed, args.call.name);
1464
+ const requestedTimeoutMs = readShellTimeoutMs(parsed);
1465
+ const timeoutMs = requestedTimeoutMs === undefined
1466
+ ? args.commandTimeoutMs
1467
+ : Math.min(
1468
+ requestedTimeoutMs,
1469
+ args.commandTimeoutMs ?? DEFAULT_WORKSPACE_COMMAND_TIMEOUT_MS,
1470
+ );
1187
1471
  const result = await runWorkspaceCommand({
1188
1472
  workspaceRoot: args.workspaceRoot,
1189
1473
  command: buildWorkspaceShellCommand({
@@ -1191,12 +1475,31 @@ async function execShellTool(args: {
1191
1475
  command,
1192
1476
  shell: parsed.shell,
1193
1477
  }),
1194
- timeoutMs: args.commandTimeoutMs,
1478
+ timeoutMs,
1195
1479
  commandPrefix: args.commandPrefix,
1196
1480
  });
1481
+ let fullOutputPath: string | undefined;
1482
+ if (result.outputTruncated) {
1483
+ const relativeOutputPath = `.tmp/agent-runtime/execShell/${sanitizeWorkspaceTempName(args.call.id)}.log`;
1484
+ const absoluteOutputPath = resolve(args.workspaceRoot, relativeOutputPath);
1485
+ await mkdir(dirname(absoluteOutputPath), { recursive: true });
1486
+ await writeFile(absoluteOutputPath, result.fullContent, "utf8");
1487
+ fullOutputPath = normalizeWorkspaceRelativePath({
1488
+ workspaceRoot: resolve(args.workspaceRoot),
1489
+ targetPath: absoluteOutputPath,
1490
+ });
1491
+ }
1197
1492
  return {
1198
- content: result.content,
1199
- metadata: { exitCode: result.exitCode, timedOut: result.timedOut },
1493
+ content: fullOutputPath
1494
+ ? `${result.content}\n\n[full output saved to ${fullOutputPath}]`
1495
+ : result.content,
1496
+ metadata: {
1497
+ exitCode: result.exitCode,
1498
+ timedOut: result.timedOut,
1499
+ timeoutMs: timeoutMs ?? DEFAULT_WORKSPACE_COMMAND_TIMEOUT_MS,
1500
+ ...(result.outputTruncated ? { outputTruncated: true } : {}),
1501
+ ...(fullOutputPath ? { fullOutputPath } : {}),
1502
+ },
1200
1503
  };
1201
1504
  }
1202
1505
 
@@ -230,7 +230,9 @@ export function hasDirectOpenAiCompatibleProvider(env: EnvLike) {
230
230
  }
231
231
 
232
232
  function agentRequiresPlatformChatProvider(agentConfig?: AgentRuntimeAgentConfig) {
233
- return agentConfig?.apiSource === "platform" || agentConfig?.rawRecord?.useServerProxy === true;
233
+ if (agentConfig?.apiSource === "platform") return true;
234
+ if (agentConfig?.customProviderUrl?.trim()) return false;
235
+ return agentConfig?.rawRecord?.useServerProxy === true;
234
236
  }
235
237
 
236
238
  export function shouldUsePlatformChatProvider(
@@ -238,6 +240,7 @@ export function shouldUsePlatformChatProvider(
238
240
  agentConfig?: AgentRuntimeAgentConfig
239
241
  ) {
240
242
  if (agentRequiresPlatformChatProvider(agentConfig)) return true;
243
+ if (agentConfig?.customProviderUrl?.trim()) return false;
241
244
  if (env.NOLO_LOCAL_LLM === "platform") return true;
242
245
  if (env.NOLO_LOCAL_LLM === "direct") return false;
243
246
  return !hasDirectOpenAiCompatibleProvider(env) && canUsePlatformChatProvider(env);
@@ -1,5 +1,5 @@
1
1
  import type { AgentRuntimeAgentConfig } from "./hostAdapter";
2
- import type { AgentRuntimeHost, AgentRuntimeToolPolicy } from "./types";
2
+ import type { AgentRuntimeToolPolicy } from "./types";
3
3
 
4
4
  function isRecord(value: unknown): value is Record<string, unknown> {
5
5
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
@@ -77,57 +77,42 @@ export function mergeAgentRuntimeToolPolicies(
77
77
  };
78
78
  }
79
79
 
80
- function policyRequestsHostedWorkspace(policy: AgentRuntimeToolPolicy | undefined) {
81
- if (!policy) return false;
82
- const workspaceMode = policy.workspace?.mode;
83
- return (
84
- policy.shell?.enabled === true ||
85
- policy.runtimeTools?.some((tool) => tool === "execShell") ||
86
- workspaceMode === "lease" ||
87
- workspaceMode === "task-worktree"
88
- );
80
+ function runtimeBindingRecord(runtimeBinding: unknown): Record<string, unknown> | undefined {
81
+ return isRecord(runtimeBinding) ? runtimeBinding : undefined;
89
82
  }
90
83
 
91
- function applyWebRuntimeSafetyBaseline(
92
- policy: AgentRuntimeToolPolicy | undefined,
93
- ): AgentRuntimeToolPolicy | undefined {
94
- if (!policyRequestsHostedWorkspace(policy)) return policy;
95
- return mergeAgentRuntimeToolPolicies(
96
- policy,
97
- {
98
- version: 1,
99
- shell: {
100
- commandPolicy: "approval",
101
- networkPolicy: "default-deny",
102
- },
103
- isolation: {
104
- mode: "os-sandbox",
105
- },
106
- audit: {
107
- logToolCalls: true,
108
- logShellCommands: true,
109
- writeToDialog: true,
110
- },
111
- },
112
- );
84
+ function runtimePolicyFromRuntimeBinding(runtimeBinding: unknown): AgentRuntimeToolPolicy | undefined {
85
+ const binding = runtimeBindingRecord(runtimeBinding);
86
+ if (!binding) return undefined;
87
+ return normalizeAgentRuntimeToolPolicy(binding.runtimeToolPolicy);
88
+ }
89
+
90
+ function runtimePolicySnapshotFromRuntimeBinding(runtimeBinding: unknown): AgentRuntimeToolPolicy | undefined {
91
+ const binding = runtimeBindingRecord(runtimeBinding);
92
+ if (!binding) return undefined;
93
+ return normalizeAgentRuntimeToolPolicy(binding.runtimeToolPolicySnapshot);
94
+ }
95
+
96
+ export function resolveRequestedRuntimeToolNames(args: {
97
+ agentConfig: Pick<AgentRuntimeAgentConfig, "toolNames" | "runtimeToolPolicy" | "runtimeBinding">;
98
+ }) {
99
+ const agentPolicy = normalizeAgentRuntimeToolPolicy(args.agentConfig.runtimeToolPolicy);
100
+ const bindingPolicy = runtimePolicyFromRuntimeBinding(args.agentConfig.runtimeBinding);
101
+ const bindingSnapshotPolicy = runtimePolicySnapshotFromRuntimeBinding(args.agentConfig.runtimeBinding);
102
+ return unique([
103
+ ...stringArray(args.agentConfig.toolNames),
104
+ ...(agentPolicy?.runtimeTools ?? []),
105
+ ...(bindingPolicy?.runtimeTools ?? []),
106
+ ...(bindingSnapshotPolicy?.runtimeTools ?? []),
107
+ ]);
113
108
  }
114
109
 
115
110
  export function resolveEffectiveRuntimeToolPolicy(args: {
116
111
  agentConfig: Pick<AgentRuntimeAgentConfig, "runtimeToolPolicy" | "runtimeBinding">;
117
- taskRunControl?: { runtimeToolPolicy?: unknown } | null;
118
- host?: AgentRuntimeHost;
119
112
  }): AgentRuntimeToolPolicy | undefined {
120
- const agentPolicy = normalizeAgentRuntimeToolPolicy(
121
- args.agentConfig.runtimeToolPolicy ??
122
- (isRecord(args.agentConfig.runtimeBinding)
123
- ? args.agentConfig.runtimeBinding.runtimeToolPolicy
124
- : undefined),
125
- );
126
- const taskPolicy = normalizeAgentRuntimeToolPolicy(
127
- args.taskRunControl?.runtimeToolPolicy,
128
- );
129
- const effectivePolicy = mergeAgentRuntimeToolPolicies(agentPolicy, taskPolicy);
130
- return args.host === "web"
131
- ? applyWebRuntimeSafetyBaseline(effectivePolicy)
132
- : effectivePolicy;
113
+ const bindingSnapshot = runtimePolicySnapshotFromRuntimeBinding(args.agentConfig.runtimeBinding);
114
+ if (bindingSnapshot) return bindingSnapshot;
115
+ const topLevelPolicy = normalizeAgentRuntimeToolPolicy(args.agentConfig.runtimeToolPolicy);
116
+ if (topLevelPolicy) return topLevelPolicy;
117
+ return runtimePolicyFromRuntimeBinding(args.agentConfig.runtimeBinding);
133
118
  }