@zhin.js/core 1.0.57 → 1.1.2

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 (126) 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/ai/index.d.ts +2 -0
  6. package/lib/ai/index.d.ts.map +1 -1
  7. package/lib/ai/index.js +1 -0
  8. package/lib/ai/index.js.map +1 -1
  9. package/lib/built/adapter-process.d.ts +0 -4
  10. package/lib/built/adapter-process.d.ts.map +1 -1
  11. package/lib/built/adapter-process.js +0 -95
  12. package/lib/built/adapter-process.js.map +1 -1
  13. package/lib/built/agent-preset.d.ts +2 -0
  14. package/lib/built/agent-preset.d.ts.map +1 -1
  15. package/lib/built/agent-preset.js +4 -0
  16. package/lib/built/agent-preset.js.map +1 -1
  17. package/lib/built/command.d.ts +4 -0
  18. package/lib/built/command.d.ts.map +1 -1
  19. package/lib/built/command.js +6 -0
  20. package/lib/built/command.js.map +1 -1
  21. package/lib/built/component.d.ts.map +1 -1
  22. package/lib/built/component.js +1 -0
  23. package/lib/built/component.js.map +1 -1
  24. package/lib/built/dispatcher.d.ts.map +1 -1
  25. package/lib/built/dispatcher.js +0 -13
  26. package/lib/built/dispatcher.js.map +1 -1
  27. package/lib/built/message-filter.d.ts +2 -0
  28. package/lib/built/message-filter.d.ts.map +1 -1
  29. package/lib/built/message-filter.js +5 -0
  30. package/lib/built/message-filter.js.map +1 -1
  31. package/lib/built/skill.d.ts +11 -0
  32. package/lib/built/skill.d.ts.map +1 -1
  33. package/lib/built/skill.js +14 -0
  34. package/lib/built/skill.js.map +1 -1
  35. package/lib/built/tool.d.ts +11 -44
  36. package/lib/built/tool.d.ts.map +1 -1
  37. package/lib/built/tool.js +14 -353
  38. package/lib/built/tool.js.map +1 -1
  39. package/lib/plugin.d.ts +1 -25
  40. package/lib/plugin.d.ts.map +1 -1
  41. package/lib/plugin.js +1 -77
  42. package/lib/plugin.js.map +1 -1
  43. package/lib/types.d.ts +0 -25
  44. package/lib/types.d.ts.map +1 -1
  45. package/package.json +10 -7
  46. package/CHANGELOG.md +0 -538
  47. package/REFACTORING_COMPLETE.md +0 -178
  48. package/REFACTORING_STATUS.md +0 -263
  49. package/src/adapter.ts +0 -275
  50. package/src/ai/index.ts +0 -52
  51. package/src/ai/providers/anthropic.ts +0 -379
  52. package/src/ai/providers/base.ts +0 -175
  53. package/src/ai/providers/index.ts +0 -13
  54. package/src/ai/providers/ollama.ts +0 -302
  55. package/src/ai/providers/openai.ts +0 -174
  56. package/src/ai/types.ts +0 -348
  57. package/src/bot.ts +0 -37
  58. package/src/built/adapter-process.ts +0 -177
  59. package/src/built/agent-preset.ts +0 -136
  60. package/src/built/ai-trigger.ts +0 -259
  61. package/src/built/command.ts +0 -108
  62. package/src/built/common-adapter-tools.ts +0 -242
  63. package/src/built/component.ts +0 -130
  64. package/src/built/config.ts +0 -335
  65. package/src/built/cron.ts +0 -156
  66. package/src/built/database.ts +0 -134
  67. package/src/built/dispatcher.ts +0 -496
  68. package/src/built/login-assist.ts +0 -131
  69. package/src/built/message-filter.ts +0 -390
  70. package/src/built/permission.ts +0 -151
  71. package/src/built/schema-feature.ts +0 -190
  72. package/src/built/skill.ts +0 -221
  73. package/src/built/tool.ts +0 -948
  74. package/src/command.ts +0 -87
  75. package/src/component.ts +0 -565
  76. package/src/cron.ts +0 -4
  77. package/src/errors.ts +0 -46
  78. package/src/feature.ts +0 -7
  79. package/src/index.ts +0 -53
  80. package/src/jsx-dev-runtime.ts +0 -2
  81. package/src/jsx-runtime.ts +0 -12
  82. package/src/jsx.ts +0 -135
  83. package/src/message.ts +0 -48
  84. package/src/models/system-log.ts +0 -20
  85. package/src/models/user.ts +0 -15
  86. package/src/notice.ts +0 -98
  87. package/src/plugin.ts +0 -896
  88. package/src/prompt.ts +0 -293
  89. package/src/request.ts +0 -95
  90. package/src/scheduler/index.ts +0 -19
  91. package/src/scheduler/scheduler.ts +0 -372
  92. package/src/scheduler/types.ts +0 -74
  93. package/src/tool-zod.ts +0 -115
  94. package/src/types-generator.ts +0 -78
  95. package/src/types.ts +0 -505
  96. package/src/utils.ts +0 -227
  97. package/tests/adapter.test.ts +0 -638
  98. package/tests/ai/ai-trigger.test.ts +0 -368
  99. package/tests/ai/providers.integration.test.ts +0 -227
  100. package/tests/ai/setup.ts +0 -308
  101. package/tests/ai/tool.test.ts +0 -800
  102. package/tests/bot.test.ts +0 -151
  103. package/tests/command.test.ts +0 -737
  104. package/tests/component-new.test.ts +0 -361
  105. package/tests/config.test.ts +0 -372
  106. package/tests/cron.test.ts +0 -82
  107. package/tests/dispatcher.test.ts +0 -293
  108. package/tests/errors.test.ts +0 -21
  109. package/tests/expression-evaluation.test.ts +0 -258
  110. package/tests/features-builtin.test.ts +0 -191
  111. package/tests/jsx-runtime.test.ts +0 -45
  112. package/tests/jsx.test.ts +0 -319
  113. package/tests/message-filter.test.ts +0 -566
  114. package/tests/message.test.ts +0 -402
  115. package/tests/notice.test.ts +0 -198
  116. package/tests/plugin.test.ts +0 -779
  117. package/tests/prompt.test.ts +0 -78
  118. package/tests/redos-protection.test.ts +0 -198
  119. package/tests/request.test.ts +0 -221
  120. package/tests/schema.test.ts +0 -248
  121. package/tests/skill-feature.test.ts +0 -179
  122. package/tests/test-utils.ts +0 -59
  123. package/tests/tool-feature.test.ts +0 -254
  124. package/tests/types.test.ts +0 -162
  125. package/tests/utils.test.ts +0 -135
  126. 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';