@zhin.js/ai 0.0.1

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/src/tools.ts ADDED
@@ -0,0 +1,205 @@
1
+ /**
2
+ * @zhin.js/ai - Built-in Tools
3
+ * 内置工具集合 - 使用 ZhinTool 类定义
4
+ */
5
+
6
+ import { ZhinTool, type Tool } from '@zhin.js/core';
7
+
8
+ /**
9
+ * 计算器工具
10
+ * 支持基本运算和数学函数
11
+ */
12
+ export const calculatorTool = new ZhinTool('calculator')
13
+ .desc('执行数学计算。支持基本运算(+、-、*、/、^)和数学函数(sin、cos、sqrt 等)')
14
+ .param('expression', { type: 'string', description: '数学表达式,例如 "2 + 3 * 4" 或 "sqrt(16)"' }, true)
15
+ .execute(async ({ expression }) => {
16
+ try {
17
+ // 安全的数学表达式求值
18
+ const sanitized = (expression as string)
19
+ .replace(/[^0-9+\-*/().^eEsincosqrtabspowlogxMathPI\s]/g, '')
20
+ .replace(/\bsqrt\b/g, 'Math.sqrt')
21
+ .replace(/\bsin\b/g, 'Math.sin')
22
+ .replace(/\bcos\b/g, 'Math.cos')
23
+ .replace(/\btan\b/g, 'Math.tan')
24
+ .replace(/\blog\b/g, 'Math.log')
25
+ .replace(/\babs\b/g, 'Math.abs')
26
+ .replace(/\bpow\b/g, 'Math.pow')
27
+ .replace(/\bPI\b/g, 'Math.PI')
28
+ .replace(/\bE\b(?![0-9])/g, 'Math.E')
29
+ .replace(/\^/g, '**');
30
+
31
+ const result = new Function(`return ${sanitized}`)();
32
+ return { result, expression };
33
+ } catch (error) {
34
+ return { error: '无法计算表达式', expression };
35
+ }
36
+ });
37
+
38
+ /**
39
+ * 时间工具
40
+ * 获取当前时间和日期
41
+ */
42
+ export const timeTool = new ZhinTool('get_time')
43
+ .desc('获取当前时间和日期信息')
44
+ .param('timezone', { type: 'string', description: '时区,例如 "Asia/Shanghai" 或 "UTC"' })
45
+ .param('format', { type: 'string', description: '输出格式: full(完整), date(日期), time(时间), timestamp(时间戳)' })
46
+ .execute(async ({ timezone, format = 'full' }) => {
47
+ const now = new Date();
48
+ const options: Intl.DateTimeFormatOptions = {
49
+ timeZone: (timezone as string) || 'Asia/Shanghai',
50
+ };
51
+
52
+ switch (format) {
53
+ case 'date':
54
+ options.dateStyle = 'full';
55
+ break;
56
+ case 'time':
57
+ options.timeStyle = 'long';
58
+ break;
59
+ case 'timestamp':
60
+ return { timestamp: now.getTime(), iso: now.toISOString() };
61
+ default:
62
+ options.dateStyle = 'full';
63
+ options.timeStyle = 'long';
64
+ }
65
+
66
+ return {
67
+ formatted: now.toLocaleString('zh-CN', options),
68
+ timestamp: now.getTime(),
69
+ iso: now.toISOString(),
70
+ };
71
+ });
72
+
73
+ /**
74
+ * 网页搜索工具
75
+ * 需要配置搜索 API
76
+ */
77
+ export const searchTool = new ZhinTool('web_search')
78
+ .desc('在互联网上搜索信息(需要配置搜索 API)')
79
+ .param('query', { type: 'string', description: '搜索关键词' }, true)
80
+ .param('limit', { type: 'number', description: '返回结果数量(默认 5)' })
81
+ .execute(async ({ query, limit = 5 }) => {
82
+ // 默认实现提示需要配置
83
+ return {
84
+ query,
85
+ error: '搜索功能未配置,请提供搜索 API',
86
+ hint: '可以集成 SerpAPI、Bing Search API 或 Google Custom Search',
87
+ };
88
+ });
89
+
90
+ /**
91
+ * 代码执行工具
92
+ * 在安全沙箱中执行 JavaScript
93
+ */
94
+ export const codeRunnerTool = new ZhinTool('run_code')
95
+ .desc('执行 JavaScript 代码(在安全沙箱中)')
96
+ .param('code', { type: 'string', description: 'JavaScript 代码' }, true)
97
+ .execute(async ({ code }) => {
98
+ try {
99
+ // 简单的沙箱执行(生产环境应使用 vm2 或 isolated-vm)
100
+ const result = new Function(`
101
+ 'use strict';
102
+ const console = { log: (...args) => args.join(' ') };
103
+ return (function() { ${code} })();
104
+ `)();
105
+
106
+ return {
107
+ success: true,
108
+ result: result !== undefined ? String(result) : 'undefined',
109
+ };
110
+ } catch (error) {
111
+ return {
112
+ success: false,
113
+ error: error instanceof Error ? error.message : String(error),
114
+ };
115
+ }
116
+ });
117
+
118
+ /**
119
+ * HTTP 请求工具
120
+ * 发送 HTTP 请求获取数据
121
+ */
122
+ export const httpTool = new ZhinTool('http_request')
123
+ .desc('发送 HTTP 请求获取数据')
124
+ .param('url', { type: 'string', description: '请求 URL' }, true)
125
+ .param('method', { type: 'string', description: 'HTTP 方法: GET, POST, PUT, DELETE(默认 GET)' })
126
+ .param('headers', { type: 'object', description: '请求头(JSON 对象)' })
127
+ .param('body', { type: 'string', description: '请求体(JSON 字符串)' })
128
+ .execute(async ({ url, method = 'GET', headers = {}, body }) => {
129
+ try {
130
+ const response = await fetch(url as string, {
131
+ method: method as string,
132
+ headers: {
133
+ 'Content-Type': 'application/json',
134
+ ...(headers as Record<string, string>),
135
+ },
136
+ body: body ? (body as string) : undefined,
137
+ });
138
+
139
+ const contentType = response.headers.get('content-type') || '';
140
+ let data: any;
141
+
142
+ if (contentType.includes('application/json')) {
143
+ data = await response.json();
144
+ } else {
145
+ data = await response.text();
146
+ // 限制文本长度
147
+ if (data.length > 5000) {
148
+ data = data.substring(0, 5000) + '... (truncated)';
149
+ }
150
+ }
151
+
152
+ return {
153
+ status: response.status,
154
+ statusText: response.statusText,
155
+ data,
156
+ };
157
+ } catch (error) {
158
+ return {
159
+ error: error instanceof Error ? error.message : String(error),
160
+ };
161
+ }
162
+ });
163
+
164
+ /**
165
+ * 记忆工具
166
+ * 让 AI 记住重要信息
167
+ */
168
+ export const memoryTool = new ZhinTool('remember')
169
+ .desc('记住用户告诉你的重要信息,以便后续对话中使用')
170
+ .param('key', { type: 'string', description: '记忆的标识符,如 "user_name", "preference"' }, true)
171
+ .param('value', { type: 'string', description: '要记住的内容' }, true)
172
+ .execute(async ({ key, value }, context) => {
173
+ // 这里需要与 session/context manager 集成
174
+ return {
175
+ success: true,
176
+ message: `已记住 ${key}: ${value}`,
177
+ key,
178
+ value,
179
+ };
180
+ });
181
+
182
+ /**
183
+ * 获取所有内置工具(ZhinTool 实例)
184
+ * 注意:天气工具已移除,请使用 weather-tool 插件,支持多平台配置
185
+ */
186
+ export function getBuiltinTools(): ZhinTool[] {
187
+ return [
188
+ calculatorTool,
189
+ timeTool,
190
+ ];
191
+ }
192
+
193
+ /**
194
+ * 获取所有可用的内置工具(包括可选工具)
195
+ */
196
+ export function getAllBuiltinTools(): ZhinTool[] {
197
+ return [
198
+ calculatorTool,
199
+ timeTool,
200
+ searchTool,
201
+ codeRunnerTool,
202
+ httpTool,
203
+ memoryTool,
204
+ ];
205
+ }
package/src/types.ts ADDED
@@ -0,0 +1,274 @@
1
+ /**
2
+ * @zhin.js/ai - AI Service Types
3
+ * 统一的 AI 服务类型定义
4
+ */
5
+
6
+ // ============================================================================
7
+ // 基础类型
8
+ // ============================================================================
9
+
10
+ /** 消息角色 */
11
+ export type MessageRole = 'system' | 'user' | 'assistant' | 'tool';
12
+
13
+ /** 聊天消息 */
14
+ export interface ChatMessage {
15
+ role: MessageRole;
16
+ content: string | ContentPart[];
17
+ name?: string;
18
+ tool_call_id?: string;
19
+ tool_calls?: ToolCall[];
20
+ }
21
+
22
+ /** 内容部分(支持多模态) */
23
+ export type ContentPart =
24
+ | { type: 'text'; text: string }
25
+ | { type: 'image_url'; image_url: { url: string; detail?: 'auto' | 'low' | 'high' } }
26
+ | { type: 'audio'; audio: { data: string; format: 'wav' | 'mp3' } };
27
+
28
+ /** 工具调用 */
29
+ export interface ToolCall {
30
+ id: string;
31
+ type: 'function';
32
+ function: {
33
+ name: string;
34
+ arguments: string;
35
+ };
36
+ }
37
+
38
+ /** 工具定义 */
39
+ export interface ToolDefinition {
40
+ type: 'function';
41
+ function: {
42
+ name: string;
43
+ description: string;
44
+ parameters: JsonSchema;
45
+ };
46
+ }
47
+
48
+ /** JSON Schema */
49
+ export interface JsonSchema {
50
+ type: string;
51
+ properties?: Record<string, JsonSchema>;
52
+ required?: string[];
53
+ items?: JsonSchema;
54
+ enum?: any[];
55
+ description?: string;
56
+ default?: any;
57
+ [key: string]: any;
58
+ }
59
+
60
+ // ============================================================================
61
+ // 请求/响应类型
62
+ // ============================================================================
63
+
64
+ /** 聊天补全请求 */
65
+ export interface ChatCompletionRequest {
66
+ model: string;
67
+ messages: ChatMessage[];
68
+ tools?: ToolDefinition[];
69
+ tool_choice?: 'auto' | 'none' | 'required' | { type: 'function'; function: { name: string } };
70
+ temperature?: number;
71
+ top_p?: number;
72
+ max_tokens?: number;
73
+ stream?: boolean;
74
+ stop?: string | string[];
75
+ presence_penalty?: number;
76
+ frequency_penalty?: number;
77
+ user?: string;
78
+ }
79
+
80
+ /** 聊天补全响应 */
81
+ export interface ChatCompletionResponse {
82
+ id: string;
83
+ object: 'chat.completion';
84
+ created: number;
85
+ model: string;
86
+ choices: ChatCompletionChoice[];
87
+ usage?: Usage;
88
+ }
89
+
90
+ /** 选择 */
91
+ export interface ChatCompletionChoice {
92
+ index: number;
93
+ message: ChatMessage;
94
+ finish_reason: 'stop' | 'length' | 'tool_calls' | 'content_filter' | null;
95
+ }
96
+
97
+ /** 用量统计 */
98
+ export interface Usage {
99
+ prompt_tokens: number;
100
+ completion_tokens: number;
101
+ total_tokens: number;
102
+ }
103
+
104
+ // ============================================================================
105
+ // 流式响应类型
106
+ // ============================================================================
107
+
108
+ /** 流式响应块 */
109
+ export interface ChatCompletionChunk {
110
+ id: string;
111
+ object: 'chat.completion.chunk';
112
+ created: number;
113
+ model: string;
114
+ choices: ChatCompletionChunkChoice[];
115
+ usage?: Usage;
116
+ }
117
+
118
+ /** 流式选择 */
119
+ export interface ChatCompletionChunkChoice {
120
+ index: number;
121
+ delta: Partial<ChatMessage>;
122
+ finish_reason: 'stop' | 'length' | 'tool_calls' | 'content_filter' | null;
123
+ }
124
+
125
+ // ============================================================================
126
+ // Provider 类型
127
+ // ============================================================================
128
+
129
+ /** Provider 配置 */
130
+ export interface ProviderConfig {
131
+ apiKey?: string;
132
+ baseUrl?: string;
133
+ defaultModel?: string;
134
+ timeout?: number;
135
+ maxRetries?: number;
136
+ headers?: Record<string, string>;
137
+ }
138
+
139
+ /** Provider 接口 */
140
+ export interface AIProvider {
141
+ name: string;
142
+ models: string[];
143
+
144
+ /** 聊天补全 */
145
+ chat(request: ChatCompletionRequest): Promise<ChatCompletionResponse>;
146
+
147
+ /** 流式聊天补全 */
148
+ chatStream(request: ChatCompletionRequest): AsyncIterable<ChatCompletionChunk>;
149
+
150
+ /** 列出可用模型 */
151
+ listModels?(): Promise<string[]>;
152
+
153
+ /** 检查连接 */
154
+ healthCheck?(): Promise<boolean>;
155
+ }
156
+
157
+ // ============================================================================
158
+ // Agent 类型
159
+ // ============================================================================
160
+
161
+ /** Agent 工具 */
162
+ export interface AgentTool {
163
+ name: string;
164
+ description: string;
165
+ parameters: JsonSchema;
166
+ execute: (args: Record<string, any>) => Promise<any>;
167
+ }
168
+
169
+ /** Agent 配置 */
170
+ export interface AgentConfig {
171
+ provider: string;
172
+ model?: string;
173
+ systemPrompt?: string;
174
+ tools?: AgentTool[];
175
+ maxIterations?: number;
176
+ temperature?: number;
177
+ }
178
+
179
+ /** Agent 运行结果 */
180
+ export interface AgentResult {
181
+ content: string;
182
+ toolCalls: {
183
+ tool: string;
184
+ args: Record<string, any>;
185
+ result: any;
186
+ }[];
187
+ usage: Usage;
188
+ iterations: number;
189
+ }
190
+
191
+ // ============================================================================
192
+ // Session 类型
193
+ // ============================================================================
194
+
195
+ /** 会话配置 */
196
+ export interface SessionConfig {
197
+ provider: string;
198
+ model?: string;
199
+ systemPrompt?: string;
200
+ maxHistory?: number;
201
+ expireMs?: number;
202
+ }
203
+
204
+ /** 会话 */
205
+ export interface Session {
206
+ id: string;
207
+ config: SessionConfig;
208
+ messages: ChatMessage[];
209
+ createdAt: number;
210
+ updatedAt: number;
211
+ metadata?: Record<string, any>;
212
+ }
213
+
214
+ // ============================================================================
215
+ // AI Service 配置
216
+ // ============================================================================
217
+
218
+ /** AI 服务配置 */
219
+ export interface AIConfig {
220
+ enabled?: boolean;
221
+ defaultProvider?: string;
222
+ providers?: {
223
+ openai?: ProviderConfig;
224
+ anthropic?: ProviderConfig;
225
+ deepseek?: ProviderConfig;
226
+ moonshot?: ProviderConfig;
227
+ zhipu?: ProviderConfig;
228
+ ollama?: ProviderConfig & { host?: string; models?: string[] };
229
+ custom?: ProviderConfig[];
230
+ };
231
+ sessions?: {
232
+ /** 最大历史消息数(数据库模式默认200,内存模式默认100) */
233
+ maxHistory?: number;
234
+ /** 会话过期时间(毫秒,数据库模式默认7天,内存模式默认24小时) */
235
+ expireMs?: number;
236
+ /** 是否使用数据库持久化存储(默认 true) */
237
+ useDatabase?: boolean;
238
+ };
239
+ context?: {
240
+ /** 是否启用消息记录(默认 true) */
241
+ enabled?: boolean;
242
+ /** 读取的最近消息数量(默认 100) */
243
+ maxRecentMessages?: number;
244
+ /** 触发总结的消息数量阈值(默认 50) */
245
+ summaryThreshold?: number;
246
+ /** 总结后保留的消息数量(默认 10) */
247
+ keepAfterSummary?: number;
248
+ /** 上下文最大 token 估算(默认 4000) */
249
+ maxContextTokens?: number;
250
+ /** 自定义总结提示词 */
251
+ summaryPrompt?: string;
252
+ };
253
+ /** AI 触发配置 */
254
+ trigger?: {
255
+ /** 是否启用(默认 true) */
256
+ enabled?: boolean;
257
+ /** 触发前缀列表(默认 ['#', 'AI:']) */
258
+ prefixes?: string[];
259
+ /** 是否响应 @ 机器人(默认 true) */
260
+ respondToAt?: boolean;
261
+ /** 是否响应私聊(默认 true) */
262
+ respondToPrivate?: boolean;
263
+ /** 触发关键词(可选) */
264
+ keywords?: string[];
265
+ /** 忽略的前缀(命令前缀,避免与命令冲突,默认 ['/', '!', '!']) */
266
+ ignorePrefixes?: string[];
267
+ /** 超时时间(毫秒,默认 60000) */
268
+ timeout?: number;
269
+ /** 思考中提示语(可选,设置后会在处理前发送) */
270
+ thinkingMessage?: string;
271
+ /** 错误提示模板(默认 '❌ AI 处理失败: {error}') */
272
+ errorTemplate?: string;
273
+ };
274
+ }