nolo-cli 0.1.19 → 0.1.21
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/README.md +9 -1
- package/agent-runtime/agentConfigOptions.ts +12 -0
- package/agent-runtime/agentRecordConfig.ts +99 -0
- package/agent-runtime/agentRecordKeys.ts +14 -0
- package/agent-runtime/dialogMessageRecord.ts +16 -0
- package/agent-runtime/dialogWritePlan.ts +130 -0
- package/agent-runtime/hostAdapter.ts +13 -0
- package/agent-runtime/hybridRecordStore.ts +147 -0
- package/agent-runtime/index.ts +69 -0
- package/agent-runtime/localLoop.ts +69 -5
- package/agent-runtime/localToolPolicy.ts +130 -0
- package/agent-runtime/localWorkspaceTools.ts +1532 -0
- package/agent-runtime/openAiCompatibleProvider.ts +70 -0
- package/agent-runtime/openAiCompatibleProviderConfig.ts +38 -0
- package/agent-runtime/platformChatProvider.ts +241 -0
- package/agent-runtime/taskWorkspace.ts +193 -0
- package/agent-runtime/types.ts +1 -0
- package/agent-runtime/workspaceSession.ts +76 -0
- package/agentAliases.ts +37 -0
- package/agentPullCommand.ts +1 -1
- package/agentRunCommand.ts +278 -52
- package/agentRuntimeCommands.ts +354 -164
- package/agentRuntimeLocal.ts +38 -0
- package/ai/agent/agentSlice.ts +10 -0
- package/ai/agent/buildEditingContext.ts +5 -0
- package/ai/agent/buildSystemPrompt.ts +41 -18
- package/ai/agent/canvasEditingContext.ts +49 -0
- package/ai/agent/cliExecutor.ts +15 -4
- package/ai/agent/createAgentSchema.ts +2 -0
- package/ai/agent/executeToolCall.ts +3 -2
- package/ai/agent/hooks/usePublicAgents.ts +6 -0
- package/ai/agent/pageBuilderHandoffRules.ts +75 -0
- package/ai/agent/runAgentClientLoop.ts +4 -1
- package/ai/agent/runtimeGuidance.ts +19 -0
- package/ai/agent/server/fetchPublicAgents.ts +51 -1
- package/ai/agent/streamAgentChatTurn.ts +20 -2
- package/ai/agent/streamAgentChatTurnUtils.ts +60 -16
- package/ai/chat/accumulateToolCallChunks.ts +40 -9
- package/ai/chat/parseApiError.ts +3 -0
- package/ai/chat/sendOpenAICompletionsRequest.native.ts +23 -10
- package/ai/chat/sendOpenAICompletionsRequest.ts +13 -1
- package/ai/chat/updateTotalUsage.ts +26 -9
- package/ai/llm/deepinfra.ts +51 -0
- package/ai/llm/getPricing.ts +6 -0
- package/ai/llm/kimi.ts +2 -0
- package/ai/llm/openrouterModels.ts +0 -135
- package/ai/llm/providers.ts +1 -0
- package/ai/llm/types.ts +8 -0
- package/ai/taskRun/taskRunProtocol.ts +882 -0
- package/ai/token/calculatePrice.ts +30 -0
- package/ai/token/externalToolCost.ts +49 -29
- package/ai/token/prepareTokenUsageData.ts +6 -1
- package/ai/token/serverTokenWriter.ts +4 -2
- package/ai/tools/agent/agentTools.ts +21 -0
- package/ai/tools/agent/presets/appBuilderPreset.ts +7 -0
- package/ai/tools/agent/streamParallelAgentsTool.ts +2 -1
- package/ai/tools/agent/taskRunTool.ts +112 -0
- package/ai/tools/applyEditTool.ts +6 -3
- package/ai/tools/applyLineEditsTool.ts +6 -3
- package/ai/tools/checkEnvTool.ts +14 -9
- package/ai/tools/codeSearchTool.ts +17 -5
- package/ai/tools/execBashTool.ts +33 -29
- package/ai/tools/fetchWebpageSupport.ts +24 -0
- package/ai/tools/fetchWebpageTool.ts +18 -5
- package/ai/tools/index.ts +158 -0
- package/ai/tools/jdProductScraperTool.ts +821 -0
- package/ai/tools/listFilesTool.ts +6 -3
- package/ai/tools/localFilesTool.ts +200 -0
- package/ai/tools/readFileTool.ts +6 -3
- package/ai/tools/searchRepoTool.ts +6 -3
- package/ai/tools/table/rowTools.ts +6 -1
- package/ai/tools/taobaoTmallProductScraperTool.ts +49 -0
- package/ai/tools/toolApiClient.ts +20 -6
- package/ai/tools/wereadGatewayTool.ts +152 -0
- package/ai/tools/writeFileTool.ts +6 -3
- package/client/agentConfigResolver.test.ts +70 -0
- package/client/agentConfigResolver.ts +1 -0
- package/client/agentRun.test.ts +430 -7
- package/client/agentRun.ts +504 -64
- package/client/hybridRecordStore.test.ts +115 -0
- package/client/hybridRecordStore.ts +41 -0
- package/client/localAgentRecords.test.ts +27 -0
- package/client/localAgentRecords.ts +7 -0
- package/client/localDialogRecords.test.ts +124 -0
- package/client/localDialogRecords.ts +30 -0
- package/client/localProviderResolver.test.ts +78 -0
- package/client/localProviderResolver.ts +1 -0
- package/client/localRuntimeAdapter.test.ts +621 -9
- package/client/localRuntimeAdapter.ts +275 -250
- package/client/localRuntimeDryRun.test.ts +116 -0
- package/client/localToolPolicy.ts +8 -81
- package/client/taskRunPrompt.ts +26 -0
- package/client/taskWorktree.ts +8 -0
- package/client/workspaceSession.test.ts +57 -0
- package/client/workspaceSession.ts +11 -0
- package/commandRegistry.ts +23 -6
- package/connectorRunArtifact.ts +121 -0
- package/database/actions/write.ts +16 -2
- package/database/hooks/useUserData.ts +9 -3
- package/database/server/dataHandlers.ts +18 -20
- package/database/server/emailRepository.ts +3 -3
- package/database/server/patch.ts +18 -10
- package/database/server/query.ts +43 -4
- package/database/server/read.ts +24 -38
- package/database/server/recordIdentity.ts +100 -0
- package/database/server/write.ts +21 -25
- package/index.ts +70 -33
- package/machineCommands.ts +318 -144
- package/package.json +4 -1
- package/tableCommands.ts +181 -0
- package/taskRunCommand.ts +265 -0
package/agentRuntimeLocal.ts
CHANGED
|
@@ -1,7 +1,45 @@
|
|
|
1
|
+
export {
|
|
2
|
+
buildOpenAiCompatibleChatCompletionRequest,
|
|
3
|
+
buildPlatformChatCompletionRequest,
|
|
4
|
+
canUsePlatformChatProvider,
|
|
5
|
+
hasDirectOpenAiCompatibleProvider,
|
|
6
|
+
createHybridRecordStore,
|
|
7
|
+
executeLocalToolWithPolicy,
|
|
8
|
+
activateWorkspaceSession,
|
|
9
|
+
createWorkspaceSession,
|
|
10
|
+
buildAgentRuntimeAgentLookupKeys,
|
|
11
|
+
buildAgentRuntimeDialogWritePlan,
|
|
12
|
+
dialogMessageRecordToAgentRuntimeMessage,
|
|
13
|
+
formatWorkspaceSessionActivation,
|
|
14
|
+
pickAgentRuntimeInferenceOptions,
|
|
15
|
+
parseOpenAiCompatibleChatCompletionResponse,
|
|
16
|
+
parsePlatformChatCompletionData,
|
|
17
|
+
parsePlatformChatCompletionResponse,
|
|
18
|
+
resolveAgentRuntimeConfigFromRecord,
|
|
19
|
+
resolvePlatformChatProviderConfig,
|
|
20
|
+
resolveLocalToolPolicy,
|
|
21
|
+
resolveOpenAiCompatibleProviderConfig,
|
|
22
|
+
shouldUsePlatformChatProvider,
|
|
23
|
+
shouldCacheHybridRemoteRecord,
|
|
24
|
+
shouldFetchAgentRuntimeRecordRemotely,
|
|
25
|
+
} from "./agent-runtime";
|
|
1
26
|
export { runLocalAgentTurn } from "./agent-runtime/localLoop";
|
|
27
|
+
export {
|
|
28
|
+
buildLocalWorkspaceOpenAiTools,
|
|
29
|
+
buildLocalWorkspacePolicyToolNames,
|
|
30
|
+
buildLocalWorkspaceToolset,
|
|
31
|
+
createLocalWorkspaceToolExecutors,
|
|
32
|
+
} from "./agent-runtime/localWorkspaceTools";
|
|
2
33
|
export type {
|
|
3
34
|
AgentRuntimeAgentConfig,
|
|
4
35
|
AgentRuntimeHostAdapter,
|
|
5
36
|
AgentRuntimeRequestedMode,
|
|
6
37
|
AgentRuntimeSaveTurnInput,
|
|
38
|
+
HybridRecordKvDb,
|
|
39
|
+
HybridRecordStore,
|
|
40
|
+
LocalToolPolicyDecision,
|
|
41
|
+
PreparedTaskWorkspace,
|
|
42
|
+
PrepareTaskWorkspace,
|
|
43
|
+
WorkspaceSession,
|
|
44
|
+
WorkspaceSessionMode,
|
|
7
45
|
} from "./agent-runtime";
|
package/ai/agent/agentSlice.ts
CHANGED
|
@@ -193,6 +193,16 @@ const processAgentUpdateChanges = (
|
|
|
193
193
|
if ("useServerProxy" in data && data.useServerProxy !== undefined) {
|
|
194
194
|
changes.useServerProxy = !!data.useServerProxy;
|
|
195
195
|
}
|
|
196
|
+
if ("sharingLevel" in data) {
|
|
197
|
+
const sharingLevel = (data as any).sharingLevel;
|
|
198
|
+
if (
|
|
199
|
+
sharingLevel === "default" ||
|
|
200
|
+
sharingLevel === "split" ||
|
|
201
|
+
sharingLevel === "full"
|
|
202
|
+
) {
|
|
203
|
+
changes.sharingLevel = sharingLevel;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
196
206
|
|
|
197
207
|
// greeting / tools 直接透传
|
|
198
208
|
if ("greeting" in data) {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import type { RootState } from "app/store";
|
|
4
4
|
import type { AgentRuntimeOptions } from "./types";
|
|
5
|
+
import { buildCanvasNodeEditingContextSummary } from "./canvasEditingContext";
|
|
5
6
|
import { selectCurrentTable, selectTableRows } from "render/table/tableSlice";
|
|
6
7
|
import { selectDoc } from "render/page/docSlice";
|
|
7
8
|
|
|
@@ -368,6 +369,10 @@ export const buildEditingContextSummary = (
|
|
|
368
369
|
].join("\n");
|
|
369
370
|
}
|
|
370
371
|
|
|
372
|
+
if (targetKind === "canvas_node") {
|
|
373
|
+
return buildCanvasNodeEditingContextSummary(runtimeOptions);
|
|
374
|
+
}
|
|
375
|
+
|
|
371
376
|
// 其它 kind 以后按需扩展
|
|
372
377
|
return null;
|
|
373
378
|
};
|
|
@@ -7,6 +7,7 @@ import { Agent } from "app/types";
|
|
|
7
7
|
import { buildSkillGuidancePromptBlock } from "ai/skills/referenceRuntime";
|
|
8
8
|
import { buildRuntimeGuidanceBlocks } from "ai/agent/runtimeGuidance";
|
|
9
9
|
import { canonicalizeToolNames } from "ai/tools/toolNameAliases";
|
|
10
|
+
import { PAGE_BUILDER_HANDOFF_INSTRUCTIONS } from "./pageBuilderHandoffRules";
|
|
10
11
|
import { compileContextLayers, type CompiledContext } from "./contextCompiler";
|
|
11
12
|
import { Contexts } from "../types";
|
|
12
13
|
|
|
@@ -31,20 +32,18 @@ const MENU_USAGE_INSTRUCTIONS = `--- 交互说明(菜单与快捷入口) ---
|
|
|
31
32
|
|
|
32
33
|
对你来说:
|
|
33
34
|
- 不要假设或讨论用户点击了哪些按钮、使用了什么菜单,也不要在回复中提到"按钮""菜单""界面""第几个选项"等字样。
|
|
34
|
-
-
|
|
35
|
-
- 当你希望用户在几个互斥选项之间做选择时,可以调用 ui_ask_choice 工具;用户的选择会以一条新的自然语言消息的形式出现在后续对话中。`;
|
|
35
|
+
- 把所有收到的消息都当作用户刚刚输入的一句话,根据这句话的内容直接理解和回答即可。`;
|
|
36
36
|
|
|
37
37
|
// ============================================================================
|
|
38
38
|
// 网页访问(有 exa_search 工具时注入)
|
|
39
39
|
// ============================================================================
|
|
40
40
|
|
|
41
41
|
const WEBPAGE_ACCESS_INSTRUCTIONS = `--- 网页访问能力 (Web Access) ---
|
|
42
|
-
|
|
42
|
+
在需要获取外部信息时,请遵循以下由简入繁的策略:
|
|
43
43
|
|
|
44
44
|
0. **如果用户已经给了明确 URL,先直接抓这些 URL**
|
|
45
45
|
- 不要先搜索,不要先猜备用网址,不要忽略用户给的链接。
|
|
46
46
|
- 用户明确给出的 URL,默认就是本次任务的最高优先级网页真值来源。
|
|
47
|
-
- 如果 URL 是 X/Twitter status 链接(例如 \`x.com/.../status/...\` 或 \`twitter.com/.../status/...\`),并且你拥有 \`read_x_post\` 工具,应优先调用 \`read_x_post\`,不要先用搜索、镜像站或通用网页抓取替代。
|
|
48
47
|
- 如果任务是“根据这些网页更新代码 / 文档 / 配置”,先逐个 fetch,再基于抓到的内容提取字段。
|
|
49
48
|
- 只要这些 URL 能正常抓取,就不要再调用 exa_search 搜索“更权威”的来源,也不要自行切换到其他站点或镜像页。
|
|
50
49
|
- 只有在用户给的 URL 抓取失败、页面明显缺字段、或页面内容与任务不匹配时,才允许额外搜索;如果发生这种降级,最终回复里要明确说明原因。
|
|
@@ -71,6 +70,20 @@ const WEBPAGE_ACCESS_INSTRUCTIONS = `--- 网页访问能力 (Web Access) ---
|
|
|
71
70
|
3. **精准数据抓取 (Scrapers)**
|
|
72
71
|
- 如果用户明确需要 YouTube 视频信息、亚马逊商品数据、Google 搜索结果,请直接使用对应的专用 Scraper 工具 (youtubeScraper, amazonProductScraper 等),效果比自己去爬网页更好。`;
|
|
73
72
|
|
|
73
|
+
// ============================================================================
|
|
74
|
+
// 本地文件整理(有 local desktop file tools 时注入)
|
|
75
|
+
// ============================================================================
|
|
76
|
+
|
|
77
|
+
const LOCAL_FILE_ORGANIZATION_INSTRUCTIONS = `--- 本地文件整理能力 ---
|
|
78
|
+
你可以帮助用户整理 Windows 桌面客户端里已授权的本地文件夹。必须遵守:
|
|
79
|
+
|
|
80
|
+
- 只能访问用户已授权的本地文件夹,所有路径都必须是授权根目录内的相对路径。
|
|
81
|
+
- 开始整理前,先列目录和读取必要文件,理解现状后再提出计划。
|
|
82
|
+
- 对移动、重命名、写入、删除等改动,不要直接修改文件;先调用 proposeLocalFileChanges 创建待确认计划。
|
|
83
|
+
- 用户确认后,才执行已确认的本地文件整理计划。
|
|
84
|
+
- 删除类操作要保守;能通过移动到整理目录解决时,不要优先删除。
|
|
85
|
+
- 回复用户时说明将要改哪些文件、为什么改、以及是否可撤销。`;
|
|
86
|
+
|
|
74
87
|
// ============================================================================
|
|
75
88
|
// Agent 编排协作(有 callAgent / runStreamingAgent 工具时注入)
|
|
76
89
|
// ============================================================================
|
|
@@ -79,9 +92,6 @@ const AGENT_ORCHESTRATION_INSTRUCTIONS = `--- Agent 编排与协作 ---
|
|
|
79
92
|
你所在的系统支持多个子 Agent 和工作流工具,请把自己视为"总协调者":
|
|
80
93
|
|
|
81
94
|
1)子 Agent 协作
|
|
82
|
-
- 使用 callAgent 工具,可以让其它 Agent 作为"专家顾问"分别给出意见或完成子任务。
|
|
83
|
-
- 使用 runStreamingAgent 工具,可以把后续对话完全交给某个专用 Agent(例如代码助手、翻译助手)。
|
|
84
|
-
- 使用 streamParallelAgents 工具,可以并行询问多个 Agent,再由你继续综合共识和分歧。
|
|
85
95
|
- 如果目标 Agent 记录已经声明 delegation.serverBase / runtimeServerBase,工具会自动路由到对应 nolo server;你不需要重复填写 serverBase。
|
|
86
96
|
- 如果用户明确给了另一个可访问的 server origin(例如 Windows 机器的 Cloudflare 域名),可以在工具参数里传 serverBase 覆盖自动路由;不要臆造地址,也不要把普通 localhost 当成远端机器。
|
|
87
97
|
- 当用户需要多视角分析或辩论时,你可以:
|
|
@@ -105,22 +115,17 @@ const AGENT_ORCHESTRATION_INSTRUCTIONS = `--- Agent 编排与协作 ---
|
|
|
105
115
|
// ============================================================================
|
|
106
116
|
|
|
107
117
|
const KNOWLEDGE_MANAGEMENT_INSTRUCTIONS = `--- 知识管理 ---
|
|
108
|
-
你拥有 read / createDoc / updateDoc 能力,应主动管理知识,而不是每次重新推理。
|
|
109
118
|
|
|
110
119
|
## 三层知识决策
|
|
111
120
|
|
|
112
|
-
**1.
|
|
113
|
-
- 极短、每次必用的规则(角色定义、回复风格、固定限制)
|
|
114
|
-
- 标准:去掉它你就不知道自己是谁
|
|
115
|
-
|
|
116
|
-
**2. references 挂载知识(每次对话自动加载)**
|
|
121
|
+
**1. references 挂载知识(每次对话自动加载)**
|
|
117
122
|
- Agent 配置里的 references 会在每次对话开始时自动展开注入到 system prompt
|
|
118
123
|
- type=instruction:高优先级,注入到 system prompt 顶部,适合行为规则、操作指南
|
|
119
124
|
- type=knowledge:作为参考资料注入,适合领域知识、背景资料
|
|
120
125
|
- 支持挂载:page / dialog / table(内容完整展开)
|
|
121
126
|
- **page 里的 @mention 只展开元信息(标题+dbKey),不递归展开内容本身**
|
|
122
127
|
|
|
123
|
-
**
|
|
128
|
+
**2. createDoc 创建文档(按需 read 加载)**
|
|
124
129
|
- 总知识页(索引):跨会话的决策规则、路由表,用 @[page:PAGE-xxx|标题] mention 指向细分页
|
|
125
130
|
- 细分知识页(内容):具体领域内容、任务结果,通过总知识索引
|
|
126
131
|
- mention 只是指针,要获取细分页内容必须显式调用 read({ dbKey })
|
|
@@ -164,7 +169,6 @@ const MEMORY_CAPTURE_INSTRUCTIONS = `--- 长期记忆 ---
|
|
|
164
169
|
// ============================================================================
|
|
165
170
|
|
|
166
171
|
const SELF_UPDATE_INSTRUCTIONS = `--- Agent 自我更新能力 ---
|
|
167
|
-
你拥有 updateSelf 权限,可以修改自己的配置。请谨慎、精准地使用。
|
|
168
172
|
|
|
169
173
|
## 何时更新自己
|
|
170
174
|
- 重要决策/进度变化 → updateDoc 写回状态页
|
|
@@ -210,8 +214,6 @@ const CODE_EDITING_FIDELITY_INSTRUCTIONS = `--- 代码编辑真值规则 ---
|
|
|
210
214
|
- 编辑完成后,最终回复只做简短结果汇报:说清改了哪些条目、依据了哪些 URL、是否还有缺失字段。不要长篇复述网页正文。`;
|
|
211
215
|
|
|
212
216
|
const TABLE_SHARE_INSTRUCTIONS = `--- 表格创建与分享 ---
|
|
213
|
-
当用户要你整理结构化信息时,可以先用 createTable 建表,再用 addTableRow / addTableRows 填充内容。
|
|
214
|
-
|
|
215
217
|
如果用户明确要求“社区分享 / 公开分享 / 分享链接”,并且你有 shareTable 工具:
|
|
216
218
|
- 优先调用 shareTable;
|
|
217
219
|
- 传入表的 dbKey,或 tenantId + tableId;
|
|
@@ -419,7 +421,10 @@ export const buildSystemPromptContext = (options: {
|
|
|
419
421
|
const agentOrchestrationSection = agentTools.some((t) =>
|
|
420
422
|
["callAgent", "runStreamingAgent", "streamParallelAgents"].includes(t)
|
|
421
423
|
)
|
|
422
|
-
?
|
|
424
|
+
? [
|
|
425
|
+
AGENT_ORCHESTRATION_INSTRUCTIONS,
|
|
426
|
+
agentTools.includes("runStreamingAgent") ? PAGE_BUILDER_HANDOFF_INSTRUCTIONS : "",
|
|
427
|
+
].filter(Boolean).join("\n\n")
|
|
423
428
|
: "";
|
|
424
429
|
|
|
425
430
|
const menuUsageSection = agentTools.includes("ui_ask_choice")
|
|
@@ -431,6 +436,17 @@ export const buildSystemPromptContext = (options: {
|
|
|
431
436
|
)
|
|
432
437
|
? WEBPAGE_ACCESS_INSTRUCTIONS
|
|
433
438
|
: "";
|
|
439
|
+
const localFileOrganizationSection = agentTools.some((t) =>
|
|
440
|
+
[
|
|
441
|
+
"listLocalFiles",
|
|
442
|
+
"readLocalFile",
|
|
443
|
+
"proposeLocalFileChanges",
|
|
444
|
+
"executeApprovedLocalFileChanges",
|
|
445
|
+
"undoLocalFileChangeBatch",
|
|
446
|
+
].includes(t)
|
|
447
|
+
)
|
|
448
|
+
? LOCAL_FILE_ORGANIZATION_INSTRUCTIONS
|
|
449
|
+
: "";
|
|
434
450
|
const tableShareSection = agentTools.some((t) =>
|
|
435
451
|
["createTable", "shareTable", "addTableRow", "addTableRows"].includes(t)
|
|
436
452
|
)
|
|
@@ -466,6 +482,7 @@ export const buildSystemPromptContext = (options: {
|
|
|
466
482
|
startupProtocol,
|
|
467
483
|
contextLayerContract,
|
|
468
484
|
emailRegistrationWorkflow,
|
|
485
|
+
webResearchToolPolicy,
|
|
469
486
|
} =
|
|
470
487
|
buildRuntimeGuidanceBlocks(agentTools);
|
|
471
488
|
|
|
@@ -500,6 +517,7 @@ export const buildSystemPromptContext = (options: {
|
|
|
500
517
|
{ id: "core-persona", owner: "agent", content: corePersonaSection },
|
|
501
518
|
{ id: "agent-orchestration", owner: "platform", content: agentOrchestrationSection },
|
|
502
519
|
{ id: "web-access", owner: "platform", content: webAccessSection },
|
|
520
|
+
{ id: "local-file-organization", owner: "platform", content: localFileOrganizationSection },
|
|
503
521
|
{ id: "table-share", owner: "platform", content: tableShareSection },
|
|
504
522
|
{ id: "menu-usage", owner: "platform", content: menuUsageSection },
|
|
505
523
|
{ id: "clarification-mode", owner: "platform", content: clarifyingSection },
|
|
@@ -515,6 +533,11 @@ export const buildSystemPromptContext = (options: {
|
|
|
515
533
|
owner: "platform",
|
|
516
534
|
content: emailRegistrationWorkflow,
|
|
517
535
|
},
|
|
536
|
+
{
|
|
537
|
+
id: "web-research-tool-policy",
|
|
538
|
+
owner: "platform",
|
|
539
|
+
content: webResearchToolPolicy,
|
|
540
|
+
},
|
|
518
541
|
{ id: "user-global-prompt", owner: "user", content: userGlobalPromptSection },
|
|
519
542
|
{ id: "response-guidelines", owner: "platform", content: responseGuidelinesSection },
|
|
520
543
|
{ id: "skill-guidance", owner: "runtime", content: skillGuidanceSection },
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { AgentRuntimeOptions } from "./types";
|
|
2
|
+
|
|
3
|
+
export function buildCanvasNodeEditingContextSummary(
|
|
4
|
+
runtimeOptions?: AgentRuntimeOptions
|
|
5
|
+
): string | null {
|
|
6
|
+
if (runtimeOptions?.editingTarget?.kind !== "canvas_node") return null;
|
|
7
|
+
|
|
8
|
+
const editingTarget = runtimeOptions.editingTarget;
|
|
9
|
+
const metadata = editingTarget.metadata ?? {};
|
|
10
|
+
const selectedNodeId =
|
|
11
|
+
typeof metadata.selectedNodeId === "string"
|
|
12
|
+
? metadata.selectedNodeId
|
|
13
|
+
: editingTarget.key ?? "(未知节点)";
|
|
14
|
+
const part =
|
|
15
|
+
typeof metadata.part === "string"
|
|
16
|
+
? metadata.part
|
|
17
|
+
: editingTarget.title ?? selectedNodeId;
|
|
18
|
+
const nodeType =
|
|
19
|
+
typeof metadata.type === "string" ? metadata.type : "(未知类型)";
|
|
20
|
+
const path = Array.isArray(metadata.path)
|
|
21
|
+
? metadata.path.filter((item): item is string => typeof item === "string")
|
|
22
|
+
: [];
|
|
23
|
+
const props = metadata.props && typeof metadata.props === "object"
|
|
24
|
+
? metadata.props
|
|
25
|
+
: {};
|
|
26
|
+
const style = metadata.style && typeof metadata.style === "object"
|
|
27
|
+
? metadata.style
|
|
28
|
+
: {};
|
|
29
|
+
|
|
30
|
+
return [
|
|
31
|
+
"当前编辑目标:Canvas Tree 中的一个选中节点。",
|
|
32
|
+
`- 节点 ID: ${selectedNodeId}`,
|
|
33
|
+
`- part: ${part}`,
|
|
34
|
+
`- 节点类型: ${nodeType}`,
|
|
35
|
+
...(path.length ? [`- 节点路径: ${path.join(" > ")}`] : []),
|
|
36
|
+
"",
|
|
37
|
+
"当前节点 props:",
|
|
38
|
+
JSON.stringify(props, null, 2),
|
|
39
|
+
"",
|
|
40
|
+
"当前节点 style:",
|
|
41
|
+
JSON.stringify(style, null, 2),
|
|
42
|
+
"",
|
|
43
|
+
"【给 AI 的操作指南 / 非用户原话】",
|
|
44
|
+
`1. 如果用户要求修改当前模块,只输出 updateNode,目标 id 必须是 ${selectedNodeId}。`,
|
|
45
|
+
"2. 不要重建 root/shell,不要重新 append 已存在的大块内容。",
|
|
46
|
+
"3. 除非用户明确要求新增子模块,否则不要 appendNode。",
|
|
47
|
+
"4. 回复仍必须遵守 Canvas Tree MVP 协议:只输出 canvas_snapshot NDJSON,不要输出解释或源码。",
|
|
48
|
+
].join("\n");
|
|
49
|
+
}
|
package/ai/agent/cliExecutor.ts
CHANGED
|
@@ -29,6 +29,7 @@ export interface CliExecuteOptions {
|
|
|
29
29
|
model?: string;
|
|
30
30
|
timeout?: number; // ms,默认 120_000
|
|
31
31
|
cwd?: string;
|
|
32
|
+
env?: Record<string, string | undefined>;
|
|
32
33
|
yolo?: boolean; // 允许所有工具,默认 true(后台任务常用)
|
|
33
34
|
}
|
|
34
35
|
|
|
@@ -62,6 +63,16 @@ export interface CliSessionTurnResult extends CliExecuteResult {
|
|
|
62
63
|
|
|
63
64
|
const cliSessions = new Map<string, CliSessionState>();
|
|
64
65
|
|
|
66
|
+
function buildCliProcessEnv(extraEnv?: Record<string, string | undefined>) {
|
|
67
|
+
return Object.fromEntries(
|
|
68
|
+
Object.entries({
|
|
69
|
+
...process.env,
|
|
70
|
+
...extraEnv,
|
|
71
|
+
NO_COLOR: "1",
|
|
72
|
+
}).filter((entry): entry is [string, string] => typeof entry[1] === "string")
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
65
76
|
// ── 各 provider 实现 ─────────────────────────────────────────────────────────
|
|
66
77
|
|
|
67
78
|
/**
|
|
@@ -97,7 +108,7 @@ function executeCopilot(
|
|
|
97
108
|
|
|
98
109
|
exec(
|
|
99
110
|
cmd,
|
|
100
|
-
{ timeout, cwd, env:
|
|
111
|
+
{ timeout, cwd, env: buildCliProcessEnv(options.env) },
|
|
101
112
|
(error, stdout, stderr) => {
|
|
102
113
|
if (error) {
|
|
103
114
|
if (error.killed && (error as any).signal === "SIGTERM") {
|
|
@@ -198,7 +209,7 @@ function executeGemini(
|
|
|
198
209
|
|
|
199
210
|
exec(
|
|
200
211
|
cmd,
|
|
201
|
-
{ timeout, cwd, env:
|
|
212
|
+
{ timeout, cwd, env: buildCliProcessEnv(options.env) },
|
|
202
213
|
(error, stdout, stderr) => {
|
|
203
214
|
if (error) {
|
|
204
215
|
if (error.killed && (error as any).signal === "SIGTERM") {
|
|
@@ -255,7 +266,7 @@ function executeCodex(
|
|
|
255
266
|
const start = Date.now();
|
|
256
267
|
const proc = spawn("codex", [...args, prompt], {
|
|
257
268
|
cwd,
|
|
258
|
-
env:
|
|
269
|
+
env: buildCliProcessEnv(options.env),
|
|
259
270
|
stdio: ["ignore", "pipe", "pipe"],
|
|
260
271
|
});
|
|
261
272
|
let stdout = "";
|
|
@@ -335,7 +346,7 @@ function executeClaude(
|
|
|
335
346
|
const start = Date.now();
|
|
336
347
|
const proc = spawn("claude", args, {
|
|
337
348
|
cwd,
|
|
338
|
-
env:
|
|
349
|
+
env: buildCliProcessEnv(options.env),
|
|
339
350
|
stdio: ["ignore", "pipe", "pipe"],
|
|
340
351
|
});
|
|
341
352
|
let stdout = "";
|
|
@@ -112,6 +112,8 @@ export const getCreateAgentSchema = (t: TFunction) =>
|
|
|
112
112
|
|
|
113
113
|
outputPrice: z.number().min(0, t("validation.priceMin")).default(0),
|
|
114
114
|
|
|
115
|
+
sharingLevel: z.enum(["default", "split", "full"]).optional(),
|
|
116
|
+
|
|
115
117
|
avatarFileId: z.string().optional().or(z.string().length(0)),
|
|
116
118
|
|
|
117
119
|
tags: z.string().trim().optional().or(z.string().length(0)),
|
|
@@ -24,7 +24,7 @@ interface ToolCall {
|
|
|
24
24
|
export async function executeToolCall(
|
|
25
25
|
tc: ToolCall,
|
|
26
26
|
thunkApi: any,
|
|
27
|
-
parentMessageId?: string
|
|
27
|
+
context?: { parentMessageId?: string; agentKey?: string }
|
|
28
28
|
): Promise<string> {
|
|
29
29
|
const toolName: string = tc.function?.name ?? "";
|
|
30
30
|
const toolArgs = (() => {
|
|
@@ -41,7 +41,8 @@ export async function executeToolCall(
|
|
|
41
41
|
return `[工具 "${toolName}" 未找到]`;
|
|
42
42
|
}
|
|
43
43
|
const result = await executor(toolArgs, thunkApi, {
|
|
44
|
-
parentMessageId: parentMessageId ?? "",
|
|
44
|
+
parentMessageId: context?.parentMessageId ?? "",
|
|
45
|
+
agentKey: context?.agentKey,
|
|
45
46
|
});
|
|
46
47
|
// executor 返回 { rawData, displayData? } 或直接返回字符串
|
|
47
48
|
const raw = result?.rawData ?? result;
|
|
@@ -43,6 +43,8 @@ export interface UsePublicAgentsOptions {
|
|
|
43
43
|
imageOutputOnly?: boolean;
|
|
44
44
|
/** Filter agents that include this tool in their tools array */
|
|
45
45
|
toolName?: string;
|
|
46
|
+
/** Return list-card metadata only from remote public-agent APIs. */
|
|
47
|
+
summary?: boolean;
|
|
46
48
|
initialData?: Agent[];
|
|
47
49
|
reloadMode?: "preview" | "catalog";
|
|
48
50
|
}
|
|
@@ -163,6 +165,7 @@ export function usePublicAgents({
|
|
|
163
165
|
userId,
|
|
164
166
|
imageOutputOnly = false,
|
|
165
167
|
toolName,
|
|
168
|
+
summary = false,
|
|
166
169
|
initialData = [],
|
|
167
170
|
reloadMode = "catalog",
|
|
168
171
|
}: UsePublicAgentsOptions = {}) {
|
|
@@ -194,6 +197,7 @@ export function usePublicAgents({
|
|
|
194
197
|
userId,
|
|
195
198
|
imageOutputOnly,
|
|
196
199
|
toolName,
|
|
200
|
+
summary,
|
|
197
201
|
};
|
|
198
202
|
const myReqId = ++requestIdRef.current;
|
|
199
203
|
|
|
@@ -413,6 +417,7 @@ export function usePublicAgents({
|
|
|
413
417
|
userId,
|
|
414
418
|
imageOutputOnly,
|
|
415
419
|
toolName,
|
|
420
|
+
summary,
|
|
416
421
|
currentServer,
|
|
417
422
|
syncServers,
|
|
418
423
|
currentUserId,
|
|
@@ -432,6 +437,7 @@ export function usePublicAgents({
|
|
|
432
437
|
searchName,
|
|
433
438
|
sortBy,
|
|
434
439
|
toolName,
|
|
440
|
+
summary,
|
|
435
441
|
userId,
|
|
436
442
|
]);
|
|
437
443
|
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export const PAGE_BUILDER_AGENT_PUBLIC_KEY =
|
|
2
|
+
"agent-pub-01PAGEBUILDR00000000FT7R9G";
|
|
3
|
+
|
|
4
|
+
export type PageBuilderScenario = {
|
|
5
|
+
id: string;
|
|
6
|
+
label: string;
|
|
7
|
+
userIntent: string;
|
|
8
|
+
prompt: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const PAGE_BUILDER_SCENARIOS: PageBuilderScenario[] = [
|
|
12
|
+
{
|
|
13
|
+
id: "information-display",
|
|
14
|
+
label: "信息展示",
|
|
15
|
+
userIntent: "主页、产品介绍、服务介绍、作品集、活动页、报价页",
|
|
16
|
+
prompt:
|
|
17
|
+
"帮我做一个独立 AI 产品顾问的个人主页。要看起来专业,包含个人定位、能提供的服务卡片、代表成果卡片、可信背书和联系合作按钮。",
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
id: "data-analysis",
|
|
21
|
+
label: "数据分析",
|
|
22
|
+
userIntent: "日报、周报、经营看板、质检报告、销售漏斗、反馈分析",
|
|
23
|
+
prompt:
|
|
24
|
+
"帮我做一个 AI 客服质检日报,包含核心指标、近 7 天风险趋势、异常会话明细表,以及明天需要跟进的建议。",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: "process-guide",
|
|
28
|
+
label: "流程说明",
|
|
29
|
+
userIntent: "教程、SOP、onboarding、操作指南、课程步骤、申请流程",
|
|
30
|
+
prompt:
|
|
31
|
+
"帮我做一个新员工使用 CRM 的交互教程页面,包含学习目标、操作步骤、示例练习、检查清单和下一步按钮。",
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: "decision-comparison",
|
|
35
|
+
label: "决策比较",
|
|
36
|
+
userIntent: "方案对比、产品选型、候选人对比、竞品分析、采购建议",
|
|
37
|
+
prompt:
|
|
38
|
+
"帮我做一个三款 CRM 方案对比页,包含对比维度表格、每个方案的优缺点卡片、评分、适合团队类型和最终推荐。",
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: "plan-roadmap",
|
|
42
|
+
label: "计划排布",
|
|
43
|
+
userIntent: "项目计划、学习计划、健身计划、内容日历、发布节奏",
|
|
44
|
+
prompt:
|
|
45
|
+
"帮我做一个 30 天内容发布计划页面,包含阶段目标、每周任务、优先级、里程碑卡片和风险提醒。",
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: "mixed-pitch",
|
|
49
|
+
label: "混合长尾",
|
|
50
|
+
userIntent: "汇报页、融资材料、复杂项目概览,混合展示、数据、计划、对比",
|
|
51
|
+
prompt:
|
|
52
|
+
"给一个早期 AI 客服创业项目做一页融资汇报页,包含市场机会、关键数据指标卡、增长趋势图、产品路线、竞品对比表、团队介绍和下一步计划。",
|
|
53
|
+
},
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
const scenarioLines = PAGE_BUILDER_SCENARIOS.map(
|
|
57
|
+
(scenario) => `- ${scenario.label}:${scenario.userIntent}`
|
|
58
|
+
).join("\n");
|
|
59
|
+
|
|
60
|
+
export const PAGE_BUILDER_HANDOFF_INSTRUCTIONS = `--- 页面生成助手 handoff ---
|
|
61
|
+
当用户需要把内容变成“可看的页面/报告/看板/教程/对比页/计划页”时,可以把本轮交给页面生成助手。
|
|
62
|
+
|
|
63
|
+
目标 Agent:
|
|
64
|
+
- agentKey: ${PAGE_BUILDER_AGENT_PUBLIC_KEY}
|
|
65
|
+
- 推荐工具: runStreamingAgent
|
|
66
|
+
|
|
67
|
+
适合 handoff 的视觉意图大类:
|
|
68
|
+
${scenarioLines}
|
|
69
|
+
|
|
70
|
+
调用边界:
|
|
71
|
+
- 用户明确要求“做成页面 / 看板 / 报告 / 教程 / 主页 / 对比页 / 计划表 / 可视化”时,可以直接 runStreamingAgent。
|
|
72
|
+
- 如果用户只是讨论内容,但你判断“文字回答不如可视化页面”,先询问用户:“这个更适合做成一页可视化页面,要我生成一个可交互版本吗?”
|
|
73
|
+
- 不要把普通问答、闲聊、代码解释、纯文本总结强行交给页面生成助手。
|
|
74
|
+
- handoff 时,把用户原始需求和你已确认的业务上下文一起放进 userInput,不要要求用户理解 React、HTML、代码块或运行时。
|
|
75
|
+
- 页面生成助手只负责生成和修改可交互页面;你仍负责判断、解释、澄清和后续协调。`;
|
|
@@ -125,7 +125,10 @@ export async function runAgentClientLoop(
|
|
|
125
125
|
// 5. 执行工具调用
|
|
126
126
|
for (const tc of assistantMsg.tool_calls) {
|
|
127
127
|
toolCallCount++;
|
|
128
|
-
const toolResultContent = await executeToolCall(tc, thunkApi,
|
|
128
|
+
const toolResultContent = await executeToolCall(tc, thunkApi, {
|
|
129
|
+
parentMessageId,
|
|
130
|
+
agentKey,
|
|
131
|
+
});
|
|
129
132
|
messages.push({
|
|
130
133
|
role: "tool",
|
|
131
134
|
tool_call_id: tc.id,
|
|
@@ -45,6 +45,20 @@ const buildEmailRegistrationWorkflowBlock = (
|
|
|
45
45
|
].join("\n");
|
|
46
46
|
};
|
|
47
47
|
|
|
48
|
+
const buildWebResearchToolPolicyBlock = (
|
|
49
|
+
hasExecShellTool: boolean,
|
|
50
|
+
hasFetchWebpageTool: boolean
|
|
51
|
+
): string => {
|
|
52
|
+
if (!hasExecShellTool || !hasFetchWebpageTool) return "";
|
|
53
|
+
|
|
54
|
+
return [
|
|
55
|
+
"--- 生产环境网页研究工具策略 ---",
|
|
56
|
+
"生产环境网页研究优先使用 fetchWebpage、站点 Markdown / llms.txt、或专用浏览/搜索工具。",
|
|
57
|
+
"不要用 execShell/execBash 调 curl、grep、sed 等命令抓网页或截取网页段落;生产环境通常会禁用 dev shell,反复尝试只会浪费回合。",
|
|
58
|
+
"如果网页内容过长或锚点段落没有被单独提取,先寻找该文档站提供的 Markdown 版本、独立页面、llms.txt 索引或更具体 URL,再继续回答。",
|
|
59
|
+
].join("\n");
|
|
60
|
+
};
|
|
61
|
+
|
|
48
62
|
export const resolveRuntimeGuidanceToolOptions = (
|
|
49
63
|
tools: string[] = []
|
|
50
64
|
): RuntimeGuidanceToolOptions => {
|
|
@@ -80,6 +94,7 @@ export const resolveRuntimeGuidanceToolOptions = (
|
|
|
80
94
|
|
|
81
95
|
export const buildRuntimeGuidanceBlocks = (tools: string[] = []) => {
|
|
82
96
|
const options = resolveRuntimeGuidanceToolOptions(tools);
|
|
97
|
+
const normalizedTools = canonicalizeToolNames(tools);
|
|
83
98
|
|
|
84
99
|
return {
|
|
85
100
|
startupProtocol: buildStartupProtocolBlock({
|
|
@@ -93,5 +108,9 @@ export const buildRuntimeGuidanceBlocks = (tools: string[] = []) => {
|
|
|
93
108
|
emailRegistrationWorkflow: buildEmailRegistrationWorkflowBlock(
|
|
94
109
|
options.hasEmailRegistrationWorkflow
|
|
95
110
|
),
|
|
111
|
+
webResearchToolPolicy: buildWebResearchToolPolicyBlock(
|
|
112
|
+
options.hasExecShellTool,
|
|
113
|
+
normalizedTools.includes("fetchWebpage")
|
|
114
|
+
),
|
|
96
115
|
};
|
|
97
116
|
};
|
|
@@ -20,6 +20,8 @@ export interface FetchPublicAgentsOptions {
|
|
|
20
20
|
imageOutputOnly?: boolean;
|
|
21
21
|
/** Filter agents that include this tool in their tools array */
|
|
22
22
|
toolName?: string;
|
|
23
|
+
/** Return list-card metadata only. Full agent config is still available by key. */
|
|
24
|
+
summary?: boolean;
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
export interface FetchPublicAgentsResult {
|
|
@@ -80,6 +82,51 @@ async function getPublicAgents(): Promise<Agent[]> {
|
|
|
80
82
|
const DEFAULT_LIMIT = 20;
|
|
81
83
|
const MAX_LIMIT = 100;
|
|
82
84
|
|
|
85
|
+
const SUMMARY_FIELDS = new Set([
|
|
86
|
+
"dbKey",
|
|
87
|
+
"id",
|
|
88
|
+
"type",
|
|
89
|
+
"userId",
|
|
90
|
+
"name",
|
|
91
|
+
"title",
|
|
92
|
+
"displayName",
|
|
93
|
+
"introduction",
|
|
94
|
+
"tags",
|
|
95
|
+
"tools",
|
|
96
|
+
"provider",
|
|
97
|
+
"model",
|
|
98
|
+
"cliProvider",
|
|
99
|
+
"apiSource",
|
|
100
|
+
"hasVision",
|
|
101
|
+
"cover",
|
|
102
|
+
"avatarFileId",
|
|
103
|
+
"inputPrice",
|
|
104
|
+
"outputPrice",
|
|
105
|
+
"imageModel",
|
|
106
|
+
"imageConfig",
|
|
107
|
+
"imageWorkflow",
|
|
108
|
+
"pricing",
|
|
109
|
+
"metrics",
|
|
110
|
+
"runtimeBinding",
|
|
111
|
+
"spaceId",
|
|
112
|
+
"isPublic",
|
|
113
|
+
"createdAt",
|
|
114
|
+
"updatedAt",
|
|
115
|
+
"created",
|
|
116
|
+
"updated_at",
|
|
117
|
+
"deletedAt",
|
|
118
|
+
]);
|
|
119
|
+
|
|
120
|
+
const toPublicAgentSummary = (agent: Agent): Agent => {
|
|
121
|
+
const summary: Record<string, unknown> = {};
|
|
122
|
+
for (const [key, value] of Object.entries(agent as Record<string, unknown>)) {
|
|
123
|
+
if (SUMMARY_FIELDS.has(key)) {
|
|
124
|
+
summary[key] = value;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return summary as Agent;
|
|
128
|
+
};
|
|
129
|
+
|
|
83
130
|
export async function fetchPublicAgents(
|
|
84
131
|
options: FetchPublicAgentsOptions = {}
|
|
85
132
|
): Promise<FetchPublicAgentsResult> {
|
|
@@ -90,6 +137,7 @@ export async function fetchPublicAgents(
|
|
|
90
137
|
userId,
|
|
91
138
|
imageOutputOnly = false,
|
|
92
139
|
toolName,
|
|
140
|
+
summary = false,
|
|
93
141
|
} = options;
|
|
94
142
|
|
|
95
143
|
const limit = Math.min(Math.max(rawLimit, 1), MAX_LIMIT);
|
|
@@ -123,6 +171,8 @@ export async function fetchPublicAgents(
|
|
|
123
171
|
// 使用统一的排序逻辑
|
|
124
172
|
const sorted = sortAgents(list, sortBy);
|
|
125
173
|
|
|
126
|
-
const data = sorted.slice(0, limit)
|
|
174
|
+
const data = sorted.slice(0, limit).map((agent) =>
|
|
175
|
+
summary ? toPublicAgentSummary(agent) : agent
|
|
176
|
+
);
|
|
127
177
|
return { data, total: list.length, hasMore: list.length > limit };
|
|
128
178
|
}
|