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.
- package/agent-runtime/agentRecordConfig.ts +0 -2
- package/agent-runtime/hostAdapter.ts +0 -1
- package/agent-runtime/hostRuntimeCapabilities.ts +7 -0
- package/agent-runtime/hostRuntimeConfig.ts +86 -0
- package/agent-runtime/index.ts +13 -0
- package/agent-runtime/localToolPolicy.ts +13 -6
- package/agent-runtime/localWorkspaceTools.ts +333 -30
- package/agent-runtime/platformChatProvider.ts +4 -1
- package/agent-runtime/runtimeToolPolicy.ts +32 -47
- package/agent-runtime/shellCommandPolicy.ts +117 -0
- package/agent-runtime/toolGate.ts +38 -0
- package/agentCreateCustomCommands.ts +9 -4
- package/agentDialogsCommands.ts +4 -3
- package/agentDoctorCommands.ts +3 -3
- package/agentListCommands.ts +3 -3
- package/agentMachineCommands.ts +6 -6
- package/agentPullCommand.ts +4 -12
- package/agentRecordCommands.ts +5 -3
- package/agentRecordHelpers.ts +42 -23
- package/agentRunCommand.ts +2 -6
- package/agentRunParsing.ts +18 -5
- package/agentRuntimeLocal.ts +10 -0
- package/agentUnpublishCommands.ts +3 -2
- package/ai/agent/agentRunDialogLineage.ts +56 -0
- package/ai/agent/agentSlice.ts +45 -10
- package/ai/agent/avatarUtils.ts +1 -1
- package/ai/agent/buildSystemPrompt.ts +1 -2
- package/ai/agent/cliExecutor.ts +330 -19
- package/ai/agent/createAgentSchema.ts +22 -0
- package/ai/agent/hooks/fetchPublicAgents.ts +14 -39
- package/ai/agent/hooks/usePublicAgents.ts +90 -192
- package/ai/agent/publicAgentCatalog.ts +359 -0
- package/ai/agent/publicAgentIdentity.ts +76 -0
- package/ai/agent/server/fetchPublicAgents.ts +21 -46
- package/ai/agent/serverOrigin.ts +7 -0
- package/ai/agent/streamAgentChatTurn.ts +23 -21
- package/ai/agent/streamAgentChatTurnUtils.ts +292 -6
- package/ai/agent/types.ts +2 -0
- package/ai/agent/web/agentDisplayUtils.ts +171 -0
- package/ai/agent/web/useAgentModelAvatarComponent.ts +32 -0
- package/ai/ai.locale.ts +8 -0
- package/ai/chat/sendOpenAICompletionsRequest.native.ts +15 -0
- package/ai/chat/sendOpenAICompletionsRequest.ts +93 -1
- package/ai/chat/sendOpenAIResponseRequest.ts +86 -9
- package/ai/chat/updateTotalUsage.ts +7 -0
- package/ai/llm/deepinfra.ts +30 -15
- package/ai/llm/mistral.ts +3 -4
- package/ai/llm/providers.ts +2 -0
- package/ai/llm/types.ts +15 -0
- package/ai/memory/capture.ts +3 -3
- package/ai/memory/consolidate.ts +2 -2
- package/ai/memory/delete.ts +4 -3
- package/ai/memory/query.ts +3 -3
- package/ai/memory/remember.ts +2 -2
- package/ai/memory/store.ts +3 -3
- package/ai/memory/storeShared.ts +3 -2
- package/ai/policy/commercialMultiplier.ts +16 -0
- package/ai/token/billingAdminAuditEvent.ts +68 -0
- package/ai/token/billingAdminAuditEventWriter.ts +41 -0
- package/ai/token/billingAnomaly.ts +90 -0
- package/ai/token/billingAnomalyLifecycle.ts +54 -0
- package/ai/token/billingAnomalyLifecycleWriter.ts +44 -0
- package/ai/token/billingAnomalyWriter.ts +41 -0
- package/ai/token/calculatePrice.ts +3 -2
- package/ai/token/deepinfraReconciliation.ts +153 -0
- package/ai/token/deepinfraRequestIdQuery.ts +92 -0
- package/ai/token/externalToolCost.ts +54 -41
- package/ai/token/missingUsageEstimate.ts +12 -3
- package/ai/token/normalizeUsage.ts +45 -5
- package/ai/token/openaiReconciliation.ts +188 -0
- package/ai/token/providerBillableEvent.ts +84 -0
- package/ai/token/providerBillableEventWriter.ts +36 -0
- package/ai/token/providerBillingAnomalyDrilldown.ts +308 -0
- package/ai/token/providerBillingDrilldown.ts +361 -0
- package/ai/token/providerBillingHealthReport.ts +366 -0
- package/ai/token/providerCall.ts +144 -0
- package/ai/token/providerCallSweeper.ts +168 -0
- package/ai/token/providerCallWriter.ts +33 -0
- package/ai/token/providerCredential.ts +89 -0
- package/ai/token/providerCredentialAnomaly.ts +154 -0
- package/ai/token/providerCredentialLifecycle.ts +59 -0
- package/ai/token/providerCredentialLifecycleWriter.ts +44 -0
- package/ai/token/providerCredentialRegistry.ts +83 -0
- package/ai/token/providerCredentialRegistryCommand.ts +97 -0
- package/ai/token/providerCredentialRegistryList.ts +124 -0
- package/ai/token/providerCredentialRegistryResolver.ts +150 -0
- package/ai/token/providerCredentialRegistryWriter.ts +41 -0
- package/ai/token/providerCredentialRotationCommand.ts +102 -0
- package/ai/token/providerCredentialRuntime.ts +56 -0
- package/ai/token/providerDispatchIntent.ts +67 -0
- package/ai/token/providerDispatchIntentWriter.ts +36 -0
- package/ai/token/providerGateway.ts +260 -0
- package/ai/token/providerReconciliation.ts +148 -0
- package/ai/token/providerReconciliationLocal.ts +97 -0
- package/ai/token/providerReconciliationRunner.ts +165 -0
- package/ai/token/providerReconciliationWriter.ts +41 -0
- package/ai/token/ratingResult.ts +202 -0
- package/ai/token/ratingResultWriter.ts +33 -0
- package/ai/token/serverDialogProjection.ts +5 -3
- package/ai/token/serverTokenWriter.ts +11 -3
- package/ai/token/types.ts +10 -0
- package/ai/tools/agent/callAgentTool.ts +3 -4
- package/ai/tools/agent/presets/appBuilderPreset.ts +5 -7
- package/ai/tools/agent/runStreamingAgentTool.ts +1 -2
- package/ai/tools/agent/streamParallelAgentsTool.ts +2 -3
- package/ai/tools/readXPostTool.ts +1 -5
- package/app/admin/adminPages.ts +9 -0
- package/app/i18n/i18n.config.ts +5 -0
- package/app/i18n/translations/pricing.locale.ts +397 -0
- package/app/utils/desktopAgentRuntimeStatusClient.ts +5 -4
- package/app/utils/desktopAgentRuntimeTurnClient.ts +4 -1
- package/app/utils/imageUtils.ts +64 -34
- package/auth/adminPermissions.ts +18 -0
- package/auth/authSlice.ts +26 -12
- package/auth/hooks/useFetchUsers.ts +3 -0
- package/auth/routes.ts +46 -0
- package/auth/server/accessActivity.ts +4 -3
- package/auth/server/adminPermissions.ts +43 -0
- package/auth/server/adminUsageReport.ts +375 -0
- package/auth/server/billingAnomalies.ts +235 -0
- package/auth/server/billingUsageReport.ts +41 -2
- package/auth/server/creatorEarningCreditConversion.ts +10 -2
- package/auth/server/deduct.ts +14 -7
- package/auth/server/delete.ts +10 -2
- package/auth/server/disable.ts +4 -3
- package/auth/server/emailAutomation.ts +7 -5
- package/auth/server/emailDbConfig.ts +4 -2
- package/auth/server/emailDelivery.ts +24 -20
- package/auth/server/emailDeliveryGuards.ts +10 -7
- package/auth/server/emailPreferences.ts +6 -4
- package/auth/server/emailReport.ts +6 -4
- package/auth/server/emailRuntimeConfig.ts +3 -3
- package/auth/server/emailScenarioNotifications.ts +9 -8
- package/auth/server/enable.ts +4 -3
- package/auth/server/getRechargeHistory.ts +3 -2
- package/auth/server/getUser.ts +3 -2
- package/auth/server/gptProAccess.ts +44 -0
- package/auth/server/inviteReward.ts +10 -7
- package/auth/server/listusers.ts +6 -4
- package/auth/server/login.ts +2 -2
- package/auth/server/productEntitlements.ts +7 -4
- package/auth/server/productPurchase.ts +10 -2
- package/auth/server/providerBillingDrilldown.ts +47 -0
- package/auth/server/providerBillingHealth.ts +71 -0
- package/auth/server/providerCredentials.ts +136 -0
- package/auth/server/recharge.ts +14 -8
- package/auth/server/revokeSessions.ts +4 -3
- package/auth/server/route.ts +77 -0
- package/auth/server/sendEmail.ts +5 -4
- package/auth/server/signup.ts +10 -3
- package/auth/server/token.ts +53 -55
- package/auth/server/tokenUsageBilling.ts +18 -7
- package/auth/server/usageManagementAccess.ts +43 -0
- package/auth/server/usageReport.ts +59 -0
- package/auth/types.ts +12 -0
- package/auth/utils.ts +24 -22
- package/authCommands.ts +36 -2
- package/buildPublish.ts +3 -1
- package/buildPublishArtifactAssembly.ts +62 -1
- package/buildPublishImportAnalysis.ts +21 -16
- package/chat/dialog/dialogLaunchScope.ts +32 -0
- package/chat/dialog/objectAssistantRegistry.ts +2 -2
- package/chat/dialog/useCreateDialog.ts +1 -1
- package/chat/hooks/useChatInput.ts +41 -10
- package/chat/messages/messageSlice.ts +5 -1
- package/chat/messages/pendingAttachmentParts.ts +28 -2
- package/chat/messages/sendFirstMessage.ts +76 -79
- package/chat/messages/types.ts +9 -0
- package/chat/messages/web/streamingMarkdownModel.ts +41 -0
- package/chat/messages/web/useStreamingReveal.ts +91 -0
- package/chat/web/messageInputAgentUi.ts +94 -6
- package/cliEnvHelpers.ts +68 -13
- package/cliRuntimeDoctorReport.ts +193 -0
- package/client/agentConfigResolver.test.ts +0 -2
- package/client/agentRun.test.ts +171 -10
- package/client/agentRun.ts +44 -637
- package/client/agentRunInput.ts +10 -0
- package/client/agentRunLocalExecutor.ts +179 -0
- package/client/agentRunServerTransport.ts +394 -0
- package/client/agentRunTaskRunRecorder.ts +176 -0
- package/client/localRuntimeAdapter.test.ts +236 -9
- package/client/localRuntimeAdapter.ts +221 -23
- package/client/localToolPolicy.test.ts +28 -4
- package/connector-experimental/daemonLauncher.ts +38 -4
- package/connectorRunArtifact.ts +34 -10
- package/connectorWebSocketTarget.ts +40 -15
- package/core/builtinAgents.ts +155 -11
- package/create/space/contentLabels.ts +1 -1
- package/create/space/contentTypeMeta.ts +3 -2
- package/create/space/sidebarVisibleTypes.ts +27 -0
- package/create/space/space.locale.ts +76 -4
- package/database/actions/agentReadResolution.ts +2 -8
- package/database/actions/read.ts +11 -9
- package/database/actions/readAndWait.ts +10 -5
- package/database/server/agentDelegation.ts +3 -2
- package/database/server/authorityStoreConformance.ts +209 -0
- package/database/server/authorityStoreTypes.ts +31 -0
- package/database/server/coreDataProxy.ts +1 -1
- package/database/server/dataHandlers.ts +13 -5
- package/database/server/db.ts +15 -34
- package/database/server/delete.ts +88 -71
- package/database/server/emailRepository.ts +11 -9
- package/database/server/fileService.ts +2 -1
- package/database/server/legacyServerDb.ts +58 -0
- package/database/server/levelAuthorityStore.ts +75 -0
- package/database/server/memoryAuthorityStore.ts +133 -0
- package/database/server/patch.ts +13 -12
- package/database/server/query.ts +3 -2
- package/database/server/read.ts +33 -30
- package/database/server/resourceAccess.ts +7 -5
- package/database/server/serverStoreFactory.ts +124 -0
- package/database/server/spaceMemberAuthority.ts +3 -2
- package/database/server/storeBatchCompat.ts +37 -0
- package/database/server/testAuthorityStore.ts +76 -0
- package/database/server/write.ts +29 -27
- package/dialogReadCommands.ts +2 -1
- package/dialogStatusCommands.ts +2 -1
- package/integrations/anthropic/anthropicModels.ts +12 -12
- package/integrations/deepseek/models.ts +67 -67
- package/integrations/google/models.ts +111 -53
- package/integrations/openai/models.ts +22 -22
- package/integrations/xai/models.ts +1 -1
- package/localRuntimeDb.ts +39 -2
- package/machineCommandPrompts.ts +2 -0
- package/machineCommands.ts +193 -62
- package/machineStatusCommands.ts +4 -12
- package/machineWsRunDispatch.ts +80 -15
- package/machineWsSession.ts +46 -2
- package/noloReadBridgePrompt.ts +16 -0
- package/package.json +114 -21
- package/pageCreateCommands.ts +2 -2
- package/pageDeleteCommands.ts +3 -3
- package/pageReadCommands.ts +3 -3
- package/pageUpdateCommands.ts +3 -3
- package/render/layout/mainLayoutViewMode.ts +25 -0
- package/render/page/server/createPage.ts +3 -1
- package/render/page/server/handleCreatePage.ts +2 -11
- package/runtimeDoctorCommands.ts +18 -69
- package/server/api/methods.ts +34 -12
- package/server/api/tableHandlers.ts +6 -3
- package/server/authenticateToken.ts +47 -2
- package/server/billingLedgerRoutes.ts +15 -0
- package/server/buildManifest.ts +54 -0
- package/server/coreReadiness.ts +34 -25
- package/server/coreRuntime.ts +15 -10
- package/server/handlers/activityStatsHandler.ts +5 -2
- package/server/handlers/agentEmailRegistrationE2EHandler.ts +25 -23
- package/server/handlers/agentRun/agentLookup.ts +1 -7
- package/server/handlers/agentRun/autonomousRuntime.ts +11 -10
- package/server/handlers/agentRun/builtinAgents.ts +12 -88
- package/server/handlers/agentRun/continueDialogContext.ts +15 -3
- package/server/handlers/agentRun/{inheritedDialogPrompt.ts → conversationReference.ts} +3 -3
- package/server/handlers/agentRun/dialogLookup.ts +4 -3
- package/server/handlers/agentRun/index.ts +864 -404
- package/server/handlers/agentRun/localRuntimeBootstrap.ts +17 -1
- package/server/handlers/agentRun/loop.ts +920 -508
- package/server/handlers/agentRun/machineConnector.ts +56 -8
- package/server/handlers/agentRun/machineRunAudit.ts +3 -2
- package/server/handlers/agentRun/modelUsageToolHandlers.ts +13 -10
- package/server/handlers/agentRun/requestContext.ts +12 -8
- package/server/handlers/agentRun/runtimeExecutionContext.ts +15 -3
- package/server/handlers/agentRun/runtimePreparation.ts +26 -24
- package/server/handlers/agentRun/runtimeRouting.ts +25 -40
- package/server/handlers/agentRun/runtimeSystemMessages.ts +65 -0
- package/server/handlers/agentRun/saveDialog.ts +97 -87
- package/server/handlers/agentRun/taskRunToolHandler.ts +9 -7
- package/server/handlers/agentRun/toolExecutor.ts +42 -78
- package/server/handlers/agentRun/types.ts +2 -1
- package/server/handlers/appDeployStatusStore.ts +17 -10
- package/server/handlers/appDomainHandler.ts +21 -15
- package/server/handlers/appLegacyInfraCleanup.ts +5 -2
- package/server/handlers/appSandboxHandler.ts +29 -8
- package/server/handlers/appSpaceAccess.ts +15 -8
- package/server/handlers/chatHandler.ts +22 -2
- package/server/handlers/chatUpstreamRetry.ts +225 -2
- package/server/handlers/connector/connectorConnectionRegistry.ts +55 -7
- package/server/handlers/connector/connectorWebSocket.ts +14 -10
- package/server/handlers/desktopAgentRuntimeAdapter.ts +4 -4
- package/server/handlers/desktopAgentRuntimeHostCapabilities.ts +25 -0
- package/server/handlers/desktopAgentRuntimeReadiness.ts +62 -0
- package/server/handlers/desktopAgentRuntimeStatusHandler.ts +38 -30
- package/server/handlers/desktopAgentRuntimeTurnHandler.ts +7 -3
- package/server/handlers/desktopAgentRuntimeTurnService.ts +39 -45
- package/server/handlers/desktopLlamaRuntimeHandler.ts +85 -51
- package/server/handlers/desktopUpdaterHandler.ts +132 -24
- package/server/handlers/favoriteHandlers.ts +8 -2
- package/server/handlers/getDialogBillingHandler.ts +4 -3
- package/server/handlers/getTransactionsHandler.ts +5 -2
- package/server/handlers/machines/machineBinding.ts +1 -0
- package/server/handlers/machines/machineHandlers.ts +0 -14
- package/server/handlers/machines/machineInstallAssets.ts +4 -2
- package/server/handlers/notificationEmitter.ts +5 -3
- package/server/handlers/notificationsHandler.ts +5 -2
- package/server/handlers/providerCallsRecentHandler.ts +234 -0
- package/server/handlers/providerReconciliationRunHandler.ts +180 -0
- package/server/handlers/providerRequestIdsHandler.ts +105 -0
- package/server/handlers/tableAccess.ts +6 -2
- package/server/handlers/tableToolHandlers.ts +28 -14
- package/server/handlers/userSecretsHandler.ts +17 -6
- package/server/handlers/versionHandler.ts +9 -4
- package/server/handlers/versionStore.ts +18 -10
- package/server/html/ssrPreload.ts +5 -3
- package/server/payments/crypto/cryptoUsdcBasePaymentProvider.ts +11 -8
- package/server/payments/crypto/cryptoUsdcBaseScanner.ts +12 -7
- package/server/payments/crypto/cryptoUsdtTronPaymentProvider.ts +11 -8
- package/server/payments/crypto/cryptoUsdtTronScanner.ts +9 -7
- package/server/payments/waffo/waffoPaymentProvider.ts +12 -9
- package/server/runtimeRole.ts +15 -0
- package/server/scheduler/scheduledTaskRuntime.ts +4 -2
- package/server/scheduler/schedulerService.ts +2 -2
- package/server/taskRunBridgeRoutes.ts +8 -5
- package/share/server/fetchCommunityShares.ts +1 -1
- package/share/server/helpers.ts +19 -17
- package/share/server/importShare.ts +9 -13
- package/share/server/listCommunityShares.ts +4 -4
- package/share/server/purchaseDoc.ts +8 -16
- package/share/server/readCommunityShareCover.ts +3 -2
- package/share/server/readSharedTable.ts +14 -13
- package/share/server/tableReplication.ts +42 -39
- package/spaceAttachCommands.ts +135 -0
- package/spaceCategoryCommands.ts +6 -6
- package/spaceCommands.ts +3 -3
- package/spaceDeleteCommands.ts +2 -2
- package/spaceInternalCommandEntries.ts +2 -0
- package/spaceReadCommands.ts +3 -3
- package/tableMetaCommands.ts +2 -2
- package/taskRunCommand.ts +11 -0
- package/ai/agent/runtimeServerBase.ts +0 -37
- 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
|
|
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
|
|
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
|
|
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
|
+
}
|