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
@@ -28,13 +28,41 @@
28
28
 
29
29
  import { createHash } from "node:crypto";
30
30
  import { ulid } from "ulid";
31
+ import { userActor } from "../../../auth/actor";
31
32
  import { authenticateRequest } from "../../../auth/utils";
32
33
  import { WEB_AUTH_TOKEN_COOKIE } from "../../../auth/tokenCookie";
33
34
  import { getUser } from "../../../auth/server/getUser";
34
35
  import { checkBasicBalance } from "../../../auth/billing";
36
+ import {
37
+ GPT_PRO_REQUIRED_BALANCE,
38
+ hasGptProTierAccess,
39
+ isGptProModel,
40
+ } from "../../../auth/server/gptProAccess";
35
41
  import { chargeTokenUsageWithLedger } from "../../../auth/server/tokenUsageBilling";
36
42
  import { writeServerTokenRecord } from "../../../ai/token/serverTokenWriter";
37
- import serverDb, { ensureServerDbOpen } from "../../../database/server/db";
43
+ import {
44
+ createProviderCallCompletedEvent,
45
+ createProviderCallPendingEvent,
46
+ type ProviderCallEvent,
47
+ } from "../../../ai/token/providerCall";
48
+ import { writeProviderCallEvent } from "../../../ai/token/providerCallWriter";
49
+ import {
50
+ createProviderBillableEvent,
51
+ type ProviderBillableEvent,
52
+ } from "../../../ai/token/providerBillableEvent";
53
+ import { writeProviderBillableEvent } from "../../../ai/token/providerBillableEventWriter";
54
+ import { createRatingResult, type RatingResult } from "../../../ai/token/ratingResult";
55
+ import { writeRatingResult } from "../../../ai/token/ratingResultWriter";
56
+ import type { Usage } from "../../../ai/token/calculatePrice";
57
+ import {
58
+ createBillingAnomaly,
59
+ type BillingAnomaly,
60
+ type BillingAnomalyKind,
61
+ type BillingAnomalySeverity,
62
+ type BillingAnomalyStage,
63
+ } from "../../../ai/token/billingAnomaly";
64
+ import { writeBillingAnomaly } from "../../../ai/token/billingAnomalyWriter";
65
+ import { ensureServerDbOpen, getServerAuthorityStore } from "../../../database/server/db";
38
66
  import { runAgentLoop, buildSseStream } from "./loop";
39
67
  import { incActiveStream, decActiveStream } from "../../serverDrain";
40
68
  import { saveRunAsDialog, createPendingDialog, finalizeDialog, appendToExistingDialog } from "./saveDialog";
@@ -71,7 +99,6 @@ import {
71
99
  } from "./builtinAgents";
72
100
  import { resolveAgentRunAgentConfig } from "./agentLookup";
73
101
  import {
74
- resolveAgentRunDelegation,
75
102
  resolveMachineBindingPreflight,
76
103
  } from "./runtimeRouting";
