@next-open-ai/openbot 0.3.2 → 0.6.8
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 +46 -7
- package/apps/desktop/renderer/dist/assets/index-LCp1YPVA.css +10 -0
- package/apps/desktop/renderer/dist/assets/index-l5fpDsHs.js +89 -0
- package/apps/desktop/renderer/dist/index.html +2 -2
- package/dist/core/agent/agent-manager.d.ts +15 -7
- package/dist/core/agent/agent-manager.js +52 -21
- package/dist/core/agent/run.js +2 -2
- package/dist/core/config/desktop-config.d.ts +24 -0
- package/dist/core/config/desktop-config.js +19 -1
- package/dist/core/session-current-agent.d.ts +34 -0
- package/dist/core/session-current-agent.js +32 -0
- package/dist/core/tools/create-agent-tool.d.ts +6 -0
- package/dist/core/tools/create-agent-tool.js +97 -0
- package/dist/core/tools/index.d.ts +3 -0
- package/dist/core/tools/index.js +3 -0
- package/dist/core/tools/list-agents-tool.d.ts +5 -0
- package/dist/core/tools/list-agents-tool.js +45 -0
- package/dist/core/tools/switch-agent-tool.d.ts +6 -0
- package/dist/core/tools/switch-agent-tool.js +54 -0
- package/dist/gateway/channel/adapters/dingtalk.d.ts +11 -0
- package/dist/gateway/channel/adapters/dingtalk.js +190 -0
- package/dist/gateway/channel/adapters/feishu.d.ts +11 -0
- package/dist/gateway/channel/adapters/feishu.js +218 -0
- package/dist/gateway/channel/adapters/telegram.d.ts +14 -0
- package/dist/gateway/channel/adapters/telegram.js +197 -0
- package/dist/gateway/channel/channel-core.d.ts +9 -0
- package/dist/gateway/channel/channel-core.js +135 -0
- package/dist/gateway/channel/registry.d.ts +16 -0
- package/dist/gateway/channel/registry.js +54 -0
- package/dist/gateway/channel/run-agent.d.ts +26 -0
- package/dist/gateway/channel/run-agent.js +137 -0
- package/dist/gateway/channel/session-persistence.d.ts +36 -0
- package/dist/gateway/channel/session-persistence.js +46 -0
- package/dist/gateway/channel/types.d.ts +74 -0
- package/dist/gateway/channel/types.js +4 -0
- package/dist/gateway/channel-handler.d.ts +3 -4
- package/dist/gateway/channel-handler.js +8 -2
- package/dist/gateway/methods/agent-chat.js +30 -12
- package/dist/gateway/methods/run-scheduled-task.js +4 -2
- package/dist/gateway/server.js +84 -1
- package/dist/server/agent-config/agent-config.controller.d.ts +6 -1
- package/dist/server/agent-config/agent-config.service.d.ts +12 -1
- package/dist/server/agent-config/agent-config.service.js +10 -3
- package/dist/server/agents/agents.controller.d.ts +10 -0
- package/dist/server/agents/agents.controller.js +35 -1
- package/dist/server/agents/agents.gateway.js +18 -4
- package/dist/server/agents/agents.service.d.ts +4 -0
- package/dist/server/agents/agents.service.js +17 -1
- package/dist/server/config/config.controller.d.ts +2 -0
- package/dist/server/config/config.service.d.ts +3 -0
- package/dist/server/config/config.service.js +3 -1
- package/dist/server/saved-items/saved-items.controller.d.ts +32 -1
- package/dist/server/saved-items/saved-items.controller.js +154 -3
- package/dist/server/saved-items/saved-items.module.js +3 -1
- package/dist/server/workspace/workspace.service.d.ts +11 -0
- package/dist/server/workspace/workspace.service.js +40 -1
- package/package.json +3 -1
- package/apps/desktop/renderer/dist/assets/index-DKtaRFW4.js +0 -89
- package/apps/desktop/renderer/dist/assets/index-QHuqXpWQ.css +0 -10
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
<link
|
|
12
12
|
href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Roboto+Mono:wght@400;500&display=swap"
|
|
13
13
|
rel="stylesheet">
|
|
14
|
-
<script type="module" crossorigin src="/assets/index-
|
|
15
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
14
|
+
<script type="module" crossorigin src="/assets/index-l5fpDsHs.js"></script>
|
|
15
|
+
<link rel="stylesheet" crossorigin href="/assets/index-LCp1YPVA.css">
|
|
16
16
|
</head>
|
|
17
17
|
|
|
18
18
|
<body>
|
|
@@ -42,23 +42,31 @@ export declare class AgentManager {
|
|
|
42
42
|
private resolveSkillPaths;
|
|
43
43
|
/**
|
|
44
44
|
* Get or create an agent session.
|
|
45
|
-
*
|
|
46
|
-
* @param
|
|
47
|
-
* @param options.
|
|
48
|
-
* @param options.
|
|
45
|
+
* 缓存 key 为 sessionId + "::" + agentId,同一业务 session 下可切换 agent 且各自保留上下文。
|
|
46
|
+
* @param sessionId 业务会话 ID(桌面 UUID 或 channel:feishu:threadId 等)
|
|
47
|
+
* @param options.agentId 当前使用的 agent,与 sessionId 组成复合 key,必传或默认 "default"
|
|
48
|
+
* @param options.workspace 该会话绑定的工作区名(来自 agent 配置)
|
|
49
|
+
* @param options.maxSessions 若提供且当前 session 数 >= 该值,按 LRU 淘汰
|
|
50
|
+
* @param options.targetAgentId 创建时绑定到 install_skill 工具
|
|
49
51
|
*/
|
|
50
52
|
getOrCreateSession(sessionId: string, options?: {
|
|
53
|
+
agentId?: string;
|
|
51
54
|
workspace?: string;
|
|
52
55
|
provider?: string;
|
|
53
56
|
modelId?: string;
|
|
54
57
|
apiKey?: string;
|
|
55
58
|
maxSessions?: number;
|
|
56
59
|
targetAgentId?: string;
|
|
57
|
-
/** MCP 服务器配置列表(与 Skill 类似,配到 Agent 后在创建 Session 时传入) */
|
|
58
60
|
mcpServers?: McpServerConfig[];
|
|
61
|
+
/** 自定义系统提示词(来自 agent 配置),会与技能等一起组成最终 systemPrompt */
|
|
62
|
+
systemPrompt?: string;
|
|
59
63
|
}): Promise<AgentSession>;
|
|
60
|
-
|
|
61
|
-
|
|
64
|
+
/** 按复合 key 获取(key = sessionId + "::" + agentId) */
|
|
65
|
+
getSession(compositeKey: string): AgentSession | undefined;
|
|
66
|
+
/** 删除一个 Agent Session(传入复合 key) */
|
|
67
|
+
deleteSession(compositeKey: string): boolean;
|
|
68
|
+
/** 按业务 sessionId 删除该会话下所有 agent 的 Core Session(如删除会话时) */
|
|
69
|
+
deleteSessionsByBusinessId(sessionId: string): void;
|
|
62
70
|
clearAll(): void;
|
|
63
71
|
}
|
|
64
72
|
export declare const agentManager: AgentManager;
|
|
@@ -3,7 +3,12 @@ import { join } from "node:path";
|
|
|
3
3
|
import { existsSync, mkdirSync } from "node:fs";
|
|
4
4
|
import { createCompactionMemoryExtensionFactory } from "../memory/compaction-extension.js";
|
|
5
5
|
import { getCompactionContextForSystemPrompt } from "../memory/index.js";
|
|
6
|
-
import { createBrowserTool, createSaveExperienceTool, createInstallSkillTool, createGetBookmarkTagsTool, createSaveBookmarkTool } from "../tools/index.js";
|
|
6
|
+
import { createBrowserTool, createSaveExperienceTool, createInstallSkillTool, createSwitchAgentTool, createListAgentsTool, createCreateAgentTool, createGetBookmarkTagsTool, createSaveBookmarkTool } from "../tools/index.js";
|
|
7
|
+
/** Agent Session 缓存 key:sessionId + "::" + agentId,同一业务 session 下不同 agent 各自一个 Core Session */
|
|
8
|
+
const COMPOSITE_KEY_SEP = "::";
|
|
9
|
+
function toCompositeKey(sessionId, agentId) {
|
|
10
|
+
return sessionId + COMPOSITE_KEY_SEP + agentId;
|
|
11
|
+
}
|
|
7
12
|
import { createMcpToolsForSession } from "../mcp/index.js";
|
|
8
13
|
import { registerBuiltInApiProviders } from "@mariozechner/pi-ai/dist/providers/register-builtins.js";
|
|
9
14
|
import { getOpenbotAgentDir, getOpenbotWorkspaceDir, ensureDefaultAgentDir } from "./agent-dir.js";
|
|
@@ -101,7 +106,7 @@ For downloads, provide either a direct URL or a selector to click.`;
|
|
|
101
106
|
const systemPrompt = this.buildSystemPrompt(loadedSkills);
|
|
102
107
|
return { systemPrompt, skills: loadedSkills };
|
|
103
108
|
}
|
|
104
|
-
createResourceLoader(workspaceDir, sessionId, compactionBlock) {
|
|
109
|
+
createResourceLoader(workspaceDir, sessionId, compactionBlock, customAgentPrompt, identity) {
|
|
105
110
|
const loader = new DefaultResourceLoader({
|
|
106
111
|
cwd: workspaceDir,
|
|
107
112
|
agentDir: this.agentDir,
|
|
@@ -110,11 +115,18 @@ For downloads, provide either a direct URL or a selector to click.`;
|
|
|
110
115
|
extensionFactories: sessionId ? [createCompactionMemoryExtensionFactory(sessionId)] : [],
|
|
111
116
|
systemPromptOverride: (base) => {
|
|
112
117
|
const loadedSkills = loader.getSkills().skills;
|
|
113
|
-
let
|
|
118
|
+
let basePrompt = this.buildSystemPrompt(loadedSkills);
|
|
119
|
+
const withCustom = customAgentPrompt && customAgentPrompt.trim()
|
|
120
|
+
? customAgentPrompt.trim() + "\n\n" + basePrompt
|
|
121
|
+
: basePrompt;
|
|
122
|
+
const withIdentity = identity && identity.agentId
|
|
123
|
+
? `[Session identity] You are the agent with ID: ${identity.agentId}, workspace: ${identity.workspace || identity.agentId}. When asked which agent you are, answer according to this identity.\n\n` +
|
|
124
|
+
withCustom
|
|
125
|
+
: withCustom;
|
|
114
126
|
if (compactionBlock?.trim()) {
|
|
115
|
-
|
|
127
|
+
return withIdentity + "\n\n" + compactionBlock.trim();
|
|
116
128
|
}
|
|
117
|
-
return
|
|
129
|
+
return withIdentity;
|
|
118
130
|
},
|
|
119
131
|
});
|
|
120
132
|
return loader;
|
|
@@ -144,16 +156,20 @@ For downloads, provide either a direct URL or a selector to click.`;
|
|
|
144
156
|
}
|
|
145
157
|
/**
|
|
146
158
|
* Get or create an agent session.
|
|
147
|
-
*
|
|
148
|
-
* @param
|
|
149
|
-
* @param options.
|
|
150
|
-
* @param options.
|
|
159
|
+
* 缓存 key 为 sessionId + "::" + agentId,同一业务 session 下可切换 agent 且各自保留上下文。
|
|
160
|
+
* @param sessionId 业务会话 ID(桌面 UUID 或 channel:feishu:threadId 等)
|
|
161
|
+
* @param options.agentId 当前使用的 agent,与 sessionId 组成复合 key,必传或默认 "default"
|
|
162
|
+
* @param options.workspace 该会话绑定的工作区名(来自 agent 配置)
|
|
163
|
+
* @param options.maxSessions 若提供且当前 session 数 >= 该值,按 LRU 淘汰
|
|
164
|
+
* @param options.targetAgentId 创建时绑定到 install_skill 工具
|
|
151
165
|
*/
|
|
152
166
|
async getOrCreateSession(sessionId, options = {}) {
|
|
167
|
+
const agentId = options.agentId ?? "default";
|
|
168
|
+
const compositeKey = toCompositeKey(sessionId, agentId);
|
|
153
169
|
const now = Date.now();
|
|
154
|
-
if (this.sessions.has(
|
|
155
|
-
this.sessionLastActiveAt.set(
|
|
156
|
-
return this.sessions.get(
|
|
170
|
+
if (this.sessions.has(compositeKey)) {
|
|
171
|
+
this.sessionLastActiveAt.set(compositeKey, now);
|
|
172
|
+
return this.sessions.get(compositeKey);
|
|
157
173
|
}
|
|
158
174
|
const { maxSessions } = options;
|
|
159
175
|
if (typeof maxSessions === "number" && maxSessions > 0 && this.sessions.size >= maxSessions) {
|
|
@@ -223,7 +239,7 @@ For downloads, provide either a direct URL or a selector to click.`;
|
|
|
223
239
|
return process.env.OPENAI_API_KEY;
|
|
224
240
|
});
|
|
225
241
|
const compactionBlock = await getCompactionContextForSystemPrompt(sessionId);
|
|
226
|
-
const loader = this.createResourceLoader(sessionWorkspaceDir, sessionId, compactionBlock);
|
|
242
|
+
const loader = this.createResourceLoader(sessionWorkspaceDir, sessionId, compactionBlock, options.systemPrompt, { agentId, workspace: workspaceName });
|
|
227
243
|
await loader.reload();
|
|
228
244
|
const coreTools = {
|
|
229
245
|
read: createReadTool(sessionWorkspaceDir),
|
|
@@ -238,7 +254,10 @@ For downloads, provide either a direct URL or a selector to click.`;
|
|
|
238
254
|
const customTools = [
|
|
239
255
|
createBrowserTool(sessionWorkspaceDir),
|
|
240
256
|
createSaveExperienceTool(sessionId),
|
|
241
|
-
createInstallSkillTool(options.targetAgentId),
|
|
257
|
+
createInstallSkillTool(options.targetAgentId ?? agentId),
|
|
258
|
+
createSwitchAgentTool(sessionId),
|
|
259
|
+
createListAgentsTool(),
|
|
260
|
+
createCreateAgentTool(),
|
|
242
261
|
createGetBookmarkTagsTool(),
|
|
243
262
|
createSaveBookmarkTool(),
|
|
244
263
|
...mcpTools,
|
|
@@ -258,16 +277,28 @@ For downloads, provide either a direct URL or a selector to click.`;
|
|
|
258
277
|
console.log(`Setting model to ${model.provider}/${model.id} (workspace: ${workspaceName})`);
|
|
259
278
|
await session.setModel(model);
|
|
260
279
|
}
|
|
261
|
-
this.sessions.set(
|
|
262
|
-
this.sessionLastActiveAt.set(
|
|
280
|
+
this.sessions.set(compositeKey, session);
|
|
281
|
+
this.sessionLastActiveAt.set(compositeKey, now);
|
|
263
282
|
return session;
|
|
264
283
|
}
|
|
265
|
-
|
|
266
|
-
|
|
284
|
+
/** 按复合 key 获取(key = sessionId + "::" + agentId) */
|
|
285
|
+
getSession(compositeKey) {
|
|
286
|
+
return this.sessions.get(compositeKey);
|
|
287
|
+
}
|
|
288
|
+
/** 删除一个 Agent Session(传入复合 key) */
|
|
289
|
+
deleteSession(compositeKey) {
|
|
290
|
+
this.sessionLastActiveAt.delete(compositeKey);
|
|
291
|
+
return this.sessions.delete(compositeKey);
|
|
267
292
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
293
|
+
/** 按业务 sessionId 删除该会话下所有 agent 的 Core Session(如删除会话时) */
|
|
294
|
+
deleteSessionsByBusinessId(sessionId) {
|
|
295
|
+
const prefix = sessionId + COMPOSITE_KEY_SEP;
|
|
296
|
+
for (const key of Array.from(this.sessions.keys())) {
|
|
297
|
+
if (key.startsWith(prefix)) {
|
|
298
|
+
this.sessionLastActiveAt.delete(key);
|
|
299
|
+
this.sessions.delete(key);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
271
302
|
}
|
|
272
303
|
clearAll() {
|
|
273
304
|
this.sessions.clear();
|
package/dist/core/agent/run.js
CHANGED
|
@@ -17,6 +17,7 @@ export async function run(options) {
|
|
|
17
17
|
// Create a temporary session for this run
|
|
18
18
|
const sessionId = `cli-${Date.now()}`;
|
|
19
19
|
const session = await manager.getOrCreateSession(sessionId, {
|
|
20
|
+
agentId: "default",
|
|
20
21
|
provider,
|
|
21
22
|
modelId,
|
|
22
23
|
apiKey,
|
|
@@ -58,8 +59,7 @@ export async function run(options) {
|
|
|
58
59
|
});
|
|
59
60
|
// Send prompt and wait for completion
|
|
60
61
|
await session.prompt(userPrompt);
|
|
61
|
-
|
|
62
|
-
manager.deleteSession(sessionId);
|
|
62
|
+
manager.deleteSession(sessionId + "::" + "default");
|
|
63
63
|
result.assistantContent = assistantContent.trim();
|
|
64
64
|
return result;
|
|
65
65
|
}
|
|
@@ -7,6 +7,26 @@ export interface RagEmbeddingConfig {
|
|
|
7
7
|
apiKey?: string;
|
|
8
8
|
baseUrl?: string;
|
|
9
9
|
}
|
|
10
|
+
/** 通道配置:各 IM 通道的 token、key 等,与设置页「通道配置」一致 */
|
|
11
|
+
export interface ChannelsConfig {
|
|
12
|
+
feishu?: {
|
|
13
|
+
enabled?: boolean;
|
|
14
|
+
appId?: string;
|
|
15
|
+
appSecret?: string;
|
|
16
|
+
defaultAgentId?: string;
|
|
17
|
+
};
|
|
18
|
+
dingtalk?: {
|
|
19
|
+
enabled?: boolean;
|
|
20
|
+
clientId?: string;
|
|
21
|
+
clientSecret?: string;
|
|
22
|
+
defaultAgentId?: string;
|
|
23
|
+
};
|
|
24
|
+
telegram?: {
|
|
25
|
+
enabled?: boolean;
|
|
26
|
+
botToken?: string;
|
|
27
|
+
defaultAgentId?: string;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
10
30
|
/** MCP 服务器配置(与 core/mcp 类型一致,避免 core/config 依赖 core/mcp 实现) */
|
|
11
31
|
export type DesktopMcpServerConfig = import("../mcp/index.js").McpServerConfig;
|
|
12
32
|
/**
|
|
@@ -16,6 +36,8 @@ export type DesktopMcpServerConfig = import("../mcp/index.js").McpServerConfig;
|
|
|
16
36
|
export declare function getDesktopConfig(): {
|
|
17
37
|
maxAgentSessions: number;
|
|
18
38
|
};
|
|
39
|
+
/** 同步读取通道配置(Gateway 启动时用) */
|
|
40
|
+
export declare function getChannelsConfigSync(): ChannelsConfig;
|
|
19
41
|
/** 同步读取 RAG embedding 配置;未配置或无效时返回 null,长记忆将空转 */
|
|
20
42
|
export declare function getRagEmbeddingConfigSync(): RagEmbeddingConfig | null;
|
|
21
43
|
export interface DesktopAgentConfig {
|
|
@@ -26,6 +48,8 @@ export interface DesktopAgentConfig {
|
|
|
26
48
|
workspace?: string;
|
|
27
49
|
/** MCP 服务器配置,创建 Session 时传入 */
|
|
28
50
|
mcpServers?: DesktopMcpServerConfig[];
|
|
51
|
+
/** 自定义系统提示词,会与技能等一起组成最终 systemPrompt */
|
|
52
|
+
systemPrompt?: string;
|
|
29
53
|
}
|
|
30
54
|
/**
|
|
31
55
|
* 从 config.json 读取缺省智能体 id(defaultAgentId)。
|
|
@@ -43,6 +43,20 @@ export function getDesktopConfig() {
|
|
|
43
43
|
return { maxAgentSessions: DEFAULT_MAX_AGENT_SESSIONS };
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
|
+
/** 同步读取通道配置(Gateway 启动时用) */
|
|
47
|
+
export function getChannelsConfigSync() {
|
|
48
|
+
try {
|
|
49
|
+
const configPath = getConfigPath();
|
|
50
|
+
if (!existsSync(configPath))
|
|
51
|
+
return {};
|
|
52
|
+
const content = readFileSync(configPath, "utf-8");
|
|
53
|
+
const data = JSON.parse(content);
|
|
54
|
+
return data.channels ?? {};
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return {};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
46
60
|
/** 同步读取 RAG embedding 配置;未配置或无效时返回 null,长记忆将空转 */
|
|
47
61
|
export function getRagEmbeddingConfigSync() {
|
|
48
62
|
try {
|
|
@@ -146,6 +160,7 @@ export async function loadDesktopAgentConfig(agentId) {
|
|
|
146
160
|
}
|
|
147
161
|
let workspaceName = resolvedAgentId;
|
|
148
162
|
let mcpServers;
|
|
163
|
+
let systemPrompt;
|
|
149
164
|
if (existsSync(agentsPath)) {
|
|
150
165
|
try {
|
|
151
166
|
const raw = await readFile(agentsPath, "utf-8");
|
|
@@ -160,6 +175,9 @@ export async function loadDesktopAgentConfig(agentId) {
|
|
|
160
175
|
if (agent.mcpServers && Array.isArray(agent.mcpServers)) {
|
|
161
176
|
mcpServers = agent.mcpServers;
|
|
162
177
|
}
|
|
178
|
+
if (agent.systemPrompt && typeof agent.systemPrompt === "string") {
|
|
179
|
+
systemPrompt = agent.systemPrompt.trim();
|
|
180
|
+
}
|
|
163
181
|
if (agent.modelItemCode && Array.isArray(config.configuredModels)) {
|
|
164
182
|
const configured = config.configuredModels.find((m) => m.modelItemCode === agent.modelItemCode);
|
|
165
183
|
if (configured) {
|
|
@@ -189,7 +207,7 @@ export async function loadDesktopAgentConfig(agentId) {
|
|
|
189
207
|
const apiKey = provConfig?.apiKey && typeof provConfig.apiKey === "string" && provConfig.apiKey.trim()
|
|
190
208
|
? provConfig.apiKey.trim()
|
|
191
209
|
: undefined;
|
|
192
|
-
return { provider, model, apiKey: apiKey ?? undefined, workspace: workspaceName, mcpServers };
|
|
210
|
+
return { provider, model, apiKey: apiKey ?? undefined, workspace: workspaceName, mcpServers, systemPrompt };
|
|
193
211
|
}
|
|
194
212
|
function ensureDesktopDir() {
|
|
195
213
|
const desktopDir = getDesktopDir();
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 当前 session 使用的 agent 解析与更新、以及节点上 agent 列表提供。
|
|
3
|
+
* 由 Gateway 启动时注入,供 agent-chat、channel-core、以及 Core 层 switch_agent / list_agents 工具使用。
|
|
4
|
+
*/
|
|
5
|
+
export type SessionCurrentAgentResolver = (sessionId: string) => string | undefined;
|
|
6
|
+
export type SessionCurrentAgentUpdater = (sessionId: string, agentId: string) => void;
|
|
7
|
+
export type AgentListProvider = () => Promise<{
|
|
8
|
+
id: string;
|
|
9
|
+
name?: string;
|
|
10
|
+
}[]>;
|
|
11
|
+
/** 创建智能体参数:由 create_agent 工具传入,缺省由工具层补齐 */
|
|
12
|
+
export type CreateAgentParams = {
|
|
13
|
+
name: string;
|
|
14
|
+
workspace: string;
|
|
15
|
+
systemPrompt?: string;
|
|
16
|
+
provider?: string;
|
|
17
|
+
model?: string;
|
|
18
|
+
modelItemCode?: string;
|
|
19
|
+
};
|
|
20
|
+
export type CreateAgentResult = {
|
|
21
|
+
id: string;
|
|
22
|
+
name: string;
|
|
23
|
+
} | {
|
|
24
|
+
error: string;
|
|
25
|
+
};
|
|
26
|
+
export type CreateAgentProvider = (params: CreateAgentParams) => Promise<CreateAgentResult>;
|
|
27
|
+
export declare function setSessionCurrentAgentResolver(fn: SessionCurrentAgentResolver | null): void;
|
|
28
|
+
export declare function getSessionCurrentAgentResolver(): SessionCurrentAgentResolver | null;
|
|
29
|
+
export declare function setSessionCurrentAgentUpdater(fn: SessionCurrentAgentUpdater | null): void;
|
|
30
|
+
export declare function getSessionCurrentAgentUpdater(): SessionCurrentAgentUpdater | null;
|
|
31
|
+
export declare function setAgentListProvider(fn: AgentListProvider | null): void;
|
|
32
|
+
export declare function getAgentListProvider(): AgentListProvider | null;
|
|
33
|
+
export declare function setCreateAgentProvider(fn: CreateAgentProvider | null): void;
|
|
34
|
+
export declare function getCreateAgentProvider(): CreateAgentProvider | null;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 当前 session 使用的 agent 解析与更新、以及节点上 agent 列表提供。
|
|
3
|
+
* 由 Gateway 启动时注入,供 agent-chat、channel-core、以及 Core 层 switch_agent / list_agents 工具使用。
|
|
4
|
+
*/
|
|
5
|
+
let resolver = null;
|
|
6
|
+
let updater = null;
|
|
7
|
+
let agentListProvider = null;
|
|
8
|
+
let createAgentProvider = null;
|
|
9
|
+
export function setSessionCurrentAgentResolver(fn) {
|
|
10
|
+
resolver = fn;
|
|
11
|
+
}
|
|
12
|
+
export function getSessionCurrentAgentResolver() {
|
|
13
|
+
return resolver;
|
|
14
|
+
}
|
|
15
|
+
export function setSessionCurrentAgentUpdater(fn) {
|
|
16
|
+
updater = fn;
|
|
17
|
+
}
|
|
18
|
+
export function getSessionCurrentAgentUpdater() {
|
|
19
|
+
return updater;
|
|
20
|
+
}
|
|
21
|
+
export function setAgentListProvider(fn) {
|
|
22
|
+
agentListProvider = fn;
|
|
23
|
+
}
|
|
24
|
+
export function getAgentListProvider() {
|
|
25
|
+
return agentListProvider;
|
|
26
|
+
}
|
|
27
|
+
export function setCreateAgentProvider(fn) {
|
|
28
|
+
createAgentProvider = fn;
|
|
29
|
+
}
|
|
30
|
+
export function getCreateAgentProvider() {
|
|
31
|
+
return createAgentProvider;
|
|
32
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ToolDefinition } from "@mariozechner/pi-coding-agent";
|
|
2
|
+
/**
|
|
3
|
+
* 创建 create_agent 工具:根据用户意图创建新智能体配置,供用户在对话中选择使用。
|
|
4
|
+
* 缺省:未提供 workspace 时根据 name 生成英文标识;未提供 system_prompt 时根据 language 生成简短描述;模型使用全局缺省。
|
|
5
|
+
*/
|
|
6
|
+
export declare function createCreateAgentTool(): ToolDefinition;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { getCreateAgentProvider } from "../session-current-agent.js";
|
|
3
|
+
const CreateAgentSchema = Type.Object({
|
|
4
|
+
name: Type.String({
|
|
5
|
+
description: "智能体显示名称,如用户说的「美妆助手」「代码审查助手」",
|
|
6
|
+
}),
|
|
7
|
+
workspace: Type.Optional(Type.String({
|
|
8
|
+
description: "工作空间英文标识,仅允许字母、数字、下划线、连字符。不传则根据 name 自动生成(如 My Assistant → my-assistant)",
|
|
9
|
+
})),
|
|
10
|
+
system_prompt: Type.Optional(Type.String({
|
|
11
|
+
description: "系统提示词/角色描述。不传则根据 language 生成一句最简短的角色描述。",
|
|
12
|
+
})),
|
|
13
|
+
language: Type.Optional(Type.Union([Type.Literal("zh"), Type.Literal("en")], {
|
|
14
|
+
description: "用户语言,用于生成缺省 system_prompt。不传默认 en。",
|
|
15
|
+
})),
|
|
16
|
+
});
|
|
17
|
+
const WORKSPACE_NAME_REGEX = /^[a-zA-Z0-9_-]+$/;
|
|
18
|
+
const RESERVED_WORKSPACE = "default";
|
|
19
|
+
function slugifyFromName(name) {
|
|
20
|
+
const trimmed = (name || "").trim();
|
|
21
|
+
if (!trimmed)
|
|
22
|
+
return "agent-" + Date.now().toString(36);
|
|
23
|
+
const asciiOnly = trimmed
|
|
24
|
+
.replace(/\s+/g, "-")
|
|
25
|
+
.replace(/[^a-zA-Z0-9_-]/g, "")
|
|
26
|
+
.replace(/-+/g, "-")
|
|
27
|
+
.replace(/^-|-$/g, "")
|
|
28
|
+
.toLowerCase();
|
|
29
|
+
if (asciiOnly && WORKSPACE_NAME_REGEX.test(asciiOnly) && asciiOnly !== RESERVED_WORKSPACE)
|
|
30
|
+
return asciiOnly;
|
|
31
|
+
return "agent-" + Date.now().toString(36);
|
|
32
|
+
}
|
|
33
|
+
function getDefaultSystemPrompt(lang) {
|
|
34
|
+
if (lang === "zh")
|
|
35
|
+
return "你是根据用户需求定制的助手,请按用户描述的角色与能力提供帮助。";
|
|
36
|
+
return "You are a helpful assistant customized as requested by the user.";
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 创建 create_agent 工具:根据用户意图创建新智能体配置,供用户在对话中选择使用。
|
|
40
|
+
* 缺省:未提供 workspace 时根据 name 生成英文标识;未提供 system_prompt 时根据 language 生成简短描述;模型使用全局缺省。
|
|
41
|
+
*/
|
|
42
|
+
export function createCreateAgentTool() {
|
|
43
|
+
return {
|
|
44
|
+
name: "create_agent",
|
|
45
|
+
label: "Create Agent",
|
|
46
|
+
description: "根据用户意图创建一个新的智能体配置。用户可在对话中通过 list_agents 与 switch_agent 选择使用。需提供智能体名称;工作空间名与系统提示词可选,未提供时自动生成。",
|
|
47
|
+
parameters: CreateAgentSchema,
|
|
48
|
+
execute: async (_toolCallId, params, _signal, _onUpdate, _ctx) => {
|
|
49
|
+
const provider = getCreateAgentProvider();
|
|
50
|
+
if (!provider) {
|
|
51
|
+
return {
|
|
52
|
+
content: [{ type: "text", text: "当前环境不支持创建智能体。" }],
|
|
53
|
+
details: undefined,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
const name = (params.name ?? "").trim();
|
|
57
|
+
if (!name) {
|
|
58
|
+
return {
|
|
59
|
+
content: [{ type: "text", text: "请提供智能体名称(name)。" }],
|
|
60
|
+
details: undefined,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
let workspace = (params.workspace ?? "").trim() && WORKSPACE_NAME_REGEX.test((params.workspace ?? "").trim())
|
|
64
|
+
? (params.workspace ?? "").trim()
|
|
65
|
+
: slugifyFromName(name);
|
|
66
|
+
if (workspace === RESERVED_WORKSPACE)
|
|
67
|
+
workspace = "agent-" + Date.now().toString(36);
|
|
68
|
+
const systemPrompt = (params.system_prompt ?? "").trim() ||
|
|
69
|
+
getDefaultSystemPrompt(params.language === "zh" ? "zh" : "en");
|
|
70
|
+
try {
|
|
71
|
+
const result = await provider({
|
|
72
|
+
name,
|
|
73
|
+
workspace,
|
|
74
|
+
systemPrompt,
|
|
75
|
+
});
|
|
76
|
+
if ("error" in result) {
|
|
77
|
+
return {
|
|
78
|
+
content: [{ type: "text", text: `创建失败: ${result.error}` }],
|
|
79
|
+
details: undefined,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const text = `已创建智能体「${result.name}」(ID: ${result.id})。用户可通过 list_agents 查看、并调用 switch_agent 切换到该智能体使用。`;
|
|
83
|
+
return {
|
|
84
|
+
content: [{ type: "text", text }],
|
|
85
|
+
details: result,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
catch (err) {
|
|
89
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
90
|
+
return {
|
|
91
|
+
content: [{ type: "text", text: `创建失败: ${msg}` }],
|
|
92
|
+
details: undefined,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
export { createBrowserTool, closeBrowser } from "./browser-tool.js";
|
|
2
2
|
export { createSaveExperienceTool } from "./save-experience-tool.js";
|
|
3
3
|
export { createInstallSkillTool } from "./install-skill-tool.js";
|
|
4
|
+
export { createSwitchAgentTool } from "./switch-agent-tool.js";
|
|
5
|
+
export { createListAgentsTool } from "./list-agents-tool.js";
|
|
6
|
+
export { createCreateAgentTool } from "./create-agent-tool.js";
|
|
4
7
|
export { createGetBookmarkTagsTool, createSaveBookmarkTool } from "./bookmark-tool.js";
|
package/dist/core/tools/index.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
export { createBrowserTool, closeBrowser } from "./browser-tool.js";
|
|
2
2
|
export { createSaveExperienceTool } from "./save-experience-tool.js";
|
|
3
3
|
export { createInstallSkillTool } from "./install-skill-tool.js";
|
|
4
|
+
export { createSwitchAgentTool } from "./switch-agent-tool.js";
|
|
5
|
+
export { createListAgentsTool } from "./list-agents-tool.js";
|
|
6
|
+
export { createCreateAgentTool } from "./create-agent-tool.js";
|
|
4
7
|
export { createGetBookmarkTagsTool, createSaveBookmarkTool } from "./bookmark-tool.js";
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { getAgentListProvider } from "../session-current-agent.js";
|
|
3
|
+
const ListAgentsSchema = Type.Object({});
|
|
4
|
+
/**
|
|
5
|
+
* 创建 list_agents 工具:返回当前节点上配置的所有智能体列表,供用户在对话中选择切换。
|
|
6
|
+
*/
|
|
7
|
+
export function createListAgentsTool() {
|
|
8
|
+
return {
|
|
9
|
+
name: "list_agents",
|
|
10
|
+
label: "List Agents",
|
|
11
|
+
description: "列出当前可用的所有智能体(id 与名称)。用户可根据列表选择并让助手调用 switch_agent 切换到对应智能体。",
|
|
12
|
+
parameters: ListAgentsSchema,
|
|
13
|
+
execute: async (_toolCallId, _params, _signal, _onUpdate, _ctx) => {
|
|
14
|
+
const provider = getAgentListProvider();
|
|
15
|
+
if (!provider) {
|
|
16
|
+
return {
|
|
17
|
+
content: [{ type: "text", text: "当前无法获取智能体列表。" }],
|
|
18
|
+
details: undefined,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
const list = await provider();
|
|
23
|
+
if (!list?.length) {
|
|
24
|
+
return {
|
|
25
|
+
content: [{ type: "text", text: "暂无配置的智能体。" }],
|
|
26
|
+
details: { agents: [] },
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
const lines = list.map((a) => `- **${a.id}**${a.name ? `:${a.name}` : ""}`);
|
|
30
|
+
const text = "当前可用智能体:\n\n" + lines.join("\n") + "\n\n使用 switch_agent 工具并传入上述 id 可切换。";
|
|
31
|
+
return {
|
|
32
|
+
content: [{ type: "text", text }],
|
|
33
|
+
details: { agents: list },
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
38
|
+
return {
|
|
39
|
+
content: [{ type: "text", text: `获取列表失败: ${msg}` }],
|
|
40
|
+
details: undefined,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ToolDefinition } from "@mariozechner/pi-coding-agent";
|
|
2
|
+
/**
|
|
3
|
+
* 创建 switch_agent 工具:将当前会话的下一次及后续对话切换到指定 agent。
|
|
4
|
+
* 需在 Gateway 启动时通过 setSessionCurrentAgentUpdater 注入更新函数。
|
|
5
|
+
*/
|
|
6
|
+
export declare function createSwitchAgentTool(businessSessionId: string): ToolDefinition;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { getSessionCurrentAgentUpdater } from "../session-current-agent.js";
|
|
3
|
+
const SwitchAgentSchema = Type.Object({
|
|
4
|
+
agent_id: Type.String({
|
|
5
|
+
description: "要切换到的智能体 ID,与设置中智能体列表一致(如 default 或工作空间名)",
|
|
6
|
+
}),
|
|
7
|
+
});
|
|
8
|
+
/**
|
|
9
|
+
* 创建 switch_agent 工具:将当前会话的下一次及后续对话切换到指定 agent。
|
|
10
|
+
* 需在 Gateway 启动时通过 setSessionCurrentAgentUpdater 注入更新函数。
|
|
11
|
+
*/
|
|
12
|
+
export function createSwitchAgentTool(businessSessionId) {
|
|
13
|
+
return {
|
|
14
|
+
name: "switch_agent",
|
|
15
|
+
label: "Switch Agent",
|
|
16
|
+
description: "将当前对话切换为使用指定智能体。切换后,用户下一次及后续消息将由该智能体处理。可用于在对话中更换助手(如从主智能体切换到专项智能体)。",
|
|
17
|
+
parameters: SwitchAgentSchema,
|
|
18
|
+
execute: async (_toolCallId, params, _signal, _onUpdate, _ctx) => {
|
|
19
|
+
const agentId = (params.agent_id ?? "").trim();
|
|
20
|
+
if (!agentId) {
|
|
21
|
+
return {
|
|
22
|
+
content: [{ type: "text", text: "请提供要切换到的智能体 ID(如 default 或工作空间名)。" }],
|
|
23
|
+
details: undefined,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
const updateFn = getSessionCurrentAgentUpdater();
|
|
27
|
+
if (!updateFn) {
|
|
28
|
+
return {
|
|
29
|
+
content: [{ type: "text", text: "当前环境不支持切换智能体。" }],
|
|
30
|
+
details: undefined,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
updateFn(businessSessionId, agentId);
|
|
35
|
+
return {
|
|
36
|
+
content: [
|
|
37
|
+
{
|
|
38
|
+
type: "text",
|
|
39
|
+
text: `已切换到智能体「${agentId}」。后续回复将由该智能体处理。`,
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
details: { agentId },
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
47
|
+
return {
|
|
48
|
+
content: [{ type: "text", text: `切换失败: ${msg}` }],
|
|
49
|
+
details: undefined,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { IChannel } from "../types.js";
|
|
2
|
+
export interface DingTalkChannelConfig {
|
|
3
|
+
clientId: string;
|
|
4
|
+
clientSecret: string;
|
|
5
|
+
/** 默认绑定的 agentId */
|
|
6
|
+
defaultAgentId?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* 钉钉通道:Stream 入站 + Webhook 出站,共用一个 DWClient。
|
|
10
|
+
*/
|
|
11
|
+
export declare function createDingTalkChannel(config: DingTalkChannelConfig): IChannel;
|