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
package/auth/routes.ts CHANGED
@@ -37,6 +37,46 @@ export const authRoutes = {
37
37
  method: "GET" as const,
38
38
  createPath: () => `${API_VERSION}/users`,
39
39
  },
40
+ usageReport: {
41
+ path: `${API_VERSION}/users/usage-report`,
42
+ method: "GET" as const,
43
+ createPath: () => `${API_VERSION}/users/usage-report`,
44
+ },
45
+ providerBillingHealth: {
46
+ path: `${API_VERSION}/users/provider-billing-health`,
47
+ method: "GET" as const,
48
+ createPath: () => `${API_VERSION}/users/provider-billing-health`,
49
+ },
50
+ providerBillingDrilldown: {
51
+ path: `${API_VERSION}/users/provider-billing-drilldown`,
52
+ method: "GET" as const,
53
+ createPath: () => `${API_VERSION}/users/provider-billing-drilldown`,
54
+ },
55
+ providerCredentials: {
56
+ path: `${API_VERSION}/users/provider-credentials`,
57
+ method: "GET" as const,
58
+ createPath: () => `${API_VERSION}/users/provider-credentials`,
59
+ },
60
+ providerCredentialLifecycle: {
61
+ path: `${API_VERSION}/users/provider-credentials/lifecycle`,
62
+ method: "POST" as const,
63
+ createPath: () => `${API_VERSION}/users/provider-credentials/lifecycle`,
64
+ },
65
+ billingAnomalyLifecycle: {
66
+ path: `${API_VERSION}/users/billing-anomalies/lifecycle`,
67
+ method: "POST" as const,
68
+ createPath: () => `${API_VERSION}/users/billing-anomalies/lifecycle`,
69
+ },
70
+ billingAnomalyDrilldown: {
71
+ path: `${API_VERSION}/users/billing-anomalies/drilldown`,
72
+ method: "GET" as const,
73
+ createPath: () => `${API_VERSION}/users/billing-anomalies/drilldown`,
74
+ },
75
+ billingAnomalyAudit: {
76
+ path: `${API_VERSION}/users/billing-anomalies/audit`,
77
+ method: "POST" as const,
78
+ createPath: () => `${API_VERSION}/users/billing-anomalies/audit`,
79
+ },
40
80
  detail: {
41
81
  path: `${API_VERSION}/users/:userId`,
42
82
  method: "GET" as const,
@@ -72,6 +112,12 @@ export const authRoutes = {
72
112
  createPath: (params: RouteParams) =>
73
113
  `${API_VERSION}/users/${params.userId}/enable`,
74
114
  },
115
+ adminPermissions: {
116
+ path: `${API_VERSION}/users/:userId/admin-permissions`,
117
+ method: "POST" as const,
118
+ createPath: (params: RouteParams) =>
119
+ `${API_VERSION}/users/${params.userId}/admin-permissions`,
120
+ },
75
121
  sendEmail: {
76
122
  path: `${API_VERSION}/users/send-email`,
77
123
  method: "POST" as const,
@@ -1,5 +1,5 @@
1
1
  import { DB_PREFIX } from "../../database/keys";
2
- import serverDb from "../../database/server/db";
2
+ import { getServerAuthorityStore } from "../../database/server/db";
3
3
 
4
4
  import { balanceLockManager } from "./locks";
5
5
 
@@ -116,10 +116,11 @@ export async function recordUserAccessActivity(
116
116
  ) {
117
117
  const timestamp = options.timestamp ?? Date.now();
118
118
  const key = `${DB_PREFIX.USER}${userId}`;
119
+ const store = getServerAuthorityStore();
119
120
  const lock = balanceLockManager.getLock(userId);
120
121
 
121
122
  await lock.runExclusive(async () => {
122
- const user = await serverDb.get(key).catch(() => null);
123
+ const user = await store.get(key).catch(() => null);
123
124
  if (!user) return;
124
125
 
125
126
  const entry: RecentAccessEntry = {
@@ -129,7 +130,7 @@ export async function recordUserAccessActivity(
129
130
  device: summarizeUserAgent(options.userAgent),
130
131
  };
131
132
 
132
- await serverDb.put(key, {
133
+ await store.put(key, {
133
134
  ...user,
134
135
  ...(options.updateLastActiveAt ? { lastActiveAt: timestamp } : {}),
135
136
  ...(options.updateLastLoginAt ? { lastLoginAt: timestamp } : {}),
@@ -0,0 +1,43 @@
1
+ import {
2
+ checkAdminPermission,
3
+ createErrorResponse,
4
+ createSuccessResponse,
5
+ handleOptionsRequest,
6
+ } from "./shared";
7
+ import { updateUserAdminPermissions } from "./usageManagementAccess";
8
+
9
+ export async function handleUpdateUserAdminPermissions(req: Request, userId: string) {
10
+ if (req.method === "OPTIONS") {
11
+ return handleOptionsRequest();
12
+ }
13
+
14
+ const permissionError = checkAdminPermission(req.user?.userId);
15
+ if (permissionError) return permissionError;
16
+
17
+ if (!userId) {
18
+ return createErrorResponse("User ID is required", 400);
19
+ }
20
+
21
+ try {
22
+ const body = await req.json().catch(() => ({}));
23
+ const usageManagement = body?.usageManagement;
24
+ if (typeof usageManagement !== "boolean") {
25
+ return createErrorResponse("usageManagement must be boolean", 400);
26
+ }
27
+
28
+ const updatedUser = await updateUserAdminPermissions(userId, {
29
+ usageManagement,
30
+ });
31
+ if (!updatedUser) {
32
+ return createErrorResponse("User not found", 404);
33
+ }
34
+
35
+ return createSuccessResponse({
36
+ success: true,
37
+ userId,
38
+ adminPermissions: updatedUser.adminPermissions,
39
+ });
40
+ } catch {
41
+ return createErrorResponse("Failed to update admin permissions");
42
+ }
43
+ }
@@ -0,0 +1,375 @@
1
+ import { getServerAuthorityStore } from "../../database/server/db";
2
+ import { createAgentKey, createCybotKey, createKey, DB_PREFIX } from "../../database/keys";
3
+
4
+ import {
5
+ checkAdminPermission,
6
+ createErrorResponse,
7
+ createSuccessResponse,
8
+ handleOptionsRequest,
9
+ } from "./shared";
10
+
11
+ export type AdminUsageReportStore = {
12
+ iterator: (options: { gte?: string; lte?: string }) => AsyncIterable<[string, unknown]>;
13
+ get?: (key: string) => Promise<unknown>;
14
+ };
15
+
16
+ export type AdminUsageRankItem = {
17
+ count: number;
18
+ cost: number;
19
+ inputTokens: number;
20
+ outputTokens: number;
21
+ cacheCreationInputTokens: number;
22
+ cacheReadInputTokens: number;
23
+ costRatio: number;
24
+ };
25
+
26
+ export type AdminUsageReport = {
27
+ generatedAt: string;
28
+ sinceMs: number;
29
+ untilMs: number;
30
+ limit: number;
31
+ summary: AdminUsageRankItem & {
32
+ recordsScanned: number;
33
+ recordsInWindow: number;
34
+ totalCost: number;
35
+ };
36
+ rankings: {
37
+ users: (AdminUsageRankItem & {
38
+ userId: string;
39
+ username?: string;
40
+ email?: string;
41
+ })[];
42
+ dialogs: (AdminUsageRankItem & {
43
+ dialogId: string;
44
+ userId: string;
45
+ username?: string;
46
+ title?: string;
47
+ })[];
48
+ models: (AdminUsageRankItem & {
49
+ provider: string;
50
+ model: string;
51
+ serviceTier?: string;
52
+ })[];
53
+ agents: (AdminUsageRankItem & {
54
+ agentKey: string;
55
+ name?: string;
56
+ title?: string;
57
+ })[];
58
+ };
59
+ };
60
+
61
+ type TokenRecord = {
62
+ type?: string;
63
+ userId?: string;
64
+ username?: string;
65
+ cybotId?: string;
66
+ provider?: string;
67
+ model?: string;
68
+ billing_service_tier?: string;
69
+ dialogId?: string;
70
+ input_tokens?: number;
71
+ output_tokens?: number;
72
+ cache_creation_input_tokens?: number;
73
+ cache_read_input_tokens?: number;
74
+ cost?: number;
75
+ timestamp?: number;
76
+ createdAt?: string | number;
77
+ };
78
+
79
+ type Accumulator = {
80
+ count: number;
81
+ cost: number;
82
+ inputTokens: number;
83
+ outputTokens: number;
84
+ cacheCreationInputTokens: number;
85
+ cacheReadInputTokens: number;
86
+ };
87
+
88
+ const TOKEN_PREFIX = "token-";
89
+ const TOKEN_STATS_PREFIX = "token-stats-";
90
+ const MAX_LIMIT = 200;
91
+
92
+ const rangeEnd = (prefix: string) => `${prefix}\uffff`;
93
+
94
+ const roundMetric = (value: number) => Math.round(value * 1_000_000) / 1_000_000;
95
+
96
+ const isObjectRecord = (value: unknown): value is Record<string, unknown> =>
97
+ !!value && typeof value === "object" && !Array.isArray(value);
98
+
99
+ const toFiniteNumber = (value: unknown, fallback = 0) =>
100
+ typeof value === "number" && Number.isFinite(value) ? value : fallback;
101
+
102
+ const normalizeText = (value: unknown, fallback = "unknown") =>
103
+ typeof value === "string" && value.trim() ? value.trim() : fallback;
104
+
105
+ const createAccumulator = (): Accumulator => ({
106
+ count: 0,
107
+ cost: 0,
108
+ inputTokens: 0,
109
+ outputTokens: 0,
110
+ cacheCreationInputTokens: 0,
111
+ cacheReadInputTokens: 0,
112
+ });
113
+
114
+ const addToAccumulator = (acc: Accumulator, record: TokenRecord) => {
115
+ acc.count += 1;
116
+ acc.cost += toFiniteNumber(record.cost);
117
+ acc.inputTokens += toFiniteNumber(record.input_tokens);
118
+ acc.outputTokens += toFiniteNumber(record.output_tokens);
119
+ acc.cacheCreationInputTokens += toFiniteNumber(record.cache_creation_input_tokens);
120
+ acc.cacheReadInputTokens += toFiniteNumber(record.cache_read_input_tokens);
121
+ };
122
+
123
+ const getTokenTimestamp = (record: TokenRecord) => {
124
+ if (typeof record.timestamp === "number" && Number.isFinite(record.timestamp)) {
125
+ return record.timestamp;
126
+ }
127
+ if (typeof record.createdAt === "number" && Number.isFinite(record.createdAt)) {
128
+ return record.createdAt;
129
+ }
130
+ if (typeof record.createdAt === "string") {
131
+ const parsed = Date.parse(record.createdAt);
132
+ if (Number.isFinite(parsed)) return parsed;
133
+ }
134
+ return null;
135
+ };
136
+
137
+ const isTokenRecord = (key: string, value: unknown): value is TokenRecord =>
138
+ key.startsWith(TOKEN_PREFIX) &&
139
+ !key.startsWith(TOKEN_STATS_PREFIX) &&
140
+ isObjectRecord(value) &&
141
+ value.type === "token";
142
+
143
+ const metricFields = (acc: Accumulator, totalCost: number): AdminUsageRankItem => ({
144
+ count: acc.count,
145
+ cost: roundMetric(acc.cost),
146
+ inputTokens: acc.inputTokens,
147
+ outputTokens: acc.outputTokens,
148
+ cacheCreationInputTokens: acc.cacheCreationInputTokens,
149
+ cacheReadInputTokens: acc.cacheReadInputTokens,
150
+ costRatio: totalCost > 0 ? roundMetric(acc.cost / totalCost) : 0,
151
+ });
152
+
153
+ const sortedEntries = <T>(groups: Map<string, T & Accumulator>, limit: number) =>
154
+ Array.from(groups.entries())
155
+ .sort(([, a], [, b]) => b.cost - a.cost || b.outputTokens - a.outputTokens || b.count - a.count)
156
+ .slice(0, limit);
157
+
158
+ const getOptional = async (store: AdminUsageReportStore, key: string) => {
159
+ if (!store.get) return null;
160
+ try {
161
+ return await store.get(key);
162
+ } catch {
163
+ return null;
164
+ }
165
+ };
166
+
167
+ const readUserLabel = async (store: AdminUsageReportStore, userId: string) => {
168
+ const value = await getOptional(store, `${DB_PREFIX.USER}${userId}`);
169
+ if (!isObjectRecord(value)) return {};
170
+ return {
171
+ username: typeof value.username === "string" ? value.username : undefined,
172
+ email: typeof value.email === "string" ? value.email : undefined,
173
+ };
174
+ };
175
+
176
+ const readDialogTitle = async (
177
+ store: AdminUsageReportStore,
178
+ userId: string,
179
+ dialogId: string
180
+ ) => {
181
+ const value = await getOptional(store, createKey("dialog", userId, dialogId));
182
+ if (!isObjectRecord(value)) return undefined;
183
+ return typeof value.title === "string" ? value.title : undefined;
184
+ };
185
+
186
+ const readAgentLabel = async (store: AdminUsageReportStore, agentKey: string) => {
187
+ const candidateKeys = [agentKey];
188
+ if (!agentKey.startsWith("agent-") && !agentKey.startsWith("cybot-")) {
189
+ candidateKeys.push(createAgentKey.public(agentKey), createCybotKey.public(agentKey));
190
+ }
191
+
192
+ for (const key of candidateKeys) {
193
+ const value = await getOptional(store, key);
194
+ if (!isObjectRecord(value)) continue;
195
+ return {
196
+ name: typeof value.name === "string" ? value.name : undefined,
197
+ title: typeof value.title === "string" ? value.title : undefined,
198
+ };
199
+ }
200
+
201
+ return {};
202
+ };
203
+
204
+ const addGroupRecord = <T extends object>(
205
+ groups: Map<string, T & Accumulator>,
206
+ key: string,
207
+ record: TokenRecord,
208
+ meta: T
209
+ ) => {
210
+ const existing = groups.get(key);
211
+ const acc = existing ?? ({ ...meta, ...createAccumulator() } as T & Accumulator);
212
+ addToAccumulator(acc, record);
213
+ groups.set(key, acc);
214
+ };
215
+
216
+ export async function buildAdminUsageReport(args: {
217
+ store: AdminUsageReportStore;
218
+ sinceMs: number;
219
+ untilMs: number;
220
+ nowMs?: number;
221
+ limit?: number;
222
+ }): Promise<AdminUsageReport> {
223
+ const limit = Math.min(MAX_LIMIT, Math.max(1, Math.floor(args.limit ?? 20)));
224
+ const totals = createAccumulator();
225
+ const users = new Map<string, { userId: string; username?: string } & Accumulator>();
226
+ const dialogs = new Map<
227
+ string,
228
+ { userId: string; username?: string; dialogId: string } & Accumulator
229
+ >();
230
+ const models = new Map<
231
+ string,
232
+ { provider: string; model: string; serviceTier?: string } & Accumulator
233
+ >();
234
+ const agents = new Map<string, { agentKey: string } & Accumulator>();
235
+ let recordsScanned = 0;
236
+
237
+ for await (const [key, value] of args.store.iterator({
238
+ gte: TOKEN_PREFIX,
239
+ lte: rangeEnd(TOKEN_PREFIX),
240
+ })) {
241
+ if (!isTokenRecord(key, value)) continue;
242
+ recordsScanned += 1;
243
+
244
+ const timestamp = getTokenTimestamp(value);
245
+ if (timestamp === null || timestamp < args.sinceMs || timestamp > args.untilMs) {
246
+ continue;
247
+ }
248
+
249
+ addToAccumulator(totals, value);
250
+
251
+ const userId = normalizeText(value.userId);
252
+ const username = typeof value.username === "string" ? value.username : undefined;
253
+ const dialogId = normalizeText(value.dialogId);
254
+ const provider = normalizeText(value.provider);
255
+ const model = normalizeText(value.model);
256
+ const serviceTier =
257
+ typeof value.billing_service_tier === "string" && value.billing_service_tier.trim()
258
+ ? value.billing_service_tier.trim()
259
+ : undefined;
260
+ const agentKey = normalizeText(value.cybotId);
261
+
262
+ addGroupRecord(users, userId, value, { userId, username });
263
+ addGroupRecord(dialogs, `${userId}\u0000${dialogId}`, value, {
264
+ userId,
265
+ username,
266
+ dialogId,
267
+ });
268
+ addGroupRecord(models, `${provider}\u0000${model}\u0000${serviceTier ?? ""}`, value, {
269
+ provider,
270
+ model,
271
+ serviceTier,
272
+ });
273
+ addGroupRecord(agents, agentKey, value, { agentKey });
274
+ }
275
+
276
+ const totalCost = roundMetric(totals.cost);
277
+ const userLabelCache = new Map<string, Awaited<ReturnType<typeof readUserLabel>>>();
278
+ const getUserLabel = async (userId: string) => {
279
+ if (!userLabelCache.has(userId)) {
280
+ userLabelCache.set(userId, await readUserLabel(args.store, userId));
281
+ }
282
+ return userLabelCache.get(userId) ?? {};
283
+ };
284
+
285
+ return {
286
+ generatedAt: new Date(args.nowMs ?? Date.now()).toISOString(),
287
+ sinceMs: args.sinceMs,
288
+ untilMs: args.untilMs,
289
+ limit,
290
+ summary: {
291
+ ...metricFields(totals, totalCost),
292
+ recordsScanned,
293
+ recordsInWindow: totals.count,
294
+ totalCost,
295
+ },
296
+ rankings: {
297
+ users: await Promise.all(
298
+ sortedEntries(users, limit).map(async ([, acc]) => {
299
+ const userLabel = await getUserLabel(acc.userId);
300
+ return {
301
+ ...metricFields(acc, totalCost),
302
+ userId: acc.userId,
303
+ email: userLabel.email,
304
+ username: userLabel.username ?? acc.username,
305
+ };
306
+ })
307
+ ),
308
+ dialogs: await Promise.all(
309
+ sortedEntries(dialogs, limit).map(async ([, acc]) => {
310
+ const userLabel = await getUserLabel(acc.userId);
311
+ return {
312
+ ...metricFields(acc, totalCost),
313
+ userId: acc.userId,
314
+ username: userLabel.username ?? acc.username,
315
+ dialogId: acc.dialogId,
316
+ title: await readDialogTitle(args.store, acc.userId, acc.dialogId),
317
+ };
318
+ })
319
+ ),
320
+ models: sortedEntries(models, limit).map(([, acc]) => ({
321
+ ...metricFields(acc, totalCost),
322
+ provider: acc.provider,
323
+ model: acc.model,
324
+ serviceTier: acc.serviceTier,
325
+ })),
326
+ agents: await Promise.all(
327
+ sortedEntries(agents, limit).map(async ([, acc]) => ({
328
+ ...metricFields(acc, totalCost),
329
+ agentKey: acc.agentKey,
330
+ ...(await readAgentLabel(args.store, acc.agentKey)),
331
+ }))
332
+ ),
333
+ },
334
+ };
335
+ }
336
+
337
+ const parseMsParam = (value: string | null) => {
338
+ if (!value) return null;
339
+ const asNumber = Number(value);
340
+ if (Number.isFinite(asNumber)) return asNumber;
341
+ const parsed = Date.parse(value);
342
+ return Number.isFinite(parsed) ? parsed : null;
343
+ };
344
+
345
+ export async function handleAdminUsageReport(req: Request) {
346
+ if (req.method === "OPTIONS") {
347
+ return handleOptionsRequest();
348
+ }
349
+
350
+ const { userId: actionUserId } = req.user;
351
+ const permissionError = checkAdminPermission(actionUserId);
352
+ if (permissionError) return permissionError;
353
+
354
+ try {
355
+ const url = new URL(req.url);
356
+ const sinceMs = parseMsParam(url.searchParams.get("sinceMs"));
357
+ const untilMs = parseMsParam(url.searchParams.get("untilMs"));
358
+ const limit = Number(url.searchParams.get("limit") || "20");
359
+
360
+ if (sinceMs === null || untilMs === null || sinceMs > untilMs) {
361
+ return createErrorResponse("Invalid usage report time range", 400);
362
+ }
363
+
364
+ const report = await buildAdminUsageReport({
365
+ store: getServerAuthorityStore(),
366
+ sinceMs,
367
+ untilMs,
368
+ limit,
369
+ });
370
+
371
+ return createSuccessResponse(report);
372
+ } catch {
373
+ return createErrorResponse("Internal server error");
374
+ }
375
+ }