@zhin.js/core 1.1.0 → 1.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.
Files changed (122) hide show
  1. package/lib/adapter.d.ts +1 -26
  2. package/lib/adapter.d.ts.map +1 -1
  3. package/lib/adapter.js +20 -117
  4. package/lib/adapter.js.map +1 -1
  5. package/lib/built/adapter-process.d.ts +0 -4
  6. package/lib/built/adapter-process.d.ts.map +1 -1
  7. package/lib/built/adapter-process.js +0 -95
  8. package/lib/built/adapter-process.js.map +1 -1
  9. package/lib/built/agent-preset.d.ts +2 -0
  10. package/lib/built/agent-preset.d.ts.map +1 -1
  11. package/lib/built/agent-preset.js +4 -0
  12. package/lib/built/agent-preset.js.map +1 -1
  13. package/lib/built/command.d.ts +4 -0
  14. package/lib/built/command.d.ts.map +1 -1
  15. package/lib/built/command.js +6 -0
  16. package/lib/built/command.js.map +1 -1
  17. package/lib/built/component.d.ts.map +1 -1
  18. package/lib/built/component.js +1 -0
  19. package/lib/built/component.js.map +1 -1
  20. package/lib/built/dispatcher.d.ts.map +1 -1
  21. package/lib/built/dispatcher.js +0 -13
  22. package/lib/built/dispatcher.js.map +1 -1
  23. package/lib/built/message-filter.d.ts +2 -0
  24. package/lib/built/message-filter.d.ts.map +1 -1
  25. package/lib/built/message-filter.js +5 -0
  26. package/lib/built/message-filter.js.map +1 -1
  27. package/lib/built/skill.d.ts +11 -0
  28. package/lib/built/skill.d.ts.map +1 -1
  29. package/lib/built/skill.js +14 -0
  30. package/lib/built/skill.js.map +1 -1
  31. package/lib/built/tool.d.ts +11 -44
  32. package/lib/built/tool.d.ts.map +1 -1
  33. package/lib/built/tool.js +14 -353
  34. package/lib/built/tool.js.map +1 -1
  35. package/lib/plugin.d.ts +1 -25
  36. package/lib/plugin.d.ts.map +1 -1
  37. package/lib/plugin.js +1 -77
  38. package/lib/plugin.js.map +1 -1
  39. package/lib/types.d.ts +0 -25
  40. package/lib/types.d.ts.map +1 -1
  41. package/package.json +10 -7
  42. package/CHANGELOG.md +0 -561
  43. package/REFACTORING_COMPLETE.md +0 -178
  44. package/REFACTORING_STATUS.md +0 -263
  45. package/src/adapter.ts +0 -275
  46. package/src/ai/index.ts +0 -55
  47. package/src/ai/providers/anthropic.ts +0 -379
  48. package/src/ai/providers/base.ts +0 -175
  49. package/src/ai/providers/index.ts +0 -13
  50. package/src/ai/providers/ollama.ts +0 -302
  51. package/src/ai/providers/openai.ts +0 -174
  52. package/src/ai/types.ts +0 -348
  53. package/src/bot.ts +0 -37
  54. package/src/built/adapter-process.ts +0 -177
  55. package/src/built/agent-preset.ts +0 -136
  56. package/src/built/ai-trigger.ts +0 -259
  57. package/src/built/command.ts +0 -108
  58. package/src/built/common-adapter-tools.ts +0 -242
  59. package/src/built/component.ts +0 -130
  60. package/src/built/config.ts +0 -335
  61. package/src/built/cron.ts +0 -156
  62. package/src/built/database.ts +0 -134
  63. package/src/built/dispatcher.ts +0 -496
  64. package/src/built/login-assist.ts +0 -131
  65. package/src/built/message-filter.ts +0 -390
  66. package/src/built/permission.ts +0 -151
  67. package/src/built/schema-feature.ts +0 -190
  68. package/src/built/skill.ts +0 -221
  69. package/src/built/tool.ts +0 -948
  70. package/src/command.ts +0 -87
  71. package/src/component.ts +0 -565
  72. package/src/cron.ts +0 -4
  73. package/src/errors.ts +0 -46
  74. package/src/feature.ts +0 -7
  75. package/src/index.ts +0 -53
  76. package/src/jsx-dev-runtime.ts +0 -2
  77. package/src/jsx-runtime.ts +0 -12
  78. package/src/jsx.ts +0 -135
  79. package/src/message.ts +0 -48
  80. package/src/models/system-log.ts +0 -20
  81. package/src/models/user.ts +0 -15
  82. package/src/notice.ts +0 -98
  83. package/src/plugin.ts +0 -896
  84. package/src/prompt.ts +0 -293
  85. package/src/request.ts +0 -95
  86. package/src/scheduler/index.ts +0 -19
  87. package/src/scheduler/scheduler.ts +0 -372
  88. package/src/scheduler/types.ts +0 -74
  89. package/src/tool-zod.ts +0 -115
  90. package/src/types-generator.ts +0 -78
  91. package/src/types.ts +0 -505
  92. package/src/utils.ts +0 -227
  93. package/tests/adapter.test.ts +0 -638
  94. package/tests/ai/ai-trigger.test.ts +0 -368
  95. package/tests/ai/providers.integration.test.ts +0 -227
  96. package/tests/ai/setup.ts +0 -308
  97. package/tests/ai/tool.test.ts +0 -800
  98. package/tests/bot.test.ts +0 -151
  99. package/tests/command.test.ts +0 -737
  100. package/tests/component-new.test.ts +0 -361
  101. package/tests/config.test.ts +0 -372
  102. package/tests/cron.test.ts +0 -82
  103. package/tests/dispatcher.test.ts +0 -293
  104. package/tests/errors.test.ts +0 -21
  105. package/tests/expression-evaluation.test.ts +0 -258
  106. package/tests/features-builtin.test.ts +0 -191
  107. package/tests/jsx-runtime.test.ts +0 -45
  108. package/tests/jsx.test.ts +0 -319
  109. package/tests/message-filter.test.ts +0 -566
  110. package/tests/message.test.ts +0 -402
  111. package/tests/notice.test.ts +0 -198
  112. package/tests/plugin.test.ts +0 -779
  113. package/tests/prompt.test.ts +0 -78
  114. package/tests/redos-protection.test.ts +0 -198
  115. package/tests/request.test.ts +0 -221
  116. package/tests/schema.test.ts +0 -248
  117. package/tests/skill-feature.test.ts +0 -179
  118. package/tests/test-utils.ts +0 -59
  119. package/tests/tool-feature.test.ts +0 -254
  120. package/tests/types.test.ts +0 -162
  121. package/tests/utils.test.ts +0 -135
  122. package/tsconfig.json +0 -24
