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
|
@@ -120,8 +120,8 @@ export const buildBuiltinObjectAssistantAgent = (
|
|
|
120
120
|
model: FIREWORKS_KIMI_LATEST_MODEL,
|
|
121
121
|
apiSource: "platform" as const,
|
|
122
122
|
useServerProxy: true,
|
|
123
|
-
inputPrice:
|
|
124
|
-
outputPrice:
|
|
123
|
+
inputPrice: 0.95 * 8,
|
|
124
|
+
outputPrice: 4 * 8,
|
|
125
125
|
createdAt: now,
|
|
126
126
|
updatedAt: now,
|
|
127
127
|
dialogCount: 0,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useState, useCallback } from "react";
|
|
1
|
+
import { useState, useCallback, useEffect, useRef } from "react";
|
|
2
2
|
import { nanoid } from "nanoid";
|
|
3
3
|
import { readFileAsDataURL } from "../../app/utils/fileReaders";
|
|
4
4
|
|
|
@@ -25,6 +25,29 @@ export const useChatInput = (options: UseChatInputOptions = {}) => {
|
|
|
25
25
|
const [text, setText] = useState(initialText);
|
|
26
26
|
const [imageFiles, setImageFiles] = useState<Map<string, File>>(new Map());
|
|
27
27
|
const [imgPreviews, setImgPreviews] = useState<PendingImagePreview[]>([]);
|
|
28
|
+
const objectUrlByIdRef = useRef<Map<string, string>>(new Map());
|
|
29
|
+
|
|
30
|
+
const revokePreviewUrl = useCallback((id: string) => {
|
|
31
|
+
const url = objectUrlByIdRef.current.get(id);
|
|
32
|
+
if (!url) return;
|
|
33
|
+
|
|
34
|
+
if (typeof URL !== "undefined" && typeof URL.revokeObjectURL === "function") {
|
|
35
|
+
URL.revokeObjectURL(url);
|
|
36
|
+
}
|
|
37
|
+
objectUrlByIdRef.current.delete(id);
|
|
38
|
+
}, []);
|
|
39
|
+
|
|
40
|
+
const revokeAllPreviewUrls = useCallback(() => {
|
|
41
|
+
for (const id of objectUrlByIdRef.current.keys()) {
|
|
42
|
+
revokePreviewUrl(id);
|
|
43
|
+
}
|
|
44
|
+
}, [revokePreviewUrl]);
|
|
45
|
+
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
return () => {
|
|
48
|
+
revokeAllPreviewUrls();
|
|
49
|
+
};
|
|
50
|
+
}, [revokeAllPreviewUrls]);
|
|
28
51
|
|
|
29
52
|
const handleTextChange = useCallback(
|
|
30
53
|
(newText: string) => {
|
|
@@ -54,13 +77,19 @@ export const useChatInput = (options: UseChatInputOptions = {}) => {
|
|
|
54
77
|
allowedFiles.forEach((file) => {
|
|
55
78
|
const id = nanoid();
|
|
56
79
|
|
|
57
|
-
|
|
58
|
-
.
|
|
59
|
-
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
80
|
+
if (typeof URL !== "undefined" && typeof URL.createObjectURL === "function") {
|
|
81
|
+
const url = URL.createObjectURL(file);
|
|
82
|
+
objectUrlByIdRef.current.set(id, url);
|
|
83
|
+
setImgPreviews((prev) => [...prev, { id, url }]);
|
|
84
|
+
} else {
|
|
85
|
+
readFileAsDataURL(file)
|
|
86
|
+
.then((url) => {
|
|
87
|
+
setImgPreviews((prev) => [...prev, { id, url }]);
|
|
88
|
+
})
|
|
89
|
+
.catch((err) => {
|
|
90
|
+
console.warn("[useChatInput] readFileAsDataURL failed:", err);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
64
93
|
|
|
65
94
|
setImageFiles((prev) => {
|
|
66
95
|
const next = new Map(prev);
|
|
@@ -73,19 +102,21 @@ export const useChatInput = (options: UseChatInputOptions = {}) => {
|
|
|
73
102
|
);
|
|
74
103
|
|
|
75
104
|
const removeImage = useCallback((id: string) => {
|
|
105
|
+
revokePreviewUrl(id);
|
|
76
106
|
setImgPreviews((prev) => prev.filter((img) => img.id !== id));
|
|
77
107
|
setImageFiles((prev) => {
|
|
78
108
|
const next = new Map(prev);
|
|
79
109
|
next.delete(id);
|
|
80
110
|
return next;
|
|
81
111
|
});
|
|
82
|
-
}, []);
|
|
112
|
+
}, [revokePreviewUrl]);
|
|
83
113
|
|
|
84
114
|
const clear = useCallback(() => {
|
|
115
|
+
revokeAllPreviewUrls();
|
|
85
116
|
setText("");
|
|
86
117
|
setImgPreviews([]);
|
|
87
118
|
setImageFiles(new Map());
|
|
88
|
-
}, []);
|
|
119
|
+
}, [revokeAllPreviewUrls]);
|
|
89
120
|
|
|
90
121
|
return {
|
|
91
122
|
text,
|
|
@@ -788,6 +788,8 @@ export const messageSlice = createSliceWithThunks({
|
|
|
788
788
|
? agentConfig.name.trim()
|
|
789
789
|
: "";
|
|
790
790
|
const agentName = rawName || undefined;
|
|
791
|
+
const { imageGenerationState: _transientImageGenerationState, ...persistedMessageMetadata } =
|
|
792
|
+
payload.messageMetadata ?? {};
|
|
791
793
|
|
|
792
794
|
const finalMessage: Message = {
|
|
793
795
|
id: messageId,
|
|
@@ -799,7 +801,7 @@ export const messageSlice = createSliceWithThunks({
|
|
|
799
801
|
cybotKey: agentConfig.dbKey,
|
|
800
802
|
usage: finalUsageData,
|
|
801
803
|
isStreaming: false,
|
|
802
|
-
...
|
|
804
|
+
...persistedMessageMetadata,
|
|
803
805
|
...(agentName ? { agentName } : {}),
|
|
804
806
|
...(toolCalls && toolCalls.length > 0
|
|
805
807
|
? { tool_calls: toolCalls }
|
|
@@ -916,6 +918,7 @@ export const messageSlice = createSliceWithThunks({
|
|
|
916
918
|
id: action.payload.id,
|
|
917
919
|
changes: {
|
|
918
920
|
isStreaming: false,
|
|
921
|
+
imageGenerationState: undefined,
|
|
919
922
|
content: action.payload.content,
|
|
920
923
|
thinkContent: action.payload.thinkContent,
|
|
921
924
|
usage: action.payload.usage,
|
|
@@ -980,6 +983,7 @@ export const messageSlice = createSliceWithThunks({
|
|
|
980
983
|
id: messageId,
|
|
981
984
|
changes: {
|
|
982
985
|
isStreaming: false,
|
|
986
|
+
imageGenerationState: undefined,
|
|
983
987
|
content: appendSaveFailureToContent(
|
|
984
988
|
dialogState.msgs.entities[messageId]?.content
|
|
985
989
|
),
|
|
@@ -75,7 +75,9 @@ export const pendingAttachmentsToMessageParts = (
|
|
|
75
75
|
files: PendingAttachmentLike[],
|
|
76
76
|
args: { currentServer?: string | null }
|
|
77
77
|
): PendingAttachmentMessagePart[] =>
|
|
78
|
-
files.flatMap((file) =>
|
|
78
|
+
deduplicatePendingAttachments(files).flatMap((file) =>
|
|
79
|
+
pendingAttachmentToMessageParts(file, args)
|
|
80
|
+
);
|
|
79
81
|
|
|
80
82
|
export const resolvePendingAttachmentToMessageParts = async (
|
|
81
83
|
file: PendingAttachmentLike,
|
|
@@ -111,7 +113,31 @@ export const resolvePendingAttachmentsToMessageParts = async (
|
|
|
111
113
|
}
|
|
112
114
|
): Promise<PendingAttachmentMessagePart[]> => {
|
|
113
115
|
const nested = await Promise.all(
|
|
114
|
-
files.map((file) =>
|
|
116
|
+
deduplicatePendingAttachments(files).map((file) =>
|
|
117
|
+
resolvePendingAttachmentToMessageParts(file, args)
|
|
118
|
+
)
|
|
115
119
|
);
|
|
116
120
|
return nested.flat();
|
|
117
121
|
};
|
|
122
|
+
|
|
123
|
+
const pendingAttachmentIdentity = (file: PendingAttachmentLike): string => {
|
|
124
|
+
return (
|
|
125
|
+
normalizeText(file.pageKey) ||
|
|
126
|
+
normalizeText(file.sourceDialogKey) ||
|
|
127
|
+
normalizeText(file.dialogKey)
|
|
128
|
+
);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
export const deduplicatePendingAttachments = (
|
|
132
|
+
files: PendingAttachmentLike[]
|
|
133
|
+
): PendingAttachmentLike[] => {
|
|
134
|
+
const seen = new Set<string>();
|
|
135
|
+
const result: PendingAttachmentLike[] = [];
|
|
136
|
+
for (const file of files) {
|
|
137
|
+
const identity = pendingAttachmentIdentity(file);
|
|
138
|
+
if (identity && seen.has(identity)) continue;
|
|
139
|
+
if (identity) seen.add(identity);
|
|
140
|
+
result.push(file);
|
|
141
|
+
}
|
|
142
|
+
return result;
|
|
143
|
+
};
|
|
@@ -4,7 +4,7 @@ import type { AgentRuntimeOptions } from "../../ai/agent/types";
|
|
|
4
4
|
import { handleSendMessage } from "../dialog/dialogSlice";
|
|
5
5
|
import { upload } from "../../database/dbSlice";
|
|
6
6
|
import { getRuntimeServerContext } from "../../database/runtimeServerContext";
|
|
7
|
-
import { waitForFileReady,
|
|
7
|
+
import { waitForFileReady, compressImageFile } from "../../app/utils/imageUtils";
|
|
8
8
|
import { readFileAsDataURL } from "../../app/utils/fileReaders";
|
|
9
9
|
import type { RootState } from "../../app/store";
|
|
10
10
|
import { buildMessageFileContentUrl, isLocalFileContentUrl } from "./fileUrl";
|
|
@@ -41,6 +41,36 @@ const logQuickChatPerfStage = (
|
|
|
41
41
|
});
|
|
42
42
|
};
|
|
43
43
|
|
|
44
|
+
const IMAGE_PREP_CONCURRENCY = 2;
|
|
45
|
+
|
|
46
|
+
const mapWithConcurrency = async <T, R>(
|
|
47
|
+
items: T[],
|
|
48
|
+
concurrency: number,
|
|
49
|
+
mapper: (item: T, index: number) => Promise<R>
|
|
50
|
+
): Promise<R[]> => {
|
|
51
|
+
if (items.length === 0) return [];
|
|
52
|
+
|
|
53
|
+
const results = new Array<R>(items.length);
|
|
54
|
+
let nextIndex = 0;
|
|
55
|
+
const workerCount = Math.min(concurrency, items.length);
|
|
56
|
+
|
|
57
|
+
const workers = Array.from({ length: workerCount }, async () => {
|
|
58
|
+
while (true) {
|
|
59
|
+
const currentIndex = nextIndex++;
|
|
60
|
+
if (currentIndex >= items.length) return;
|
|
61
|
+
results[currentIndex] = await mapper(items[currentIndex], currentIndex);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
await Promise.all(workers);
|
|
66
|
+
return results;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const buildInlineImagePart = async (file: File): Promise<MessagePart> => ({
|
|
70
|
+
type: "image_url",
|
|
71
|
+
image_url: { url: await readFileAsDataURL(file) },
|
|
72
|
+
});
|
|
73
|
+
|
|
44
74
|
/**
|
|
45
75
|
* 发送一条首条消息:
|
|
46
76
|
* - 支持文字 + 图片 + 文档混合
|
|
@@ -84,86 +114,53 @@ export const sendFirstMessage =
|
|
|
84
114
|
// 当前文档逻辑是通过 “pendingFiles + addReferenceKeysAction + createPage”等实现的,
|
|
85
115
|
// 如需首页入口支持文档首条消息,请把那部分逻辑抽成复用函数后在这里调用。
|
|
86
116
|
|
|
87
|
-
// 2. 处理图片 files
|
|
88
|
-
const uploadedImgs
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
117
|
+
// 2. 处理图片 files:优先直传压缩后的 File,只有 fallback 时才转 data URL
|
|
118
|
+
const uploadedImgs = await mapWithConcurrency(
|
|
119
|
+
imageFiles,
|
|
120
|
+
IMAGE_PREP_CONCURRENCY,
|
|
121
|
+
async (file): Promise<MessagePart> => {
|
|
122
|
+
const uploadFile = await compressImageFile(file);
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
const metadata = await dispatch(
|
|
126
|
+
upload({
|
|
127
|
+
file: uploadFile,
|
|
128
|
+
customKey: `chat-image-${Date.now()}`,
|
|
129
|
+
}) as any
|
|
130
|
+
).unwrap();
|
|
131
|
+
const fileId = metadata?.id as string | undefined;
|
|
132
|
+
|
|
133
|
+
if (!fileId || !currentServer) {
|
|
134
|
+
return buildInlineImagePart(uploadFile);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const imageUrl = buildMessageFileContentUrl(currentServer, fileId);
|
|
138
|
+
if (!imageUrl) {
|
|
139
|
+
return buildInlineImagePart(uploadFile);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (isLocalFileContentUrl(imageUrl)) {
|
|
143
|
+
return buildInlineImagePart(uploadFile);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const ready = await waitForFileReady(imageUrl);
|
|
147
|
+
if (!ready) {
|
|
148
|
+
return buildInlineImagePart(uploadFile);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
type: "image_url",
|
|
153
|
+
image_url: { url: imageUrl },
|
|
154
|
+
};
|
|
155
|
+
} catch (error) {
|
|
156
|
+
console.warn(
|
|
157
|
+
"[sendFirstMessage] image upload failed, falling back to inline data URL",
|
|
158
|
+
error
|
|
159
|
+
);
|
|
160
|
+
return buildInlineImagePart(uploadFile);
|
|
104
161
|
}
|
|
105
|
-
} catch {
|
|
106
|
-
// 压缩失败就用原图
|
|
107
162
|
}
|
|
108
|
-
|
|
109
|
-
if (!uploadFile) {
|
|
110
|
-
uploadedImgs.push({
|
|
111
|
-
type: "image_url",
|
|
112
|
-
image_url: { url: compressedDataUrl },
|
|
113
|
-
});
|
|
114
|
-
continue;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const metadata = await dispatch(
|
|
118
|
-
upload({
|
|
119
|
-
file: uploadFile,
|
|
120
|
-
customKey: `chat-image-${Date.now()}`,
|
|
121
|
-
}) as any
|
|
122
|
-
).unwrap();
|
|
123
|
-
const fileId = metadata?.id as string | undefined;
|
|
124
|
-
|
|
125
|
-
if (!fileId || !currentServer) {
|
|
126
|
-
uploadedImgs.push({
|
|
127
|
-
type: "image_url",
|
|
128
|
-
image_url: { url: compressedDataUrl },
|
|
129
|
-
});
|
|
130
|
-
continue;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const imageUrl = buildMessageFileContentUrl(currentServer, fileId);
|
|
134
|
-
if (!imageUrl) {
|
|
135
|
-
uploadedImgs.push({
|
|
136
|
-
type: "image_url",
|
|
137
|
-
image_url: { url: compressedDataUrl },
|
|
138
|
-
});
|
|
139
|
-
continue;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
const isLocalhost = isLocalFileContentUrl(imageUrl);
|
|
143
|
-
|
|
144
|
-
// 如果是 localhost,AI 无法访问,改用 base64
|
|
145
|
-
if (isLocalhost) {
|
|
146
|
-
uploadedImgs.push({
|
|
147
|
-
type: "image_url",
|
|
148
|
-
image_url: { url: compressedDataUrl },
|
|
149
|
-
});
|
|
150
|
-
continue;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const ready = await waitForFileReady(imageUrl);
|
|
154
|
-
if (!ready) {
|
|
155
|
-
uploadedImgs.push({
|
|
156
|
-
type: "image_url",
|
|
157
|
-
image_url: { url: compressedDataUrl },
|
|
158
|
-
});
|
|
159
|
-
continue;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
uploadedImgs.push({
|
|
163
|
-
type: "image_url",
|
|
164
|
-
image_url: { url: imageUrl },
|
|
165
|
-
});
|
|
166
|
-
}
|
|
163
|
+
);
|
|
167
164
|
|
|
168
165
|
const finalParts: MessagePart[] = [
|
|
169
166
|
...parts,
|
package/chat/messages/types.ts
CHANGED
|
@@ -46,6 +46,14 @@ export interface CompletionUsage {
|
|
|
46
46
|
|
|
47
47
|
export type Content = string | MessageContentPart[];
|
|
48
48
|
|
|
49
|
+
export interface ImageGenerationState {
|
|
50
|
+
kind: "image_generation";
|
|
51
|
+
stage: "submitted" | "generating" | "saving";
|
|
52
|
+
startedAt: number;
|
|
53
|
+
waitHint?: string;
|
|
54
|
+
profileLabel?: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
49
57
|
// ========== 消息级 UI 选项(Agent 菜单 / 快速回复 等) ==========
|
|
50
58
|
|
|
51
59
|
export type UiOptionSource = "agent_menu" | "llm" | "system" | "tool";
|
|
@@ -142,6 +150,7 @@ export interface Message {
|
|
|
142
150
|
agentName?: string;
|
|
143
151
|
|
|
144
152
|
isStreaming?: boolean;
|
|
153
|
+
imageGenerationState?: ImageGenerationState;
|
|
145
154
|
userId?: string;
|
|
146
155
|
usage?: any;
|
|
147
156
|
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { markdownToSlate } from "../../../create/editor/transforms/markdownToSlate";
|
|
2
|
+
|
|
3
|
+
type StreamingMarkdownModel =
|
|
4
|
+
| { kind: "plain-text"; content: string }
|
|
5
|
+
| { kind: "structured"; nodes: any[] };
|
|
6
|
+
|
|
7
|
+
function isPlainTextLeaf(node: any): boolean {
|
|
8
|
+
return (
|
|
9
|
+
typeof node?.text === "string" &&
|
|
10
|
+
Object.keys(node).every((key) => key === "text")
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function isPlainTextParagraph(node: any): boolean {
|
|
15
|
+
return (
|
|
16
|
+
node?.type === "paragraph" &&
|
|
17
|
+
Array.isArray(node.children) &&
|
|
18
|
+
node.children.every(isPlainTextLeaf)
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function buildStreamingMarkdownModel(content: string): StreamingMarkdownModel {
|
|
23
|
+
if (!content) {
|
|
24
|
+
return { kind: "plain-text", content };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
const nodes = markdownToSlate(content) || [];
|
|
29
|
+
if (nodes.length === 1 && isPlainTextParagraph(nodes[0])) {
|
|
30
|
+
return { kind: "plain-text", content };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (nodes.length > 0) {
|
|
34
|
+
return { kind: "structured", nodes };
|
|
35
|
+
}
|
|
36
|
+
} catch {
|
|
37
|
+
// Fall through to plain-text rendering when markdown parsing fails.
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return { kind: "plain-text", content };
|
|
41
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from "react";
|
|
2
|
+
|
|
3
|
+
const STREAMING_SOFT_REVEAL_THRESHOLD = 8;
|
|
4
|
+
const STREAMING_SOFT_REVEAL_LEAD_MIN = 12;
|
|
5
|
+
const STREAMING_SOFT_REVEAL_LEAD_MAX = 24;
|
|
6
|
+
const STREAMING_SOFT_REVEAL_LEAD_RATIO = 0.4;
|
|
7
|
+
const STREAMING_SOFT_REVEAL_SETTLE_DELAY_MS = 36;
|
|
8
|
+
|
|
9
|
+
export function splitVisibleCharacters(content: string): string[] {
|
|
10
|
+
const Segmenter = Intl.Segmenter;
|
|
11
|
+
if (typeof Segmenter === "function") {
|
|
12
|
+
const segmenter = new Segmenter(undefined, { granularity: "grapheme" });
|
|
13
|
+
return Array.from(segmenter.segment(content), (part) => part.segment);
|
|
14
|
+
}
|
|
15
|
+
return Array.from(content);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function getSoftRevealCharacterCount(currentCount: number, targetCount: number): number {
|
|
19
|
+
const appendedCount = targetCount - currentCount;
|
|
20
|
+
if (appendedCount <= STREAMING_SOFT_REVEAL_THRESHOLD) {
|
|
21
|
+
return targetCount;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const leadCount = Math.min(
|
|
25
|
+
STREAMING_SOFT_REVEAL_LEAD_MAX,
|
|
26
|
+
Math.max(
|
|
27
|
+
STREAMING_SOFT_REVEAL_LEAD_MIN,
|
|
28
|
+
Math.ceil(appendedCount * STREAMING_SOFT_REVEAL_LEAD_RATIO)
|
|
29
|
+
)
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
return Math.min(targetCount, currentCount + leadCount);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function useStreamingReveal(content: string): string {
|
|
36
|
+
const [visibleContent, setVisibleContent] = useState(content);
|
|
37
|
+
const visibleContentRef = useRef(content);
|
|
38
|
+
const revealTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
39
|
+
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
visibleContentRef.current = visibleContent;
|
|
42
|
+
}, [visibleContent]);
|
|
43
|
+
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (revealTimerRef.current) {
|
|
46
|
+
clearTimeout(revealTimerRef.current);
|
|
47
|
+
revealTimerRef.current = null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const currentVisible = visibleContentRef.current;
|
|
51
|
+
if (currentVisible === content) return;
|
|
52
|
+
|
|
53
|
+
if (currentVisible && !content.startsWith(currentVisible)) {
|
|
54
|
+
visibleContentRef.current = content;
|
|
55
|
+
setVisibleContent(content);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const targetCharacters = splitVisibleCharacters(content);
|
|
60
|
+
const visibleCharacters = splitVisibleCharacters(currentVisible);
|
|
61
|
+
const nextCount = getSoftRevealCharacterCount(
|
|
62
|
+
visibleCharacters.length,
|
|
63
|
+
targetCharacters.length
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
if (nextCount >= targetCharacters.length) {
|
|
67
|
+
visibleContentRef.current = content;
|
|
68
|
+
setVisibleContent(content);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const partialContent = targetCharacters.slice(0, nextCount).join("");
|
|
73
|
+
visibleContentRef.current = partialContent;
|
|
74
|
+
setVisibleContent(partialContent);
|
|
75
|
+
|
|
76
|
+
revealTimerRef.current = setTimeout(() => {
|
|
77
|
+
revealTimerRef.current = null;
|
|
78
|
+
visibleContentRef.current = content;
|
|
79
|
+
setVisibleContent(content);
|
|
80
|
+
}, STREAMING_SOFT_REVEAL_SETTLE_DELAY_MS);
|
|
81
|
+
|
|
82
|
+
return () => {
|
|
83
|
+
if (revealTimerRef.current) {
|
|
84
|
+
clearTimeout(revealTimerRef.current);
|
|
85
|
+
revealTimerRef.current = null;
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
}, [content]);
|
|
89
|
+
|
|
90
|
+
return visibleContent;
|
|
91
|
+
}
|
|
@@ -21,12 +21,36 @@ export interface ImageUiConfig {
|
|
|
21
21
|
supportedAspectRatios: string[];
|
|
22
22
|
supportedImageSizes: ("1K" | "2K" | "4K")[];
|
|
23
23
|
pricePerImage?: number;
|
|
24
|
+
waitHint?: string;
|
|
25
|
+
defaultImageProfileKey?: ImageProfileOption["key"];
|
|
26
|
+
imageProfiles?: ImageProfileOption[];
|
|
24
27
|
pricingModel?: Pick<
|
|
25
28
|
Model,
|
|
26
29
|
"pricePerImage" | "imageTokenPricePerMillion" | "imageOutputTokenEstimateBySize"
|
|
27
30
|
>;
|
|
28
31
|
}
|
|
29
32
|
|
|
33
|
+
export interface ImageProfileOption {
|
|
34
|
+
key: "speed" | "quality";
|
|
35
|
+
label: string;
|
|
36
|
+
imageModelOverride: string;
|
|
37
|
+
waitHint?: string;
|
|
38
|
+
pricePerImage?: number;
|
|
39
|
+
pricingModel?: Pick<
|
|
40
|
+
Model,
|
|
41
|
+
"pricePerImage" | "imageTokenPricePerMillion" | "imageOutputTokenEstimateBySize"
|
|
42
|
+
>;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const formatImageWaitHint = (
|
|
46
|
+
range?: Model["imageGenerationWaitTimeSeconds"]
|
|
47
|
+
) => {
|
|
48
|
+
if (!range || typeof range.min !== "number" || typeof range.max !== "number") {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
return `通常需要 ${range.min}-${range.max} 秒`;
|
|
52
|
+
};
|
|
53
|
+
|
|
30
54
|
export function normalizeFavoriteAgentSummary(
|
|
31
55
|
agentKey: string,
|
|
32
56
|
agent: Pick<Agent, "name"> | null | undefined
|
|
@@ -95,6 +119,65 @@ function resolveAgentModelIdentity(agent: Partial<Agent>) {
|
|
|
95
119
|
return { providerKey, modelConfig };
|
|
96
120
|
}
|
|
97
121
|
|
|
122
|
+
function toPricingModel(
|
|
123
|
+
modelConfig: Model | null | undefined
|
|
124
|
+
): ImageUiConfig["pricingModel"] | undefined {
|
|
125
|
+
if (!modelConfig) return undefined;
|
|
126
|
+
return {
|
|
127
|
+
pricePerImage: modelConfig.pricePerImage,
|
|
128
|
+
imageTokenPricePerMillion: modelConfig.imageTokenPricePerMillion,
|
|
129
|
+
imageOutputTokenEstimateBySize:
|
|
130
|
+
modelConfig.imageOutputTokenEstimateBySize,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function resolveImageProfiles(args: {
|
|
135
|
+
providerKey: string;
|
|
136
|
+
modelConfig: Model | null;
|
|
137
|
+
}): {
|
|
138
|
+
imageProfiles: ImageProfileOption[];
|
|
139
|
+
defaultImageProfileKey?: ImageProfileOption["key"];
|
|
140
|
+
} {
|
|
141
|
+
const { providerKey, modelConfig } = args;
|
|
142
|
+
if (!modelConfig?.imageGenerationProfiles?.length) {
|
|
143
|
+
return { imageProfiles: [] };
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const imageProfiles = modelConfig.imageGenerationProfiles.flatMap((profile) => {
|
|
147
|
+
let profileModelConfig: Model | null = null;
|
|
148
|
+
try {
|
|
149
|
+
profileModelConfig = getModelConfig(
|
|
150
|
+
providerKey as Provider,
|
|
151
|
+
profile.imageModel
|
|
152
|
+
);
|
|
153
|
+
} catch {
|
|
154
|
+
profileModelConfig = null;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const pricingModel = toPricingModel(profileModelConfig);
|
|
158
|
+
return [
|
|
159
|
+
{
|
|
160
|
+
key: profile.key,
|
|
161
|
+
label: profile.label,
|
|
162
|
+
imageModelOverride: profile.imageModel,
|
|
163
|
+
waitHint:
|
|
164
|
+
formatImageWaitHint(profile.waitTimeSeconds) ??
|
|
165
|
+
formatImageWaitHint(profileModelConfig?.imageGenerationWaitTimeSeconds),
|
|
166
|
+
pricingModel,
|
|
167
|
+
pricePerImage:
|
|
168
|
+
getApproxPricePerImage(pricingModel, undefined) ?? undefined,
|
|
169
|
+
},
|
|
170
|
+
];
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
return {
|
|
174
|
+
imageProfiles,
|
|
175
|
+
defaultImageProfileKey: modelConfig.imageGenerationProfiles.find(
|
|
176
|
+
(profile) => profile.imageModel === modelConfig.name
|
|
177
|
+
)?.key,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
98
181
|
export function resolveMessageInputAgentUi(input: {
|
|
99
182
|
agent: Partial<Agent>;
|
|
100
183
|
userId: string | null;
|
|
@@ -148,6 +231,9 @@ export function resolveMessageInputAgentUi(input: {
|
|
|
148
231
|
supportsImageConfig: false,
|
|
149
232
|
supportedAspectRatios: [],
|
|
150
233
|
supportedImageSizes: [],
|
|
234
|
+
waitHint: undefined,
|
|
235
|
+
defaultImageProfileKey: undefined,
|
|
236
|
+
imageProfiles: [],
|
|
151
237
|
pricingModel: undefined,
|
|
152
238
|
},
|
|
153
239
|
};
|
|
@@ -166,12 +252,11 @@ export function resolveMessageInputAgentUi(input: {
|
|
|
166
252
|
(modelConfig.supportedImageSizes as ("1K" | "2K" | "4K")[]) ??
|
|
167
253
|
(imageMode === "continuous" ? ["1K", "2K"] : ["1K", "2K", "4K"]);
|
|
168
254
|
|
|
169
|
-
const pricingModel =
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
};
|
|
255
|
+
const pricingModel = toPricingModel(modelConfig);
|
|
256
|
+
const { imageProfiles, defaultImageProfileKey } = resolveImageProfiles({
|
|
257
|
+
providerKey,
|
|
258
|
+
modelConfig,
|
|
259
|
+
});
|
|
175
260
|
|
|
176
261
|
return {
|
|
177
262
|
switchModelQueryUserId,
|
|
@@ -181,6 +266,9 @@ export function resolveMessageInputAgentUi(input: {
|
|
|
181
266
|
supportsImageConfig,
|
|
182
267
|
supportedAspectRatios,
|
|
183
268
|
supportedImageSizes,
|
|
269
|
+
waitHint: formatImageWaitHint(modelConfig.imageGenerationWaitTimeSeconds),
|
|
270
|
+
defaultImageProfileKey,
|
|
271
|
+
imageProfiles,
|
|
184
272
|
pricePerImage:
|
|
185
273
|
getApproxPricePerImage(pricingModel, undefined) ?? undefined,
|
|
186
274
|
pricingModel,
|