77
104
  import {
@@ -83,7 +110,7 @@ import {
83
110
  } from "./requestContext";
84
111
  import { buildAgentRunDebugContext } from "./debugContext";
85
112
  import { resolveAgentRunBilledUsage } from "./runBilling";
86
- import { buildInheritedDialogPromptBlock } from "./inheritedDialogPrompt";
113
+ import { buildConversationReferenceBlock } from "./conversationReference";
87
114
  import { completeSyncAgentRunDialog } from "./syncRunDialog";
88
115
  import {
89
116
  AGENT_RUN_CORS_HEADERS as CORS,
@@ -94,6 +121,7 @@ import {
94
121
  import { machineRegistry } from "../machines/machineRegistry";
95
122
  import {
96
123
  ConnectorOfflineError,
124
+ InvalidBoundMachineConfigError,
97
125
  type MachineConnectorRunProgress,
98
126
  resolveAgentRuntimeMachineId,
99
127
  runViaMachineConnector,
@@ -112,6 +140,9 @@ type AgentRunBillingInput = Parameters<typeof resolveAgentRunBilledUsage>[0] & {
112
140
  const DEFAULT_BACKGROUND_RUN_TIMEOUT_MS = 10 * 60_000;
113
141
  const DEFAULT_RUNTIME_PROMPT_PAGE_THRESHOLD_BYTES = 32_000;
114
142
 
143
+ const getAgentRunStore = () => getServerAuthorityStore();
144
+ const serverDb = getAgentRunStore();
145
+
115
146
  function byteLength(value: string) {
116
147
  return Buffer.byteLength(value, "utf8");
117
148
  }
@@ -209,7 +240,11 @@ async function withBackgroundRunTimeout<T>(
209
240
  }
210
241
  }
211
242
 
212
- async function chargeAgentRunTokenCost(userId: string, tokenWrite: AgentRunTokenWrite) {
243
+ async function chargeAgentRunTokenCost(
244
+ userId: string,
245
+ tokenWrite: AgentRunTokenWrite,
246
+ ledgerIdempotencyKey: string,
247
+ ) {
213
248
  return chargeTokenUsageWithLedger({
214
249
  store: serverDb,
215
250
  userId,
@@ -217,9 +252,193 @@ async function chargeAgentRunTokenCost(userId: string, tokenWrite: AgentRunToken
217
252
  tokenRecord: tokenWrite.tokenRecord,
218
253
  reason: "agent_run",
219
254
  txId: `token-${tokenWrite.recordKey}`,
255
+ ledgerIdempotencyKey,
256
+ allowBuyerNegative: true,
220
257
  });
221
258
  }
222
259
 
260
+ function buildAggregateProviderCallLedgerIdempotencyKey(providerCallIds: string[]) {
261
+ const stableSource = [...new Set(providerCallIds)].sort().join("|");
262
+ const sourceHash = createHash("sha256").update(stableSource).digest("hex").slice(0, 16);
263
+ return `provider-call-group:sha256-${sourceHash}:charge:v1`;
264
+ }
265
+
266
+ async function writeProviderCallEventSafely(event: ProviderCallEvent) {
267
+ try {
268
+ await writeProviderCallEvent({ store: serverDb, event });
269
+ } catch (error) {
270
+ console.warn("[billing] Provider-call evidence write failed", {
271
+ providerCallId: event.providerCallId,
272
+ eventId: event.eventId,
273
+ status: event.status,
274
+ error: error instanceof Error ? error.message : String(error),
275
+ });
276
+ await writeBillingAnomalySafely(createAgentRunBillingAnomaly({
277
+ kind: "provider_call_write_failed",
278
+ severity: "high",
279
+ stage: "provider_call",
280
+ userId: event.userId,
281
+ dialogId: event.dialogId,
282
+ agentId: event.agentId,
283
+ provider: event.provider,
284
+ model: event.model,
285
+ providerCallId: event.providerCallId,
286
+ message: "Provider-call evidence write failed",
287
+ evidence: {
288
+ eventId: event.eventId,
289
+ eventStatus: event.status,
290
+ error: error instanceof Error ? error.message : String(error),
291
+ },
292
+ }));
293
+ }
294
+ }
295
+
296
+ async function writeBillingAnomalySafely(anomaly: BillingAnomaly) {
297
+ try {
298
+ await writeBillingAnomaly({ store: serverDb, anomaly });
299
+ } catch (error) {
300
+ console.warn("[billing] Billing anomaly write failed", {
301
+ anomalyId: anomaly.id,
302
+ kind: anomaly.kind,
303
+ providerCallId: anomaly.providerCallId,
304
+ error: error instanceof Error ? error.message : String(error),
305
+ });
306
+ }
307
+ }
308
+
309
+ function createAgentRunBillingAnomaly(args: {
310
+ kind: BillingAnomalyKind;
311
+ severity: BillingAnomalySeverity;
312
+ stage: BillingAnomalyStage;
313
+ userId: string;
314
+ dialogId?: string;
315
+ agentId?: string;
316
+ provider: string;
317
+ model: string;
318
+ providerCallId?: string;
319
+ billableEventId?: string;
320
+ ratingResultId?: string;
321
+ riskPlatformCredits?: number;
322
+ message: string;
323
+ evidence: Record<string, unknown>;
324
+ }) {
325
+ return createBillingAnomaly({
326
+ anomalyId: `anom_${ulid()}`,
327
+ kind: args.kind,
328
+ severity: args.severity,
329
+ stage: args.stage,
330
+ userId: args.userId,
331
+ dialogId: args.dialogId,
332
+ agentId: args.agentId,
333
+ provider: args.provider,
334
+ model: args.model,
335
+ providerCallId: args.providerCallId,
336
+ billableEventId: args.billableEventId,
337
+ ratingResultId: args.ratingResultId,
338
+ riskPlatformCredits: args.riskPlatformCredits,
339
+ message: args.message,
340
+ evidence: args.evidence,
341
+ createdAt: new Date().toISOString(),
342
+ });
343
+ }
344
+
345
+ async function writeProviderBillableEventSafely(event: ProviderBillableEvent) {
346
+ try {
347
+ await writeProviderBillableEvent({ store: serverDb, event });
348
+ } catch (error) {
349
+ console.warn("[billing] Provider billable event write failed", {
350
+ billableEventId: event.id,
351
+ sourceProviderCallIds: event.sourceProviderCallIds,
352
+ provider: event.provider,
353
+ model: event.model,
354
+ error: error instanceof Error ? error.message : String(error),
355
+ });
356
+ await writeBillingAnomalySafely(createAgentRunBillingAnomaly({
357
+ kind: "billable_event_write_failed",
358
+ severity: "high",
359
+ stage: "billable_event",
360
+ userId: event.userId,
361
+ dialogId: event.dialogId,
362
+ agentId: event.agentId,
363
+ provider: event.provider,
364
+ model: event.model,
365
+ providerCallId: event.sourceProviderCallIds[0],
366
+ billableEventId: event.id,
367
+ message: "Provider billable event write failed",
368
+ evidence: {
369
+ sourceProviderCallIds: event.sourceProviderCallIds,
370
+ error: error instanceof Error ? error.message : String(error),
371
+ },
372
+ }));
373
+ }
374
+ }
375
+
376
+ async function writeRatingResultSafely(
377
+ rating: RatingResult,
378
+ context: {
379
+ userId: string;
380
+ dialogId?: string;
381
+ agentId?: string;
382
+ providerCallId?: string;
383
+ },
384
+ ) {
385
+ try {
386
+ await writeRatingResult({ store: serverDb, rating });
387
+ } catch (error) {
388
+ console.warn("[billing] Rating result write failed", {
389
+ ratingId: rating.id,
390
+ billableEventId: rating.billableEventId,
391
+ provider: rating.provider,
392
+ model: rating.model,
393
+ error: error instanceof Error ? error.message : String(error),
394
+ });
395
+ await writeBillingAnomalySafely(createAgentRunBillingAnomaly({
396
+ kind: "rating_failed",
397
+ severity: "high",
398
+ stage: "rating",
399
+ userId: context.userId,
400
+ dialogId: context.dialogId,
401
+ agentId: context.agentId,
402
+ provider: rating.provider,
403
+ model: rating.model,
404
+ providerCallId: context.providerCallId,
405
+ billableEventId: rating.billableEventId,
406
+ ratingResultId: rating.id,
407
+ riskPlatformCredits: rating.platformCredits,
408
+ message: "Rating result write failed",
409
+ evidence: {
410
+ error: error instanceof Error ? error.message : String(error),
411
+ snapshot: rating.snapshot,
412
+ },
413
+ }));
414
+ }
415
+ }
416
+
417
+ function numberOrZero(value: unknown) {
418
+ return typeof value === "number" && Number.isFinite(value) ? value : 0;
419
+ }
420
+
421
+ function normalizeAgentRunBillingUsage(rawUsage: Record<string, any>): Usage {
422
+ return {
423
+ input_tokens: numberOrZero(rawUsage.input_tokens ?? rawUsage.prompt_tokens),
424
+ output_tokens: numberOrZero(rawUsage.output_tokens ?? rawUsage.completion_tokens),
425
+ cache_creation_input_tokens: numberOrZero(rawUsage.cache_creation_input_tokens),
426
+ cache_read_input_tokens: numberOrZero(rawUsage.cache_read_input_tokens),
427
+ ...(typeof rawUsage.cost === "number" ? { cost: rawUsage.cost } : {}),
428
+ ...(typeof rawUsage.billing_service_tier === "string"
429
+ ? { billing_service_tier: rawUsage.billing_service_tier }
430
+ : {}),
431
+ ...(typeof rawUsage.image_generation_count === "number"
432
+ ? { image_generation_count: rawUsage.image_generation_count }
433
+ : {}),
434
+ };
435
+ }
436
+
437
+ function resolveEstimateReason(rawUsage: Record<string, any>) {
438
+ const reason = rawUsage.billing_estimate_reason ?? rawUsage.estimateReason ?? rawUsage.estimate_reason;
439
+ return typeof reason === "string" && reason.trim() ? reason.trim() : undefined;
440
+ }
441
+
223
442
  async function projectBackgroundDialogActivity(args: {
224
443
  dialogId: string;
225
444
  dialogKey: string;
@@ -384,6 +603,43 @@ async function writeAgentRunBillingIfNeeded(args: AgentRunBillingInput) {
384
603
  });
385
604
  if (!args.userId || !billedUsage) return;
386
605
 
606
+ const rawUsage = billedUsage as any;
607
+ const physicalProviderCallIds = Array.isArray(args.result.providerCallIds)
608
+ ? args.result.providerCallIds.filter((id): id is string => typeof id === "string" && id.trim().startsWith("call_"))
609
+ : [];
610
+ const hasAggregatePhysicalUsage = physicalProviderCallIds.length > 1;
611
+ const providerCallId = physicalProviderCallIds[physicalProviderCallIds.length - 1] ?? `call_${ulid()}`;
612
+ const providerCallStartedAt = new Date().toISOString();
613
+ const billingProvider =
614
+ rawUsage.billing_provider ??
615
+ billingAgentConfig.provider ??
616
+ args.result.provider ??
617
+ "unknown";
618
+ const billingModel =
619
+ rawUsage.billing_model ??
620
+ billingAgentConfig.model ??
621
+ args.result.model ??
622
+ "unknown";
623
+ const billingServiceTier =
624
+ rawUsage.billing_service_tier ??
625
+ billingAgentConfig.billingServiceTier ??
626
+ billingAgentConfig.serviceTier;
627
+
628
+ if (physicalProviderCallIds.length === 0) {
629
+ await writeProviderCallEventSafely(createProviderCallPendingEvent({
630
+ providerCallId,
631
+ eventId: `evt_${ulid()}`,
632
+ userId: args.userId,
633
+ dialogId: args.dialogId,
634
+ agentId: args.agentKey,
635
+ provider: billingProvider,
636
+ model: billingModel,
637
+ endpoint: "agentRun",
638
+ ...(billingServiceTier ? { serviceTier: String(billingServiceTier) } : {}),
639
+ startedAt: providerCallStartedAt,
640
+ }));
641
+ }
642
+
387
643
  const tokenWrite = await writeServerTokenRecord({
388
644
  userId: args.userId,
389
645
  agentKey: args.agentKey,
@@ -391,7 +647,120 @@ async function writeAgentRunBillingIfNeeded(args: AgentRunBillingInput) {
391
647
  runId: args.dialogId,
392
648
  rawUsage: billedUsage as any,
393
649
  });
394
- if (tokenWrite.cost > 0) await chargeAgentRunTokenCost(args.userId, tokenWrite);
650
+ const normalizedBillingUsage = normalizeAgentRunBillingUsage(rawUsage);
651
+ if (!hasAggregatePhysicalUsage) {
652
+ await writeProviderCallEventSafely(createProviderCallCompletedEvent({
653
+ providerCallId,
654
+ eventId: `evt_${ulid()}`,
655
+ userId: args.userId,
656
+ dialogId: args.dialogId,
657
+ agentId: args.agentKey,
658
+ provider: billingProvider,
659
+ model: billingModel,
660
+ endpoint: "agentRun",
661
+ ...(billingServiceTier ? { serviceTier: String(billingServiceTier) } : {}),
662
+ startedAt: providerCallStartedAt,
663
+ completedAt: new Date().toISOString(),
664
+ inputTokens: normalizedBillingUsage.input_tokens,
665
+ outputTokens: normalizedBillingUsage.output_tokens,
666
+ cacheCreationInputTokens: normalizedBillingUsage.cache_creation_input_tokens,
667
+ cacheReadInputTokens: normalizedBillingUsage.cache_read_input_tokens,
668
+ platformCredits: tokenWrite.cost,
669
+ pricingVersion: "model-registry-current",
670
+ billingStatus: tokenWrite.cost > 0 ? "pending_ledger" : "zero_policy",
671
+ }));
672
+ }
673
+ const billableEventId = `billable_${ulid()}`;
674
+ const ledgerIdempotencyKey = hasAggregatePhysicalUsage
675
+ ? buildAggregateProviderCallLedgerIdempotencyKey(physicalProviderCallIds)
676
+ : `provider-call:${providerCallId}:charge:v1`;
677
+ const billableEvent = createProviderBillableEvent({
678
+ eventId: billableEventId,
679
+ operationId: args.dialogId,
680
+ sourceProviderCallIds: physicalProviderCallIds.length > 0
681
+ ? [...physicalProviderCallIds]
682
+ : [providerCallId],
683
+ userId: args.userId,
684
+ dialogId: args.dialogId,
685
+ agentId: args.agentKey,
686
+ provider: billingProvider,
687
+ model: billingModel,
688
+ endpoint: "agentRun",
689
+ kind: "llm_tokens",
690
+ usage: {
691
+ inputTokens: normalizedBillingUsage.input_tokens,
692
+ outputTokens: normalizedBillingUsage.output_tokens,
693
+ cacheCreationInputTokens: normalizedBillingUsage.cache_creation_input_tokens,
694
+ cacheReadInputTokens: normalizedBillingUsage.cache_read_input_tokens,
695
+ },
696
+ estimated: rawUsage.billing_estimated === true,
697
+ estimateReason: resolveEstimateReason(rawUsage),
698
+ needsReconciliation: hasAggregatePhysicalUsage,
699
+ createdAt: new Date().toISOString(),
700
+ });
701
+ await writeProviderBillableEventSafely(billableEvent);
702
+ if (hasAggregatePhysicalUsage) {
703
+ await writeBillingAnomalySafely(createAgentRunBillingAnomaly({
704
+ kind: "aggregate_usage_unallocated",
705
+ severity: "medium",
706
+ stage: "usage",
707
+ userId: args.userId,
708
+ dialogId: args.dialogId,
709
+ agentId: args.agentKey,
710
+ provider: billingProvider,
711
+ model: billingModel,
712
+ providerCallId,
713
+ billableEventId,
714
+ riskPlatformCredits: tokenWrite.cost,
715
+ message: "Aggregate agent-run usage spans multiple physical provider calls and needs per-call allocation",
716
+ evidence: {
717
+ sourceProviderCallIds: physicalProviderCallIds,
718
+ ledgerIdempotencyKey,
719
+ usage: normalizedBillingUsage,
720
+ tokenKey: tokenWrite.recordKey,
721
+ },
722
+ }));
723
+ }
724
+ await writeRatingResultSafely(createRatingResult({
725
+ ratingId: `rating_${ulid()}`,
726
+ billableEventId,
727
+ provider: billingProvider,
728
+ model: billingModel,
729
+ ...(billingServiceTier ? { serviceTier: String(billingServiceTier) } : {}),
730
+ usage: normalizedBillingUsage,
731
+ createdAt: new Date().toISOString(),
732
+ }), {
733
+ userId: args.userId,
734
+ dialogId: args.dialogId,
735
+ agentId: args.agentKey,
736
+ providerCallId,
737
+ });
738
+ if (tokenWrite.cost > 0) {
739
+ const ledgerResult = await chargeAgentRunTokenCost(args.userId, tokenWrite, ledgerIdempotencyKey);
740
+ if (!ledgerResult.success) {
741
+ await writeBillingAnomalySafely(createAgentRunBillingAnomaly({
742
+ kind: "ledger_failed",
743
+ severity: "critical",
744
+ stage: "ledger",
745
+ userId: args.userId,
746
+ dialogId: args.dialogId,
747
+ agentId: args.agentKey,
748
+ provider: billingProvider,
749
+ model: billingModel,
750
+ providerCallId,
751
+ billableEventId,
752
+ riskPlatformCredits: tokenWrite.cost,
753
+ message: "Provider-call ledger charge failed",
754
+ evidence: {
755
+ ledgerStatus: ledgerResult.status,
756
+ error: ledgerResult.error,
757
+ tokenKey: tokenWrite.recordKey,
758
+ txId: ledgerResult.txId,
759
+ ledgerIdempotencyKey,
760
+ },
761
+ }));
762
+ }
763
+ }
395
764
  } catch (error) {
396
765
  console.warn("[billing] Agent run billing write failed; preserving dialog result", {
397
766
  dialogId: args.dialogId,
@@ -455,16 +824,11 @@ const extractAgentRunUserText = (userInput: AgentRunRequest["userInput"]): strin
455
824
  const buildAgentRunUserMessageContent = (
456
825
  userInput: AgentRunRequest["userInput"],
457
826
  turnInstruction?: string | null,
458
- prelude?: string | null,
459
827
  ): ChatMessage["content"] => {
460
828
  const normalizedTurnInstruction =
461
829
  typeof turnInstruction === "string" && turnInstruction.trim()
462
830
  ? turnInstruction.trim()
463
831
  : "";
464
- const normalizedPrelude =
465
- typeof prelude === "string" && prelude.trim()
466
- ? prelude.trim()
467
- : "";
468
832
  const normalizedParts = normalizeAgentRunUserParts(userInput);
469
833
  if (normalizedParts.length > 0) {
470
834
  // Inject URL hints so the model uses original HTTPS URLs in tool calls
@@ -484,9 +848,6 @@ const buildAgentRunUserMessageContent = (
484
848
  : null;
485
849
 
486
850
  return [
487
- ...(normalizedPrelude
488
- ? [{ type: "text" as const, text: `${normalizedPrelude}\n\n--- User task ---` }]
489
- : []),
490
851
  ...(normalizedTurnInstruction
491
852
  ? [{ type: "text" as const, text: `${normalizedTurnInstruction}\n\n--- User task ---` }]
492
853
  : []),
@@ -503,14 +864,13 @@ const buildAgentRunUserMessageContent = (
503
864
  }
504
865
 
505
866
  const userText = extractAgentRunUserText(userInput);
506
- const prefix = [normalizedPrelude, normalizedTurnInstruction].filter(Boolean).join("\n\n");
507
- if (!prefix) {
867
+ if (!normalizedTurnInstruction) {
508
868
  return userText;
509
869
  }
510
870
  if (!userText) {
511
- return prefix;
871
+ return normalizedTurnInstruction;
512
872
  }
513
- return [prefix, "--- User task ---", userText].join("\n\n");
873
+ return [normalizedTurnInstruction, "--- User task ---", userText].join("\n\n");
514
874
  };
515
875
 
516
876
  function resolveDirectSpecialistAgentKey(args: {
@@ -655,6 +1015,7 @@ function buildBillableForegroundSseStream(
655
1015
  let lastInputPrice = context.agentConfig.inputPrice;
656
1016
  let lastOutputPrice = context.agentConfig.outputPrice;
657
1017
  let lastArtifacts: unknown;
1018
+ let lastProviderCallIds: string[] | undefined;
658
1019
  let toolCallCount = 0;
659
1020
  let sawDone = false;
660
1021
  const trace: ChatMessage[] = [];
@@ -711,6 +1072,11 @@ function buildBillableForegroundSseStream(
711
1072
  ? payload.outputPrice
712
1073
  : lastOutputPrice;
713
1074
  lastArtifacts = payload.artifacts ?? lastArtifacts;
1075
+ if (Array.isArray(payload.providerCallIds)) {
1076
+ lastProviderCallIds = payload.providerCallIds.filter(
1077
+ (id: unknown): id is string => typeof id === "string" && id.trim()
1078
+ );
1079
+ }
714
1080
  if (assistantText) {
715
1081
  trace.push({ role: "assistant", content: assistantText });
716
1082
  }
@@ -750,6 +1116,7 @@ function buildBillableForegroundSseStream(
750
1116
  inputPrice: lastInputPrice,
751
1117
  outputPrice: lastOutputPrice,
752
1118
  usage: lastUsage,
1119
+ ...(lastProviderCallIds?.length ? { providerCallIds: lastProviderCallIds } : {}),
753
1120
  ...(lastArtifacts ? { artifacts: lastArtifacts } : {}),
754
1121
  trace,
755
1122
  runtimeToolNames: [],
@@ -850,6 +1217,13 @@ function shouldBypassBalanceForLocalSmokeAgent(
850
1217
  }
851
1218
 
852
1219
  function resolveConnectorFailureResponse(error: any, agentConfig: any): Response | null {
1220
+ if (error instanceof InvalidBoundMachineConfigError) {
1221
+ return agentRunJson({
1222
+ error: "Invalid runtime binding",
1223
+ reason: error.reason,
1224
+ message: error.message,
1225
+ }, error.status);
1226
+ }
853
1227
  if (error instanceof ConnectorOfflineError) {
854
1228
  return agentRunJson({
855
1229
  error: "Connector offline",
@@ -925,7 +1299,7 @@ export async function handleAgentRun(req: Request): Promise<Response> {
925
1299
  const {
926
1300
  requestedAgentKey,
927
1301
  userInput,
928
- history,
1302
+ requestHistory,
929
1303
  stream,
930
1304
  runtimeContext,
931
1305
  effectiveMaxRounds,
@@ -978,32 +1352,18 @@ export async function handleAgentRun(req: Request): Promise<Response> {
978
1352
  try { await ensureServerDbOpen(); } catch (e: any) { return agentRunError(e.message, 500); }
979
1353
  const agentLookup = await resolveAgentRunAgentConfig({
980
1354
  agentKey,
981
- getAgentRecord: (key) => serverDb.get(key),
1355
+ getAgentRecord: (key) => getAgentRunStore().get(key),
982
1356
  });
983
1357
  if (!agentLookup.ok) {
984
1358
  return agentRunError(agentLookup.message, agentLookup.status);
985
1359
  }
986
- let agentConfig: any = agentLookup.agentConfig;
987
- agentConfig = {
988
- ...agentConfig,
989
- dbKey: agentConfig.dbKey ?? agentKey,
1360
+ const storedAgentConfig = {
1361
+ ...agentLookup.agentConfig,
1362
+ dbKey: agentLookup.agentConfig.dbKey ?? agentKey,
990
1363
  };
991
1364
 
992
- const runtimeDelegation = resolveAgentRunDelegation({ agentConfig, serverBase });
993
- if (!runtimeDelegation.ok) {
994
- return agentRunError(runtimeDelegation.message, runtimeDelegation.status);
995
- }
996
- if (runtimeDelegation.route === "remote") {
997
- return proxyAgentRunToRemote({
998
- targetBase: runtimeDelegation.targetBase,
999
- body,
1000
- authToken,
1001
- stream,
1002
- });
1003
- }
1004
-
1005
1365
  const machineBinding = resolveMachineBindingPreflight({
1006
- agentConfig,
1366
+ agentConfig: storedAgentConfig,
1007
1367
  userId,
1008
1368
  listMachines: (ownerUserId) => machineRegistry.listMachines(ownerUserId),
1009
1369
  });
@@ -1016,47 +1376,83 @@ export async function handleAgentRun(req: Request): Promise<Response> {
1016
1376
  authToken,
1017
1377
  });
1018
1378
  const taskRunPreflightPrompt = taskRunPreflight.prompt;
1019
- agentConfig = await prepareAgentRunRuntimeConfig({
1020
- agentConfig,
1379
+ const currentUserActor = userActor(userId);
1380
+ const fetchAuthorizedDialogMessages = (args: { dialogId: string; limit: number }) =>
1381
+ fetchConvMsgs(args, {
1382
+ userId,
1383
+ actor: currentUserActor,
1384
+ });
1385
+ if (continueDialogId && (body.inheritedFromDialogKey || body.parentDialogId)) {
1386
+ console.info("[agentRun] continue-history-overrides-inherited-reference", {
1387
+ continueDialogId,
1388
+ inheritedFromDialogKey: body.inheritedFromDialogKey ?? null,
1389
+ parentDialogId: body.parentDialogId ?? null,
1390
+ });
1391
+ }
1392
+ const preparedRuntimeConfig = await prepareAgentRunRuntimeConfig({
1393
+ agentConfig: storedAgentConfig,
1021
1394
  runtimeContext,
1022
1395
  taskRunPreflightPrompt,
1023
1396
  runtimeOptions,
1024
1397
  parentDialogId,
1025
1398
  inheritedFromDialogKey,
1399
+ includeConversationReference: !continueDialogId,
1026
1400
  resolveReferenceRuntime: (references) =>
1027
1401
  resolveServerReferenceRuntime({
1028
1402
  references,
1029
1403
  loadPage: async (identifier: string) => {
1030
1404
  try {
1031
- return await serverDb.get(identifier);
1405
+ return await getAgentRunStore().get(identifier);
1032
1406
  } catch {
1033
1407
  return null;
1034
1408
  }
1035
1409
  },
1036
1410
  }),
1037
- buildInheritedDialogPromptBlock: (args) =>
1038
- buildInheritedDialogPromptBlock({
1411
+ buildConversationReferenceBlock: (args) =>
1412
+ buildConversationReferenceBlock({
1039
1413
  ...args,
1040
1414
  getDialogRecord: async (dialogKey) => {
1041
1415
  try {
1042
- return await serverDb.get(dialogKey);
1416
+ return await getAgentRunStore().get(dialogKey);
1043
1417
  } catch {
1044
1418
  return null;
1045
1419
  }
1046
1420
  },
1047
- fetchConversationMessages: fetchConvMsgs,
1421
+ fetchConversationMessages: fetchAuthorizedDialogMessages,
1048
1422
  }),
1049
1423
  });
1424
+ const {
1425
+ runtimeEntrypointBlock,
1426
+ taskRunPreflightBlock,
1427
+ referenceRuntimeBlock,
1428
+ conversationReferenceBlock,
1429
+ editingContextBlock,
1430
+ ...preparedAgentConfig
1431
+ } = preparedRuntimeConfig;
1432
+ const runtimePreparedAgentConfig = preparedAgentConfig;
1050
1433
  const runtimeToolPolicySnapshot = resolveEffectiveRuntimeToolPolicy({
1051
- agentConfig,
1052
- taskRunControl: taskRunPreflight.control,
1053
- host: "web",
1434
+ agentConfig: runtimePreparedAgentConfig,
1054
1435
  });
1055
1436
 
1056
1437
  // 余额检查(仅 JWT 登录用户)
1057
- const bypassBalanceCheck = shouldBypassBalanceForLocalSmokeAgent(agentKey, agentConfig, serverBase);
1438
+ const bypassBalanceCheck = shouldBypassBalanceForLocalSmokeAgent(
1439
+ agentKey,
1440
+ runtimePreparedAgentConfig,
1441
+ serverBase,
1442
+ );
1058
1443
  if (userId && !bypassBalanceCheck) {
1059
1444
  const user = await getUser(userId);
1445
+ if (isGptProModel(runtimePreparedAgentConfig.provider, runtimePreparedAgentConfig.model)) {
1446
+ const gptProAccess = hasGptProTierAccess({ userData: user });
1447
+ if (!gptProAccess.allowed) {
1448
+ return agentRunJson({
1449
+ error: "GPT Pro requires 199 current balance",
1450
+ reason: "gpt_pro_tier_required",
1451
+ requiredBalance: GPT_PRO_REQUIRED_BALANCE,
1452
+ message: `GPT Pro 系列需要当前余额大于等于 ${GPT_PRO_REQUIRED_BALANCE}。`,
1453
+ }, 402);
1454
+ }
1455
+ }
1060
1456
  const balanceCheck = checkBasicBalance(user?.balance ?? 0);
1061
1457
  if (!balanceCheck.allowed) {
1062
1458
  return agentRunJson({ error: balanceCheck.error }, 402);
@@ -1070,15 +1466,15 @@ export async function handleAgentRun(req: Request): Promise<Response> {
1070
1466
  continueDialogUserId,
1071
1467
  } = await resolveContinueDialogContext({
1072
1468
  continueDialogId,
1073
- history,
1469
+ requestHistoryFallback: requestHistory,
1074
1470
  userId,
1075
1471
  resolveExistingDialogRef,
1076
- fetchConvMsgs,
1472
+ fetchConvMsgs: fetchAuthorizedDialogMessages,
1077
1473
  summarizeMessagesForDebug,
1078
1474
  });
1079
1475
 
1080
1476
  const executionContext = await prepareAgentRunExecutionContext({
1081
- agentConfig,
1477
+ agentConfig: runtimePreparedAgentConfig,
1082
1478
  agentKey,
1083
1479
  userId,
1084
1480
  userInput,
@@ -1087,9 +1483,13 @@ export async function handleAgentRun(req: Request): Promise<Response> {
1087
1483
  spaceId,
1088
1484
  runtimeProfile,
1089
1485
  existingDialogRecord,
1090
- taskRunPreflightPrompt,
1486
+ runtimeEntrypointBlock,
1487
+ taskRunPreflightBlock,
1488
+ referenceRuntimeBlock,
1489
+ conversationReferenceBlock,
1490
+ editingContextBlock,
1091
1491
  loadUserSettings: (settingsUserId) =>
1092
- serverDb.get(createUserKey.settings(settingsUserId)),
1492
+ getAgentRunStore().get(createUserKey.settings(settingsUserId)),
1093
1493
  resolveRuntimePolicy,
1094
1494
  buildUserPolicyContext,
1095
1495
  resolveMemoryRuntime,
@@ -1099,16 +1499,125 @@ export async function handleAgentRun(req: Request): Promise<Response> {
1099
1499
  canonicalizeToolNames,
1100
1500
  prioritizeToolNames,
1101
1501
  });
1102
- agentConfig = executionContext.agentConfig;
1103
- const runtimePolicy = executionContext.runtimePolicy;
1502
+ const executionAgentConfig = executionContext.agentConfig;
1503
+ const executionRuntimePolicy = executionContext.runtimePolicy;
1104
1504
  const effectiveRuntimeProfile = executionContext.effectiveRuntimeProfile;
1105
- const memoryRuntime = executionContext.memoryRuntime;
1106
- const autonomousRuntime = executionContext.autonomousRuntime;
1505
+ const executionMemoryRuntime = executionContext.memoryRuntime;
1107
1506
  const runtimeSystemMessageContext = executionContext.runtimeSystemMessageContext;
1108
- const messages = executionContext.messages;
1507
+ const executionMessages = executionContext.messages;
1508
+ const executionMachineId = resolveAgentRuntimeMachineId(executionAgentConfig);
1509
+ const buildExecutionWorkspaceLease = (
1510
+ connectorResult: ConnectorAgentRunResult | null | undefined,
1511
+ ) =>
1512
+ buildWorkspaceLeaseFromConnectorResult({
1513
+ result: connectorResult,
1514
+ agentKey,
1515
+ machineId: executionMachineId,
1516
+ runtimeToolPolicySnapshot,
1517
+ });
1518
+ const runExecutionConnector = async (args: {
1519
+ userId: string;
1520
+ requestTimeoutMs?: number;
1521
+ runtimePromptPage?: Record<string, unknown> | null;
1522
+ onProgress?: (progress: MachineConnectorRunProgress) => Promise<void>;
1523
+ }) =>
1524
+ runViaMachineConnector({
1525
+ agentConfig: executionAgentConfig,
1526
+ agentKey,
1527
+ authToken,
1528
+ category,
1529
+ continueDialogId: continueDialogId ?? undefined,
1530
+ messages: executionMessages,
1531
+ runtimeContext,
1532
+ spaceId,
1533
+ userId: args.userId,
1534
+ userInput: userInputText,
1535
+ requestTimeoutMs: args.requestTimeoutMs,
1536
+ runtimeToolPolicySnapshot,
1537
+ ...(args.runtimePromptPage ? { runtimePromptPage: args.runtimePromptPage } : {}),
1538
+ ...(args.onProgress ? { onProgress: args.onProgress } : {}),
1539
+ });
1540
+ const runExecutionLoop = (args: {
1541
+ userId: string;
1542
+ dialogId?: string;
1543
+ spaceId?: string | null;
1544
+ }) =>
1545
+ runAgentLoopImpl(
1546
+ executionAgentConfig,
1547
+ executionMessages,
1548
+ effectiveMaxRounds,
1549
+ serverBase,
1550
+ authToken,
1551
+ executionRuntimePolicy,
1552
+ args.userId,
1553
+ args.dialogId,
1554
+ args.spaceId,
1555
+ userInputText,
1556
+ runtimeContext,
1557
+ serverDb,
1558
+ );
1559
+ const runExecutionResult = async (args: {
1560
+ userId: string;
1561
+ dialogId?: string;
1562
+ spaceId?: string | null;
1563
+ requestTimeoutMs?: number;
1564
+ runtimePromptPage?: Record<string, unknown> | null;
1565
+ onProgress?: (progress: MachineConnectorRunProgress) => Promise<void>;
1566
+ }) => {
1567
+ const connectorResult = await runExecutionConnector({
1568
+ userId: args.userId,
1569
+ requestTimeoutMs: args.requestTimeoutMs,
1570
+ runtimePromptPage: args.runtimePromptPage,
1571
+ onProgress: args.onProgress,
1572
+ });
1573
+ return {
1574
+ connectorResult,
1575
+ workspaceLease: buildExecutionWorkspaceLease(connectorResult),
1576
+ result: (connectorResult ?? await runExecutionLoop({
1577
+ userId: args.userId,
1578
+ dialogId: args.dialogId,
1579
+ spaceId: args.spaceId,
1580
+ })) as LoopResult,
1581
+ };
1582
+ };
1583
+ const buildExecutionSourceStream = (args: {
1584
+ userId: string;
1585
+ dialogId: string;
1586
+ spaceId?: string | null;
1587
+ }) =>
1588
+ buildSseStreamImpl(
1589
+ executionAgentConfig,
1590
+ executionMessages,
1591
+ effectiveMaxRounds,
1592
+ serverBase,
1593
+ authToken,
1594
+ executionRuntimePolicy,
1595
+ args.userId,
1596
+ args.dialogId,
1597
+ args.spaceId,
1598
+ userInputText,
1599
+ runtimeContext,
1600
+ serverDb,
1601
+ );
1602
+ const dialogLifecyclePersistenceContext = {
1603
+ userId,
1604
+ callerType,
1605
+ userInput: userInputText,
1606
+ spaceId,
1607
+ category,
1608
+ inheritedFromDialogKey,
1609
+ parentDialogId,
1610
+ runtimeProfile: effectiveRuntimeProfile,
1611
+ runtimeContext,
1612
+ runtimeToolPolicySnapshot,
1613
+ };
1614
+ const buildPendingDialogInput = (pendingAgentKey: string) => ({
1615
+ agentKey: pendingAgentKey,
1616
+ ...dialogLifecyclePersistenceContext,
1617
+ });
1109
1618
 
1110
1619
  try {
1111
- await ensureLocalModelRuntimeIfNeeded(agentConfig);
1620
+ await ensureLocalModelRuntimeIfNeeded(executionAgentConfig);
1112
1621
  } catch (e: any) {
1113
1622
  if (isLocalRuntimeUnavailableError(e)) {
1114
1623
  return agentRunJson({
@@ -1139,112 +1648,81 @@ export async function handleAgentRun(req: Request): Promise<Response> {
1139
1648
  continueDialogUserId,
1140
1649
  fallbackSpaceId: spaceId,
1141
1650
  createPendingDialog,
1142
- pendingDialogInput: {
1143
- agentKey: dialogAgentKey,
1144
- userId,
1145
- callerType,
1146
- userInput: userInputText,
1147
- spaceId,
1148
- category,
1149
- inheritedFromDialogKey,
1150
- parentDialogId,
1151
- runtimeProfile: effectiveRuntimeProfile,
1152
- runtimeContext,
1153
- runtimeToolPolicySnapshot,
1154
- },
1651
+ pendingDialogInput: buildPendingDialogInput(dialogAgentKey),
1155
1652
  });
1156
1653
  return {
1157
1654
  ...prepared,
1158
1655
  persistDialog: true,
1159
1656
  };
1160
1657
  };
1658
+ const buildForegroundStreamLifecycleContext = (args: {
1659
+ streamDialog: Awaited<ReturnType<typeof prepareCurrentForegroundStreamDialog>>;
1660
+ startedAt: number;
1661
+ workspaceLease?: Record<string, unknown>;
1662
+ }) => ({
1663
+ agentConfig: executionAgentConfig,
1664
+ agentKey,
1665
+ dialogAgentKey,
1666
+ traceAgentKey,
1667
+ userId: args.streamDialog.effectiveUserId,
1668
+ dialogId: args.streamDialog.dialogId,
1669
+ dialogKey: args.streamDialog.dialogKey,
1670
+ userInputText,
1671
+ startedAt: args.startedAt,
1672
+ isContinue: Boolean(continueDialogId),
1673
+ spaceId: args.streamDialog.effectiveSpaceId,
1674
+ runtimeProfile: effectiveRuntimeProfile,
1675
+ runtimeToolPolicySnapshot,
1676
+ persistDialog: args.streamDialog.persistDialog,
1677
+ ...(args.workspaceLease ? { workspaceLease: args.workspaceLease } : {}),
1678
+ });
1161
1679
 
1162
1680
  if (stream) {
1163
- try {
1164
- const connectorResult = await runViaMachineConnector({
1165
- agentConfig,
1166
- agentKey,
1167
- category,
1168
- continueDialogId: continueDialogId ?? undefined,
1169
- messages,
1170
- runtimeContext,
1171
- spaceId,
1172
- userId,
1173
- userInput: userInputText,
1174
- requestTimeoutMs: effectiveAgentRunTimeoutMs,
1175
- runtimeToolPolicySnapshot,
1176
- });
1177
- if (connectorResult) {
1178
- const workspaceLease = buildWorkspaceLeaseFromConnectorResult({
1179
- result: connectorResult,
1180
- agentKey,
1181
- machineId: resolveAgentRuntimeMachineId(agentConfig),
1182
- runtimeToolPolicySnapshot,
1681
+ const dispatchForegroundStreamExecution = async () => {
1682
+ try {
1683
+ const connectorResult = await runExecutionConnector({
1684
+ userId,
1685
+ requestTimeoutMs: effectiveAgentRunTimeoutMs,
1183
1686
  });
1184
- const streamDialog = await prepareCurrentForegroundStreamDialog();
1185
- const startedAt = Date.now();
1186
- return agentRunSse(buildBillableForegroundSseStream(
1187
- buildMachineConnectorSseStream(connectorResult),
1188
- {
1189
- agentConfig,
1190
- agentKey,
1191
- dialogAgentKey,
1192
- traceAgentKey,
1193
- userId: streamDialog.effectiveUserId,
1194
- dialogId: streamDialog.dialogId,
1195
- dialogKey: streamDialog.dialogKey,
1196
- userInputText,
1197
- startedAt,
1198
- isContinue: Boolean(continueDialogId),
1199
- spaceId: streamDialog.effectiveSpaceId,
1200
- runtimeProfile: effectiveRuntimeProfile,
1201
- runtimeToolPolicySnapshot,
1202
- workspaceLease,
1203
- persistDialog: streamDialog.persistDialog,
1204
- }
1205
- ));
1687
+ if (connectorResult) {
1688
+ const workspaceLease = buildExecutionWorkspaceLease(connectorResult);
1689
+ const streamDialog = await prepareCurrentForegroundStreamDialog();
1690
+ const startedAt = Date.now();
1691
+ return agentRunSse(buildBillableForegroundSseStream(
1692
+ buildMachineConnectorSseStream(connectorResult),
1693
+ buildForegroundStreamLifecycleContext({
1694
+ streamDialog,
1695
+ startedAt,
1696
+ workspaceLease,
1697
+ })
1698
+ ));
1699
+ }
1700
+ } catch (e: any) {
1701
+ const connectorFailureResponse = resolveConnectorFailureResponse(e, executionAgentConfig);
1702
+ if (connectorFailureResponse) return connectorFailureResponse;
1703
+ throw e;
1206
1704
  }
1207
- } catch (e: any) {
1208
- const connectorFailureResponse = resolveConnectorFailureResponse(e, agentConfig);
1209
- if (connectorFailureResponse) return connectorFailureResponse;
1210
- throw e;
1211
- }
1212
- let streamDialog: Awaited<ReturnType<typeof prepareForegroundStreamDialog>>;
1213
- try {
1214
- streamDialog = await prepareCurrentForegroundStreamDialog();
1215
- } catch (e: any) {
1216
- return agentRunError(e.message ?? "Failed to create dialog", e.status ?? 500);
1217
- }
1218
- const startedAt = Date.now();
1219
- const sourceStream = buildSseStreamImpl(
1220
- agentConfig,
1221
- messages,
1222
- effectiveMaxRounds,
1223
- serverBase,
1224
- authToken,
1225
- runtimePolicy,
1226
- streamDialog.effectiveUserId,
1227
- streamDialog.dialogId,
1228
- streamDialog.effectiveSpaceId,
1229
- userInputText,
1230
- runtimeContext,
1231
- );
1232
- return agentRunSse(buildBillableForegroundSseStream(sourceStream, {
1233
- agentConfig,
1234
- agentKey,
1235
- dialogAgentKey,
1236
- traceAgentKey,
1237
- userId: streamDialog.effectiveUserId,
1238
- dialogId: streamDialog.dialogId,
1239
- dialogKey: streamDialog.dialogKey,
1240
- userInputText,
1241
- startedAt,
1242
- isContinue: Boolean(continueDialogId),
1243
- spaceId: streamDialog.effectiveSpaceId,
1244
- runtimeProfile: effectiveRuntimeProfile,
1245
- runtimeToolPolicySnapshot,
1246
- persistDialog: streamDialog.persistDialog,
1247
- }));
1705
+ let streamDialog: Awaited<ReturnType<typeof prepareForegroundStreamDialog>>;
1706
+ try {
1707
+ streamDialog = await prepareCurrentForegroundStreamDialog();
1708
+ } catch (e: any) {
1709
+ return agentRunError(e.message ?? "Failed to create dialog", e.status ?? 500);
1710
+ }
1711
+ const startedAt = Date.now();
1712
+ const sourceStream = buildExecutionSourceStream({
1713
+ userId: streamDialog.effectiveUserId,
1714
+ dialogId: streamDialog.dialogId,
1715
+ spaceId: streamDialog.effectiveSpaceId,
1716
+ });
1717
+ return agentRunSse(buildBillableForegroundSseStream(
1718
+ sourceStream,
1719
+ buildForegroundStreamLifecycleContext({
1720
+ streamDialog,
1721
+ startedAt,
1722
+ }),
1723
+ ));
1724
+ };
1725
+ return await dispatchForegroundStreamExecution();
1248
1726
  }
1249
1727
 
1250
1728
  // ── background 模式:立即返回 dialogId,后台执行 ───────────────────────────
@@ -1256,19 +1734,7 @@ export async function handleAgentRun(req: Request): Promise<Response> {
1256
1734
  continueDialogUserId,
1257
1735
  fallbackSpaceId: spaceId,
1258
1736
  createPendingDialog,
1259
- pendingDialogInput: {
1260
- agentKey,
1261
- userId,
1262
- callerType,
1263
- userInput: userInputText,
1264
- spaceId,
1265
- category,
1266
- inheritedFromDialogKey,
1267
- parentDialogId,
1268
- runtimeProfile: effectiveRuntimeProfile,
1269
- runtimeContext,
1270
- runtimeToolPolicySnapshot,
1271
- },
1737
+ pendingDialogInput: buildPendingDialogInput(agentKey),
1272
1738
  });
1273
1739
  if (isBackgroundRunDialogError(backgroundDialog)) {
1274
1740
  return agentRunError(backgroundDialog.error, backgroundDialog.status);
@@ -1279,150 +1745,112 @@ export async function handleAgentRun(req: Request): Promise<Response> {
1279
1745
  effectiveUserId: effectiveBackgroundUserId,
1280
1746
  effectiveSpaceId: effectiveBackgroundSpaceId,
1281
1747
  } = backgroundDialog;
1748
+ const backgroundDialogPersistenceContext = {
1749
+ dialogId,
1750
+ dialogKey,
1751
+ agentKey,
1752
+ parentDialogId,
1753
+ runtimeContext,
1754
+ spaceId: effectiveBackgroundSpaceId,
1755
+ };
1282
1756
  const startedAt = Date.now();
1757
+ const persistBackgroundDialogRecord = async (args: {
1758
+ status: "running" | "failed";
1759
+ updatedAt: number;
1760
+ extraFields?: Record<string, unknown>;
1761
+ buildRuntimeCheckpoint: (existingDialog: any) => unknown;
1762
+ failureLogLabel: string;
1763
+ }) => {
1764
+ try {
1765
+ const store = getAgentRunStore();
1766
+ const existingDialog = await store.get(dialogKey);
1767
+ await store.put(dialogKey, {
1768
+ ...existingDialog,
1769
+ status: args.status,
1770
+ updatedAt: new Date(args.updatedAt).toISOString(),
1771
+ ...(args.extraFields ?? {}),
1772
+ runtimeCheckpoint: args.buildRuntimeCheckpoint(existingDialog),
1773
+ });
1774
+ return true;
1775
+ } catch (persistError) {
1776
+ console.error(
1777
+ `[background] dialog=${dialogId} ${args.failureLogLabel} persist failed:`,
1778
+ persistError,
1779
+ );
1780
+ return false;
1781
+ }
1782
+ };
1783
+ const publishBackgroundDialogTransition = async (args: {
1784
+ status: "running" | "done" | "failed";
1785
+ projectActivity?: boolean;
1786
+ progress?: MachineConnectorRunProgress;
1787
+ content?: string;
1788
+ usage?: LoopResult["usage"];
1789
+ error?: string;
1790
+ }) => {
1791
+ if (args.projectActivity !== false) {
1792
+ await projectBackgroundDialogActivity({
1793
+ ...backgroundDialogPersistenceContext,
1794
+ status: args.status,
1795
+ });
1796
+ }
1797
+ if (args.progress) {
1798
+ pushEvent(`dialog-${dialogId}`, {
1799
+ type: "runtime.progress",
1800
+ progress: args.progress,
1801
+ });
1802
+ return;
1803
+ }
1804
+ if (args.status === "running") {
1805
+ pushEvent(`dialog-${dialogId}`, { type: "status", status: "running" });
1806
+ return;
1807
+ }
1808
+ if (args.status === "done") {
1809
+ pushEvent(`dialog-${dialogId}`, {
1810
+ type: "done",
1811
+ content: args.content,
1812
+ usage: args.usage,
1813
+ });
1814
+ if (effectiveBackgroundSpaceId) {
1815
+ pushEvent(`space-${effectiveBackgroundSpaceId}`, { type: "dialog.done", dialogId });
1816
+ }
1817
+ return;
1818
+ }
1819
+ pushEvent(`dialog-${dialogId}`, {
1820
+ type: "failed",
1821
+ error: args.error,
1822
+ });
1823
+ if (effectiveBackgroundSpaceId) {
1824
+ pushEvent(`space-${effectiveBackgroundSpaceId}`, { type: "dialog.failed", dialogId });
1825
+ }
1826
+ };
1283
1827
 
1284
1828
  // 更新 status=running
1285
- try {
1286
- const existingDialog = await serverDb.get(dialogKey);
1287
- const runningAt = Date.now();
1288
- await serverDb.put(dialogKey, {
1289
- ...existingDialog,
1290
- status: "running",
1291
- startedAt,
1292
- updatedAt: new Date(runningAt).toISOString(),
1293
- runtimeCheckpoint: buildRunningRuntimeCheckpoint({
1294
- dialogId,
1295
- userInputText,
1296
- updatedAt: runningAt,
1297
- runtimeBinding: existingDialog?.runtimeBinding,
1298
- }),
1299
- });
1300
- await projectBackgroundDialogActivity({
1829
+ const runningAt = Date.now();
1830
+ const persistedRunning = await persistBackgroundDialogRecord({
1831
+ status: "running",
1832
+ updatedAt: runningAt,
1833
+ extraFields: { startedAt },
1834
+ buildRuntimeCheckpoint: (existingDialog: any) => buildRunningRuntimeCheckpoint({
1301
1835
  dialogId,
1302
- dialogKey,
1303
- agentKey,
1304
- parentDialogId,
1305
- runtimeContext,
1306
- status: "running",
1307
- });
1308
- } catch (e) {
1309
- console.error(`[background] dialog=${dialogId} status update failed:`, e);
1310
- }
1311
- pushEvent(`dialog-${dialogId}`, { type: "status", status: "running" });
1836
+ userInputText,
1837
+ updatedAt: runningAt,
1838
+ runtimeBinding: existingDialog?.runtimeBinding,
1839
+ }),
1840
+ failureLogLabel: "status update",
1841
+ });
1842
+ await publishBackgroundDialogTransition({
1843
+ status: "running",
1844
+ projectActivity: persistedRunning,
1845
+ });
1312
1846
 
1313
1847
  // 后台执行(不阻塞响应)
1314
1848
  incActiveStream();
1315
- (async () => {
1316
- try {
1317
- const backgroundTimeoutMs =
1318
- effectiveAgentRunTimeoutMs ?? DEFAULT_BACKGROUND_RUN_TIMEOUT_MS;
1319
- let workspaceLease: Record<string, unknown> | undefined;
1320
- const persistConnectorProgress = async (progress: MachineConnectorRunProgress) => {
1321
- const progressAt = Date.now();
1322
- try {
1323
- const existingDialog = await serverDb.get(dialogKey);
1324
- await serverDb.put(dialogKey, {
1325
- ...existingDialog,
1326
- status: "running",
1327
- updatedAt: new Date(progressAt).toISOString(),
1328
- runtimeCheckpoint: buildProgressRuntimeCheckpoint({
1329
- existingDialog,
1330
- dialogId,
1331
- userInputText,
1332
- progress,
1333
- updatedAt: progressAt,
1334
- }),
1335
- });
1336
- await projectBackgroundDialogActivity({
1337
- dialogId,
1338
- dialogKey,
1339
- agentKey,
1340
- parentDialogId,
1341
- runtimeContext,
1342
- status: "running",
1343
- });
1344
- pushEvent(`dialog-${dialogId}`, {
1345
- type: "runtime.progress",
1346
- progress,
1347
- });
1348
- } catch (progressError) {
1349
- console.error(`[background] dialog=${dialogId} progress persist failed:`, progressError);
1350
- }
1351
- };
1352
- const runtimePromptPage = await createRuntimePromptPageIfLarge({
1353
- agentConfig,
1354
- agentKey,
1355
- dialogId,
1356
- runtimeContext,
1357
- spaceId: effectiveBackgroundSpaceId,
1358
- userId: effectiveBackgroundUserId,
1359
- userInputText,
1360
- }).catch((error) => {
1361
- console.warn("[agentRun.background] runtime prompt page create failed", {
1362
- dialogId,
1363
- agentKey,
1364
- error: error instanceof Error ? error.message : String(error),
1365
- });
1366
- return null;
1367
- });
1368
- if (runtimePromptPage) {
1369
- await persistConnectorProgress({
1370
- message: "runtime-prompt-page-created",
1371
- promptPageKey: runtimePromptPage.dbKey,
1372
- promptPageHash: runtimePromptPage.promptHash,
1373
- promptBytes: runtimePromptPage.contentBytes,
1374
- updatedAt: Date.now(),
1375
- });
1376
- }
1377
- const result = await withBackgroundRunTimeout((async () => {
1378
- console.log("[agentRun.background] dispatch", {
1379
- dialogId,
1380
- agentKey,
1381
- backgroundTimeoutMs,
1382
- userInputBytes: byteLength(userInputText),
1383
- runtimePromptPageKey: runtimePromptPage?.dbKey,
1384
- });
1385
- const connectorResult = await runViaMachineConnector({
1386
- agentConfig,
1387
- agentKey,
1388
- category,
1389
- continueDialogId: continueDialogId ?? undefined,
1390
- messages,
1391
- runtimeContext,
1392
- spaceId,
1393
- userId: effectiveBackgroundUserId,
1394
- userInput: userInputText,
1395
- requestTimeoutMs: backgroundTimeoutMs,
1396
- runtimeToolPolicySnapshot,
1397
- runtimePromptPage,
1398
- onProgress: persistConnectorProgress,
1399
- });
1400
- console.log("[agentRun.background] connector-result", {
1401
- dialogId,
1402
- agentKey,
1403
- usedMachineConnector: Boolean(connectorResult),
1404
- contentBytes: byteLength(String(connectorResult?.content ?? "")),
1405
- });
1406
- workspaceLease = buildWorkspaceLeaseFromConnectorResult({
1407
- result: connectorResult,
1408
- agentKey,
1409
- machineId: resolveAgentRuntimeMachineId(agentConfig),
1410
- runtimeToolPolicySnapshot,
1411
- });
1412
- return (connectorResult ?? await runAgentLoopImpl(
1413
- agentConfig,
1414
- messages,
1415
- effectiveMaxRounds,
1416
- serverBase,
1417
- authToken,
1418
- runtimePolicy,
1419
- effectiveBackgroundUserId,
1420
- dialogId,
1421
- effectiveBackgroundSpaceId,
1422
- userInputText,
1423
- runtimeContext,
1424
- )) as LoopResult;
1425
- })(), backgroundTimeoutMs);
1849
+ const dispatchBackgroundExecution = async () => {
1850
+ const settleBackgroundExecutionSuccess = async (args: {
1851
+ result: LoopResult;
1852
+ workspaceLease?: Record<string, unknown>;
1853
+ }) => {
1426
1854
  if (continueDialogId) {
1427
1855
  await appendToExistingDialog({
1428
1856
  dialogId,
@@ -1430,20 +1858,20 @@ export async function handleAgentRun(req: Request): Promise<Response> {
1430
1858
  agentKey,
1431
1859
  userId: effectiveBackgroundUserId,
1432
1860
  userInput: userInputText,
1433
- result,
1861
+ result: args.result,
1434
1862
  durationMs: Date.now() - startedAt,
1435
1863
  spaceId: effectiveBackgroundSpaceId,
1436
1864
  runtimeProfile: effectiveRuntimeProfile,
1437
1865
  runtimeContext,
1438
1866
  runtimeToolPolicySnapshot,
1439
- workspaceLease,
1867
+ workspaceLease: args.workspaceLease,
1440
1868
  });
1441
1869
  } else {
1442
1870
  await finalizeDialog({
1443
1871
  dialogId,
1444
1872
  dialogKey,
1445
1873
  agentKey,
1446
- result,
1874
+ result: args.result,
1447
1875
  startedAt,
1448
1876
  status: "done",
1449
1877
  userInput: userInputText,
@@ -1451,131 +1879,169 @@ export async function handleAgentRun(req: Request): Promise<Response> {
1451
1879
  spaceId,
1452
1880
  runtimeContext,
1453
1881
  runtimeToolPolicySnapshot,
1454
- workspaceLease,
1882
+ workspaceLease: args.workspaceLease,
1455
1883
  });
1456
1884
  }
1457
- await projectBackgroundDialogActivity({
1458
- dialogId,
1459
- dialogKey,
1460
- agentKey,
1461
- parentDialogId,
1462
- runtimeContext,
1885
+ await publishBackgroundDialogTransition({
1463
1886
  status: "done",
1887
+ content: args.result.content,
1888
+ usage: args.result.usage,
1464
1889
  });
1465
- pushEvent(`dialog-${dialogId}`, {
1466
- type: "done",
1467
- content: result.content,
1468
- usage: result.usage,
1469
- });
1470
- if (effectiveBackgroundSpaceId) {
1471
- pushEvent(`space-${effectiveBackgroundSpaceId}`, { type: "dialog.done", dialogId });
1472
- }
1473
1890
  await writeAgentRunBillingIfNeeded({
1474
- agentConfig,
1891
+ agentConfig: executionAgentConfig,
1475
1892
  agentKey,
1476
- result,
1893
+ result: args.result,
1477
1894
  dialogId,
1478
1895
  mode: "background",
1479
1896
  userId: effectiveBackgroundUserId,
1480
1897
  });
1481
- } catch (e) {
1482
- console.error(`[background] dialog=${dialogId} failed:`, e);
1898
+ };
1899
+ const settleBackgroundExecutionFailure = async (args: {
1900
+ error: unknown;
1901
+ }) => {
1483
1902
  const failedAt = Date.now();
1484
- const errorMessage = e instanceof Error ? e.message : String(e);
1485
- await serverDb.get(dialogKey).then((d: any) =>
1486
- serverDb.put(dialogKey, {
1487
- ...d,
1488
- status: "failed",
1489
- updatedAt: new Date(failedAt).toISOString(),
1903
+ const errorMessage =
1904
+ args.error instanceof Error ? args.error.message : String(args.error);
1905
+ await persistBackgroundDialogRecord({
1906
+ status: "failed",
1907
+ updatedAt: failedAt,
1908
+ extraFields: {
1490
1909
  finishedAt: failedAt,
1491
1910
  durationMs: Math.max(0, failedAt - startedAt),
1492
- runtimeCheckpoint: {
1493
- ...buildFailedRuntimeCheckpoint({
1494
- existingDialog: d,
1495
- dialogId,
1496
- userInputText,
1497
- updatedAt: failedAt,
1498
- errorMessage,
1499
- }),
1500
- errorMessage,
1501
- },
1502
1911
  errorMessage,
1503
- })
1504
- ).catch((putErr) => { console.error(`[background] dialog=${dialogId} status persist failed:`, putErr); });
1505
- await projectBackgroundDialogActivity({
1506
- dialogId,
1507
- dialogKey,
1508
- agentKey,
1509
- parentDialogId,
1510
- runtimeContext,
1511
- status: "failed",
1912
+ },
1913
+ buildRuntimeCheckpoint: (existingDialog: any) => buildFailedRuntimeCheckpoint({
1914
+ existingDialog,
1915
+ dialogId,
1916
+ userInputText,
1917
+ updatedAt: failedAt,
1918
+ errorMessage,
1919
+ }),
1920
+ failureLogLabel: "status",
1512
1921
  });
1513
- pushEvent(`dialog-${dialogId}`, {
1514
- type: "failed",
1922
+ await publishBackgroundDialogTransition({
1923
+ status: "failed",
1515
1924
  error: errorMessage,
1516
1925
  });
1517
- if (effectiveBackgroundSpaceId) {
1518
- pushEvent(`space-${effectiveBackgroundSpaceId}`, { type: "dialog.failed", dialogId });
1519
- }
1520
1926
  const dialogTitle =
1521
1927
  existingDialogRecord?.title ??
1522
1928
  buildDialogFallbackTitleFromUserInput(userInputText);
1523
1929
  await emitDialogStatusNotification({
1524
1930
  userId: effectiveBackgroundUserId,
1525
- dialogId,
1526
- dialogKey,
1931
+ ...backgroundDialogPersistenceContext,
1527
1932
  dialogTitle,
1528
- spaceId: effectiveBackgroundSpaceId,
1529
1933
  status: "failed",
1530
1934
  createdAt: failedAt,
1531
1935
  errorMessage,
1532
1936
  });
1937
+ };
1938
+ try {
1939
+ const backgroundTimeoutMs =
1940
+ effectiveAgentRunTimeoutMs ?? DEFAULT_BACKGROUND_RUN_TIMEOUT_MS;
1941
+ let workspaceLease: Record<string, unknown> | undefined;
1942
+ const prepareBackgroundProgressPhase = async () => {
1943
+ const persistConnectorProgress = async (progress: MachineConnectorRunProgress) => {
1944
+ const progressAt = Date.now();
1945
+ const persistedProgress = await persistBackgroundDialogRecord({
1946
+ status: "running",
1947
+ updatedAt: progressAt,
1948
+ buildRuntimeCheckpoint: (existingDialog: any) => buildProgressRuntimeCheckpoint({
1949
+ existingDialog,
1950
+ dialogId,
1951
+ userInputText,
1952
+ progress,
1953
+ updatedAt: progressAt,
1954
+ }),
1955
+ failureLogLabel: "progress",
1956
+ });
1957
+ if (persistedProgress) {
1958
+ await publishBackgroundDialogTransition({
1959
+ status: "running",
1960
+ progress,
1961
+ });
1962
+ }
1963
+ };
1964
+ const maybeRuntimePromptPage = await createRuntimePromptPageIfLarge({
1965
+ agentConfig: executionAgentConfig,
1966
+ agentKey,
1967
+ dialogId,
1968
+ runtimeContext,
1969
+ spaceId: effectiveBackgroundSpaceId,
1970
+ userId: effectiveBackgroundUserId,
1971
+ userInputText,
1972
+ }).catch((error) => {
1973
+ console.warn("[agentRun.background] runtime prompt page create failed", {
1974
+ dialogId,
1975
+ agentKey,
1976
+ error: error instanceof Error ? error.message : String(error),
1977
+ });
1978
+ return null;
1979
+ });
1980
+ if (maybeRuntimePromptPage) {
1981
+ await persistConnectorProgress({
1982
+ message: "runtime-prompt-page-created",
1983
+ promptPageKey: maybeRuntimePromptPage.dbKey,
1984
+ promptPageHash: maybeRuntimePromptPage.promptHash,
1985
+ promptBytes: maybeRuntimePromptPage.contentBytes,
1986
+ updatedAt: Date.now(),
1987
+ });
1988
+ }
1989
+ return {
1990
+ persistConnectorProgress,
1991
+ runtimePromptPage: maybeRuntimePromptPage,
1992
+ };
1993
+ };
1994
+ const { persistConnectorProgress, runtimePromptPage } = await prepareBackgroundProgressPhase();
1995
+ const { result, workspaceLease: resolvedWorkspaceLease } = await withBackgroundRunTimeout((async () => {
1996
+ console.log("[agentRun.background] dispatch", {
1997
+ dialogId,
1998
+ agentKey,
1999
+ backgroundTimeoutMs,
2000
+ userInputBytes: byteLength(userInputText),
2001
+ runtimePromptPageKey: runtimePromptPage?.dbKey,
2002
+ });
2003
+ const executionRun = await runExecutionResult({
2004
+ userId: effectiveBackgroundUserId,
2005
+ dialogId,
2006
+ spaceId: effectiveBackgroundSpaceId,
2007
+ requestTimeoutMs: backgroundTimeoutMs,
2008
+ runtimePromptPage,
2009
+ onProgress: persistConnectorProgress,
2010
+ });
2011
+ console.log("[agentRun.background] connector-result", {
2012
+ dialogId,
2013
+ agentKey,
2014
+ usedMachineConnector: Boolean(executionRun.connectorResult),
2015
+ contentBytes: byteLength(String(executionRun.connectorResult?.content ?? "")),
2016
+ });
2017
+ return executionRun;
2018
+ })(), backgroundTimeoutMs);
2019
+ workspaceLease = resolvedWorkspaceLease;
2020
+ await settleBackgroundExecutionSuccess({ result, workspaceLease });
2021
+ } catch (e) {
2022
+ console.error(`[background] dialog=${dialogId} failed:`, e);
2023
+ await settleBackgroundExecutionFailure({ error: e });
1533
2024
  } finally {
1534
2025
  decActiveStream();
1535
2026
  }
1536
- })().catch((e) => { console.error(`[background] unhandled rejection dialog=${dialogId}:`, e); });
2027
+ };
2028
+ dispatchBackgroundExecution().catch((e) => { console.error(`[background] unhandled rejection dialog=${dialogId}:`, e); });
1537
2029
 
1538
2030
  return agentRunJson({ dialogId, status: "pending" }, 202);
1539
2031
  }
1540
2032
 
1541
2033
  // ── 前台同步模式 ───────────────────────────────────────────────────────────
1542
- try {
2034
+ const dispatchSyncExecution = async () => {
1543
2035
  const startTime = Date.now();
1544
2036
  // 注意:sync 新建 dialog 的首轮执行在 saveRunAsDialog 之前,runAgentLoop 此时还拿不到最终 dialogId。
1545
2037
  // 这意味着首轮 server-side external tool charge 还无法稳定投影进 dialog.totalCost;
1546
2038
  // continue/background 场景已有 dialogId,可正常回写。后续若要补齐这里,需要先拿稳定 dialogId 再执行工具链。
1547
- const connectorResult = await runViaMachineConnector({
1548
- agentConfig,
1549
- agentKey,
1550
- category,
1551
- continueDialogId: continueDialogId ?? undefined,
1552
- messages,
1553
- runtimeContext,
1554
- spaceId,
2039
+ const { result, workspaceLease } = await runExecutionResult({
1555
2040
  userId,
1556
- userInput: userInputText,
1557
2041
  requestTimeoutMs: effectiveAgentRunTimeoutMs,
1558
- runtimeToolPolicySnapshot,
1559
- });
1560
- const workspaceLease = buildWorkspaceLeaseFromConnectorResult({
1561
- result: connectorResult,
1562
- agentKey,
1563
- machineId: resolveAgentRuntimeMachineId(agentConfig),
1564
- runtimeToolPolicySnapshot,
1565
- });
1566
- const result = (connectorResult ?? await runAgentLoopImpl(
1567
- agentConfig,
1568
- messages,
1569
- effectiveMaxRounds,
1570
- serverBase,
1571
- authToken,
1572
- runtimePolicy,
1573
- userId,
1574
- continueDialogId ?? undefined,
2042
+ dialogId: continueDialogId ?? undefined,
1575
2043
  spaceId,
1576
- userInputText,
1577
- runtimeContext,
1578
- )) as LoopResult;
2044
+ });
1579
2045
  const durationMs = Date.now() - startTime;
1580
2046
 
1581
2047
  const { dialogId, dialogKey } = await completeSyncAgentRunDialog({
@@ -1583,26 +2049,17 @@ export async function handleAgentRun(req: Request): Promise<Response> {
1583
2049
  existingDialogKey,
1584
2050
  dialogAgentKey,
1585
2051
  traceAgentKey,
1586
- userId,
1587
2052
  continueDialogUserId,
1588
- callerType,
1589
- userInput: userInputText,
1590
2053
  result,
1591
2054
  durationMs,
1592
- spaceId,
1593
- category,
1594
- inheritedFromDialogKey,
1595
- parentDialogId,
1596
- runtimeProfile: effectiveRuntimeProfile,
1597
- runtimeContext,
1598
- runtimeToolPolicySnapshot,
1599
2055
  workspaceLease,
1600
2056
  appendToExistingDialog,
1601
2057
  saveRunAsDialog,
1602
2058
  summarizeMessagesForDebug,
2059
+ ...dialogLifecyclePersistenceContext,
1603
2060
  });
1604
2061
  await writeAgentRunBillingIfNeeded({
1605
- agentConfig,
2062
+ agentConfig: executionAgentConfig,
1606
2063
  agentKey,
1607
2064
  result,
1608
2065
  dialogId,
@@ -1613,7 +2070,7 @@ export async function handleAgentRun(req: Request): Promise<Response> {
1613
2070
  const debugContext = buildAgentRunDebugContext({
1614
2071
  enabled: debugContextLayers,
1615
2072
  runtimeSystemMessageContext,
1616
- selectedMemoryItems: memoryRuntime.selectedItems,
2073
+ selectedMemoryItems: executionMemoryRuntime.selectedItems,
1617
2074
  });
1618
2075
 
1619
2076
  return agentRunJson({
@@ -1622,8 +2079,11 @@ export async function handleAgentRun(req: Request): Promise<Response> {
1622
2079
  dialogKey,
1623
2080
  ...(debugContext ? { debug: debugContext } : {}),
1624
2081
  });
2082
+ };
2083
+ try {
2084
+ return await dispatchSyncExecution();
1625
2085
  } catch (e: any) {
1626
- const connectorFailureResponse = resolveConnectorFailureResponse(e, agentConfig);
2086
+ const connectorFailureResponse = resolveConnectorFailureResponse(e, executionAgentConfig);
1627
2087
  if (connectorFailureResponse) return connectorFailureResponse;
1628
2088
  return agentRunError(e.message ?? "Internal server error", 500);
1629
2089
  }