nolo-cli 0.1.30 → 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/agentRecordCommands.ts +1 -1
- package/agentRecordHelpers.ts +35 -20
- package/agentRunParsing.ts +18 -5
- package/agentRuntimeLocal.ts +10 -0
- 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 +8 -0
- 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 +9 -5
- 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/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 -63
- package/machineWsRunDispatch.ts +80 -15
- package/machineWsSession.ts +39 -2
- package/noloReadBridgePrompt.ts +16 -0
- package/package.json +99 -6
- 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 +15 -66
- 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/spaceInternalCommandEntries.ts +2 -0
- package/ai/agent/runtimeServerBase.ts +0 -37
- package/server/handlers/desktopAgentRuntimeHostFacts.ts +0 -40
|
@@ -56,6 +56,8 @@ import {
|
|
|
56
56
|
} from "../tools/toolRunSlice";
|
|
57
57
|
import { buildRecentAppToolMemory } from "./appWorkingMemory";
|
|
58
58
|
import type { AgentRuntimeOptions } from "./types";
|
|
59
|
+
import { getModelConfig, getProviderByModelName, type Provider } from "../llm/providers";
|
|
60
|
+
import type { ImageGenerationState } from "../../chat/messages/types";
|
|
59
61
|
|
|
60
62
|
const BROWSER_UNAVAILABLE_CORE_TOOLS = new Set([
|
|
61
63
|
"queryModelUsage",
|
|
@@ -270,6 +272,103 @@ export const readSafe = async <T>(
|
|
|
270
272
|
export const joinMapValues = (map: Map<string, string>): string =>
|
|
271
273
|
Array.from(map.values()).join("");
|
|
272
274
|
|
|
275
|
+
const LARGE_REFERENCE_CONTEXT_CHAR_LIMIT = 50_000;
|
|
276
|
+
const LARGE_REFERENCE_SNIPPET_CHARS = 6_000;
|
|
277
|
+
const LARGE_REFERENCE_MAX_SNIPPETS = 4;
|
|
278
|
+
|
|
279
|
+
const getPendingFileReferenceKey = (file: PendingFile): string =>
|
|
280
|
+
file.sourceDialogKey || file.dialogKey || file.pageKey || "";
|
|
281
|
+
|
|
282
|
+
const normalizeContextText = (value: unknown): string =>
|
|
283
|
+
String(value ?? "").trim();
|
|
284
|
+
|
|
285
|
+
const userInputToText = (userInput: string | any[]): string => {
|
|
286
|
+
if (typeof userInput === "string") return userInput;
|
|
287
|
+
if (!Array.isArray(userInput)) return "";
|
|
288
|
+
return userInput
|
|
289
|
+
.map((part) => {
|
|
290
|
+
if (typeof part === "string") return part;
|
|
291
|
+
if (typeof part?.text === "string") return part.text;
|
|
292
|
+
if (typeof part?.content === "string") return part.content;
|
|
293
|
+
return "";
|
|
294
|
+
})
|
|
295
|
+
.join("\n");
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
const userRequestsFullReference = (userText: string): boolean =>
|
|
299
|
+
/全文|完整|全部内容|完整内容|full\s+text|entire\s+(file|document|doc)/i.test(userText);
|
|
300
|
+
|
|
301
|
+
const extractReferenceSearchTerms = (userText: string): string[] => {
|
|
302
|
+
const terms = new Set<string>();
|
|
303
|
+
for (const match of userText.matchAll(/[A-Za-z0-9_./:-]{3,}/g)) {
|
|
304
|
+
terms.add(match[0].toLowerCase());
|
|
305
|
+
}
|
|
306
|
+
for (const match of userText.matchAll(/[\p{Script=Han}]{2,12}/gu)) {
|
|
307
|
+
const value = match[0];
|
|
308
|
+
terms.add(value);
|
|
309
|
+
if (value.length > 4) {
|
|
310
|
+
for (let index = 0; index <= value.length - 4; index++) {
|
|
311
|
+
terms.add(value.slice(index, index + 4));
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return Array.from(terms).slice(0, 20);
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
const buildRelevantReferenceSnippets = (content: string, userText: string): string => {
|
|
319
|
+
const terms = extractReferenceSearchTerms(userText);
|
|
320
|
+
const lowerContent = content.toLowerCase();
|
|
321
|
+
const ranges: Array<{ start: number; end: number }> = [];
|
|
322
|
+
|
|
323
|
+
for (const term of terms) {
|
|
324
|
+
const needle = /[A-Z]/i.test(term) ? term.toLowerCase() : term;
|
|
325
|
+
const index = /[A-Z]/i.test(term)
|
|
326
|
+
? lowerContent.indexOf(needle)
|
|
327
|
+
: content.indexOf(needle);
|
|
328
|
+
if (index < 0) continue;
|
|
329
|
+
const half = Math.floor(LARGE_REFERENCE_SNIPPET_CHARS / 2);
|
|
330
|
+
ranges.push({
|
|
331
|
+
start: Math.max(0, index - half),
|
|
332
|
+
end: Math.min(content.length, index + term.length + half),
|
|
333
|
+
});
|
|
334
|
+
if (ranges.length >= LARGE_REFERENCE_MAX_SNIPPETS) break;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (ranges.length === 0) {
|
|
338
|
+
ranges.push({
|
|
339
|
+
start: 0,
|
|
340
|
+
end: Math.min(content.length, LARGE_REFERENCE_SNIPPET_CHARS),
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
return ranges
|
|
345
|
+
.map((range, index) => {
|
|
346
|
+
const prefix = range.start > 0 ? "...[前文已省略]\n" : "";
|
|
347
|
+
const suffix = range.end < content.length ? "\n...[后文已省略]" : "";
|
|
348
|
+
return `### Relevant excerpt ${index + 1}\n${prefix}${content.slice(range.start, range.end)}${suffix}`;
|
|
349
|
+
})
|
|
350
|
+
.join("\n\n");
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
export const formatReferenceContentForCostControl = (
|
|
354
|
+
dbKey: string,
|
|
355
|
+
content: string,
|
|
356
|
+
userText: string,
|
|
357
|
+
): string => {
|
|
358
|
+
if (content.length <= LARGE_REFERENCE_CONTEXT_CHAR_LIMIT) return content;
|
|
359
|
+
if (userRequestsFullReference(userText)) {
|
|
360
|
+
return [
|
|
361
|
+
`[Large reference cost notice] ${dbKey} is ${content.length} characters. The user explicitly requested full content, so the full text is included despite higher token cost.`,
|
|
362
|
+
content,
|
|
363
|
+
].join("\n\n");
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
return [
|
|
367
|
+
`[Large reference cost notice] ${dbKey} is ${content.length} characters. To control token cost and keep the model focused, only relevant excerpts are included. If the user asks for the full text explicitly, include the full content next turn.`,
|
|
368
|
+
buildRelevantReferenceSnippets(content, userText),
|
|
369
|
+
].join("\n\n");
|
|
370
|
+
};
|
|
371
|
+
|
|
273
372
|
/** 检查 OpenAI 消息数组中是否包含 image_url 片段 */
|
|
274
373
|
export const hasImageInMessages = (messages: any[]): boolean => {
|
|
275
374
|
if (!Array.isArray(messages)) return false;
|
|
@@ -299,9 +398,12 @@ export const formatCurrentInputContext = (
|
|
|
299
398
|
return joinMapValues(currentInputMap);
|
|
300
399
|
}
|
|
301
400
|
|
|
401
|
+
const seenKeys = new Set<string>();
|
|
302
402
|
const relevantPendingFiles = pendingFiles.filter((file) => {
|
|
303
|
-
const key = file
|
|
304
|
-
|
|
403
|
+
const key = getPendingFileReferenceKey(file);
|
|
404
|
+
if (!key || !currentInputMap.has(key) || seenKeys.has(key)) return false;
|
|
405
|
+
seenKeys.add(key);
|
|
406
|
+
return true;
|
|
305
407
|
});
|
|
306
408
|
|
|
307
409
|
if (relevantPendingFiles.length === 0) {
|
|
@@ -331,7 +433,7 @@ export const formatCurrentInputContext = (
|
|
|
331
433
|
output += `--- Source ${sourceCounter}: "${sourceName}" ---\n`;
|
|
332
434
|
|
|
333
435
|
filesInGroup.forEach((file) => {
|
|
334
|
-
const key = file
|
|
436
|
+
const key = getPendingFileReferenceKey(file);
|
|
335
437
|
if (!key) return; // Skip if no key
|
|
336
438
|
const content = currentInputMap.get(key);
|
|
337
439
|
if (!content) return;
|
|
@@ -347,9 +449,90 @@ export const formatCurrentInputContext = (
|
|
|
347
449
|
sourceCounter++;
|
|
348
450
|
});
|
|
349
451
|
|
|
452
|
+
for (const [key, content] of currentInputMap) {
|
|
453
|
+
if (seenKeys.has(key)) continue;
|
|
454
|
+
output += `${content}\n`;
|
|
455
|
+
}
|
|
456
|
+
|
|
350
457
|
return output;
|
|
351
458
|
};
|
|
352
459
|
|
|
460
|
+
const formatReferenceSummary = (dbKey: string, refContent: any): string => {
|
|
461
|
+
const title =
|
|
462
|
+
typeof refContent?.title === "string" && refContent.title.trim()
|
|
463
|
+
? refContent.title.trim()
|
|
464
|
+
: dbKey;
|
|
465
|
+
const type =
|
|
466
|
+
typeof refContent?.type === "string" && refContent.type.trim()
|
|
467
|
+
? refContent.type.trim()
|
|
468
|
+
: "unknown";
|
|
469
|
+
const updated =
|
|
470
|
+
refContent?.updatedAt ?? refContent?.updated ?? refContent?.createdAt ?? refContent?.created;
|
|
471
|
+
|
|
472
|
+
return [
|
|
473
|
+
"Previously referenced item:",
|
|
474
|
+
`DB Key: ${dbKey}`,
|
|
475
|
+
`Title: ${title}`,
|
|
476
|
+
`Type: ${type}`,
|
|
477
|
+
updated ? `Updated At: ${updated}` : "",
|
|
478
|
+
"Note: full content is not auto-included again to control token cost. Re-attach this item when exact source text is needed.",
|
|
479
|
+
"---",
|
|
480
|
+
"",
|
|
481
|
+
].filter(Boolean).join("\n");
|
|
482
|
+
};
|
|
483
|
+
|
|
484
|
+
const fetchReferenceSummaries = async (
|
|
485
|
+
keys: string[],
|
|
486
|
+
dispatch: any,
|
|
487
|
+
preloaded?: Map<string, any>,
|
|
488
|
+
): Promise<Map<string, string>> => {
|
|
489
|
+
const result = new Map<string, string>();
|
|
490
|
+
await Promise.all(
|
|
491
|
+
keys.map(async (dbKey) => {
|
|
492
|
+
try {
|
|
493
|
+
const refContent = preloaded?.has(dbKey)
|
|
494
|
+
? preloaded.get(dbKey)
|
|
495
|
+
: await dispatch(read({ dbKey })).unwrap();
|
|
496
|
+
result.set(dbKey, formatReferenceSummary(dbKey, refContent));
|
|
497
|
+
} catch {
|
|
498
|
+
result.set(dbKey, formatReferenceSummary(dbKey, null));
|
|
499
|
+
}
|
|
500
|
+
}),
|
|
501
|
+
);
|
|
502
|
+
return result;
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
const getReferenceTitle = (refContent: any): string =>
|
|
506
|
+
typeof refContent?.title === "string" ? refContent.title.trim() : "";
|
|
507
|
+
|
|
508
|
+
const resolveExplicitHistoryReferenceKeys = async (
|
|
509
|
+
keys: string[],
|
|
510
|
+
dispatch: any,
|
|
511
|
+
userText: string,
|
|
512
|
+
preloaded?: Map<string, any>,
|
|
513
|
+
): Promise<string[]> => {
|
|
514
|
+
const text = normalizeContextText(userText);
|
|
515
|
+
if (!text) return [];
|
|
516
|
+
|
|
517
|
+
const matches: string[] = [];
|
|
518
|
+
await Promise.all(
|
|
519
|
+
keys.map(async (dbKey) => {
|
|
520
|
+
try {
|
|
521
|
+
const refContent = preloaded?.has(dbKey)
|
|
522
|
+
? preloaded.get(dbKey)
|
|
523
|
+
: await dispatch(read({ dbKey })).unwrap();
|
|
524
|
+
const title = getReferenceTitle(refContent);
|
|
525
|
+
if (text.includes(dbKey) || (title && text.includes(title))) {
|
|
526
|
+
matches.push(dbKey);
|
|
527
|
+
}
|
|
528
|
+
} catch {
|
|
529
|
+
if (text.includes(dbKey)) matches.push(dbKey);
|
|
530
|
+
}
|
|
531
|
+
}),
|
|
532
|
+
);
|
|
533
|
+
return matches;
|
|
534
|
+
};
|
|
535
|
+
|
|
353
536
|
/** 校验当前用户是否有权限使用该 Agent,并且余额是否充足(每轮调用) */
|
|
354
537
|
export const validateAccessAndBalance = (
|
|
355
538
|
agentConfig: Agent,
|
|
@@ -610,6 +793,23 @@ export const buildDynamicContexts = async (
|
|
|
610
793
|
dialogConfig,
|
|
611
794
|
);
|
|
612
795
|
const finalKeys = deduplicateContextKeys(keySets);
|
|
796
|
+
const userText = userInputToText(userInput);
|
|
797
|
+
const explicitHistoryReferenceKeys = await resolveExplicitHistoryReferenceKeys(
|
|
798
|
+
finalKeys.historyContext,
|
|
799
|
+
dispatch,
|
|
800
|
+
userText,
|
|
801
|
+
referenceContentCache,
|
|
802
|
+
);
|
|
803
|
+
const explicitHistoryReferenceKeySet = new Set(explicitHistoryReferenceKeys);
|
|
804
|
+
const currentInputContextKeys = Array.from(
|
|
805
|
+
new Set([
|
|
806
|
+
...finalKeys.currentInputContext,
|
|
807
|
+
...explicitHistoryReferenceKeys,
|
|
808
|
+
]),
|
|
809
|
+
);
|
|
810
|
+
const historySummaryKeys = finalKeys.historyContext.filter(
|
|
811
|
+
(key) => !explicitHistoryReferenceKeySet.has(key),
|
|
812
|
+
);
|
|
613
813
|
|
|
614
814
|
const fetchReferences = (keys: string[]) =>
|
|
615
815
|
fetchReferenceContents(keys, dispatch, {
|
|
@@ -620,14 +820,24 @@ export const buildDynamicContexts = async (
|
|
|
620
820
|
|
|
621
821
|
// 只获取动态引用内容
|
|
622
822
|
const [currentInputMap, historyMap] = await Promise.all([
|
|
623
|
-
fetchReferences(
|
|
624
|
-
|
|
823
|
+
fetchReferences(currentInputContextKeys),
|
|
824
|
+
fetchReferenceSummaries(
|
|
825
|
+
historySummaryKeys,
|
|
826
|
+
dispatch,
|
|
827
|
+
referenceContentCache,
|
|
828
|
+
),
|
|
625
829
|
]);
|
|
830
|
+
const costControlledCurrentInputMap = new Map(
|
|
831
|
+
Array.from(currentInputMap.entries()).map(([key, content]) => [
|
|
832
|
+
key,
|
|
833
|
+
formatReferenceContentForCostControl(key, content, userText),
|
|
834
|
+
]),
|
|
835
|
+
);
|
|
626
836
|
|
|
627
837
|
const pendingFiles = selectPendingFiles(state);
|
|
628
838
|
const formattedCurrentInputContext = formatCurrentInputContext(
|
|
629
839
|
pendingFiles,
|
|
630
|
-
|
|
840
|
+
costControlledCurrentInputMap,
|
|
631
841
|
);
|
|
632
842
|
|
|
633
843
|
const dialogId = dialogConfig?.id ?? null;
|
|
@@ -774,9 +984,85 @@ export const applyImageConfigRuntimeOverride = (
|
|
|
774
984
|
|
|
775
985
|
return {
|
|
776
986
|
...agentConfig,
|
|
987
|
+
...(override.imageModelOverride
|
|
988
|
+
? { model: override.imageModelOverride }
|
|
989
|
+
: {}),
|
|
777
990
|
imageConfig: {
|
|
778
991
|
...baseImageConfig,
|
|
779
992
|
...override,
|
|
780
993
|
},
|
|
781
994
|
};
|
|
782
995
|
};
|
|
996
|
+
|
|
997
|
+
const formatImageWaitHint = (
|
|
998
|
+
range?: {
|
|
999
|
+
min: number;
|
|
1000
|
+
max: number;
|
|
1001
|
+
},
|
|
1002
|
+
) => {
|
|
1003
|
+
if (!range || typeof range.min !== "number" || typeof range.max !== "number") {
|
|
1004
|
+
return undefined;
|
|
1005
|
+
}
|
|
1006
|
+
return `通常需要 ${range.min}-${range.max} 秒`;
|
|
1007
|
+
};
|
|
1008
|
+
|
|
1009
|
+
const resolveAgentImageModelIdentity = (agentConfig: Partial<Agent>) => {
|
|
1010
|
+
let providerKey = (agentConfig.provider || "").toLowerCase();
|
|
1011
|
+
let modelName = agentConfig.model ?? "";
|
|
1012
|
+
|
|
1013
|
+
if (modelName.includes("/")) {
|
|
1014
|
+
const slash = modelName.indexOf("/");
|
|
1015
|
+
if (!providerKey) providerKey = modelName.slice(0, slash);
|
|
1016
|
+
modelName = modelName.slice(slash + 1);
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
try {
|
|
1020
|
+
return {
|
|
1021
|
+
providerKey,
|
|
1022
|
+
modelConfig: getModelConfig(providerKey as Provider, modelName),
|
|
1023
|
+
};
|
|
1024
|
+
} catch {
|
|
1025
|
+
try {
|
|
1026
|
+
const detected = getProviderByModelName(modelName);
|
|
1027
|
+
if (!detected) {
|
|
1028
|
+
return { providerKey, modelConfig: null };
|
|
1029
|
+
}
|
|
1030
|
+
return {
|
|
1031
|
+
providerKey: detected,
|
|
1032
|
+
modelConfig: getModelConfig(detected, modelName),
|
|
1033
|
+
};
|
|
1034
|
+
} catch {
|
|
1035
|
+
return { providerKey, modelConfig: null };
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
};
|
|
1039
|
+
|
|
1040
|
+
export const resolveImageGenerationStreamingState = (
|
|
1041
|
+
agentConfig: Agent,
|
|
1042
|
+
args?: {
|
|
1043
|
+
stage?: ImageGenerationState["stage"];
|
|
1044
|
+
previous?: ImageGenerationState | null;
|
|
1045
|
+
},
|
|
1046
|
+
): ImageGenerationState | undefined => {
|
|
1047
|
+
const { modelConfig } = resolveAgentImageModelIdentity(agentConfig);
|
|
1048
|
+
const hasImageOutput =
|
|
1049
|
+
!!(modelConfig?.hasImageOutput ?? (modelConfig as any)?.supportsImageOutput) ||
|
|
1050
|
+
agentConfig.imageConfig?.enabled === true;
|
|
1051
|
+
if (!hasImageOutput) {
|
|
1052
|
+
return undefined;
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
const currentProfile = modelConfig?.imageGenerationProfiles?.find(
|
|
1056
|
+
(profile) => profile.imageModel === modelConfig.name,
|
|
1057
|
+
);
|
|
1058
|
+
|
|
1059
|
+
return {
|
|
1060
|
+
kind: "image_generation",
|
|
1061
|
+
stage: args?.stage ?? args?.previous?.stage ?? "submitted",
|
|
1062
|
+
startedAt: args?.previous?.startedAt ?? Date.now(),
|
|
1063
|
+
waitHint:
|
|
1064
|
+
formatImageWaitHint(modelConfig?.imageGenerationWaitTimeSeconds) ??
|
|
1065
|
+
"通常需要几十秒",
|
|
1066
|
+
profileLabel: currentProfile?.label,
|
|
1067
|
+
};
|
|
1068
|
+
};
|
package/ai/agent/types.ts
CHANGED
|
@@ -51,6 +51,8 @@ export interface AgentRuntimeOptions {
|
|
|
51
51
|
imageConfigOverride?: {
|
|
52
52
|
/** 是否在本轮启用图片输出(不写或 true 表示按默认;false 可强制关闭) */
|
|
53
53
|
enabled?: boolean;
|
|
54
|
+
/** 本轮强制切换到另一个图片模型变体,仅作用于本次调用 */
|
|
55
|
+
imageModelOverride?: string;
|
|
54
56
|
|
|
55
57
|
/** 本轮期望的宽高比,不指定则使用上层(Dialog / Agent / 模型)的默认值 */
|
|
56
58
|
aspectRatio?:
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { format } from "date-fns";
|
|
2
|
+
|
|
3
|
+
import type { Agent, DialogConfig } from "../../../app/types";
|
|
4
|
+
import { resolveAvatarUrl } from "../../agent/avatarUtils";
|
|
5
|
+
import {
|
|
6
|
+
type AgentPriceHint,
|
|
7
|
+
formatModelCostPerMillion,
|
|
8
|
+
} from "../../llm/getPricing";
|
|
9
|
+
|
|
10
|
+
type AgentCreatorRecord = Pick<
|
|
11
|
+
Agent,
|
|
12
|
+
"creatorName" | "originServer" | "userId" | "userName"
|
|
13
|
+
> & {
|
|
14
|
+
authorAvatar?: unknown;
|
|
15
|
+
creator?: {
|
|
16
|
+
avatar?: unknown;
|
|
17
|
+
avatarFileId?: unknown;
|
|
18
|
+
};
|
|
19
|
+
creatorAvatar?: unknown;
|
|
20
|
+
userAvatar?: unknown;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
type CreatorProfileRecord = {
|
|
24
|
+
avatar?: unknown;
|
|
25
|
+
avatarFileId?: unknown;
|
|
26
|
+
avatarUrl?: unknown;
|
|
27
|
+
name?: unknown;
|
|
28
|
+
nickname?: unknown;
|
|
29
|
+
username?: unknown;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export interface AgentDialogHistoryEntry {
|
|
33
|
+
dbKey: string;
|
|
34
|
+
spaceId: string | null;
|
|
35
|
+
spaceName: string | null;
|
|
36
|
+
title: string;
|
|
37
|
+
updatedAt: unknown;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const formatCliProviderLabel = (provider?: string) => {
|
|
41
|
+
if (provider === "codex") return "OpenAI Codex CLI (codex exec)";
|
|
42
|
+
if (provider === "gemini") return "Gemini CLI (gemini)";
|
|
43
|
+
if (provider === "claude") return "Claude CLI (claude)";
|
|
44
|
+
if (provider === "agy") return "Google Antigravity CLI (agy)";
|
|
45
|
+
return "GitHub Copilot CLI (gh copilot)";
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const formatRuntimeLocationLabel = (
|
|
49
|
+
machineId?: string,
|
|
50
|
+
localLabel = "默认环境"
|
|
51
|
+
) => (machineId ? `远程电脑 (${machineId})` : localLabel);
|
|
52
|
+
|
|
53
|
+
export const toNonEmptyString = (value: unknown): string | null =>
|
|
54
|
+
typeof value === "string" && value.trim() ? value.trim() : null;
|
|
55
|
+
|
|
56
|
+
export const toTimestamp = (value: unknown): number => {
|
|
57
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
58
|
+
if (typeof value === "string") {
|
|
59
|
+
const parsed = Date.parse(value);
|
|
60
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
61
|
+
}
|
|
62
|
+
return 0;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const formatDateValue = (value: unknown, pattern: string): string => {
|
|
66
|
+
const timestamp = toTimestamp(value);
|
|
67
|
+
return timestamp > 0 ? format(new Date(timestamp), pattern) : "--";
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export const shouldShowAgentTokenCost = (
|
|
71
|
+
agent: Pick<Agent, "apiSource" | "inputPrice" | "outputPrice"> | null | undefined,
|
|
72
|
+
priceHint: AgentPriceHint | null | undefined
|
|
73
|
+
) =>
|
|
74
|
+
!!agent &&
|
|
75
|
+
agent.apiSource !== "cli" &&
|
|
76
|
+
priceHint?.type === "per_turn" &&
|
|
77
|
+
((typeof agent.inputPrice === "number" && Number.isFinite(agent.inputPrice)) ||
|
|
78
|
+
(typeof agent.outputPrice === "number" && Number.isFinite(agent.outputPrice)));
|
|
79
|
+
|
|
80
|
+
export const formatAgentOutputPrice = (outputPrice?: number) =>
|
|
81
|
+
outputPrice === 0
|
|
82
|
+
? formatModelCostPerMillion(outputPrice)
|
|
83
|
+
: `1M / ${formatModelCostPerMillion(outputPrice)}`;
|
|
84
|
+
|
|
85
|
+
export const resolveAgentCreatorSummary = ({
|
|
86
|
+
item,
|
|
87
|
+
creatorProfile,
|
|
88
|
+
server,
|
|
89
|
+
unknownUserLabel,
|
|
90
|
+
}: {
|
|
91
|
+
creatorProfile?: CreatorProfileRecord | null;
|
|
92
|
+
item: AgentCreatorRecord;
|
|
93
|
+
server?: string | null;
|
|
94
|
+
unknownUserLabel: string;
|
|
95
|
+
}) => {
|
|
96
|
+
const name =
|
|
97
|
+
toNonEmptyString(creatorProfile?.nickname) ||
|
|
98
|
+
toNonEmptyString(creatorProfile?.name) ||
|
|
99
|
+
toNonEmptyString(creatorProfile?.username) ||
|
|
100
|
+
toNonEmptyString(item.userName) ||
|
|
101
|
+
toNonEmptyString(item.creatorName) ||
|
|
102
|
+
toNonEmptyString(item.userId) ||
|
|
103
|
+
unknownUserLabel;
|
|
104
|
+
|
|
105
|
+
const creatorAvatarRaw =
|
|
106
|
+
creatorProfile?.avatarFileId ||
|
|
107
|
+
creatorProfile?.avatar ||
|
|
108
|
+
creatorProfile?.avatarUrl ||
|
|
109
|
+
item.creator?.avatarFileId ||
|
|
110
|
+
item.creator?.avatar ||
|
|
111
|
+
item.creatorAvatar ||
|
|
112
|
+
item.userAvatar ||
|
|
113
|
+
item.authorAvatar;
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
avatarUrl: toNonEmptyString(creatorAvatarRaw)
|
|
117
|
+
? resolveAvatarUrl(creatorAvatarRaw, item.originServer || server)
|
|
118
|
+
: null,
|
|
119
|
+
name,
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
export const buildAgentDialogHistory = ({
|
|
124
|
+
historyAgentKeys,
|
|
125
|
+
historySpaceNameById,
|
|
126
|
+
limit = 8,
|
|
127
|
+
records,
|
|
128
|
+
untitledDialogLabel,
|
|
129
|
+
}: {
|
|
130
|
+
historyAgentKeys: ReadonlySet<string>;
|
|
131
|
+
historySpaceNameById: ReadonlyMap<string, string>;
|
|
132
|
+
limit?: number;
|
|
133
|
+
records: readonly unknown[];
|
|
134
|
+
untitledDialogLabel: string;
|
|
135
|
+
}): AgentDialogHistoryEntry[] =>
|
|
136
|
+
records
|
|
137
|
+
.flatMap((record) => {
|
|
138
|
+
const dialog = record as DialogConfig & {
|
|
139
|
+
dbKey?: unknown;
|
|
140
|
+
};
|
|
141
|
+
const cybots = Array.isArray(dialog.cybots)
|
|
142
|
+
? dialog.cybots.filter(
|
|
143
|
+
(dialogAgentKey): dialogAgentKey is string =>
|
|
144
|
+
typeof dialogAgentKey === "string" &&
|
|
145
|
+
dialogAgentKey.trim().length > 0
|
|
146
|
+
)
|
|
147
|
+
: [];
|
|
148
|
+
if (!cybots.some((dialogAgentKey) => historyAgentKeys.has(dialogAgentKey))) {
|
|
149
|
+
return [];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const dbKey = toNonEmptyString(dialog.dbKey);
|
|
153
|
+
if (!dbKey) return [];
|
|
154
|
+
|
|
155
|
+
return [
|
|
156
|
+
{
|
|
157
|
+
dbKey,
|
|
158
|
+
spaceId: toNonEmptyString(dialog.spaceId),
|
|
159
|
+
title: toNonEmptyString(dialog.title) || untitledDialogLabel,
|
|
160
|
+
updatedAt: dialog.updatedAt ?? dialog.createdAt,
|
|
161
|
+
},
|
|
162
|
+
];
|
|
163
|
+
})
|
|
164
|
+
.sort((left, right) => toTimestamp(right.updatedAt) - toTimestamp(left.updatedAt))
|
|
165
|
+
.slice(0, limit)
|
|
166
|
+
.map((dialog) => ({
|
|
167
|
+
...dialog,
|
|
168
|
+
spaceName: dialog.spaceId
|
|
169
|
+
? historySpaceNameById.get(dialog.spaceId) ?? dialog.spaceId
|
|
170
|
+
: null,
|
|
171
|
+
}));
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
|
|
3
|
+
import { getModelAvatarComponent } from "../../llm/modelAvatar";
|
|
4
|
+
|
|
5
|
+
export const useAgentModelAvatarComponent = ({
|
|
6
|
+
cliProvider,
|
|
7
|
+
model,
|
|
8
|
+
provider,
|
|
9
|
+
}: {
|
|
10
|
+
cliProvider?: string;
|
|
11
|
+
model?: string;
|
|
12
|
+
provider?: string;
|
|
13
|
+
}) => {
|
|
14
|
+
const [modelAvatarStyle, setModelAvatarStyle] = useState<Awaited<
|
|
15
|
+
ReturnType<typeof getModelAvatarComponent>
|
|
16
|
+
> | null>(null);
|
|
17
|
+
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
let cancelled = false;
|
|
20
|
+
setModelAvatarStyle(null);
|
|
21
|
+
getModelAvatarComponent(provider, model, cliProvider).then((avatar) => {
|
|
22
|
+
if (!cancelled) {
|
|
23
|
+
setModelAvatarStyle(() => avatar);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
return () => {
|
|
27
|
+
cancelled = true;
|
|
28
|
+
};
|
|
29
|
+
}, [cliProvider, model, provider]);
|
|
30
|
+
|
|
31
|
+
return modelAvatarStyle;
|
|
32
|
+
};
|
package/ai/ai.locale.ts
CHANGED
|
@@ -153,6 +153,8 @@ export default {
|
|
|
153
153
|
"API Key is required when not using Server Proxy, Ollama or Custom provider",
|
|
154
154
|
customUrlRequired:
|
|
155
155
|
"Custom Provider URL is required for the 'custom' provider",
|
|
156
|
+
machineBindingRequiresCliOrLocalCustom:
|
|
157
|
+
"Machine binding is only available for CLI agents or custom providers hosted on localhost.",
|
|
156
158
|
},
|
|
157
159
|
|
|
158
160
|
// Legacy Errors (kept for compatibility)
|
|
@@ -444,6 +446,8 @@ export default {
|
|
|
444
446
|
apiKeyRequired:
|
|
445
447
|
"未使用代理模式、Ollama或自定义服务商时,API密钥为必填项",
|
|
446
448
|
customUrlRequired: "使用自定义服务商时,URL为必填项",
|
|
449
|
+
machineBindingRequiresCliOrLocalCustom:
|
|
450
|
+
"只有 CLI Agent 或运行在 localhost 的自定义 Provider 才能绑定机器。",
|
|
447
451
|
},
|
|
448
452
|
|
|
449
453
|
// 旧版错误(保留以兼容)
|
|
@@ -735,6 +739,8 @@ export default {
|
|
|
735
739
|
apiKeyRequired:
|
|
736
740
|
"未使用代理模式、Ollama或自訂服務提供者時,API金鑰為必填項",
|
|
737
741
|
customUrlRequired: "使用自訂服務提供者時,URL為必填項",
|
|
742
|
+
machineBindingRequiresCliOrLocalCustom:
|
|
743
|
+
"只有 CLI Agent 或執行於 localhost 的自訂 Provider 才能綁定電腦。",
|
|
738
744
|
},
|
|
739
745
|
|
|
740
746
|
// 舊版錯誤(保留以相容)
|
|
@@ -991,6 +997,8 @@ export default {
|
|
|
991
997
|
apiKeyRequired:
|
|
992
998
|
"プロキシモード、Ollama、またはカスタムプロバイダーを使用しない場合、APIキーは必須です",
|
|
993
999
|
customUrlRequired: "カスタムプロバイダーを使用する場合、URLは必須です",
|
|
1000
|
+
machineBindingRequiresCliOrLocalCustom:
|
|
1001
|
+
"マシンバインドを使えるのは CLI Agent か localhost 上のカスタム Provider のみです。",
|
|
994
1002
|
},
|
|
995
1003
|
|
|
996
1004
|
// レガシーエラー(互換性のため保持)
|
|
@@ -27,6 +27,7 @@ import { accumulateToolCallChunks, AccumulatedToolCall } from "./accumulateToolC
|
|
|
27
27
|
import { prepareTools } from "../tools/prepareTools";
|
|
28
28
|
|
|
29
29
|
import { getModelInfo } from "../llm/getModelContextWindow";
|
|
30
|
+
import { supportsImageGeneration } from "../agent/utils/imageOutput";
|
|
30
31
|
|
|
31
32
|
import type { RootState } from "../../app/store";
|
|
32
33
|
|
|
@@ -62,6 +63,13 @@ type AssistantToolCall = {
|
|
|
62
63
|
function: { name: string; arguments: string };
|
|
63
64
|
};
|
|
64
65
|
|
|
66
|
+
const EXPLICIT_IMAGE_TOOL_NAMES = new Set([
|
|
67
|
+
"openAIGptImage",
|
|
68
|
+
"openAIGptImageGenerate",
|
|
69
|
+
"openAIGptImageEdit",
|
|
70
|
+
"geminiProImagePreview",
|
|
71
|
+
]);
|
|
72
|
+
|
|
65
73
|
/** 单次流式请求过程中的全部中间状态(显式 state) */
|
|
66
74
|
type StreamState = {
|
|
67
75
|
contentBuffer: MessageContentPart[];
|
|
@@ -145,6 +153,13 @@ function buildRequestBodyWithTools(
|
|
|
145
153
|
|
|
146
154
|
const rawTools = agentConfig.tools;
|
|
147
155
|
if (!Array.isArray(rawTools) || rawTools.length === 0) return bodyData;
|
|
156
|
+
const hasExplicitImageTool = rawTools.some(
|
|
157
|
+
(toolName: unknown) =>
|
|
158
|
+
typeof toolName === "string" && EXPLICIT_IMAGE_TOOL_NAMES.has(toolName)
|
|
159
|
+
);
|
|
160
|
+
if (supportsImageGeneration(agentConfig) && !hasExplicitImageTool) {
|
|
161
|
+
return bodyData;
|
|
162
|
+
}
|
|
148
163
|
|
|
149
164
|
const tools = prepareTools(rawTools, { provider: agentConfig.provider });
|
|
150
165
|
if (!tools.length) return bodyData;
|