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
@@ -1,9 +1,24 @@
1
1
  type RetryLogger = {
2
2
  warn?: (...args: any[]) => void;
3
+ error?: (...args: any[]) => void;
3
4
  };
4
5
 
5
6
  import type { OpenAIServiceTier } from "../../integrations/openai/flexTier";
6
7
  import { isFireworksKimiModel } from "../../ai/llm/kimi";
8
+ import {
9
+ createProviderCallCompletedEvent,
10
+ } from "../../ai/token/providerCall";
11
+ import {
12
+ writeProviderCallEvent,
13
+ type ProviderCallStore,
14
+ } from "../../ai/token/providerCallWriter";
15
+ import { dispatchProviderRequest } from "../../ai/token/providerGateway";
16
+ import type { ProviderCredentialIdentity } from "../../ai/token/providerCredential";
17
+ import { writeBillingAnomaly } from "../../ai/token/billingAnomalyWriter";
18
+ import {
19
+ writeRevokedProviderCredentialUsedAnomalyIfNeeded,
20
+ } from "../../ai/token/providerCredentialAnomaly";
21
+ import { ulid } from "ulid";
7
22
 
8
23
  const FIREWORKS_GENTLE_RETRY_DELAY_MS = 1200;
9
24
  const FIREWORKS_GENTLE_RETRY_STATUSES = new Set([429, 503]);
@@ -14,8 +29,168 @@ type UpstreamRequest = {
14
29
  provider?: string;
15
30
  model?: string;
16
31
  serviceTier?: OpenAIServiceTier;
32
+ credential?: ProviderCredentialIdentity;
17
33
  };
18
34
 