@@ -1,379 +0,0 @@
1
- /**
2
- * @zhin.js/ai - Anthropic Provider
3
- * 支持 Claude 系列模型
4
- */
5
-
6
- import { BaseProvider } from './base.js';
7
- import type {
8
- ProviderConfig,
9
- ChatCompletionRequest,
10
- ChatCompletionResponse,
11
- ChatCompletionChunk,
12
- ChatMessage,
13
- ToolDefinition,
14
- ContentPart,
15
- } from '../types.js';
16
-
17
- export interface AnthropicConfig extends ProviderConfig {
18
- anthropicVersion?: string;
19
- }
20
-
21
- /**
22
- * Anthropic API 格式转换
23
- */
24
- function toAnthropicMessages(messages: ChatMessage[]): {
25
- system?: string;
26
- messages: any[];
27
- } {
28
- let system: string | undefined;
29
- const anthropicMessages: any[] = [];
30
-
31
- for (const msg of messages) {
32
- if (msg.role === 'system') {
33
- system = typeof msg.content === 'string'
34
- ? msg.content
35
- : msg.content.map(p => p.type === 'text' ? p.text : '').join('');
36
- continue;
37
- }
38
-
39
- if (msg.role === 'tool') {
40
- anthropicMessages.push({
41
- role: 'user',
42
- content: [{
43
- type: 'tool_result',
44
- tool_use_id: msg.tool_call_id,
45
- content: typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content),
46
- }],
47
- });
48
- continue;
49
- }
50
-
51
- let content: any;
52
- if (typeof msg.content === 'string') {
53
- content = msg.content;
54
- } else {
55
- content = msg.content.map((part: ContentPart) => {
56
- if (part.type === 'text') {
57
- return { type: 'text', text: part.text };
58
- }
59
- if (part.type === 'image_url') {
60
- // Anthropic 需要 base64 格式
61
- const url = part.image_url.url;
62
- if (url.startsWith('data:')) {
63
- const [meta, data] = url.split(',');
64
- // 使用更安全的正则表达式,避免 ReDoS
65
- const mediaType = meta.match(/^data:([^;]+);/)?.[1] || 'image/png';
66
- return {
67
- type: 'image',
68
- source: { type: 'base64', media_type: mediaType, data },
69
- };
70
- }
71
- return {
72
- type: 'image',
73
- source: { type: 'url', url },
74
- };
75
- }
76
- return { type: 'text', text: '' };
77
- });
78
- }
79
-
80
- // 处理 tool_calls
81
- if (msg.tool_calls?.length) {
82
- const toolUseContent = msg.tool_calls.map(tc => ({
83
- type: 'tool_use',
84
- id: tc.id,
85
- name: tc.function.name,
86
- input: JSON.parse(tc.function.arguments),
87
- }));
88
-
89
- if (typeof content === 'string' && content) {
90
- content = [{ type: 'text', text: content }, ...toolUseContent];
91
- } else if (Array.isArray(content)) {
92
- content = [...content, ...toolUseContent];
93
- } else {
94
- content = toolUseContent;
95
- }
96
- }
97
-
98
- anthropicMessages.push({
99
- role: msg.role === 'assistant' ? 'assistant' : 'user',
100
- content,
101
- });
102
- }
103
-
104
- return { system, messages: anthropicMessages };
105
- }
106
-
107
- /**
108
- * 转换工具定义
109
- */
110
- function toAnthropicTools(tools?: ToolDefinition[]): any[] | undefined {
111
- if (!tools?.length) return undefined;
112
-
113
- return tools.map(tool => ({
114
- name: tool.function.name,
115
- description: tool.function.description,
116
- input_schema: tool.function.parameters,
117
- }));
118
- }
119
-
120
- /**
121
- * 转换 Anthropic 响应为 OpenAI 格式
122
- */
123
- function fromAnthropicResponse(response: any): ChatCompletionResponse {
124
- const content: ContentPart[] = [];
125
- const toolCalls: any[] = [];
126
-
127
- for (const block of response.content || []) {
128
- if (block.type === 'text') {
129
- content.push({ type: 'text', text: block.text });
130
- } else if (block.type === 'tool_use') {
131
- toolCalls.push({
132
- id: block.id,
133
- type: 'function',
134
- function: {
135
- name: block.name,
136
- arguments: JSON.stringify(block.input),
137
- },
138
- });
139
- }
140
- }
141
-
142
- const textContent = content
143
- .filter(c => c.type === 'text')
144
- .map(c => (c as { type: 'text'; text: string }).text)
145
- .join('');
146
-
147
- return {
148
- id: response.id,
149
- object: 'chat.completion',
150
- created: Date.now(),
151
- model: response.model,
152
- choices: [{
153
- index: 0,
154
- message: {
155
- role: 'assistant',
156
- content: textContent,
157
- tool_calls: toolCalls.length ? toolCalls : undefined,
158
- },
159
- finish_reason: response.stop_reason === 'tool_use' ? 'tool_calls' : 'stop',
160
- }],
161
- usage: {
162
- prompt_tokens: response.usage?.input_tokens || 0,
163
- completion_tokens: response.usage?.output_tokens || 0,
164
- total_tokens: (response.usage?.input_tokens || 0) + (response.usage?.output_tokens || 0),
165
- },
166
- };
167
- }
168
-
169
- export class AnthropicProvider extends BaseProvider {
170
- name = 'anthropic';
171
- models = [
172
- 'claude-opus-4-20250514',
173
- 'claude-sonnet-4-20250514',
174
- 'claude-3-7-sonnet-20250219',
175
- 'claude-3-5-sonnet-20241022',
176
- 'claude-3-5-haiku-20241022',
177
- 'claude-3-opus-20240229',
178
- 'claude-3-sonnet-20240229',
179
- 'claude-3-haiku-20240307',
180
- ];
181
- contextWindow: number;
182
- capabilities = { vision: true, streaming: true, toolCalling: true, thinking: false };
183
-
184
- private baseUrl: string;
185
- private anthropicVersion: string;
186
-
187
- constructor(config: AnthropicConfig = {}) {
188
- super(config);
189
- this.contextWindow = config.contextWindow ?? 200000;
190
- this.baseUrl = config.baseUrl || 'https://api.anthropic.com';
191
- this.anthropicVersion = config.anthropicVersion || '2023-06-01';
192
- if (config.models?.length) this.models = config.models;
193
- }
194
-
195
- protected async fetch<T>(url: string, options: RequestInit & { json?: any } = {}): Promise<T> {
196
- const { json, ...fetchOptions } = options;
197
-
198
- const headers: Record<string, string> = {
199
- 'Content-Type': 'application/json',
200
- 'x-api-key': this.config.apiKey || '',
201
- 'anthropic-version': this.anthropicVersion,
202
- ...this.config.headers,
203
- ...(options.headers as Record<string, string>),
204
- };
205
-
206
- const controller = new AbortController();
207
- const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
208
-
209
- try {
210
- const response = await globalThis.fetch(url, {
211
- ...fetchOptions,
212
- headers,
213
- body: json ? JSON.stringify(json) : fetchOptions.body,
214
- signal: controller.signal,
215
- });
216
-
217
- if (!response.ok) {
218
- const error = await response.text();
219
- throw new Error(`Anthropic API Error (${response.status}): ${error}`);
220
- }
221
-
222
- return response.json() as Promise<T>;
223
- } finally {
224
- clearTimeout(timeoutId);
225
- }
226
- }
227
-
228
- async chat(request: ChatCompletionRequest): Promise<ChatCompletionResponse> {
229
- const { system, messages } = toAnthropicMessages(request.messages);
230
-
231
- const anthropicRequest: any = {
232
- model: request.model,
233
- messages,
234
- max_tokens: request.max_tokens || 4096,
235
- };
236
-
237
- if (system) {
238
- anthropicRequest.system = system;
239
- }
240
-
241
- if (request.temperature !== undefined) {
242
- anthropicRequest.temperature = request.temperature;
243
- }
244
-
245
- if (request.top_p !== undefined) {
246
- anthropicRequest.top_p = request.top_p;
247
- }
248
-
249
- if (request.stop) {
250
- anthropicRequest.stop_sequences = Array.isArray(request.stop) ? request.stop : [request.stop];
251
- }
252
-
253
- const tools = toAnthropicTools(request.tools);
254
- if (tools) {
255
- anthropicRequest.tools = tools;
256
- }
257
-
258
- const response = await this.fetch<any>(`${this.baseUrl}/v1/messages`, {
259
- method: 'POST',
260
- json: anthropicRequest,
261
- });
262
-
263
- return fromAnthropicResponse(response);
264
- }
265
-
266
- async *chatStream(request: ChatCompletionRequest): AsyncIterable<ChatCompletionChunk> {
267
- const { system, messages } = toAnthropicMessages(request.messages);
268
-
269
- const anthropicRequest: any = {
270
- model: request.model,
271
- messages,
272
- max_tokens: request.max_tokens || 4096,
273
- stream: true,
274
- };
275
-
276
- if (system) {
277
- anthropicRequest.system = system;
278
- }
279
-
280
- if (request.temperature !== undefined) {
281
- anthropicRequest.temperature = request.temperature;
282
- }
283
-
284
- const tools = toAnthropicTools(request.tools);
285
- if (tools) {
286
- anthropicRequest.tools = tools;
287
- }
288
-
289
- const headers: Record<string, string> = {
290
- 'Content-Type': 'application/json',
291
- 'x-api-key': this.config.apiKey || '',
292
- 'anthropic-version': this.anthropicVersion,
293
- };
294
-
295
- const response = await globalThis.fetch(`${this.baseUrl}/v1/messages`, {
296
- method: 'POST',
297
- headers,
298
- body: JSON.stringify(anthropicRequest),
299
- });
300
-
301
- if (!response.ok) {
302
- const error = await response.text();
303
- throw new Error(`Anthropic API Error (${response.status}): ${error}`);
304
- }
305
-
306
- if (!response.body) {
307
- throw new Error('Response body is empty');
308
- }
309
-
310
- const reader = response.body.getReader();
311
- const decoder = new TextDecoder();
312
- let buffer = '';
313
- let messageId = '';
314
- let model = request.model;
315
-
316
- while (true) {
317
- const { done, value } = await reader.read();
318
- if (done) break;
319
-
320
- buffer += decoder.decode(value, { stream: true });
321
- const lines = buffer.split('\n');
322
- buffer = lines.pop() || '';
323
-
324
- for (const line of lines) {
325
- const trimmed = line.trim();
326
- if (trimmed.startsWith('data: ')) {
327
- const data = trimmed.slice(6);
328
- if (data === '[DONE]') continue;
329
-
330
- try {
331
- const event = JSON.parse(data);
332
-
333
- if (event.type === 'message_start') {
334
- messageId = event.message?.id || '';
335
- model = event.message?.model || model;
336
- } else if (event.type === 'content_block_delta') {
337
- if (event.delta?.type === 'text_delta') {
338
- yield {
339
- id: messageId,
340
- object: 'chat.completion.chunk',
341
- created: Date.now(),
342
- model,
343
- choices: [{
344
- index: 0,
345
- delta: { content: event.delta.text },
346
- finish_reason: null,
347
- }],
348
- };
349
- }
350
- } else if (event.type === 'message_delta') {
351
- yield {
352
- id: messageId,
353
- object: 'chat.completion.chunk',
354
- created: Date.now(),
355
- model,
356
- choices: [{
357
- index: 0,
358
- delta: {},
359
- finish_reason: event.delta?.stop_reason === 'tool_use' ? 'tool_calls' : 'stop',
360
- }],
361
- usage: event.usage ? {
362
- prompt_tokens: event.usage.input_tokens || 0,
363
- completion_tokens: event.usage.output_tokens || 0,
364
- total_tokens: (event.usage.input_tokens || 0) + (event.usage.output_tokens || 0),
365
- } : undefined,
366
- };
367
- }
368
- } catch {
369
- // 忽略解析错误
370
- }
371
- }
372
- }
373
- }
374
- }
375
-
376
- async listModels(): Promise<string[]> {
377
- return this.models;
378
- }
379
- }
@@ -1,175 +0,0 @@
1
- /**
2
- * @zhin.js/ai - Base Provider
3
- * AI Provider 抽象基类
4
- */
5
-
6
- import type {
7
- AIProvider,
8
- ProviderConfig,
9
- ChatCompletionRequest,
10
- ChatCompletionResponse,
11
- ChatCompletionChunk,
12
- } from '../types.js';
13
-
14
- /**
15
- * Provider 基类
16
- * 提供通用的 HTTP 请求和流式解析能力
17
- */
18
- export abstract class BaseProvider implements AIProvider {
19
- abstract name: string;
20
- abstract models: string[];
21
-
22
- protected config: ProviderConfig;
23
- protected abortControllers: Map<string, AbortController> = new Map();
24
-
25
- constructor(config: ProviderConfig = {}) {
26
- this.config = {
27
- timeout: 60000,
28
- maxRetries: 3,
29
- ...config,
30
- };
31
- }
32
-
33
- abstract chat(request: ChatCompletionRequest): Promise<ChatCompletionResponse>;
34
- abstract chatStream(request: ChatCompletionRequest): AsyncIterable<ChatCompletionChunk>;
35
-
36
- /**
37
- * 发送 HTTP 请求
38
- */
39
- protected async fetch<T>(
40
- url: string,
41
- options: RequestInit & { json?: any } = {}
42
- ): Promise<T> {
43
- const { json, ...fetchOptions } = options;
44
-
45
- const headers: Record<string, string> = {
46
- 'Content-Type': 'application/json',
47
- ...this.config.headers,
48
- ...(options.headers as Record<string, string>),
49
- };
50
-
51
- if (this.config.apiKey) {
52
- const scheme = this.config.authScheme !== undefined ? this.config.authScheme : 'Bearer ';
53
- headers['Authorization'] = scheme + this.config.apiKey;
54
- }
55
-
56
- const controller = new AbortController();
57
- const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
58
-
59
- try {
60
- const response = await fetch(url, {
61
- ...fetchOptions,
62
- headers,
63
- body: json ? JSON.stringify(json) : fetchOptions.body,
64
- signal: controller.signal,
65
- });
66
-
67
- if (!response.ok) {
68
- const error = await response.text();
69
- throw new Error(`API Error (${response.status}): ${error}`);
70
- }
71
-
72
- return response.json() as Promise<T>;
73
- } finally {
74
- clearTimeout(timeoutId);
75
- }
76
- }
77
-
78
- /**
79
- * 发送流式请求
80
- */
81
- protected async *fetchStream(
82
- url: string,
83
- options: RequestInit & { json?: any } = {}
84
- ): AsyncIterable<string> {
85
- const { json, ...fetchOptions } = options;
86
-
87
- const headers: Record<string, string> = {
88
- 'Content-Type': 'application/json',
89
- Accept: 'text/event-stream',
90
- ...this.config.headers,
91
- ...(options.headers as Record<string, string>),
92
- };
93
-
94
- if (this.config.apiKey) {
95
- const scheme = this.config.authScheme !== undefined ? this.config.authScheme : 'Bearer ';
96
- headers['Authorization'] = scheme + this.config.apiKey;
97
- }
98
-
99
- const controller = new AbortController();
100
- const requestId = Math.random().toString(36).slice(2);
101
- this.abortControllers.set(requestId, controller);
102
-
103
- try {
104
- const response = await fetch(url, {
105
- ...fetchOptions,
106
- headers,
107
- body: json ? JSON.stringify(json) : fetchOptions.body,
108
- signal: controller.signal,
109
- });
110
-
111
- if (!response.ok) {
112
- const error = await response.text();
113
- throw new Error(`API Error (${response.status}): ${error}`);
114
- }
115
-
116
- if (!response.body) {
117
- throw new Error('Response body is empty');
118
- }
119
-
120
- const reader = response.body.getReader();
121
- const decoder = new TextDecoder();
122
- let buffer = '';
123
-
124
- while (true) {
125
- const { done, value } = await reader.read();
126
- if (done) break;
127
-
128
- buffer += decoder.decode(value, { stream: true });
129
- const lines = buffer.split('\n');
130
- buffer = lines.pop() || '';
131
-
132
- for (const line of lines) {
133
- const trimmed = line.trim();
134
- if (trimmed.startsWith('data: ')) {
135
- const data = trimmed.slice(6);
136
- if (data !== '[DONE]') {
137
- yield data;
138
- }
139
- }
140
- }
141
- }
142
- } finally {
143
- this.abortControllers.delete(requestId);
144
- }
145
- }
146
-
147
- /**
148
- * 取消所有进行中的请求
149
- */
150
- cancelAll(): void {
151
- for (const controller of this.abortControllers.values()) {
152
- controller.abort();
153
- }
154
- this.abortControllers.clear();
155
- }
156
-
157
- /**
158
- * 健康检查
159
- */
160
- async healthCheck(): Promise<boolean> {
161
- try {
162
- await this.listModels?.();
163
- return true;
164
- } catch {
165
- return false;
166
- }
167
- }
168
-
169
- /**
170
- * 列出可用模型(子类可覆盖)
171
- */
172
- async listModels(): Promise<string[]> {
173
- return this.models;
174
- }
175
- }
@@ -1,13 +0,0 @@
1
- /**
2
- * @zhin.js/ai - Providers Index
3
- * 导出所有 Provider
4
- */
5
-
6
- export { BaseProvider } from './base.js';
7
- export { OpenAIProvider, DeepSeekProvider, MoonshotProvider, ZhipuProvider } from './openai.js';
8
- export { AnthropicProvider } from './anthropic.js';
9
- export { OllamaProvider } from './ollama.js';
10
-
11
- export type { OpenAIConfig } from './openai.js';
12
- export type { AnthropicConfig } from './anthropic.js';
13
- export type { OllamaConfig } from './ollama.js';