nolo-cli 0.1.29 → 0.1.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (329) hide show
  1. package/agent-runtime/agentRecordConfig.ts +0 -2
  2. package/agent-runtime/hostAdapter.ts +0 -1
  3. package/agent-runtime/hostRuntimeCapabilities.ts +7 -0
  4. package/agent-runtime/hostRuntimeConfig.ts +86 -0
  5. package/agent-runtime/index.ts +13 -0
  6. package/agent-runtime/localToolPolicy.ts +13 -6
  7. package/agent-runtime/localWorkspaceTools.ts +333 -30
  8. package/agent-runtime/platformChatProvider.ts +4 -1
  9. package/agent-runtime/runtimeToolPolicy.ts +32 -47
  10. package/agent-runtime/shellCommandPolicy.ts +117 -0
  11. package/agent-runtime/toolGate.ts +38 -0
  12. package/agentCreateCustomCommands.ts +9 -4
  13. package/agentDialogsCommands.ts +4 -3
  14. package/agentDoctorCommands.ts +3 -3
  15. package/agentListCommands.ts +3 -3
  16. package/agentMachineCommands.ts +6 -6
  17. package/agentPullCommand.ts +4 -12
  18. package/agentRecordCommands.ts +5 -3
  19. package/agentRecordHelpers.ts +42 -23
  20. package/agentRunCommand.ts +2 -6
  21. package/agentRunParsing.ts +18 -5
  22. package/agentRuntimeLocal.ts +10 -0
  23. package/agentUnpublishCommands.ts +3 -2
  24. package/ai/agent/agentRunDialogLineage.ts +56 -0
  25. package/ai/agent/agentSlice.ts +45 -10
  26. package/ai/agent/avatarUtils.ts +1 -1
  27. package/ai/agent/buildSystemPrompt.ts +1 -2
  28. package/ai/agent/cliExecutor.ts +330 -19
  29. package/ai/agent/createAgentSchema.ts +22 -0
  30. package/ai/agent/hooks/fetchPublicAgents.ts +14 -39
  31. package/ai/agent/hooks/usePublicAgents.ts +90 -192
  32. package/ai/agent/publicAgentCatalog.ts +359 -0
  33. package/ai/agent/publicAgentIdentity.ts +76 -0
  34. package/ai/agent/server/fetchPublicAgents.ts +21 -46
  35. package/ai/agent/serverOrigin.ts +7 -0
  36. package/ai/agent/streamAgentChatTurn.ts +23 -21
  37. package/ai/agent/streamAgentChatTurnUtils.ts +292 -6
  38. package/ai/agent/types.ts +2 -0
  39. package/ai/agent/web/agentDisplayUtils.ts +171 -0
  40. package/ai/agent/web/useAgentModelAvatarComponent.ts +32 -0
  41. package/ai/ai.locale.ts +8 -0
  42. package/ai/chat/sendOpenAICompletionsRequest.native.ts +15 -0
  43. package/ai/chat/sendOpenAICompletionsRequest.ts +93 -1
  44. package/ai/chat/sendOpenAIResponseRequest.ts +86 -9
  45. package/ai/chat/updateTotalUsage.ts +7 -0
  46. package/ai/llm/deepinfra.ts +30 -15
  47. package/ai/llm/mistral.ts +3 -4
  48. package/ai/llm/providers.ts +2 -0
  49. package/ai/llm/types.ts +15 -0
  50. package/ai/memory/capture.ts +3 -3
  51. package/ai/memory/consolidate.ts +2 -2
  52. package/ai/memory/delete.ts +4 -3
  53. package/ai/memory/query.ts +3 -3
  54. package/ai/memory/remember.ts +2 -2
  55. package/ai/memory/store.ts +3 -3
  56. package/ai/memory/storeShared.ts +3 -2
  57. package/ai/policy/commercialMultiplier.ts +16 -0
  58. package/ai/token/billingAdminAuditEvent.ts +68 -0
  59. package/ai/token/billingAdminAuditEventWriter.ts +41 -0
  60. package/ai/token/billingAnomaly.ts +90 -0
  61. package/ai/token/billingAnomalyLifecycle.ts +54 -0
  62. package/ai/token/billingAnomalyLifecycleWriter.ts +44 -0
  63. package/ai/token/billingAnomalyWriter.ts +41 -0
  64. package/ai/token/calculatePrice.ts +3 -2
  65. package/ai/token/deepinfraReconciliation.ts +153 -0
  66. package/ai/token/deepinfraRequestIdQuery.ts +92 -0
  67. package/ai/token/externalToolCost.ts +54 -41
  68. package/ai/token/missingUsageEstimate.ts +12 -3
  69. package/ai/token/normalizeUsage.ts +45 -5
  70. package/ai/token/openaiReconciliation.ts +188 -0
  71. package/ai/token/providerBillableEvent.ts +84 -0
  72. package/ai/token/providerBillableEventWriter.ts +36 -0
  73. package/ai/token/providerBillingAnomalyDrilldown.ts +308 -0
  74. package/ai/token/providerBillingDrilldown.ts +361 -0
  75. package/ai/token/providerBillingHealthReport.ts +366 -0
  76. package/ai/token/providerCall.ts +144 -0
  77. package/ai/token/providerCallSweeper.ts +168 -0
  78. package/ai/token/providerCallWriter.ts +33 -0
  79. package/ai/token/providerCredential.ts +89 -0
  80. package/ai/token/providerCredentialAnomaly.ts +154 -0
  81. package/ai/token/providerCredentialLifecycle.ts +59 -0
  82. package/ai/token/providerCredentialLifecycleWriter.ts +44 -0
  83. package/ai/token/providerCredentialRegistry.ts +83 -0
  84. package/ai/token/providerCredentialRegistryCommand.ts +97 -0
  85. package/ai/token/providerCredentialRegistryList.ts +124 -0
  86. package/ai/token/providerCredentialRegistryResolver.ts +150 -0
  87. package/ai/token/providerCredentialRegistryWriter.ts +41 -0
  88. package/ai/token/providerCredentialRotationCommand.ts +102 -0
  89. package/ai/token/providerCredentialRuntime.ts +56 -0
  90. package/ai/token/providerDispatchIntent.ts +67 -0
  91. package/ai/token/providerDispatchIntentWriter.ts +36 -0
  92. package/ai/token/providerGateway.ts +260 -0
  93. package/ai/token/providerReconciliation.ts +148 -0
  94. package/ai/token/providerReconciliationLocal.ts +97 -0
  95. package/ai/token/providerReconciliationRunner.ts +165 -0
  96. package/ai/token/providerReconciliationWriter.ts +41 -0
  97. package/ai/token/ratingResult.ts +202 -0
  98. package/ai/token/ratingResultWriter.ts +33 -0
  99. package/ai/token/serverDialogProjection.ts +5 -3
  100. package/ai/token/serverTokenWriter.ts +11 -3
  101. package/ai/token/types.ts +10 -0
  102. package/ai/tools/agent/callAgentTool.ts +3 -4
  103. package/ai/tools/agent/presets/appBuilderPreset.ts +5 -7
  104. package/ai/tools/agent/runStreamingAgentTool.ts +1 -2
  105. package/ai/tools/agent/streamParallelAgentsTool.ts +2 -3
  106. package/ai/tools/readXPostTool.ts +1 -5
  107. package/app/admin/adminPages.ts +9 -0
  108. package/app/i18n/i18n.config.ts +5 -0
  109. package/app/i18n/translations/pricing.locale.ts +397 -0
  110. package/app/utils/desktopAgentRuntimeStatusClient.ts +5 -4
  111. package/app/utils/desktopAgentRuntimeTurnClient.ts +4 -1
  112. package/app/utils/imageUtils.ts +64 -34
  113. package/auth/adminPermissions.ts +18 -0
  114. package/auth/authSlice.ts +26 -12
  115. package/auth/hooks/useFetchUsers.ts +3 -0
  116. package/auth/routes.ts +46 -0
  117. package/auth/server/accessActivity.ts +4 -3
  118. package/auth/server/adminPermissions.ts +43 -0
  119. package/auth/server/adminUsageReport.ts +375 -0
  120. package/auth/server/billingAnomalies.ts +235 -0
  121. package/auth/server/billingUsageReport.ts +41 -2
  122. package/auth/server/creatorEarningCreditConversion.ts +10 -2
  123. package/auth/server/deduct.ts +14 -7
  124. package/auth/server/delete.ts +10 -2
  125. package/auth/server/disable.ts +4 -3
  126. package/auth/server/emailAutomation.ts +7 -5
  127. package/auth/server/emailDbConfig.ts +4 -2
  128. package/auth/server/emailDelivery.ts +24 -20
  129. package/auth/server/emailDeliveryGuards.ts +10 -7
  130. package/auth/server/emailPreferences.ts +6 -4
  131. package/auth/server/emailReport.ts +6 -4
  132. package/auth/server/emailRuntimeConfig.ts +3 -3
  133. package/auth/server/emailScenarioNotifications.ts +9 -8
  134. package/auth/server/enable.ts +4 -3
  135. package/auth/server/getRechargeHistory.ts +3 -2
  136. package/auth/server/getUser.ts +3 -2
  137. package/auth/server/gptProAccess.ts +44 -0
  138. package/auth/server/inviteReward.ts +10 -7
  139. package/auth/server/listusers.ts +6 -4
  140. package/auth/server/login.ts +2 -2
  141. package/auth/server/productEntitlements.ts +7 -4
  142. package/auth/server/productPurchase.ts +10 -2
  143. package/auth/server/providerBillingDrilldown.ts +47 -0
  144. package/auth/server/providerBillingHealth.ts +71 -0
  145. package/auth/server/providerCredentials.ts +136 -0
  146. package/auth/server/recharge.ts +14 -8
  147. package/auth/server/revokeSessions.ts +4 -3
  148. package/auth/server/route.ts +77 -0
  149. package/auth/server/sendEmail.ts +5 -4
  150. package/auth/server/signup.ts +10 -3
  151. package/auth/server/token.ts +53 -55
  152. package/auth/server/tokenUsageBilling.ts +18 -7
  153. package/auth/server/usageManagementAccess.ts +43 -0
  154. package/auth/server/usageReport.ts +59 -0
  155. package/auth/types.ts +12 -0
  156. package/auth/utils.ts +24 -22
  157. package/authCommands.ts +36 -2
  158. package/buildPublish.ts +3 -1
  159. package/buildPublishArtifactAssembly.ts +62 -1
  160. package/buildPublishImportAnalysis.ts +21 -16
  161. package/chat/dialog/dialogLaunchScope.ts +32 -0
  162. package/chat/dialog/objectAssistantRegistry.ts +2 -2
  163. package/chat/dialog/useCreateDialog.ts +1 -1
  164. package/chat/hooks/useChatInput.ts +41 -10
  165. package/chat/messages/messageSlice.ts +5 -1
  166. package/chat/messages/pendingAttachmentParts.ts +28 -2
  167. package/chat/messages/sendFirstMessage.ts +76 -79
  168. package/chat/messages/types.ts +9 -0
  169. package/chat/messages/web/streamingMarkdownModel.ts +41 -0
  170. package/chat/messages/web/useStreamingReveal.ts +91 -0
  171. package/chat/web/messageInputAgentUi.ts +94 -6
  172. package/cliEnvHelpers.ts +68 -13
  173. package/cliRuntimeDoctorReport.ts +193 -0
  174. package/client/agentConfigResolver.test.ts +0 -2
  175. package/client/agentRun.test.ts +171 -10
  176. package/client/agentRun.ts +44 -637
  177. package/client/agentRunInput.ts +10 -0
  178. package/client/agentRunLocalExecutor.ts +179 -0
  179. package/client/agentRunServerTransport.ts +394 -0
  180. package/client/agentRunTaskRunRecorder.ts +176 -0
  181. package/client/localRuntimeAdapter.test.ts +236 -9
  182. package/client/localRuntimeAdapter.ts +221 -23
  183. package/client/localToolPolicy.test.ts +28 -4
  184. package/connector-experimental/daemonLauncher.ts +38 -4
  185. package/connectorRunArtifact.ts +34 -10
  186. package/connectorWebSocketTarget.ts +40 -15
  187. package/core/builtinAgents.ts +155 -11
  188. package/create/space/contentLabels.ts +1 -1
  189. package/create/space/contentTypeMeta.ts +3 -2
  190. package/create/space/sidebarVisibleTypes.ts +27 -0
  191. package/create/space/space.locale.ts +76 -4
  192. package/database/actions/agentReadResolution.ts +2 -8
  193. package/database/actions/read.ts +11 -9
  194. package/database/actions/readAndWait.ts +10 -5
  195. package/database/server/agentDelegation.ts +3 -2
  196. package/database/server/authorityStoreConformance.ts +209 -0
  197. package/database/server/authorityStoreTypes.ts +31 -0
  198. package/database/server/coreDataProxy.ts +1 -1
  199. package/database/server/dataHandlers.ts +13 -5
  200. package/database/server/db.ts +15 -34
  201. package/database/server/delete.ts +88 -71
  202. package/database/server/emailRepository.ts +11 -9
  203. package/database/server/fileService.ts +2 -1
  204. package/database/server/legacyServerDb.ts +58 -0
  205. package/database/server/levelAuthorityStore.ts +75 -0
  206. package/database/server/memoryAuthorityStore.ts +133 -0
  207. package/database/server/patch.ts +13 -12
  208. package/database/server/query.ts +3 -2
  209. package/database/server/read.ts +33 -30
  210. package/database/server/resourceAccess.ts +7 -5
  211. package/database/server/serverStoreFactory.ts +124 -0
  212. package/database/server/spaceMemberAuthority.ts +3 -2
  213. package/database/server/storeBatchCompat.ts +37 -0
  214. package/database/server/testAuthorityStore.ts +76 -0
  215. package/database/server/write.ts +29 -27
  216. package/dialogReadCommands.ts +2 -1
  217. package/dialogStatusCommands.ts +2 -1
  218. package/integrations/anthropic/anthropicModels.ts +12 -12
  219. package/integrations/deepseek/models.ts +67 -67
  220. package/integrations/google/models.ts +111 -53
  221. package/integrations/openai/models.ts +22 -22
  222. package/integrations/xai/models.ts +1 -1
  223. package/localRuntimeDb.ts +39 -2
  224. package/machineCommandPrompts.ts +2 -0
  225. package/machineCommands.ts +193 -62
  226. package/machineStatusCommands.ts +4 -12
  227. package/machineWsRunDispatch.ts +80 -15
  228. package/machineWsSession.ts +46 -2
  229. package/noloReadBridgePrompt.ts +16 -0
  230. package/package.json +114 -21
  231. package/pageCreateCommands.ts +2 -2
  232. package/pageDeleteCommands.ts +3 -3
  233. package/pageReadCommands.ts +3 -3
  234. package/pageUpdateCommands.ts +3 -3
  235. package/render/layout/mainLayoutViewMode.ts +25 -0
  236. package/render/page/server/createPage.ts +3 -1
  237. package/render/page/server/handleCreatePage.ts +2 -11
  238. package/runtimeDoctorCommands.ts +18 -69
  239. package/server/api/methods.ts +34 -12
  240. package/server/api/tableHandlers.ts +6 -3
  241. package/server/authenticateToken.ts +47 -2
  242. package/server/billingLedgerRoutes.ts +15 -0
  243. package/server/buildManifest.ts +54 -0
  244. package/server/coreReadiness.ts +34 -25
  245. package/server/coreRuntime.ts +15 -10
  246. package/server/handlers/activityStatsHandler.ts +5 -2
  247. package/server/handlers/agentEmailRegistrationE2EHandler.ts +25 -23
  248. package/server/handlers/agentRun/agentLookup.ts +1 -7
  249. package/server/handlers/agentRun/autonomousRuntime.ts +11 -10
  250. package/server/handlers/agentRun/builtinAgents.ts +12 -88
  251. package/server/handlers/agentRun/continueDialogContext.ts +15 -3
  252. package/server/handlers/agentRun/{inheritedDialogPrompt.ts → conversationReference.ts} +3 -3
  253. package/server/handlers/agentRun/dialogLookup.ts +4 -3
  254. package/server/handlers/agentRun/index.ts +864 -404
  255. package/server/handlers/agentRun/localRuntimeBootstrap.ts +17 -1
  256. package/server/handlers/agentRun/loop.ts +920 -508
  257. package/server/handlers/agentRun/machineConnector.ts +56 -8
  258. package/server/handlers/agentRun/machineRunAudit.ts +3 -2
  259. package/server/handlers/agentRun/modelUsageToolHandlers.ts +13 -10
  260. package/server/handlers/agentRun/requestContext.ts +12 -8
  261. package/server/handlers/agentRun/runtimeExecutionContext.ts +15 -3
  262. package/server/handlers/agentRun/runtimePreparation.ts +26 -24
  263. package/server/handlers/agentRun/runtimeRouting.ts +25 -40
  264. package/server/handlers/agentRun/runtimeSystemMessages.ts +65 -0
  265. package/server/handlers/agentRun/saveDialog.ts +97 -87
  266. package/server/handlers/agentRun/taskRunToolHandler.ts +9 -7
  267. package/server/handlers/agentRun/toolExecutor.ts +42 -78
  268. package/server/handlers/agentRun/types.ts +2 -1
  269. package/server/handlers/appDeployStatusStore.ts +17 -10
  270. package/server/handlers/appDomainHandler.ts +21 -15
  271. package/server/handlers/appLegacyInfraCleanup.ts +5 -2
  272. package/server/handlers/appSandboxHandler.ts +29 -8
  273. package/server/handlers/appSpaceAccess.ts +15 -8
  274. package/server/handlers/chatHandler.ts +22 -2
  275. package/server/handlers/chatUpstreamRetry.ts +225 -2
  276. package/server/handlers/connector/connectorConnectionRegistry.ts +55 -7
  277. package/server/handlers/connector/connectorWebSocket.ts +14 -10
  278. package/server/handlers/desktopAgentRuntimeAdapter.ts +4 -4
  279. package/server/handlers/desktopAgentRuntimeHostCapabilities.ts +25 -0
  280. package/server/handlers/desktopAgentRuntimeReadiness.ts +62 -0
  281. package/server/handlers/desktopAgentRuntimeStatusHandler.ts +38 -30
  282. package/server/handlers/desktopAgentRuntimeTurnHandler.ts +7 -3
  283. package/server/handlers/desktopAgentRuntimeTurnService.ts +39 -45
  284. package/server/handlers/desktopLlamaRuntimeHandler.ts +85 -51
  285. package/server/handlers/desktopUpdaterHandler.ts +132 -24
  286. package/server/handlers/favoriteHandlers.ts +8 -2
  287. package/server/handlers/getDialogBillingHandler.ts +4 -3
  288. package/server/handlers/getTransactionsHandler.ts +5 -2
  289. package/server/handlers/machines/machineBinding.ts +1 -0
  290. package/server/handlers/machines/machineHandlers.ts +0 -14
  291. package/server/handlers/machines/machineInstallAssets.ts +4 -2
  292. package/server/handlers/notificationEmitter.ts +5 -3
  293. package/server/handlers/notificationsHandler.ts +5 -2
  294. package/server/handlers/providerCallsRecentHandler.ts +234 -0
  295. package/server/handlers/providerReconciliationRunHandler.ts +180 -0
  296. package/server/handlers/providerRequestIdsHandler.ts +105 -0
  297. package/server/handlers/tableAccess.ts +6 -2
  298. package/server/handlers/tableToolHandlers.ts +28 -14
  299. package/server/handlers/userSecretsHandler.ts +17 -6
  300. package/server/handlers/versionHandler.ts +9 -4
  301. package/server/handlers/versionStore.ts +18 -10
  302. package/server/html/ssrPreload.ts +5 -3
  303. package/server/payments/crypto/cryptoUsdcBasePaymentProvider.ts +11 -8
  304. package/server/payments/crypto/cryptoUsdcBaseScanner.ts +12 -7
  305. package/server/payments/crypto/cryptoUsdtTronPaymentProvider.ts +11 -8
  306. package/server/payments/crypto/cryptoUsdtTronScanner.ts +9 -7
  307. package/server/payments/waffo/waffoPaymentProvider.ts +12 -9
  308. package/server/runtimeRole.ts +15 -0
  309. package/server/scheduler/scheduledTaskRuntime.ts +4 -2
  310. package/server/scheduler/schedulerService.ts +2 -2
  311. package/server/taskRunBridgeRoutes.ts +8 -5
  312. package/share/server/fetchCommunityShares.ts +1 -1
  313. package/share/server/helpers.ts +19 -17
  314. package/share/server/importShare.ts +9 -13
  315. package/share/server/listCommunityShares.ts +4 -4
  316. package/share/server/purchaseDoc.ts +8 -16
  317. package/share/server/readCommunityShareCover.ts +3 -2
  318. package/share/server/readSharedTable.ts +14 -13
  319. package/share/server/tableReplication.ts +42 -39
  320. package/spaceAttachCommands.ts +135 -0
  321. package/spaceCategoryCommands.ts +6 -6
  322. package/spaceCommands.ts +3 -3
  323. package/spaceDeleteCommands.ts +2 -2
  324. package/spaceInternalCommandEntries.ts +2 -0
  325. package/spaceReadCommands.ts +3 -3
  326. package/tableMetaCommands.ts +2 -2
  327. package/taskRunCommand.ts +11 -0
  328. package/ai/agent/runtimeServerBase.ts +0 -37
  329. package/server/handlers/desktopAgentRuntimeHostFacts.ts +0 -40
@@ -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.sourceDialogKey || file.dialogKey || file.pageKey;
304
- return key && currentInputMap.has(key);
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.sourceDialogKey || file.dialogKey || file.pageKey;
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(finalKeys.currentInputContext),
624
- fetchReferences(finalKeys.historyContext),
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
- currentInputMap,
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;