35
+ type ProviderCallContext = {
36
+ userId: string;
37
+ dialogId?: string;
38
+ agentId?: string;
39
+ endpoint?: string;
40
+ credential?: ProviderCredentialIdentity;
41
+ };
42
+
43
+ const isoNow = () => new Date().toISOString();
44
+ type ProviderCallWriter = typeof writeProviderCallEvent;
45
+ type BillingAnomalyWriter = typeof writeBillingAnomaly;
46
+ type ProviderDispatchIntentWriter =
47
+ NonNullable<Parameters<typeof dispatchProviderRequest>[0]["writers"]>["providerDispatchIntentWriter"];
48
+
49
+ async function writeProviderCallEvidence({
50
+ store,
51
+ event,
52
+ providerCallWriter,
53
+ }: {
54
+ store: ProviderCallStore;
55
+ event: Parameters<typeof writeProviderCallEvent>[0]["event"];
56
+ providerCallWriter?: ProviderCallWriter;
57
+ }) {
58
+ const writer = providerCallWriter ?? writeProviderCallEvent;
59
+ if (typeof writer === "function") {
60
+ return writer({ store, event });
61
+ }
62
+ const key = `provider-call-${event.providerCallId}-event-${event.eventId}`;
63
+ await store.put(key, event);
64
+ return { key };
65
+ }
66
+
67
+ async function writeTerminalProviderCallEventSafely({
68
+ store,
69
+ event,
70
+ log,
71
+ providerCallWriter = writeProviderCallEvent,
72
+ billingAnomalyWriter = writeBillingAnomaly,
73
+ }: {
74
+ store: ProviderCallStore;
75
+ event: Parameters<typeof writeProviderCallEvent>[0]["event"];
76
+ log?: RetryLogger;
77
+ providerCallWriter?: ProviderCallWriter;
78
+ billingAnomalyWriter?: BillingAnomalyWriter;
79
+ }) {
80
+ try {
81
+ await writeProviderCallEvidence({ store, event, providerCallWriter });
82
+ } catch (error) {
83
+ log?.error?.("provider-call terminal event write failed", {
84
+ err: error,
85
+ providerCallId: event.providerCallId,
86
+ status: event.status,
87
+ });
88
+ return;
89
+ }
90
+ await writeRevokedProviderCredentialUsedAnomalyIfNeeded({
91
+ store,
92
+ event,
93
+ onError: (error) =>
94
+ log?.error?.("provider-call revoked credential anomaly write failed", {
95
+ err: error,
96
+ providerCallId: event.providerCallId,
97
+ }),
98
+ billingAnomalyWriter,
99
+ });
100
+ }
101
+
102
+ async function fetchWithProviderCallEvidence({
103
+ url,
104
+ init,
105
+ provider,
106
+ model,
107
+ serviceTier,
108
+ fetchImpl,
109
+ providerCallStore,
110
+ providerCallContext,
111
+ log,
112
+ providerCallWriter,
113
+ providerDispatchIntentWriter,
114
+ billingAnomalyWriter,
115
+ credential,
116
+ }: {
117
+ url: string;
118
+ init: RequestInit;
119
+ provider?: string;
120
+ model?: string;
121
+ serviceTier?: OpenAIServiceTier;
122
+ fetchImpl: typeof fetch;
123
+ providerCallStore?: ProviderCallStore;
124
+ providerCallContext?: ProviderCallContext;
125
+ log?: RetryLogger;
126
+ providerCallWriter?: ProviderCallWriter;
127
+ providerDispatchIntentWriter?: ProviderDispatchIntentWriter;
128
+ billingAnomalyWriter?: BillingAnomalyWriter;
129
+ credential?: ProviderCredentialIdentity;
130
+ }): Promise<{ response: Response; providerCallId?: string }> {
131
+ if (!providerCallStore || !providerCallContext) {
132
+ return { response: await fetchImpl(url, init) };
133
+ }
134
+
135
+ const providerCallId = `call_${ulid()}`;
136
+ const startedAt = isoNow();
137
+
138
+ const { response } = await dispatchProviderRequest({
139
+ store: providerCallStore,
140
+ fetchImpl,
141
+ now: () => new Date(startedAt),
142
+ ids: {
143
+ providerCallId: () => providerCallId,
144
+ pendingEventId: () => `evt_${ulid()}`,
145
+ dispatchIntentId: () => `intent_${ulid()}`,
146
+ failedEventId: () => `evt_${ulid()}`,
147
+ },
148
+ writers: {
149
+ providerCallWriter,
150
+ providerDispatchIntentWriter,
151
+ billingAnomalyWriter,
152
+ },
153
+ call: {
154
+ userId: providerCallContext.userId,
155
+ dialogId: providerCallContext.dialogId,
156
+ agentId: providerCallContext.agentId,
157
+ provider: provider || "unknown",
158
+ model: model || "unknown",
159
+ endpoint: providerCallContext.endpoint,
160
+ serviceTier,
161
+ credential: credential ?? providerCallContext.credential,
162
+ url,
163
+ init,
164
+ },
165
+ });
166
+ await writeTerminalProviderCallEventSafely({
167
+ store: providerCallStore,
168
+ log,
169
+ providerCallWriter,
170
+ billingAnomalyWriter,
171
+ event: createProviderCallCompletedEvent({
172
+ providerCallId,
173
+ eventId: `evt_${ulid()}`,
174
+ userId: providerCallContext.userId,
175
+ dialogId: providerCallContext.dialogId,
176
+ agentId: providerCallContext.agentId,
177
+ provider: provider || "unknown",
178
+ model: model || "unknown",
179
+ endpoint: providerCallContext.endpoint,
180
+ serviceTier,
181
+ credential: credential ?? providerCallContext.credential,
182
+ startedAt,
183
+ completedAt: isoNow(),
184
+ inputTokens: 0,
185
+ outputTokens: 0,
186
+ cacheCreationInputTokens: 0,
187
+ cacheReadInputTokens: 0,
188
+ billingStatus: "unpriced",
189
+ }),
190
+ });
191
+ return { response, providerCallId };
192
+ }
193
+
19
194
  function createAbortError(reason?: unknown): Error {
20
195
  const error = new Error(typeof reason === "string" ? reason : "Aborted");
21
196
  error.name = "AbortError";
@@ -57,6 +232,12 @@ export async function fetchUpstreamWithGentleRetry({
57
232
  fallbackOnStatuses,
58
233
  retryDelayMs = FIREWORKS_GENTLE_RETRY_DELAY_MS,
59
234
  fetchImpl = fetch,
235
+ providerCallStore,
236
+ providerCallContext,
237
+ providerCallWriter,
238
+ providerDispatchIntentWriter,
239
+ billingAnomalyWriter,
240
+ credential,
60
241
  }: {
61
242
  url: string;
62
243
  init: RequestInit;
@@ -68,17 +249,40 @@ export async function fetchUpstreamWithGentleRetry({
68
249
  fallbackOnStatuses?: Iterable<number>;
69
250
  retryDelayMs?: number;
70
251
  fetchImpl?: typeof fetch;
252
+ providerCallStore?: ProviderCallStore;
253
+ providerCallContext?: ProviderCallContext;
254
+ providerCallWriter?: ProviderCallWriter;
255
+ providerDispatchIntentWriter?: ProviderDispatchIntentWriter;
256
+ billingAnomalyWriter?: BillingAnomalyWriter;
257
+ credential?: ProviderCredentialIdentity;
71
258
  }): Promise<{
72
259
  response: Response;
73
260
  provider?: string;
74
261
  model?: string;
75
262
  serviceTier?: OpenAIServiceTier;
263
+ providerCallIds?: string[];
76
264
  }> {
77
265
  const maxAttempts = provider === "fireworks" ? 2 : 1;
78
266
  let response: Response | undefined;
267
+ const providerCallIds: string[] = [];
79
268
 
80
269
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
81
- response = await fetchImpl(url, init);
270
+ const evidence = await fetchWithProviderCallEvidence({
271
+ url,
272
+ init,
273
+ provider,
274
+ model,
275
+ fetchImpl,
276
+ providerCallStore,
277
+ providerCallContext,
278
+ log,
279
+ providerCallWriter,
280
+ providerDispatchIntentWriter,
281
+ billingAnomalyWriter,
282
+ credential,
283
+ });
284
+ response = evidence.response;
285
+ if (evidence.providerCallId) providerCallIds.push(evidence.providerCallId);
82
286
  const shouldRetry =
83
287
  provider === "fireworks" &&
84
288
  attempt < maxAttempts &&
@@ -122,6 +326,7 @@ export async function fetchUpstreamWithGentleRetry({
122
326
  response,
123
327
  provider,
124
328
  model,
329
+ ...(providerCallIds.length > 0 ? { providerCallIds: [...providerCallIds] } : {}),
125
330
  };
126
331
  }
127
332
 
@@ -138,13 +343,30 @@ export async function fetchUpstreamWithGentleRetry({
138
343
  fallbackModel: nextFallback.model,
139
344
  });
140
345
 
141
- const fallbackResponse = await fetchImpl(nextFallback.url, nextFallback.init);
346
+ const fallbackEvidence = await fetchWithProviderCallEvidence({
347
+ url: nextFallback.url,
348
+ init: nextFallback.init,
349
+ provider: nextFallback.provider,
350
+ model: nextFallback.model,
351
+ serviceTier: nextFallback.serviceTier,
352
+ fetchImpl,
353
+ providerCallStore,
354
+ providerCallContext,
355
+ log,
356
+ providerCallWriter,
357
+ providerDispatchIntentWriter,
358
+ billingAnomalyWriter,
359
+ credential: nextFallback.credential,
360
+ });
361
+ const fallbackResponse = fallbackEvidence.response;
362
+ if (fallbackEvidence.providerCallId) providerCallIds.push(fallbackEvidence.providerCallId);
142
363
  if (!fallbackStatuses.has(fallbackResponse.status)) {
143
364
  return {
144
365
  response: fallbackResponse,
145
366
  provider: nextFallback.provider,
146
367
  model: nextFallback.model,
147
368
  serviceTier: nextFallback.serviceTier,
369
+ ...(providerCallIds.length > 0 ? { providerCallIds: [...providerCallIds] } : {}),
148
370
  };
149
371
  }
150
372
 
@@ -158,5 +380,6 @@ export async function fetchUpstreamWithGentleRetry({
158
380
  response,
159
381
  provider: currentProvider,
160
382
  model: currentModel,
383
+ ...(providerCallIds.length > 0 ? { providerCallIds: [...providerCallIds] } : {}),
161
384
  };
162
385
  }
@@ -43,6 +43,7 @@ export type ConnectorAgentRunProgress = {
43
43
  export type ConnectorAgentRunOptions = {
44
44
  requestTimeoutMs?: number;
45
45
  onProgress?: (progress: ConnectorAgentRunProgress) => void | Promise<void>;
46
+ connectorSurface?: string;
46
47
  };
47
48
 
48
49
  type ConnectorSocket = {
@@ -60,8 +61,10 @@ type PendingRequest = {
60
61
  };
61
62
 
62
63
  type RegisteredConnection = {
64
+ sessionId: string;
63
65
  machineId: string;
64
66
  ownerUserId: string;
67
+ connectorSurface?: string;
65
68
  receive(message: string): void;
66
69
  close(): void;
67
70
  };
@@ -70,8 +73,14 @@ function connectionKey(ownerUserId: string, machineId: string) {
70
73
  return `${ownerUserId}:${machineId}`;
71
74
  }
72
75
 
76
+ function normalizeConnectorSurface(surface: unknown) {
77
+ return typeof surface === "string" && surface.trim()
78
+ ? surface.trim().toLowerCase()
79
+ : undefined;
80
+ }
81
+
73
82
  export function createConnectorConnectionRegistry(options: { requestTimeoutMs?: number } = {}) {
74
- const connections = new Map<string, RegisteredConnection & { socket: ConnectorSocket }>();
83
+ const connections = new Map<string, Array<RegisteredConnection & { socket: ConnectorSocket }>>();
75
84
  const pending = new Map<string, PendingRequest>();
76
85
  const requestTimeoutMs = options.requestTimeoutMs ?? 120_000;
77
86
 
@@ -84,22 +93,58 @@ export function createConnectorConnectionRegistry(options: { requestTimeoutMs?:
84
93
  }
85
94
  };
86
95
 
87
- const unregister = (ownerUserId: string, machineId: string) => {
96
+ const unregister = (ownerUserId: string, machineId: string, sessionId?: string) => {
88
97
  const key = connectionKey(ownerUserId, machineId);
98
+ if (!sessionId) {
99
+ connections.delete(key);
100
+ rejectPendingForConnection(key, machineId);
101
+ return;
102
+ }
103
+ const remaining = (connections.get(key) ?? []).filter((connection) =>
104
+ connection.sessionId !== sessionId
105
+ );
106
+ if (remaining.length > 0) {
107
+ connections.set(key, remaining);
108
+ return;
109
+ }
89
110
  connections.delete(key);
90
111
  rejectPendingForConnection(key, machineId);
91
112
  };
92
113
 
114
+ const findConnection = (
115
+ ownerUserId: string,
116
+ machineId: string,
117
+ connectorSurface?: string,
118
+ ) => {
119
+ const list = connections.get(connectionKey(ownerUserId, machineId)) ?? [];
120
+ if (list.length === 0) return null;
121
+ const surface = normalizeConnectorSurface(connectorSurface);
122
+ if (surface) {
123
+ const exact = list.find((connection) => connection.connectorSurface === surface);
124
+ if (exact) return exact;
125
+ if (surface === "desktop") {
126
+ const legacyDesktop = list.find((connection) => !connection.connectorSurface);
127
+ if (legacyDesktop) return legacyDesktop;
128
+ }
129
+ return null;
130
+ }
131
+ return list.at(-1) ?? null;
132
+ };
133
+
93
134
  return {
94
135
  register(args: {
95
136
  machineId: string;
96
137
  ownerUserId: string;
138
+ connectorSurface?: string;
97
139
  send: (message: string) => unknown;
98
140
  }): RegisteredConnection {
99
141
  const key = connectionKey(args.ownerUserId, args.machineId);
142
+ const sessionId = randomUUID();
100
143
  const connection: RegisteredConnection & { socket: ConnectorSocket } = {
144
+ sessionId,
101
145
  machineId: args.machineId,
102
146
  ownerUserId: args.ownerUserId,
147
+ connectorSurface: normalizeConnectorSurface(args.connectorSurface),
103
148
  socket: { send: args.send },
104
149
  receive(message) {
105
150
  let parsed: any;
@@ -135,15 +180,18 @@ export function createConnectorConnectionRegistry(options: { requestTimeoutMs?:
135
180
  });
136
181
  },
137
182
  close() {
138
- unregister(args.ownerUserId, args.machineId);
183
+ unregister(args.ownerUserId, args.machineId, sessionId);
139
184
  },
140
185
  };
141
- connections.set(key, connection);
186
+ connections.set(key, [
187
+ ...(connections.get(key) ?? []),
188
+ connection,
189
+ ]);
142
190
  return connection;
143
191
  },
144
192
 
145
- hasConnection(ownerUserId: string, machineId: string) {
146
- return connections.has(connectionKey(ownerUserId, machineId));
193
+ hasConnection(ownerUserId: string, machineId: string, connectorSurface?: string) {
194
+ return Boolean(findConnection(ownerUserId, machineId, connectorSurface));
147
195
  },
148
196
 
149
197
  unregister,
@@ -154,7 +202,7 @@ export function createConnectorConnectionRegistry(options: { requestTimeoutMs?:
154
202
  payload: ConnectorAgentRunPayload,
155
203
  options: ConnectorAgentRunOptions = {}
156
204
  ): Promise<ConnectorAgentRunResult> {
157
- const connection = connections.get(connectionKey(ownerUserId, machineId));
205
+ const connection = findConnection(ownerUserId, machineId, options.connectorSurface);
158
206
  if (!connection) {
159
207
  return Promise.reject(new Error(`Connector offline for machine: ${machineId}`));
160
208
  }
@@ -12,7 +12,8 @@ type ConnectorRegistry = ReturnType<typeof createConnectorConnectionRegistry>;
12
12
  type ConnectorWsData = {
13
13
  connector?: {
14
14
  ownerUserId: string;
15
- machineId: string;
15
+ machineId: string;
16
+ connectorSurface?: string;
16
17
  preview?: {
17
18
  slotSlug: string;
18
19
  capability: "realtime";
@@ -44,7 +45,8 @@ export async function handleConnectorUpgradeRequest(
44
45
  } = {}
45
46
  ) {
46
47
  const url = new URL(req.url);
47
- const machineId = url.searchParams.get("machineId")?.trim();
48
+ const machineId = url.searchParams.get("machineId")?.trim();
49
+ const connectorSurface = url.searchParams.get("connectorSurface")?.trim().toLowerCase();
48
50
  if (!machineId) {
49
51
  return new Response("machineId is required", { status: 400 });
50
52
  }
@@ -70,10 +72,11 @@ export async function handleConnectorUpgradeRequest(
70
72
  const upgraded = server.upgrade(req, {
71
73
  data: {
72
74
  connector: {
73
- ownerUserId: auth.userId,
74
- machineId,
75
- preview: deps.preview ?? null,
76
- },
75
+ ownerUserId: auth.userId,
76
+ machineId,
77
+ ...(connectorSurface ? { connectorSurface } : {}),
78
+ preview: deps.preview ?? null,
79
+ },
77
80
  },
78
81
  });
79
82
  return upgraded ? undefined : new Response("WebSocket upgrade failed", { status: 400 });
@@ -87,10 +90,11 @@ export function handleConnectorOpen(
87
90
  if (!connector) return false;
88
91
  const registry = deps.registry ?? connectorConnectionRegistry;
89
92
  connector.connection = registry.register({
90
- ownerUserId: connector.ownerUserId,
91
- machineId: connector.machineId,
92
- send: (message) => ws.send(message),
93
- });
93
+ ownerUserId: connector.ownerUserId,
94
+ machineId: connector.machineId,
95
+ connectorSurface: connector.connectorSurface,
96
+ send: (message) => ws.send(message),
97
+ });
94
98
  return true;
95
99
  }
96
100
 
@@ -22,9 +22,9 @@ import {
22
22
  shouldUsePlatformChatProvider,
23
23
  } from "../../agent-runtime";
24
24
  import {
25
- describeDesktopAgentRuntimeHostFacts,
25
+ describeDesktopAgentRuntimeHostCapabilities,
26
26
  type DesktopAgentRuntimeEnv,
27
- } from "./desktopAgentRuntimeHostFacts";
27
+ } from "./desktopAgentRuntimeHostCapabilities";
28
28
  import { normalizeBuiltinPlatformAgentModelConfig } from "./agentRun/builtinAgents";
29
29
 
30
30
  export type DesktopAgentRuntimeActions = {
@@ -278,11 +278,11 @@ export function createDesktopAgentRuntimeAdapter(args: {
278
278
  actions: DesktopAgentRuntimeActions;
279
279
  capabilities?: string[];
280
280
  }): AgentRuntimeHostAdapter {
281
- const facts = describeDesktopAgentRuntimeHostFacts(args.env);
281
+ const capabilities = describeDesktopAgentRuntimeHostCapabilities(args.env);
282
282
 
283
283
  return {
284
284
  host: "desktop",
285
- capabilities: [...new Set([...facts.capabilities, ...(args.capabilities ?? [])])],
285
+ capabilities: [...new Set([...capabilities, ...(args.capabilities ?? [])])],
286
286
  loadAgentConfig: (agentRef) => loadDesktopAgentRuntimeAgentConfig({
287
287
  actions: args.actions,
288
288
  agentRef,
@@ -0,0 +1,25 @@
1
+ import {
2
+ canUsePlatformChatProvider,
3
+ hasDirectOpenAiCompatibleProvider,
4
+ } from "../../agent-runtime";
5
+
6
+ export type DesktopAgentRuntimeEnv = Record<string, string | undefined>;
7
+
8
+ function hasDesktopLocalPersistence(env: DesktopAgentRuntimeEnv) {
9
+ return Boolean(env.NOLO_SERVER_DB_PATH?.trim());
10
+ }
11
+
12
+ function hasDesktopProviderEndpoint(env: DesktopAgentRuntimeEnv) {
13
+ return hasDirectOpenAiCompatibleProvider(env) || canUsePlatformChatProvider(env);
14
+ }
15
+
16
+ export function describeDesktopAgentRuntimeHostCapabilities(
17
+ env: DesktopAgentRuntimeEnv
18
+ ) {
19
+ const hasLocalPersistence = hasDesktopLocalPersistence(env);
20
+ return [
21
+ ...(hasLocalPersistence ? ["leveldb-agent-config"] : []),
22
+ ...(hasDesktopProviderEndpoint(env) ? ["local-provider"] : []),
23
+ ...(hasLocalPersistence ? ["leveldb-persistence"] : []),
24
+ ];
25
+ }
@@ -0,0 +1,62 @@
1
+ import {
2
+ resolveAgentRuntimeDecision,
3
+ type AgentRuntimeDecision,
4
+ } from "../../agent-runtime";
5
+ import type {
6
+ DesktopProviderRuntimeSnapshot,
7
+ } from "./desktopLlamaRuntimeHandler";
8
+ import type { DesktopAgentRuntimeEnv } from "./desktopAgentRuntimeHostCapabilities";
9
+
10
+ export type DesktopAgentRuntimeReadinessStatus = {
11
+ ok: true;
12
+ host: "desktop";
13
+ providerRuntimeState: DesktopProviderRuntimeSnapshot["state"];
14
+ localCapabilities: string[];
15
+ decision: AgentRuntimeDecision;
16
+ missingLocalCapabilities: string[];
17
+ };
18
+
19
+ function hasDesktopLocalPersistence(env: DesktopAgentRuntimeEnv) {
20
+ return Boolean(env.NOLO_SERVER_DB_PATH?.trim());
21
+ }
22
+
23
+ function isDesktopProviderRuntimeReady(snapshot: DesktopProviderRuntimeSnapshot) {
24
+ return snapshot.state === "running";
25
+ }
26
+
27
+ export function buildDesktopAgentRuntimeReadiness(args: {
28
+ env: DesktopAgentRuntimeEnv;
29
+ providerRuntimeSnapshot: DesktopProviderRuntimeSnapshot;
30
+ }): DesktopAgentRuntimeReadinessStatus {
31
+ const hasLocalPersistence = hasDesktopLocalPersistence(args.env);
32
+ const hasLocalAgentConfig = hasLocalPersistence;
33
+ const hasLocalProvider = isDesktopProviderRuntimeReady(args.providerRuntimeSnapshot);
34
+ const localCapabilities = [
35
+ ...(hasLocalAgentConfig ? ["agent-config"] : []),
36
+ ...(hasLocalProvider ? ["provider"] : []),
37
+ ...(hasLocalPersistence ? ["persistence"] : []),
38
+ ];
39
+ const decision = resolveAgentRuntimeDecision({
40
+ host: "desktop",
41
+ syncRequested: false,
42
+ hasLocalAgentConfig,
43
+ hasLocalProvider,
44
+ hasLocalPersistence,
45
+ missingLocalCapabilities: [
46
+ ...(hasLocalAgentConfig ? [] : ["agent-config"]),
47
+ ...(hasLocalProvider ? [] : ["provider"]),
48
+ ...(hasLocalPersistence ? [] : ["persistence"]),
49
+ ],
50
+ requiresServer: false,
51
+ serverFallbackAvailable: true,
52
+ });
53
+
54
+ return {
55
+ ok: true,
56
+ host: "desktop",
57
+ providerRuntimeState: args.providerRuntimeSnapshot.state,
58
+ localCapabilities,
59
+ decision,
60
+ missingLocalCapabilities: decision.missingLocalCapabilities,
61
+ };
62
+ }
@@ -1,43 +1,39 @@
1
1
  import {
2
- resolveAgentRuntimeDecision,
3
- type AgentRuntimeDecision,
4
- } from "../../agent-runtime";
2
+ buildDesktopAgentRuntimeReadiness,
3
+ type DesktopAgentRuntimeReadinessStatus,
4
+ } from "./desktopAgentRuntimeReadiness";
5
5
  import {
6
- buildDesktopAgentRuntimeDecisionInput,
7
- describeDesktopAgentRuntimeHostFacts,
8
- type DesktopAgentRuntimeEnv,
9
- } from "./desktopAgentRuntimeHostFacts";
6
+ readDesktopProviderRuntimeSnapshot,
7
+ type DesktopProviderRuntimeSnapshot,
8
+ } from "./desktopLlamaRuntimeHandler";
9
+ import type { DesktopAgentRuntimeEnv } from "./desktopAgentRuntimeHostCapabilities";
10
10
 
11
- export type DesktopAgentRuntimeStatus = {
12
- ok: true;
13
- host: "desktop";
14
- capabilities: string[];
15
- decision: AgentRuntimeDecision;
16
- missingLocalCapabilities: string[];
17
- };
11
+ export type { DesktopAgentRuntimeReadinessStatus } from "./desktopAgentRuntimeReadiness";
18
12
 
19
13
  const JSON_HEADERS = {
20
14
  "Content-Type": "application/json; charset=utf-8",
21
15
  };
22
16
 
23
- export function buildDesktopAgentRuntimeStatus(args: {
17
+ export async function buildDesktopAgentRuntimeReadinessStatus(args: {
24
18
  env?: DesktopAgentRuntimeEnv;
25
- } = {}): DesktopAgentRuntimeStatus {
19
+ readDesktopProviderRuntimeSnapshot?: () => Promise<DesktopProviderRuntimeSnapshot>;
20
+ } = {}): Promise<DesktopAgentRuntimeReadinessStatus> {
26
21
  const env = args.env ?? process.env;
27
- const facts = describeDesktopAgentRuntimeHostFacts(env);
28
- const decision = resolveAgentRuntimeDecision(buildDesktopAgentRuntimeDecisionInput(env));
29
- return {
30
- ok: true,
31
- host: "desktop",
32
- capabilities: facts.capabilities,
33
- decision,
34
- missingLocalCapabilities: decision.missingLocalCapabilities,
35
- };
22
+ const providerRuntimeSnapshot = await (
23
+ args.readDesktopProviderRuntimeSnapshot ?? readDesktopProviderRuntimeSnapshot
24
+ )();
25
+ return buildDesktopAgentRuntimeReadiness({
26
+ env,
27
+ providerRuntimeSnapshot,
28
+ });
36
29
  }
37
30
 
38
31
  export async function handleDesktopAgentRuntimeStatusGet(
39
32
  _req: Request,
40
- deps: { env?: DesktopAgentRuntimeEnv } = {}
33
+ deps: {
34
+ env?: DesktopAgentRuntimeEnv;
35
+ readDesktopProviderRuntimeSnapshot?: () => Promise<DesktopProviderRuntimeSnapshot>;
36
+ } = {}
41
37
  ) {
42
38
  const env = deps.env ?? process.env;
43
39
  if (env.NOLO_DESKTOP !== "1") {
@@ -47,8 +43,20 @@ export async function handleDesktopAgentRuntimeStatusGet(
47
43
  });
48
44
  }
49
45
 
50
- return new Response(JSON.stringify(buildDesktopAgentRuntimeStatus({ env })), {
51
- status: 200,
52
- headers: JSON_HEADERS,
53
- });
46
+ try {
47
+ return new Response(JSON.stringify(await buildDesktopAgentRuntimeReadinessStatus({
48
+ env,
49
+ readDesktopProviderRuntimeSnapshot: deps.readDesktopProviderRuntimeSnapshot,
50
+ })), {
51
+ status: 200,
52
+ headers: JSON_HEADERS,
53
+ });
54
+ } catch (error) {
55
+ return new Response(JSON.stringify({
56
+ error: error instanceof Error ? error.message : "Failed to read desktop agent runtime readiness",
57
+ }), {
58
+ status: 500,
59
+ headers: JSON_HEADERS,
60
+ });
61
+ }
54
62
  }