@zhin.js/agent 0.1.0 → 0.1.3
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/lib/cron-engine.d.ts +20 -2
- package/lib/cron-engine.d.ts.map +1 -1
- package/lib/cron-engine.js +59 -18
- package/lib/cron-engine.js.map +1 -1
- package/lib/discover-skills.d.ts +3 -1
- package/lib/discover-skills.d.ts.map +1 -1
- package/lib/discover-skills.js +7 -9
- package/lib/discover-skills.js.map +1 -1
- package/lib/discover-tools.d.ts +1 -6
- package/lib/discover-tools.d.ts.map +1 -1
- package/lib/discover-tools.js +2 -6
- package/lib/discover-tools.js.map +1 -1
- package/lib/index.d.ts +2 -4
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -2
- package/lib/index.js.map +1 -1
- package/lib/init/create-zhin-agent.d.ts.map +1 -1
- package/lib/init/create-zhin-agent.js +42 -20
- package/lib/init/create-zhin-agent.js.map +1 -1
- package/lib/init/register-ai-trigger.d.ts.map +1 -1
- package/lib/init/register-ai-trigger.js +10 -3
- package/lib/init/register-ai-trigger.js.map +1 -1
- package/lib/init/register-builtin-tools.d.ts.map +1 -1
- package/lib/init/register-builtin-tools.js +85 -15
- package/lib/init/register-builtin-tools.js.map +1 -1
- package/lib/init/register-db-models.d.ts.map +1 -1
- package/lib/init/register-db-models.js +1 -3
- package/lib/init/register-db-models.js.map +1 -1
- package/lib/init/register-db-upgrade.d.ts.map +1 -1
- package/lib/init/register-db-upgrade.js +1 -8
- package/lib/init/register-db-upgrade.js.map +1 -1
- package/lib/init/register-management-tools.d.ts.map +1 -1
- package/lib/init/register-management-tools.js +33 -20
- package/lib/init/register-management-tools.js.map +1 -1
- package/lib/service.d.ts.map +1 -1
- package/lib/service.js +0 -8
- package/lib/service.js.map +1 -1
- package/lib/zhin-agent/builtin-tools.d.ts +0 -2
- package/lib/zhin-agent/builtin-tools.d.ts.map +1 -1
- package/lib/zhin-agent/builtin-tools.js +0 -55
- package/lib/zhin-agent/builtin-tools.js.map +1 -1
- package/lib/zhin-agent/config.d.ts +2 -1
- package/lib/zhin-agent/config.d.ts.map +1 -1
- package/lib/zhin-agent/config.js +1 -1
- package/lib/zhin-agent/config.js.map +1 -1
- package/lib/zhin-agent/index.d.ts +1 -6
- package/lib/zhin-agent/index.d.ts.map +1 -1
- package/lib/zhin-agent/index.js +26 -34
- package/lib/zhin-agent/index.js.map +1 -1
- package/lib/zhin-agent/prompt.d.ts.map +1 -1
- package/lib/zhin-agent/prompt.js +31 -76
- package/lib/zhin-agent/prompt.js.map +1 -1
- package/lib/zhin-agent/tool-collector.d.ts.map +1 -1
- package/lib/zhin-agent/tool-collector.js +7 -7
- package/lib/zhin-agent/tool-collector.js.map +1 -1
- package/package.json +7 -4
- package/CHANGELOG.md +0 -190
- package/lib/follow-up.d.ts +0 -131
- package/lib/follow-up.d.ts.map +0 -1
- package/lib/follow-up.js +0 -265
- package/lib/follow-up.js.map +0 -1
- package/src/agent.ts +0 -6
- package/src/bootstrap.ts +0 -309
- package/src/builtin-tools.ts +0 -958
- package/src/compaction.ts +0 -28
- package/src/context-manager.ts +0 -15
- package/src/conversation-memory.ts +0 -5
- package/src/cron-engine.ts +0 -338
- package/src/discover-agents.ts +0 -138
- package/src/discover-skills.ts +0 -325
- package/src/discover-tools.ts +0 -302
- package/src/discovery-utils.ts +0 -96
- package/src/file-policy.ts +0 -333
- package/src/follow-up.ts +0 -357
- package/src/hooks.ts +0 -223
- package/src/index.ts +0 -183
- package/src/init/create-zhin-agent.ts +0 -161
- package/src/init/register-ai-service.ts +0 -53
- package/src/init/register-ai-trigger.ts +0 -253
- package/src/init/register-builtin-tools.ts +0 -308
- package/src/init/register-db-models.ts +0 -31
- package/src/init/register-db-upgrade.ts +0 -77
- package/src/init/register-management-tools.ts +0 -71
- package/src/init/register-message-recorder.ts +0 -31
- package/src/init/register-tool-service.ts +0 -9
- package/src/init/shared-refs.ts +0 -20
- package/src/init/types.ts +0 -18
- package/src/init.ts +0 -50
- package/src/output.ts +0 -15
- package/src/rate-limiter.ts +0 -5
- package/src/service.ts +0 -228
- package/src/session.ts +0 -13
- package/src/storage.ts +0 -9
- package/src/subagent.ts +0 -209
- package/src/tone-detector.ts +0 -5
- package/src/tools.ts +0 -214
- package/src/user-profile.ts +0 -182
- package/src/zhin-agent/builtin-tools.ts +0 -247
- package/src/zhin-agent/config.ts +0 -124
- package/src/zhin-agent/exec-policy.ts +0 -285
- package/src/zhin-agent/index.ts +0 -633
- package/src/zhin-agent/prompt.ts +0 -305
- package/src/zhin-agent/tool-collector.ts +0 -249
- package/tests/ai/follow-up.test.ts +0 -175
- package/tests/ai/integration.test.ts +0 -582
- package/tests/ai/multimodal.test.ts +0 -106
- package/tests/ai/setup.ts +0 -186
- package/tests/ai/subagent.test.ts +0 -270
- package/tests/ai/tools-builtin.test.ts +0 -310
- package/tests/ai/user-profile.test.ts +0 -73
- package/tests/ai/zhin-agent.test.ts +0 -306
- package/tests/exec-policy.test.ts +0 -355
- package/tests/file-policy.test.ts +0 -405
- package/tsconfig.json +0 -22
package/src/service.ts
DELETED
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AIService — AI 服务核心类
|
|
3
|
-
* 统一管理多个模型提供商,提供会话和 Agent 能力
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { Logger } from '@zhin.js/core';
|
|
7
|
-
import type { Plugin, Tool, ToolContext, AITriggerConfig } from '@zhin.js/core';
|
|
8
|
-
import type {
|
|
9
|
-
AIProvider,
|
|
10
|
-
AIConfig,
|
|
11
|
-
ChatMessage,
|
|
12
|
-
ChatCompletionRequest,
|
|
13
|
-
ChatCompletionResponse,
|
|
14
|
-
ChatCompletionChunk,
|
|
15
|
-
AgentTool,
|
|
16
|
-
} from '@zhin.js/core';
|
|
17
|
-
import {
|
|
18
|
-
OpenAIProvider,
|
|
19
|
-
DeepSeekProvider,
|
|
20
|
-
MoonshotProvider,
|
|
21
|
-
ZhipuProvider,
|
|
22
|
-
AnthropicProvider,
|
|
23
|
-
OllamaProvider,
|
|
24
|
-
} from '@zhin.js/core';
|
|
25
|
-
import {
|
|
26
|
-
SessionManager,
|
|
27
|
-
createMemorySessionManager,
|
|
28
|
-
} from '@zhin.js/ai';
|
|
29
|
-
import { Agent, createAgent } from '@zhin.js/ai';
|
|
30
|
-
import type { ModelRegistry } from '@zhin.js/ai';
|
|
31
|
-
import { getBuiltinTools } from './tools.js';
|
|
32
|
-
import type { ContextManager, ContextConfig } from '@zhin.js/ai';
|
|
33
|
-
import { PERM_MAP } from './zhin-agent/config.js';
|
|
34
|
-
|
|
35
|
-
const aiLogger = new Logger(null, 'AI');
|
|
36
|
-
|
|
37
|
-
/** Provider 注册表:key → 构造函数 + 是否需要 apiKey */
|
|
38
|
-
const PROVIDER_REGISTRY: Array<{
|
|
39
|
-
key: keyof NonNullable<AIConfig['providers']>;
|
|
40
|
-
factory: new (config: any) => AIProvider;
|
|
41
|
-
requireApiKey: boolean;
|
|
42
|
-
}> = [
|
|
43
|
-
{ key: 'openai', factory: OpenAIProvider, requireApiKey: true },
|
|
44
|
-
{ key: 'anthropic', factory: AnthropicProvider, requireApiKey: true },
|
|
45
|
-
{ key: 'deepseek', factory: DeepSeekProvider, requireApiKey: true },
|
|
46
|
-
{ key: 'moonshot', factory: MoonshotProvider, requireApiKey: true },
|
|
47
|
-
{ key: 'zhipu', factory: ZhipuProvider, requireApiKey: true },
|
|
48
|
-
{ key: 'ollama', factory: OllamaProvider, requireApiKey: false },
|
|
49
|
-
];
|
|
50
|
-
|
|
51
|
-
export class AIService {
|
|
52
|
-
private providers: Map<string, AIProvider> = new Map();
|
|
53
|
-
private defaultProvider: string;
|
|
54
|
-
public sessions: SessionManager;
|
|
55
|
-
public contextManager?: ContextManager;
|
|
56
|
-
private builtinTools: AgentTool[];
|
|
57
|
-
private sessionConfig: { maxHistory?: number; expireMs?: number };
|
|
58
|
-
private contextConfig: ContextConfig;
|
|
59
|
-
private triggerConfig: AITriggerConfig;
|
|
60
|
-
private agentConfig: AIConfig['agent'];
|
|
61
|
-
private plugin?: Plugin;
|
|
62
|
-
private customTools: Map<string, AgentTool> = new Map();
|
|
63
|
-
private _modelRegistry: ModelRegistry | null = null;
|
|
64
|
-
|
|
65
|
-
constructor(config: AIConfig = {}) {
|
|
66
|
-
this.defaultProvider = config.defaultProvider || 'openai';
|
|
67
|
-
this.sessionConfig = config.sessions || {};
|
|
68
|
-
this.contextConfig = config.context || {};
|
|
69
|
-
this.triggerConfig = config.trigger || {};
|
|
70
|
-
this.agentConfig = config.agent;
|
|
71
|
-
this.sessions = createMemorySessionManager(this.sessionConfig);
|
|
72
|
-
this.builtinTools = getBuiltinTools().map(tool => this.convertToolToAgentTool(tool.toTool()));
|
|
73
|
-
|
|
74
|
-
for (const { key, factory, requireApiKey } of PROVIDER_REGISTRY) {
|
|
75
|
-
const providerConfig = config.providers?.[key];
|
|
76
|
-
if (!providerConfig) continue;
|
|
77
|
-
if (requireApiKey && !(providerConfig as any).apiKey) continue;
|
|
78
|
-
this.registerProvider(new factory(providerConfig as any));
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
isReady(): boolean {
|
|
83
|
-
return this.providers.size > 0;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
async process(
|
|
87
|
-
content: string,
|
|
88
|
-
context: ToolContext,
|
|
89
|
-
_tools: Tool[],
|
|
90
|
-
): Promise<string> {
|
|
91
|
-
const { platform, senderId, sceneId } = context;
|
|
92
|
-
const sessionId = SessionManager.generateId(platform || '', senderId || '', sceneId);
|
|
93
|
-
const systemPrompt = 'You are a helpful AI assistant. Reply in the language specified in [User profile] (key: language / preferred_language), or in the user\'s message language if not set.';
|
|
94
|
-
return this.finishAndSave(sessionId, content, systemPrompt, sceneId);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
private async finishAndSave(sessionId: string, content: string, systemPrompt: string, sceneId?: string): Promise<string> {
|
|
98
|
-
const response = await this.simpleChat(content, systemPrompt);
|
|
99
|
-
await this.sessions.addMessage(sessionId, { role: 'user', content });
|
|
100
|
-
await this.sessions.addMessage(sessionId, { role: 'assistant', content: response });
|
|
101
|
-
if (this.contextManager && sceneId) {
|
|
102
|
-
this.contextManager.autoSummarizeIfNeeded(sceneId).catch(() => {});
|
|
103
|
-
}
|
|
104
|
-
return response;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
private async simpleChat(content: string, systemPrompt: string): Promise<string> {
|
|
108
|
-
const provider = this.getProvider();
|
|
109
|
-
const response = await this.chat({
|
|
110
|
-
model: provider.models[0],
|
|
111
|
-
messages: [
|
|
112
|
-
{ role: 'system', content: systemPrompt },
|
|
113
|
-
{ role: 'user', content },
|
|
114
|
-
],
|
|
115
|
-
});
|
|
116
|
-
const msgContent = response.choices[0]?.message?.content;
|
|
117
|
-
return typeof msgContent === 'string' ? msgContent : '';
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
private convertToolToAgentTool(tool: Tool): AgentTool {
|
|
121
|
-
const agentTool: AgentTool = {
|
|
122
|
-
name: tool.name,
|
|
123
|
-
description: tool.description,
|
|
124
|
-
parameters: tool.parameters,
|
|
125
|
-
execute: async (args) => tool.execute(args),
|
|
126
|
-
};
|
|
127
|
-
if (tool.tags?.length) agentTool.tags = tool.tags;
|
|
128
|
-
if (tool.permissionLevel) agentTool.permissionLevel = PERM_MAP[tool.permissionLevel] ?? 0;
|
|
129
|
-
if (tool.keywords?.length) agentTool.keywords = tool.keywords;
|
|
130
|
-
return agentTool;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
setSessionManager(manager: SessionManager): void { this.sessions.dispose(); this.sessions = manager; }
|
|
134
|
-
setContextManager(manager: ContextManager): void {
|
|
135
|
-
this.contextManager = manager;
|
|
136
|
-
const defaultProvider = this.providers.get(this.defaultProvider);
|
|
137
|
-
if (defaultProvider) manager.setAIProvider(defaultProvider);
|
|
138
|
-
}
|
|
139
|
-
setPlugin(plugin: Plugin): void { this.plugin = plugin; }
|
|
140
|
-
setModelRegistry(registry: ModelRegistry): void { this._modelRegistry = registry; }
|
|
141
|
-
getModelRegistry(): ModelRegistry | null { return this._modelRegistry; }
|
|
142
|
-
registerTool(tool: AgentTool): () => void { this.customTools.set(tool.name, tool); return () => { this.customTools.delete(tool.name); }; }
|
|
143
|
-
|
|
144
|
-
collectAllTools(): AgentTool[] {
|
|
145
|
-
const tools: AgentTool[] = [...this.builtinTools, ...this.customTools.values()];
|
|
146
|
-
if (this.plugin) {
|
|
147
|
-
for (const tool of this.plugin.collectAllTools()) tools.push(this.convertToolToAgentTool(tool));
|
|
148
|
-
}
|
|
149
|
-
return tools;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
getContextConfig(): ContextConfig { return this.contextConfig; }
|
|
153
|
-
getSessionConfig() { return this.sessionConfig; }
|
|
154
|
-
getTriggerConfig(): AITriggerConfig { return this.triggerConfig; }
|
|
155
|
-
/** Agent 配置(如 disabledTools / allowedTools),供 ZhinAgent 使用 */
|
|
156
|
-
getAgentConfig(): AIConfig['agent'] { return this.agentConfig; }
|
|
157
|
-
|
|
158
|
-
registerProvider(provider: AIProvider): void { this.providers.set(provider.name, provider); }
|
|
159
|
-
getProvider(name?: string): AIProvider {
|
|
160
|
-
const providerName = name || this.defaultProvider;
|
|
161
|
-
const provider = this.providers.get(providerName);
|
|
162
|
-
if (!provider) throw new Error(`AI Provider "${providerName}" not found. Available: ${this.listProviders().join(', ')}`);
|
|
163
|
-
return provider;
|
|
164
|
-
}
|
|
165
|
-
listProviders(): string[] { return Array.from(this.providers.keys()); }
|
|
166
|
-
|
|
167
|
-
getProviderCapabilities(name?: string): { contextWindow?: number; capabilities?: import('@zhin.js/core').ProviderCapabilities } {
|
|
168
|
-
const provider = this.getProvider(name);
|
|
169
|
-
return {
|
|
170
|
-
contextWindow: provider.contextWindow,
|
|
171
|
-
capabilities: provider.capabilities,
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
async listModels(providerName?: string): Promise<{ provider: string; models: string[] }[]> {
|
|
176
|
-
const result: { provider: string; models: string[] }[] = [];
|
|
177
|
-
if (providerName) {
|
|
178
|
-
const provider = this.getProvider(providerName);
|
|
179
|
-
result.push({ provider: providerName, models: await provider.listModels?.() || provider.models });
|
|
180
|
-
} else {
|
|
181
|
-
for (const [name, provider] of this.providers) {
|
|
182
|
-
result.push({ provider: name, models: await provider.listModels?.() || provider.models });
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
return result;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
async chat(request: ChatCompletionRequest, providerName?: string): Promise<ChatCompletionResponse> {
|
|
189
|
-
return this.getProvider(providerName).chat(request);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
async *chatStream(request: ChatCompletionRequest, providerName?: string): AsyncIterable<ChatCompletionChunk> {
|
|
193
|
-
yield* this.getProvider(providerName).chatStream(request);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
async ask(question: string, options: { provider?: string; model?: string; systemPrompt?: string; temperature?: number } = {}): Promise<string> {
|
|
197
|
-
const messages: ChatMessage[] = [];
|
|
198
|
-
if (options.systemPrompt) messages.push({ role: 'system', content: options.systemPrompt });
|
|
199
|
-
messages.push({ role: 'user', content: question });
|
|
200
|
-
const provider = this.getProvider(options.provider);
|
|
201
|
-
const response = await provider.chat({ model: options.model || provider.models[0], messages, temperature: options.temperature });
|
|
202
|
-
const content = response.choices[0]?.message?.content;
|
|
203
|
-
return typeof content === 'string' ? content : '';
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
createAgent(options: { provider?: string; model?: string; systemPrompt?: string; tools?: AgentTool[]; useBuiltinTools?: boolean; collectExternalTools?: boolean; maxIterations?: number } = {}): Agent {
|
|
207
|
-
const provider = this.getProvider(options.provider);
|
|
208
|
-
let tools: AgentTool[] = [];
|
|
209
|
-
if (options.useBuiltinTools !== false) tools.push(...this.builtinTools);
|
|
210
|
-
if (options.collectExternalTools !== false) { tools.push(...this.customTools.values()); if (this.plugin) { for (const t of this.plugin.collectAllTools()) tools.push(this.convertToolToAgentTool(t)); } }
|
|
211
|
-
if (options.tools?.length) tools.push(...options.tools);
|
|
212
|
-
return createAgent(provider, { model: options.model, systemPrompt: options.systemPrompt, tools, maxIterations: options.maxIterations });
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
async runAgent(task: string, options: { provider?: string; model?: string; tools?: AgentTool[]; systemPrompt?: string } = {}): Promise<{ content: string; toolCalls: any[]; usage: any }> {
|
|
216
|
-
return this.createAgent(options).run(task);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
async healthCheck(): Promise<Record<string, boolean>> {
|
|
220
|
-
const results: Record<string, boolean> = {};
|
|
221
|
-
for (const [name, provider] of this.providers) {
|
|
222
|
-
try { results[name] = await provider.healthCheck?.() ?? true; } catch { results[name] = false; }
|
|
223
|
-
}
|
|
224
|
-
return results;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
dispose(): void { this.sessions.dispose(); this.providers.clear(); }
|
|
228
|
-
}
|
package/src/session.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Re-export from @zhin.js/ai for backward compatibility.
|
|
3
|
-
*/
|
|
4
|
-
export {
|
|
5
|
-
SessionManager,
|
|
6
|
-
MemorySessionManager,
|
|
7
|
-
DatabaseSessionManager,
|
|
8
|
-
createSessionManager,
|
|
9
|
-
createMemorySessionManager,
|
|
10
|
-
createDatabaseSessionManager,
|
|
11
|
-
AI_SESSION_MODEL,
|
|
12
|
-
} from '@zhin.js/ai';
|
|
13
|
-
export type { ISessionManager } from '@zhin.js/ai';
|
package/src/storage.ts
DELETED
package/src/subagent.ts
DELETED
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SubagentManager — 后台子任务执行管理器
|
|
3
|
-
*
|
|
4
|
-
* 职责:
|
|
5
|
-
* 1. 接收主 agent 发起的 spawn 请求,创建后台子 agent
|
|
6
|
-
* 2. 为子 agent 配备受限工具集(文件/Shell/网络,不含消息/spawn/技能)
|
|
7
|
-
* 3. 管理子 agent 生命周期(运行跟踪、完成/失败回告)
|
|
8
|
-
* 4. 完成后将结果投递回主流程,由主 agent 摘要后发送到原始频道
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { randomUUID } from 'crypto';
|
|
12
|
-
import { Logger } from '@zhin.js/core';
|
|
13
|
-
import type { AIProvider, AgentTool } from '@zhin.js/core';
|
|
14
|
-
import { createAgent } from '@zhin.js/ai';
|
|
15
|
-
import type { ZhinAgentConfig } from './zhin-agent/config.js';
|
|
16
|
-
import { applyExecPolicyToTools } from './zhin-agent/exec-policy.js';
|
|
17
|
-
|
|
18
|
-
const logger = new Logger(null, 'Subagent');
|
|
19
|
-
|
|
20
|
-
// ============================================================================
|
|
21
|
-
// 类型
|
|
22
|
-
// ============================================================================
|
|
23
|
-
|
|
24
|
-
export interface SubagentOrigin {
|
|
25
|
-
platform: string;
|
|
26
|
-
botId: string;
|
|
27
|
-
sceneId: string;
|
|
28
|
-
senderId: string;
|
|
29
|
-
sceneType: string;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export interface SpawnOptions {
|
|
33
|
-
task: string;
|
|
34
|
-
label?: string;
|
|
35
|
-
origin: SubagentOrigin;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export type SubagentResultSender = (origin: SubagentOrigin, content: string) => Promise<void>;
|
|
39
|
-
|
|
40
|
-
export interface SubagentManagerOptions {
|
|
41
|
-
provider: AIProvider;
|
|
42
|
-
workspace: string;
|
|
43
|
-
createTools: () => AgentTool[];
|
|
44
|
-
maxIterations?: number;
|
|
45
|
-
/** Exec policy config to enforce on subagent bash tools */
|
|
46
|
-
execPolicyConfig?: Required<ZhinAgentConfig>;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// ============================================================================
|
|
50
|
-
// 子 agent 允许使用的工具名单
|
|
51
|
-
// ============================================================================
|
|
52
|
-
|
|
53
|
-
const SUBAGENT_ALLOWED_TOOLS = new Set([
|
|
54
|
-
'read_file',
|
|
55
|
-
'write_file',
|
|
56
|
-
'edit_file',
|
|
57
|
-
'list_dir',
|
|
58
|
-
'glob',
|
|
59
|
-
'grep',
|
|
60
|
-
'bash',
|
|
61
|
-
'web_search',
|
|
62
|
-
'web_fetch',
|
|
63
|
-
]);
|
|
64
|
-
|
|
65
|
-
// ============================================================================
|
|
66
|
-
// SubagentManager
|
|
67
|
-
// ============================================================================
|
|
68
|
-
|
|
69
|
-
export class SubagentManager {
|
|
70
|
-
private provider: AIProvider;
|
|
71
|
-
private workspace: string;
|
|
72
|
-
private createTools: () => AgentTool[];
|
|
73
|
-
private maxIterations: number;
|
|
74
|
-
private execPolicyConfig: Required<ZhinAgentConfig> | null;
|
|
75
|
-
private runningTasks: Map<string, AbortController> = new Map();
|
|
76
|
-
private resultSender: SubagentResultSender | null = null;
|
|
77
|
-
|
|
78
|
-
constructor(options: SubagentManagerOptions) {
|
|
79
|
-
this.provider = options.provider;
|
|
80
|
-
this.workspace = options.workspace;
|
|
81
|
-
this.createTools = options.createTools;
|
|
82
|
-
this.maxIterations = options.maxIterations ?? 15;
|
|
83
|
-
this.execPolicyConfig = options.execPolicyConfig ?? null;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
setSender(sender: SubagentResultSender): void {
|
|
87
|
-
this.resultSender = sender;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
async spawn(options: SpawnOptions): Promise<string> {
|
|
91
|
-
const taskId = randomUUID().slice(0, 8);
|
|
92
|
-
const displayLabel =
|
|
93
|
-
options.label ||
|
|
94
|
-
options.task.slice(0, 30) + (options.task.length > 30 ? '...' : '');
|
|
95
|
-
|
|
96
|
-
const abortController = new AbortController();
|
|
97
|
-
this.runningTasks.set(taskId, abortController);
|
|
98
|
-
|
|
99
|
-
this.runSubagent(taskId, options.task, displayLabel, options.origin)
|
|
100
|
-
.catch((error) => {
|
|
101
|
-
logger.error({ error, taskId }, 'Subagent failed');
|
|
102
|
-
})
|
|
103
|
-
.finally(() => {
|
|
104
|
-
this.runningTasks.delete(taskId);
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
logger.info({ taskId, label: displayLabel }, 'Spawned subagent');
|
|
108
|
-
return `子任务 [${displayLabel}] 已启动 (id: ${taskId}),完成后会自动通知你。`;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
getRunningCount(): number {
|
|
112
|
-
return this.runningTasks.size;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// ── 内部方法 ──────────────────────────────────────────────────────
|
|
116
|
-
|
|
117
|
-
private async runSubagent(
|
|
118
|
-
taskId: string,
|
|
119
|
-
task: string,
|
|
120
|
-
label: string,
|
|
121
|
-
origin: SubagentOrigin,
|
|
122
|
-
): Promise<void> {
|
|
123
|
-
logger.info({ taskId, label }, 'Subagent starting task');
|
|
124
|
-
|
|
125
|
-
try {
|
|
126
|
-
const allTools = this.createTools();
|
|
127
|
-
let tools = allTools.filter(t => SUBAGENT_ALLOWED_TOOLS.has(t.name));
|
|
128
|
-
if (this.execPolicyConfig) {
|
|
129
|
-
tools = applyExecPolicyToTools(this.execPolicyConfig, tools);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
const systemPrompt = this.buildSubagentPrompt(task);
|
|
133
|
-
const agent = createAgent(this.provider, {
|
|
134
|
-
systemPrompt,
|
|
135
|
-
tools,
|
|
136
|
-
maxIterations: this.maxIterations,
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
const result = await agent.run(task);
|
|
140
|
-
const finalResult = result.content || '任务已完成,但未生成最终响应。';
|
|
141
|
-
|
|
142
|
-
logger.info({ taskId }, 'Subagent completed successfully');
|
|
143
|
-
await this.announceResult(taskId, label, task, finalResult, origin, 'ok');
|
|
144
|
-
} catch (error) {
|
|
145
|
-
const errorMsg = `Error: ${error}`;
|
|
146
|
-
logger.error({ taskId, error }, 'Subagent failed');
|
|
147
|
-
await this.announceResult(taskId, label, task, errorMsg, origin, 'error');
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
private async announceResult(
|
|
152
|
-
taskId: string,
|
|
153
|
-
label: string,
|
|
154
|
-
task: string,
|
|
155
|
-
result: string,
|
|
156
|
-
origin: SubagentOrigin,
|
|
157
|
-
status: 'ok' | 'error',
|
|
158
|
-
): Promise<void> {
|
|
159
|
-
if (!this.resultSender) {
|
|
160
|
-
logger.warn({ taskId }, 'No result sender configured, discarding subagent result');
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const statusText = status === 'ok' ? '已完成' : '执行失败';
|
|
165
|
-
const announceContent = `[后台任务 '${label}' ${statusText}]\n\n任务: ${task}\n\n结果:\n${result}`;
|
|
166
|
-
|
|
167
|
-
try {
|
|
168
|
-
await this.resultSender(origin, announceContent);
|
|
169
|
-
logger.debug({ taskId, origin }, 'Subagent announced result');
|
|
170
|
-
} catch (e) {
|
|
171
|
-
logger.error({ taskId, error: e }, 'Failed to announce subagent result');
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
private buildSubagentPrompt(task: string): string {
|
|
176
|
-
return `# Sub-task Agent
|
|
177
|
-
|
|
178
|
-
You are a sub-agent spawned by the main agent to perform a specific task.
|
|
179
|
-
|
|
180
|
-
## Your task
|
|
181
|
-
${task}
|
|
182
|
-
|
|
183
|
-
## Rules
|
|
184
|
-
1. Focus only on the assigned task
|
|
185
|
-
2. Your final reply will be reported to the main agent and relayed to the user
|
|
186
|
-
3. Do not start new conversations or take on extra tasks
|
|
187
|
-
4. Keep replies concise but informative
|
|
188
|
-
|
|
189
|
-
## You may
|
|
190
|
-
- Read/write files in the workspace
|
|
191
|
-
- Run shell commands
|
|
192
|
-
- Search and fetch the web
|
|
193
|
-
- Complete the task thoroughly
|
|
194
|
-
|
|
195
|
-
## You must not
|
|
196
|
-
- Send messages directly to the user
|
|
197
|
-
- Spawn further sub-tasks
|
|
198
|
-
- Access the main agent's conversation history
|
|
199
|
-
|
|
200
|
-
## Workspace
|
|
201
|
-
Workspace path: ${this.workspace}
|
|
202
|
-
|
|
203
|
-
When done, provide a clear summary of findings or actions.`;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
dispose(): void {
|
|
207
|
-
this.runningTasks.clear();
|
|
208
|
-
}
|
|
209
|
-
}
|
package/src/tone-detector.ts
DELETED
package/src/tools.ts
DELETED
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @zhin.js/ai - Built-in Tools
|
|
3
|
-
* 内置工具集合 - 使用 ZhinTool 类定义
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { ZhinTool, type Tool, evaluate, execute } from '@zhin.js/core';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* 计算器工具
|
|
10
|
-
* 支持基本运算和数学函数
|
|
11
|
-
*/
|
|
12
|
-
export const calculatorTool = new ZhinTool('calculator')
|
|
13
|
-
.desc('执行数学计算。支持基本运算(+、-、*、/、^)和数学函数(sin、cos、sqrt 等)')
|
|
14
|
-
.keyword('计算', '算', 'calc', '数学', '求值', '运算')
|
|
15
|
-
.tag('math', 'utility')
|
|
16
|
-
.param('expression', { type: 'string', description: '数学表达式,例如 "2 + 3 * 4" 或 "sqrt(16)"' }, true)
|
|
17
|
-
.execute(async ({ expression }) => {
|
|
18
|
-
try {
|
|
19
|
-
const sanitized = (expression as string)
|
|
20
|
-
.replace(/[^0-9+\-*/().^eEsincosqrtabspowlogxMathPI\s]/g, '')
|
|
21
|
-
.replace(/\bsqrt\b/g, 'Math.sqrt')
|
|
22
|
-
.replace(/\bsin\b/g, 'Math.sin')
|
|
23
|
-
.replace(/\bcos\b/g, 'Math.cos')
|
|
24
|
-
.replace(/\btan\b/g, 'Math.tan')
|
|
25
|
-
.replace(/\blog\b/g, 'Math.log')
|
|
26
|
-
.replace(/\babs\b/g, 'Math.abs')
|
|
27
|
-
.replace(/\bpow\b/g, 'Math.pow')
|
|
28
|
-
.replace(/\bPI\b/g, 'Math.PI')
|
|
29
|
-
.replace(/\bE\b(?![0-9])/g, 'Math.E')
|
|
30
|
-
.replace(/\^/g, '**');
|
|
31
|
-
|
|
32
|
-
const result = evaluate(sanitized, { Math });
|
|
33
|
-
if (result === undefined) return { error: '无法计算表达式', expression };
|
|
34
|
-
return { result, expression };
|
|
35
|
-
} catch (error) {
|
|
36
|
-
return { error: '无法计算表达式', expression };
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* 时间工具
|
|
42
|
-
* 获取当前时间和日期
|
|
43
|
-
*/
|
|
44
|
-
export const timeTool = new ZhinTool('get_time')
|
|
45
|
-
.desc('获取当前时间和日期信息')
|
|
46
|
-
.keyword('时间', '日期', '几点', '今天', '现在', 'time', 'date')
|
|
47
|
-
.tag('time', 'utility')
|
|
48
|
-
.param('timezone', { type: 'string', description: '时区,例如 "Asia/Shanghai" 或 "UTC"' })
|
|
49
|
-
.param('format', { type: 'string', description: '输出格式: full(完整), date(日期), time(时间), timestamp(时间戳)' })
|
|
50
|
-
.execute(async ({ timezone, format = 'full' }) => {
|
|
51
|
-
const now = new Date();
|
|
52
|
-
const options: Intl.DateTimeFormatOptions = {
|
|
53
|
-
timeZone: (timezone as string) || 'Asia/Shanghai',
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
switch (format) {
|
|
57
|
-
case 'date':
|
|
58
|
-
options.dateStyle = 'full';
|
|
59
|
-
break;
|
|
60
|
-
case 'time':
|
|
61
|
-
options.timeStyle = 'long';
|
|
62
|
-
break;
|
|
63
|
-
case 'timestamp':
|
|
64
|
-
return { timestamp: now.getTime(), iso: now.toISOString() };
|
|
65
|
-
default:
|
|
66
|
-
options.dateStyle = 'full';
|
|
67
|
-
options.timeStyle = 'long';
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return {
|
|
71
|
-
formatted: now.toLocaleString('zh-CN', options),
|
|
72
|
-
timestamp: now.getTime(),
|
|
73
|
-
iso: now.toISOString(),
|
|
74
|
-
};
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* 网页搜索工具
|
|
79
|
-
* 需要配置搜索 API
|
|
80
|
-
*/
|
|
81
|
-
export const searchTool = new ZhinTool('web_search')
|
|
82
|
-
.desc('在互联网上搜索信息(需要配置搜索 API)')
|
|
83
|
-
.keyword('搜索', '搜一下', '查找', '查一查', 'search', 'google')
|
|
84
|
-
.tag('search', 'web')
|
|
85
|
-
.param('query', { type: 'string', description: '搜索关键词' }, true)
|
|
86
|
-
.param('limit', { type: 'number', description: '返回结果数量(默认 5)' })
|
|
87
|
-
.execute(async ({ query, limit = 5 }) => {
|
|
88
|
-
// 默认实现提示需要配置
|
|
89
|
-
return {
|
|
90
|
-
query,
|
|
91
|
-
error: '搜索功能未配置,请提供搜索 API',
|
|
92
|
-
hint: '可以集成 SerpAPI、Bing Search API 或 Google Custom Search',
|
|
93
|
-
};
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* 代码执行工具
|
|
98
|
-
* 在安全沙箱中执行 JavaScript
|
|
99
|
-
*/
|
|
100
|
-
export const codeRunnerTool = new ZhinTool('run_code')
|
|
101
|
-
.desc('执行 JavaScript 代码(在安全沙箱中)')
|
|
102
|
-
.keyword('代码', '执行', '运行', 'code', 'js', 'javascript')
|
|
103
|
-
.tag('code', 'dev')
|
|
104
|
-
.param('code', { type: 'string', description: 'JavaScript 代码' }, true)
|
|
105
|
-
.execute(async ({ code }) => {
|
|
106
|
-
try {
|
|
107
|
-
const sandbox = {
|
|
108
|
-
console: { log: (...args: unknown[]) => args.map(String).join(' ') },
|
|
109
|
-
};
|
|
110
|
-
const result = execute(code as string, sandbox);
|
|
111
|
-
return {
|
|
112
|
-
success: true,
|
|
113
|
-
result: result !== undefined ? String(result) : 'undefined',
|
|
114
|
-
};
|
|
115
|
-
} catch (error) {
|
|
116
|
-
return {
|
|
117
|
-
success: false,
|
|
118
|
-
error: error instanceof Error ? error.message : String(error),
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* HTTP 请求工具
|
|
125
|
-
* 发送 HTTP 请求获取数据
|
|
126
|
-
*/
|
|
127
|
-
export const httpTool = new ZhinTool('http_request')
|
|
128
|
-
.desc('发送 HTTP 请求获取数据')
|
|
129
|
-
.keyword('http', 'api', '请求', '接口', 'url', 'fetch')
|
|
130
|
-
.tag('http', 'web')
|
|
131
|
-
.param('url', { type: 'string', description: '请求 URL' }, true)
|
|
132
|
-
.param('method', { type: 'string', description: 'HTTP 方法: GET, POST, PUT, DELETE(默认 GET)' })
|
|
133
|
-
.param('headers', { type: 'object', description: '请求头(JSON 对象)' })
|
|
134
|
-
.param('body', { type: 'string', description: '请求体(JSON 字符串)' })
|
|
135
|
-
.execute(async ({ url, method = 'GET', headers = {}, body }) => {
|
|
136
|
-
try {
|
|
137
|
-
const response = await fetch(url as string, {
|
|
138
|
-
method: method as string,
|
|
139
|
-
headers: {
|
|
140
|
-
'Content-Type': 'application/json',
|
|
141
|
-
...(headers as Record<string, string>),
|
|
142
|
-
},
|
|
143
|
-
body: body ? (body as string) : undefined,
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
const contentType = response.headers.get('content-type') || '';
|
|
147
|
-
let data: any;
|
|
148
|
-
|
|
149
|
-
if (contentType.includes('application/json')) {
|
|
150
|
-
data = await response.json();
|
|
151
|
-
} else {
|
|
152
|
-
data = await response.text();
|
|
153
|
-
// 限制文本长度
|
|
154
|
-
if (data.length > 5000) {
|
|
155
|
-
data = data.substring(0, 5000) + '... (truncated)';
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
return {
|
|
160
|
-
status: response.status,
|
|
161
|
-
statusText: response.statusText,
|
|
162
|
-
data,
|
|
163
|
-
};
|
|
164
|
-
} catch (error) {
|
|
165
|
-
return {
|
|
166
|
-
error: error instanceof Error ? error.message : String(error),
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* 记忆工具
|
|
173
|
-
* 让 AI 记住重要信息
|
|
174
|
-
*/
|
|
175
|
-
export const memoryTool = new ZhinTool('remember')
|
|
176
|
-
.desc('记住用户告诉你的重要信息,以便后续对话中使用')
|
|
177
|
-
.keyword('记住', '记忆', '记下', 'remember', '别忘了')
|
|
178
|
-
.tag('memory', 'context')
|
|
179
|
-
.param('key', { type: 'string', description: '记忆的标识符,如 "user_name", "preference"' }, true)
|
|
180
|
-
.param('value', { type: 'string', description: '要记住的内容' }, true)
|
|
181
|
-
.execute(async ({ key, value }, context) => {
|
|
182
|
-
// 这里需要与 session/context manager 集成
|
|
183
|
-
return {
|
|
184
|
-
success: true,
|
|
185
|
-
message: `已记住 ${key}: ${value}`,
|
|
186
|
-
key,
|
|
187
|
-
value,
|
|
188
|
-
};
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* 获取所有内置工具(ZhinTool 实例)
|
|
193
|
-
* 注意:天气工具已移除,请使用 weather-tool 插件,支持多平台配置
|
|
194
|
-
*/
|
|
195
|
-
export function getBuiltinTools(): ZhinTool[] {
|
|
196
|
-
return [
|
|
197
|
-
calculatorTool,
|
|
198
|
-
timeTool,
|
|
199
|
-
];
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* 获取所有可用的内置工具(包括可选工具)
|
|
204
|
-
*/
|
|
205
|
-
export function getAllBuiltinTools(): ZhinTool[] {
|
|
206
|
-
return [
|
|
207
|
-
calculatorTool,
|
|
208
|
-
timeTool,
|
|
209
|
-
searchTool,
|
|
210
|
-
codeRunnerTool,
|
|
211
|
-
httpTool,
|
|
212
|
-
memoryTool,
|
|
213
|
-
];
|
|
214
|
-
}
|