@aalis/plugin-llm-ollama 0.9.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ace Nyan <ace@acenyan.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,20 @@
1
+ # @aalis/plugin-llm-ollama
2
+
3
+ Ollama 本地 LLM 提供者
4
+ ## 角色
5
+
6
+ 运行时插件
7
+
8
+ ## 安装
9
+
10
+ ```bash
11
+ pnpm add @aalis/plugin-llm-ollama
12
+ ```
13
+
14
+ ## 文档
15
+
16
+ 详见 [docs/plugins/plugin-llm-ollama.md](../../docs/plugins/plugin-llm-ollama.md)。
17
+
18
+ ## 许可
19
+
20
+ 见仓库根目录 LICENSE。
@@ -0,0 +1,25 @@
1
+ import type { Context } from '@aalis/core';
2
+ import type { ConfigSchema } from '@aalis/schema-config';
3
+ export declare const name = "@aalis/plugin-llm-ollama";
4
+ export declare const displayName = "Ollama";
5
+ export declare const subsystem = "llm";
6
+ export declare const provides: string[];
7
+ export declare const inject: {
8
+ optional: string[];
9
+ };
10
+ export declare const reusable = true;
11
+ export declare const configSchema: ConfigSchema;
12
+ export declare const defaultConfig: {
13
+ baseUrl: string;
14
+ customModels: string;
15
+ modelCapabilities: string;
16
+ providerCapabilities: string;
17
+ timeout: number;
18
+ temperature: number;
19
+ maxTokens: number;
20
+ contextLength: number;
21
+ keepAlive: string;
22
+ thinking: boolean;
23
+ };
24
+ export declare function apply(ctx: Context, config: Record<string, unknown>): Promise<void>;
25
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAU,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAOzD,eAAO,MAAM,IAAI,6BAA6B,CAAC;AAC/C,eAAO,MAAM,WAAW,WAAW,CAAC;AACpC,eAAO,MAAM,SAAS,QAAQ,CAAC;AAC/B,eAAO,MAAM,QAAQ,UAAU,CAAC;AAChC,eAAO,MAAM,MAAM;;CAA4B,CAAC;AAChD,eAAO,MAAM,QAAQ,OAAO,CAAC;AAE7B,eAAO,MAAM,YAAY,EAAE,YAsD1B,CAAC;AAEF,eAAO,MAAM,aAAa;;;;;;;;;;;CAWzB,CAAC;AAk7BF,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAmHxF"}
package/dist/index.js ADDED
@@ -0,0 +1,1003 @@
1
+ import { LLMCapabilities } from '@aalis/api-llm';
2
+ import { createProcessGateway } from '@aalis/api-process';
3
+ import { prepareLLMMessages, toLLMRole } from '@aalis/schema-message';
4
+ import { safeFetch } from '@aalis/util-network-guard';
5
+ // ===== 插件元数据 =====
6
+ export const name = '@aalis/plugin-llm-ollama';
7
+ export const displayName = 'Ollama';
8
+ export const subsystem = 'llm';
9
+ export const provides = ['llm'];
10
+ export const inject = { optional: ['process'] };
11
+ export const reusable = true;
12
+ export const configSchema = {
13
+ baseUrl: {
14
+ type: 'string',
15
+ label: 'Ollama 地址',
16
+ default: 'http://localhost:11434',
17
+ description: '本地 Ollama 服务的 HTTP 地址',
18
+ },
19
+ customModels: {
20
+ type: 'textarea',
21
+ label: '自定义模型',
22
+ default: '',
23
+ description: '手动添加的模型名称(每行一个或逗号分隔)。用于补充自动发现列表中未出现的模型。与自动发现重复时会提示去重。',
24
+ },
25
+ modelCapabilities: {
26
+ type: 'textarea',
27
+ label: '单模型能力覆盖',
28
+ default: '',
29
+ description: '强制覆盖某模型的能力(优先级最高,高于 /api/show 自动探测与家族表),与 adapter 默认能力取并集。\n格式:`<modelId>: <cap1>,<cap2>,...`,每行一条。如:nemotron3:33b: chat,vision,tool_calling',
30
+ },
31
+ providerCapabilities: {
32
+ type: 'string',
33
+ label: '适配器默认能力(逗号分隔)',
34
+ default: '',
35
+ description: '兜底默认能力:仅当某模型既无法从 Ollama /api/show 探测、又不在内置家族表时才使用。能力现已自动探测,通常留空即可(填了反而可能给不支持的模型乱标能力)。例:chat,tool_calling,streaming',
36
+ },
37
+ timeout: {
38
+ type: 'number',
39
+ label: '请求超时 (秒)',
40
+ default: 120,
41
+ description: 'LLM 请求超时时间(秒)。大模型或长上下文建议适当调大。0 = 不限制。',
42
+ },
43
+ temperature: { type: 'number', label: '温度', default: 0.7, description: '0-2,越高越随机' },
44
+ maxTokens: {
45
+ type: 'number',
46
+ label: '最大 Token',
47
+ default: 4096,
48
+ description: '单次回复最大生成 token 数(num_predict)',
49
+ },
50
+ contextLength: { type: 'number', label: '上下文长度', default: 8192, description: '模型上下文窗口大小(num_ctx)' },
51
+ keepAlive: {
52
+ type: 'string',
53
+ label: '模型保活时间',
54
+ default: '5m',
55
+ description: '模型在显存中保留的时间,如 5m、1h、0(立即卸载)',
56
+ },
57
+ thinking: {
58
+ type: 'boolean',
59
+ label: '启用思考',
60
+ default: true,
61
+ description: '为支持思考的模型启用扩展思考(think 参数)。无 thinking 能力的模型该参数无效。',
62
+ },
63
+ };
64
+ export const defaultConfig = {
65
+ baseUrl: 'http://localhost:11434',
66
+ customModels: '',
67
+ modelCapabilities: '',
68
+ providerCapabilities: '',
69
+ timeout: 120,
70
+ temperature: 0.7,
71
+ maxTokens: 4096,
72
+ contextLength: 8192,
73
+ keepAlive: '5m',
74
+ thinking: true,
75
+ };
76
+ // ===== <think> 标签解析辅助 =====
77
+ /**
78
+ * 检查 text 末尾是否有不完整的 tag 前缀。
79
+ * 返回匹配到的部分长度(0 = 无匹配)。
80
+ *
81
+ * 例如 findPartialTag("hello<th", "<think>") → 3(匹配 "<th")
82
+ */
83
+ function findPartialTag(text, tag) {
84
+ // 从 tag 长度 -1 开始向下检查,直到 1
85
+ const maxCheck = Math.min(tag.length - 1, text.length);
86
+ for (let len = maxCheck; len >= 1; len--) {
87
+ if (text.endsWith(tag.slice(0, len)))
88
+ return len;
89
+ }
90
+ return 0;
91
+ }
92
+ /**
93
+ * 从完整文本中提取 <think>...</think> 内容。
94
+ * 返回 { reasoning, content },reasoning 为思考内容,content 为剩余内容。
95
+ */
96
+ function extractThinkTags(text) {
97
+ let reasoning = '';
98
+ let content = '';
99
+ let remaining = text;
100
+ while (remaining.length > 0) {
101
+ const openIdx = remaining.indexOf('<think>');
102
+ if (openIdx === -1) {
103
+ content += remaining;
104
+ break;
105
+ }
106
+ content += remaining.slice(0, openIdx);
107
+ remaining = remaining.slice(openIdx + 7);
108
+ const closeIdx = remaining.indexOf('</think>');
109
+ if (closeIdx === -1) {
110
+ // 未闭合的 think 标签,剩余全部视为 reasoning
111
+ reasoning += remaining;
112
+ break;
113
+ }
114
+ reasoning += remaining.slice(0, closeIdx);
115
+ remaining = remaining.slice(closeIdx + 8);
116
+ }
117
+ return { reasoning, content };
118
+ }
119
+ // ===== Ollama 客户端(共享底层 fetch 封装,多个 ModelHandle 复用) =====
120
+ class OllamaClient {
121
+ baseUrl;
122
+ timeout;
123
+ temperature;
124
+ maxTokens;
125
+ contextLength;
126
+ keepAlive;
127
+ logger;
128
+ proc;
129
+ constructor(config, logger, proc) {
130
+ this.baseUrl = config.baseUrl.replace(/\/$/, '');
131
+ // schema 中 timeout 单位为「秒」,存储为毫秒;0 视为不限制 → 用一个非常大的值
132
+ this.timeout = config.timeout && config.timeout > 0 ? config.timeout * 1000 : 2_147_483_647;
133
+ this.temperature = config.temperature;
134
+ this.maxTokens = config.maxTokens;
135
+ this.contextLength = config.contextLength;
136
+ this.keepAlive = config.keepAlive;
137
+ this.logger = logger;
138
+ this.proc = proc;
139
+ }
140
+ /** 发现远端模型 id 列表 */
141
+ async fetchRemoteModelIds() {
142
+ try {
143
+ const res = await fetch(`${this.baseUrl}/api/tags`);
144
+ if (!res.ok)
145
+ return [];
146
+ const data = (await res.json());
147
+ return data.models.map(m => m.name);
148
+ }
149
+ catch {
150
+ return [];
151
+ }
152
+ }
153
+ /**
154
+ * 查某模型的真实能力(Ollama /api/show 的 `capabilities`,如 completion/vision/audio/tools/thinking)。
155
+ * 失败返回 null → 调用方回退家族表。fetch 不读 proxy 环境变量,本机调用不受 SOCKS 影响。
156
+ */
157
+ async fetchModelCapabilities(modelId) {
158
+ try {
159
+ const res = await fetch(`${this.baseUrl}/api/show`, {
160
+ method: 'POST',
161
+ headers: { 'Content-Type': 'application/json' },
162
+ body: JSON.stringify({ model: modelId }),
163
+ signal: AbortSignal.timeout(10000),
164
+ });
165
+ if (!res.ok)
166
+ return null;
167
+ const data = (await res.json());
168
+ return Array.isArray(data.capabilities) ? data.capabilities : null;
169
+ }
170
+ catch {
171
+ return null;
172
+ }
173
+ }
174
+ async chat(model, request, defaultThinking) {
175
+ // 包含音频输入 → 改走 OpenAI 兼容的 /v1/chat/completions(/api/chat 不支持 audios)
176
+ if (request.messages.some(m => m.audios && m.audios.length > 0)) {
177
+ return this.chatOpenAIWithAudio(model, request);
178
+ }
179
+ // 与 chatStream 一致先走 prepareLLMMessages(归一 role + 拼 kind/自定义 role 内容前缀),否则非流式丢
180
+ // [系统通知]/[跨会话委派] 等前缀。
181
+ const messages = await Promise.all(prepareLLMMessages(request.messages).map(m => this.toOllamaMessage(m)));
182
+ const tools = request.tools?.map(t => this.toOllamaTool(t));
183
+ const body = {
184
+ model,
185
+ messages,
186
+ stream: false,
187
+ options: {
188
+ temperature: request.temperature ?? this.temperature,
189
+ num_predict: request.maxTokens ?? this.maxTokens,
190
+ num_ctx: this.contextLength,
191
+ },
192
+ keep_alive: this.keepAlive,
193
+ };
194
+ if (tools && tools.length > 0) {
195
+ body.tools = tools;
196
+ }
197
+ // 启用原生思考模式(Ollama API think 参数)
198
+ // 调用方可通过 request.think === false 显式关闭
199
+ // 必须显式传 think:false 才能关闭 gemma4:31b 等原生 thinking 模型的思考;
200
+ // 仅省略字段会被模型默认启用思考,导致 content 为空。
201
+ const shouldThink = request.think !== undefined ? request.think : defaultThinking;
202
+ body.think = shouldThink;
203
+ this.logger.debug(`请求 Ollama${shouldThink ? ' [think]' : ''}: ${body.model}, ${messages.length} 条消息, ${tools?.length ?? 0} 个工具`);
204
+ const signals = [AbortSignal.timeout(this.timeout)];
205
+ if (request.signal)
206
+ signals.push(request.signal);
207
+ const response = await fetch(`${this.baseUrl}/api/chat`, {
208
+ method: 'POST',
209
+ headers: { 'Content-Type': 'application/json' },
210
+ body: JSON.stringify(body),
211
+ signal: AbortSignal.any(signals),
212
+ });
213
+ if (!response.ok) {
214
+ const errorText = await response.text();
215
+ throw new Error(`Ollama API 错误 (${response.status}): ${errorText}`);
216
+ }
217
+ const data = (await response.json());
218
+ // 优先使用原生 thinking 字段(Ollama think API),回退到 <think> 标签解析
219
+ const nativeThinking = data.message.thinking || '';
220
+ const rawContent = data.message.content || '';
221
+ const { reasoning: tagReasoning, content: cleanContent } = extractThinkTags(rawContent);
222
+ const allReasoning = [nativeThinking, tagReasoning].filter(Boolean).join('');
223
+ const result = {
224
+ content: cleanContent || null,
225
+ reasoningContent: allReasoning || null,
226
+ };
227
+ if (data.message.tool_calls && data.message.tool_calls.length > 0) {
228
+ result.toolCalls = data.message.tool_calls.map((tc, i) => ({
229
+ id: `call_ollama_${Date.now()}_${i}`,
230
+ type: 'function',
231
+ function: {
232
+ name: tc.function.name,
233
+ arguments: JSON.stringify(tc.function.arguments),
234
+ },
235
+ }));
236
+ }
237
+ if (data.prompt_eval_count != null || data.eval_count != null) {
238
+ const promptTokens = data.prompt_eval_count ?? 0;
239
+ const completionTokens = data.eval_count ?? 0;
240
+ result.usage = {
241
+ promptTokens,
242
+ completionTokens,
243
+ totalTokens: promptTokens + completionTokens,
244
+ };
245
+ }
246
+ return result;
247
+ }
248
+ async *chatStream(model, request, defaultThinking) {
249
+ // 包含音频输入 → 回退为非流式(OpenAI compat 路径不支持 SSE 交互)后以单 chunk 交付。
250
+ if (request.messages.some(m => m.audios && m.audios.length > 0)) {
251
+ const r = await this.chatOpenAIWithAudio(model, request);
252
+ yield {
253
+ contentDelta: r.content ?? '',
254
+ reasoningDelta: r.reasoningContent ?? '',
255
+ usage: r.usage,
256
+ done: true,
257
+ };
258
+ return;
259
+ }
260
+ const messages = await Promise.all(prepareLLMMessages(request.messages).map(m => this.toOllamaMessage(m)));
261
+ const tools = request.tools?.map(t => this.toOllamaTool(t));
262
+ const body = {
263
+ model,
264
+ messages,
265
+ stream: true,
266
+ options: {
267
+ temperature: request.temperature ?? this.temperature,
268
+ num_predict: request.maxTokens ?? this.maxTokens,
269
+ num_ctx: this.contextLength,
270
+ },
271
+ keep_alive: this.keepAlive,
272
+ };
273
+ if (tools && tools.length > 0) {
274
+ body.tools = tools;
275
+ }
276
+ // 启用原生思考模式(调用方可通过 request.think === false 显式关闭)
277
+ // 必须显式传 think:false 才能关闭原生 thinking 模型的思考。
278
+ const shouldThink = request.think !== undefined ? request.think : defaultThinking;
279
+ body.think = shouldThink;
280
+ this.logger.debug(`流式请求 Ollama${shouldThink ? ' [think]' : ''}: ${body.model}, ${messages.length} 条消息`);
281
+ const signals = [AbortSignal.timeout(this.timeout)];
282
+ if (request.signal)
283
+ signals.push(request.signal);
284
+ const reqStart = Date.now();
285
+ const slowConnectTimer = setTimeout(() => {
286
+ this.logger.warn(`Ollama 连接慢:已等待 15s 仍未收到响应头 (url=${this.baseUrl}/api/chat)`);
287
+ }, 15_000);
288
+ let response;
289
+ try {
290
+ response = await fetch(`${this.baseUrl}/api/chat`, {
291
+ method: 'POST',
292
+ headers: { 'Content-Type': 'application/json' },
293
+ body: JSON.stringify(body),
294
+ signal: AbortSignal.any(signals),
295
+ });
296
+ }
297
+ catch (err) {
298
+ clearTimeout(slowConnectTimer);
299
+ const elapsed = Date.now() - reqStart;
300
+ const msg = err instanceof Error ? err.message : String(err);
301
+ this.logger.warn(`Ollama fetch 失败 (耗时 ${elapsed}ms): ${msg}`);
302
+ throw err;
303
+ }
304
+ clearTimeout(slowConnectTimer);
305
+ this.logger.debug(`Ollama 响应头到达: status=${response.status}, 耗时 ${Date.now() - reqStart}ms`);
306
+ if (!response.ok) {
307
+ const errorText = await response.text();
308
+ throw new Error(`Ollama API 错误 (${response.status}): ${errorText}`);
309
+ }
310
+ if (!response.body) {
311
+ throw new Error('Ollama API 返回了空的响应体,无法进行流式读取');
312
+ }
313
+ const reader = response.body.getReader();
314
+ const decoder = new TextDecoder();
315
+ let buffer = '';
316
+ const toolCallBuffers = [];
317
+ // <think> 标签流式解析状态
318
+ let inThink = false; // 当前是否在 <think> 块内
319
+ let tagBuffer = ''; // 未确定的部分标签缓冲(如 "<", "<th", "</thi" 等)
320
+ let firstChunkLogged = false;
321
+ const streamStart = Date.now();
322
+ const streamStallTimer = setTimeout(() => {
323
+ if (!firstChunkLogged) {
324
+ this.logger.warn(`Ollama 流停滞:响应头已到但 30s 仍未收到首帧`);
325
+ }
326
+ }, 30_000);
327
+ try {
328
+ while (true) {
329
+ const { done, value } = await reader.read();
330
+ if (done)
331
+ break;
332
+ if (!firstChunkLogged) {
333
+ firstChunkLogged = true;
334
+ clearTimeout(streamStallTimer);
335
+ this.logger.debug(`Ollama 首帧到达: 耗时 ${Date.now() - streamStart}ms (从响应头算起)`);
336
+ }
337
+ buffer += decoder.decode(value, { stream: true });
338
+ const lines = buffer.split('\n');
339
+ buffer = lines.pop();
340
+ for (const line of lines) {
341
+ const trimmed = line.trim();
342
+ if (!trimmed)
343
+ continue;
344
+ try {
345
+ const data = JSON.parse(trimmed);
346
+ // 累积工具调用
347
+ if (data.message?.tool_calls) {
348
+ toolCallBuffers.push(...data.message.tool_calls);
349
+ // Ollama 是非增量地一次性返回 tool_calls,但我们仍 emit 一次 progress
350
+ // 让上层 UI 知道「已检测到工具调用」(与 OpenAI/DeepSeek 行为对齐)
351
+ for (let i = 0; i < data.message.tool_calls.length; i++) {
352
+ const tc = data.message.tool_calls[i];
353
+ yield {
354
+ toolCallProgress: {
355
+ index: toolCallBuffers.length - data.message.tool_calls.length + i,
356
+ name: tc.function.name,
357
+ charsAccumulated: JSON.stringify(tc.function.arguments).length,
358
+ },
359
+ };
360
+ }
361
+ }
362
+ if (data.done) {
363
+ // 刷出残留的 tagBuffer
364
+ if (tagBuffer) {
365
+ if (inThink)
366
+ yield { reasoningDelta: tagBuffer };
367
+ else
368
+ yield { contentDelta: tagBuffer };
369
+ tagBuffer = '';
370
+ }
371
+ // 最后一个 chunk
372
+ const chunk = { done: true };
373
+ if (toolCallBuffers.length > 0) {
374
+ chunk.toolCalls = toolCallBuffers.map((tc, i) => ({
375
+ id: `call_ollama_${Date.now()}_${i}`,
376
+ type: 'function',
377
+ function: {
378
+ name: tc.function.name,
379
+ arguments: JSON.stringify(tc.function.arguments),
380
+ },
381
+ }));
382
+ }
383
+ if (data.prompt_eval_count != null || data.eval_count != null) {
384
+ const promptTokens = data.prompt_eval_count ?? 0;
385
+ const completionTokens = data.eval_count ?? 0;
386
+ chunk.usage = {
387
+ promptTokens,
388
+ completionTokens,
389
+ totalTokens: promptTokens + completionTokens,
390
+ };
391
+ }
392
+ yield chunk;
393
+ return;
394
+ }
395
+ // 原生 thinking 字段(Ollama think API)—— 优先级高于 <think> 标签解析
396
+ if (data.message?.thinking) {
397
+ yield { reasoningDelta: data.message.thinking };
398
+ }
399
+ if (data.message?.content) {
400
+ // 解析 <think> / </think> 标签,将内部内容路由为 reasoningDelta
401
+ let text = tagBuffer + data.message.content;
402
+ tagBuffer = '';
403
+ while (text.length > 0) {
404
+ if (inThink) {
405
+ // 在 think 块内:查找 </think>
406
+ const closeIdx = text.indexOf('</think>');
407
+ if (closeIdx !== -1) {
408
+ // 找到关闭标签
409
+ const reasoning = text.slice(0, closeIdx);
410
+ if (reasoning)
411
+ yield { reasoningDelta: reasoning };
412
+ text = text.slice(closeIdx + 8); // '</think>'.length === 8
413
+ inThink = false;
414
+ }
415
+ else {
416
+ // 未找到完整关闭标签,检查末尾是否有不完整的 "</thi..." 等
417
+ const partialClose = findPartialTag(text, '</think>');
418
+ if (partialClose > 0) {
419
+ const safe = text.slice(0, text.length - partialClose);
420
+ tagBuffer = text.slice(text.length - partialClose);
421
+ if (safe)
422
+ yield { reasoningDelta: safe };
423
+ }
424
+ else {
425
+ yield { reasoningDelta: text };
426
+ }
427
+ text = '';
428
+ }
429
+ }
430
+ else {
431
+ // 不在 think 块:查找 <think>
432
+ const openIdx = text.indexOf('<think>');
433
+ if (openIdx !== -1) {
434
+ // 找到开启标签
435
+ const before = text.slice(0, openIdx);
436
+ if (before)
437
+ yield { contentDelta: before };
438
+ text = text.slice(openIdx + 7); // '<think>'.length === 7
439
+ inThink = true;
440
+ }
441
+ else {
442
+ // 未找到完整开启标签,检查末尾是否有不完整的 "<thi..." 等
443
+ const partialOpen = findPartialTag(text, '<think>');
444
+ if (partialOpen > 0) {
445
+ const safe = text.slice(0, text.length - partialOpen);
446
+ tagBuffer = text.slice(text.length - partialOpen);
447
+ if (safe)
448
+ yield { contentDelta: safe };
449
+ }
450
+ else {
451
+ yield { contentDelta: text };
452
+ }
453
+ text = '';
454
+ }
455
+ }
456
+ }
457
+ }
458
+ }
459
+ catch {
460
+ /* skip malformed JSON */
461
+ }
462
+ }
463
+ }
464
+ }
465
+ finally {
466
+ clearTimeout(streamStallTimer);
467
+ reader.releaseLock();
468
+ }
469
+ // 流意外结束时补发 done
470
+ const finalChunk = { done: true };
471
+ if (toolCallBuffers.length > 0) {
472
+ finalChunk.toolCalls = toolCallBuffers.map((tc, i) => ({
473
+ id: `call_${i}`,
474
+ type: 'function',
475
+ function: {
476
+ name: tc.function.name,
477
+ arguments: JSON.stringify(tc.function.arguments),
478
+ },
479
+ }));
480
+ }
481
+ yield finalChunk;
482
+ }
483
+ /**
484
+ * 将图片字符串解析为 Ollama 所需的纯 base64 格式。
485
+ * 支持 data URI、HTTP(S) URL、纯 base64、文件路径。
486
+ * 返回 null 表示图片无法获取。
487
+ */
488
+ resolveImage(img) {
489
+ return this.resolveBinary(img, 'image');
490
+ }
491
+ /**
492
+ * 通用二进制资源解析(图片 / 音频)。
493
+ * 支持 data URI、HTTP(S) URL、纯 base64、文件路径。返回 null 表示获取失败。
494
+ * 所有返回都会去除空白字符(Ollama 校验时不容忍 base64 内的换行/空格,
495
+ * 否则会返回 `illegal base64 data at input byte N` 错误)。
496
+ */
497
+ async resolveBinary(data, label) {
498
+ const sanitize = (b64) => b64.replace(/[\s\r\n]+/g, '');
499
+ const trimmed = data.trim();
500
+ // data URI → 提取 base64(兼容多参数格式如 data:image/png;charset=utf-8;base64,...)
501
+ const dataMatch = trimmed.match(/^data:[^,]*;base64,(.+)$/);
502
+ if (dataMatch)
503
+ return sanitize(dataMatch[1]);
504
+ // HTTP(S) URL → 下载并转 base64
505
+ if (/^https?:\/\//i.test(trimmed)) {
506
+ try {
507
+ const res = await safeFetch(trimmed, { signal: AbortSignal.timeout(30000) });
508
+ if (!res.ok) {
509
+ this.logger.warn(`下载${label === 'image' ? '图片' : '音频'}失败 (${res.status}): ${trimmed}`);
510
+ return null;
511
+ }
512
+ const buf = Buffer.from(await res.arrayBuffer());
513
+ return buf.toString('base64');
514
+ }
515
+ catch (err) {
516
+ this.logger.warn(`下载${label === 'image' ? '图片' : '音频'}异常: ${trimmed}`, err);
517
+ return null;
518
+ }
519
+ }
520
+ // 其他情况:可能是本地文件路径(file:// 或绝对路径),或者已经是裸 base64。
521
+ // 走 ProcessService.readExternalFile 探测是否为文件,避免把路径当作 base64 送给 Ollama
522
+ // 触发 `illegal base64 data` 错误。读盘失败则按裸 base64 透传。
523
+ // 注意:不再治「相对 cwd 路径」场景(原先的 resolve(process.cwd(), data))——
524
+ // 该场景脆弱且需要插件层读 process.cwd,请上游只传绝对路径或 file://。
525
+ if (this.proc && (trimmed.startsWith('file://') || trimmed.startsWith('/'))) {
526
+ try {
527
+ const bytes = await this.proc.readExternalFile(trimmed);
528
+ return Buffer.from(bytes).toString('base64');
529
+ }
530
+ catch {
531
+ return sanitize(trimmed);
532
+ }
533
+ }
534
+ return sanitize(trimmed);
535
+ }
536
+ /**
537
+ * 转换为 Ollama API 消息格式
538
+ * Ollama 的图片通过 images 字段传递 base64 数据(或 URL)
539
+ * 工具调用结果通过 role: tool 传递
540
+ */
541
+ async toOllamaMessage(msg) {
542
+ // 调用方已经 prepareLLMMessages 处理过:role 已是 WellKnownRole,自定义 role / kind
543
+ // 对应的前缀已拼接进 content。这里只需透传。
544
+ const ollamaMsg = {
545
+ role: toLLMRole(msg.role),
546
+ content: msg.content ?? '',
547
+ };
548
+ // 传递思考内容(用于历史上下文)
549
+ if (msg.role === 'assistant' && msg.reasoningContent) {
550
+ ollamaMsg.thinking = msg.reasoningContent;
551
+ }
552
+ // 多模态:Ollama 支持 images 字段(base64 或文件路径)
553
+ if (msg.images && msg.images.length > 0 && msg.role === 'user') {
554
+ const resolved = await Promise.all(msg.images.map(img => this.resolveImage(img)));
555
+ const valid = resolved.filter((r) => r !== null);
556
+ if (valid.length > 0)
557
+ ollamaMsg.images = valid;
558
+ }
559
+ // 音频:Ollama 原生 /api/chat 不支持 audios,有音频时会在 chat() 中
560
+ // 改走 OpenAI 兼容的 /v1/chat/completions 路径。这里只透传字段。
561
+ if (msg.audios && msg.audios.length > 0 && msg.role === 'user') {
562
+ ollamaMsg.audios = msg.audios.map(stripAudioDataPrefix);
563
+ }
564
+ // 传递工具调用(assistant 消息中的)
565
+ if (msg.toolCalls && msg.toolCalls.length > 0) {
566
+ ollamaMsg.tool_calls = msg.toolCalls.map(tc => ({
567
+ function: {
568
+ name: tc.function.name,
569
+ arguments: safeParseJSON(tc.function.arguments),
570
+ },
571
+ }));
572
+ }
573
+ return ollamaMsg;
574
+ }
575
+ toOllamaTool(tool) {
576
+ return {
577
+ type: 'function',
578
+ function: {
579
+ name: tool.function.name,
580
+ description: tool.function.description,
581
+ parameters: tool.function.parameters,
582
+ },
583
+ };
584
+ }
585
+ /**
586
+ * 调用 Ollama 的 OpenAI 兼容 /v1/chat/completions 端点。当 messages 包含
587
+ * audios 字段时,/api/chat 原生路径不支持,必须走这里。
588
+ * 文本与工具调用等其它能力仍由 chat() 走原生路径。
589
+ */
590
+ async chatOpenAIWithAudio(model, request) {
591
+ // 将 Aalis Message 转为 OpenAI multimodal content blocks
592
+ const oaiMessages = await Promise.all(prepareLLMMessages(request.messages).map(async (m) => {
593
+ const role = toLLMRole(m.role);
594
+ const blocks = [];
595
+ // Modality order:Ollama 官方 best practice 要求 image/audio content
596
+ // 必须在 text 之前。参见 /memories/repo/aalis-ollama-gemma4-audio.md
597
+ if (m.images && m.images.length > 0 && m.role === 'user') {
598
+ for (const img of m.images) {
599
+ const url = await this.resolveImage(img);
600
+ if (url)
601
+ blocks.push({
602
+ type: 'image_url',
603
+ image_url: { url: url.startsWith('http') ? url : `data:image/png;base64,${url}` },
604
+ });
605
+ }
606
+ }
607
+ if (m.audios && m.audios.length > 0 && m.role === 'user') {
608
+ for (const a of m.audios) {
609
+ const { data, format } = decodeAudioForOpenAI(a);
610
+ blocks.push({ type: 'input_audio', input_audio: { data, format } });
611
+ }
612
+ }
613
+ if (m.content) {
614
+ blocks.push({ type: 'text', text: m.content });
615
+ }
616
+ // 纯文本 → string;有多模态 → array
617
+ const content = blocks.length === 1 && blocks[0].type === 'text' ? blocks[0].text : blocks;
618
+ return { role, content };
619
+ }));
620
+ const body = {
621
+ model,
622
+ messages: oaiMessages,
623
+ stream: false,
624
+ max_tokens: request.maxTokens ?? this.maxTokens,
625
+ temperature: request.temperature ?? this.temperature,
626
+ };
627
+ // Ollama 0.20+ thinking 控制:OpenAI 兼容路径只认 reasoning_effort,
628
+ // 不认 /api/chat 的 think 字段。think=false → reasoning_effort: "none"
629
+ // 节省 ~5-8x completion tokens(实测 935 → 155)。
630
+ // 详见 /memories/repo/aalis-ollama-gemma4-audio.md
631
+ if (request.think === false) {
632
+ body.reasoning_effort = 'none';
633
+ }
634
+ this.logger.debug(`请求 Ollama (OpenAI compat, audio): ${model}, ${oaiMessages.length} 条消息`);
635
+ // 统计本次发送的音频载荷大小,便于诊断模型是否真的收到了音频
636
+ let totalAudioBytes = 0;
637
+ let audioCount = 0;
638
+ for (const m of oaiMessages) {
639
+ if (Array.isArray(m.content)) {
640
+ for (const block of m.content) {
641
+ const b = block;
642
+ if (b.type === 'input_audio' && b.input_audio?.data) {
643
+ audioCount++;
644
+ totalAudioBytes += Math.floor((b.input_audio.data.length * 3) / 4);
645
+ }
646
+ }
647
+ }
648
+ }
649
+ if (audioCount > 0) {
650
+ this.logger.info(`[ollama-audio] 发送 ${audioCount} 段音频,合计 ${(totalAudioBytes / 1024).toFixed(1)}KB`);
651
+ }
652
+ const signals = [AbortSignal.timeout(this.timeout)];
653
+ if (request.signal)
654
+ signals.push(request.signal);
655
+ const httpT0 = Date.now();
656
+ const resp = await fetch(`${this.baseUrl}/v1/chat/completions`, {
657
+ method: 'POST',
658
+ headers: { 'Content-Type': 'application/json' },
659
+ body: JSON.stringify(body),
660
+ signal: AbortSignal.any(signals),
661
+ });
662
+ if (!resp.ok) {
663
+ const errText = await resp.text();
664
+ this.logger.warn(`[ollama-audio] HTTP ${resp.status} 失败 ${Date.now() - httpT0}ms: ${errText}`);
665
+ // 诊断提示:ollama runner 把 input_audio 当 image 解码失败时报 "image: unknown format",
666
+ // 99% 是模型本身不支持 audio modality(如 Nemotron-3 是纯文本/纯推理,
667
+ // 多模态版 Nemotron-Nano-VL 也只有 vision)。提示用户换 gemma3n / qwen2.5-omni
668
+ // 等明确支持 audio 的多模态模型。
669
+ const lowerErr = errText.toLowerCase();
670
+ if (lowerErr.includes('image: unknown format') || lowerErr.includes('unknown format')) {
671
+ throw new Error(`Ollama /v1/chat/completions 错误 (${resp.status}): ${errText}\n` +
672
+ `[诊断] 模型 "${model}" 很可能不支持 audio modality(ollama runner 把 input_audio 当 image 解码失败)。` +
673
+ `请改用明确支持音频的模型(如 gemma3n、qwen2.5-omni)。`);
674
+ }
675
+ throw new Error(`Ollama /v1/chat/completions 错误 (${resp.status}): ${errText}`);
676
+ }
677
+ const data = (await resp.json());
678
+ const rawContent = data.choices?.[0]?.message?.content ?? '';
679
+ const finishReason = data.choices?.[0]?.finish_reason ?? '?';
680
+ const text = rawContent.trim();
681
+ if (audioCount > 0) {
682
+ this.logger.info(`[ollama-audio] ${model} HTTP ${Date.now() - httpT0}ms, finish=${finishReason}, ` +
683
+ `raw=${rawContent.length}字 trim=${text.length}字, ` +
684
+ `tokens prompt=${data.usage?.prompt_tokens ?? '?'} completion=${data.usage?.completion_tokens ?? '?'}` +
685
+ (rawContent.length > 0 ? `, 原文="${rawContent.replace(/\n/g, ' ')}"` : ' [模型返回空字符串]'));
686
+ }
687
+ const result = { content: text || null, reasoningContent: null };
688
+ if (data.usage) {
689
+ result.usage = {
690
+ promptTokens: data.usage.prompt_tokens ?? 0,
691
+ completionTokens: data.usage.completion_tokens ?? 0,
692
+ totalTokens: data.usage.total_tokens ?? 0,
693
+ };
694
+ }
695
+ return result;
696
+ }
697
+ }
698
+ /** 去掉 base64 音频的 data: 前缀,返回纯 payload。 */
699
+ function stripAudioDataPrefix(s) {
700
+ const m = s.match(/^data:[^;]+;base64,(.+)$/);
701
+ return m ? m[1] : s;
702
+ }
703
+ /**
704
+ * 将 Aalis 传过来的 audio payload(可能带 data: 前缀也可能不带)解析为
705
+ * OpenAI input_audio 需要的 `{ data, format }`。format 推断优先级:
706
+ * data URL 的 mime 后缀 → 默认 wav。
707
+ */
708
+ function decodeAudioForOpenAI(payload) {
709
+ const m = payload.match(/^data:audio\/([^;]+);base64,(.+)$/);
710
+ if (m) {
711
+ const fmt = m[1].toLowerCase();
712
+ const norm = fmt === 'mpeg' || fmt === 'mp3'
713
+ ? 'mp3'
714
+ : fmt === 'x-wav' || fmt === 'wave' || fmt === 'wav'
715
+ ? 'wav'
716
+ : fmt === 'ogg' || fmt === 'oga' || fmt === 'opus'
717
+ ? 'ogg'
718
+ : fmt === 'm4a' || fmt === 'mp4' || fmt === 'aac'
719
+ ? 'm4a'
720
+ : 'wav';
721
+ return { data: m[2], format: norm };
722
+ }
723
+ return { data: stripAudioDataPrefix(payload), format: 'wav' };
724
+ }
725
+ function safeParseJSON(str) {
726
+ try {
727
+ return JSON.parse(str);
728
+ }
729
+ catch {
730
+ return {};
731
+ }
732
+ }
733
+ // ===== 模型能力映射 =====
734
+ const { Chat, ToolCalling, Streaming, Vision, Audio, Thinking } = LLMCapabilities;
735
+ const MODEL_CAPABILITIES = {
736
+ 'llama3.1': [Chat, ToolCalling, Streaming],
737
+ 'llama3.2': [Chat, ToolCalling, Streaming],
738
+ 'llama3.3': [Chat, ToolCalling, Streaming],
739
+ llava: [Chat, Streaming, Vision],
740
+ 'llava-llama3': [Chat, Streaming, Vision],
741
+ gemma2: [Chat, Streaming],
742
+ gemma3: [Chat, ToolCalling, Streaming, Vision],
743
+ gemma4: [Chat, ToolCalling, Streaming, Vision],
744
+ 'qwen2.5': [Chat, ToolCalling, Streaming],
745
+ 'qwen2.5-coder': [Chat, ToolCalling, Streaming],
746
+ qwen3: [Chat, ToolCalling, Streaming],
747
+ mistral: [Chat, ToolCalling, Streaming],
748
+ 'deepseek-r1': [Chat, Streaming],
749
+ phi4: [Chat, Streaming],
750
+ 'command-r': [Chat, ToolCalling, Streaming],
751
+ };
752
+ const DEFAULT_CAPABILITIES = [Chat];
753
+ /** Ollama /api/show 的 capabilities 字符串 → Aalis LLMCapability(无关项忽略)。 */
754
+ function mapOllamaCapabilities(caps) {
755
+ const out = new Set();
756
+ for (const c of caps) {
757
+ switch (c.toLowerCase()) {
758
+ case 'completion':
759
+ out.add(Chat);
760
+ break;
761
+ case 'tools':
762
+ out.add(ToolCalling);
763
+ break;
764
+ case 'vision':
765
+ out.add(Vision);
766
+ break;
767
+ case 'audio':
768
+ out.add(Audio);
769
+ break;
770
+ case 'thinking':
771
+ out.add(Thinking);
772
+ break;
773
+ // insert / embedding / 其它:与对话能力无关,忽略
774
+ }
775
+ }
776
+ // Ollama 对话模型一律支持流式
777
+ if (out.size > 0)
778
+ out.add(Streaming);
779
+ return [...out];
780
+ }
781
+ /**
782
+ * 解析某模型能力。优先级(高→低):
783
+ * 1. 用户 per-model 覆盖(modelCapabilities,∪ provider 默认)——逃生舱,最高
784
+ * 2. Ollama /api/show 真实能力(detected)——权威;不再叠加 provider 默认,避免误标
785
+ * 3. 家族表启发式(MODEL_CAPABILITIES)——detected 不可用时的回退
786
+ * 4. provider 默认(providerCapabilities) + DEFAULT_CAPABILITIES——最后兜底
787
+ */
788
+ function resolveCapabilities(model, userOverride, providerCaps, detected) {
789
+ // 1. 用户逐模型覆盖(沿用原语义:与 provider 默认取并集)
790
+ if (Array.isArray(userOverride) && userOverride.length > 0) {
791
+ const out = new Set(userOverride);
792
+ for (const c of providerCaps ?? [])
793
+ out.add(c);
794
+ return [...out];
795
+ }
796
+ // 2. /api/show 真实能力(权威)
797
+ if (detected && detected.length > 0) {
798
+ const mapped = mapOllamaCapabilities(detected);
799
+ if (mapped.length > 0)
800
+ return mapped;
801
+ }
802
+ // 去掉 tag 部分(如 llama3.1:8b → llama3.1)
803
+ const baseName = model.split(':')[0].toLowerCase();
804
+ // Gemma 4 E 系列(e2b / e4b)原生支持音频输入。参考 https://ollama.com/library/gemma4
805
+ const isGemma4Audio = /^gemma4:e[24]b/.test(model.toLowerCase());
806
+ // 3. 家族表启发式回退
807
+ if (MODEL_CAPABILITIES[baseName]) {
808
+ const out = new Set(MODEL_CAPABILITIES[baseName]);
809
+ if (isGemma4Audio)
810
+ out.add(Audio);
811
+ return [...out];
812
+ }
813
+ for (const [known, caps] of Object.entries(MODEL_CAPABILITIES)) {
814
+ if (baseName.startsWith(known)) {
815
+ const out = new Set(caps);
816
+ if (isGemma4Audio)
817
+ out.add(Audio);
818
+ return [...out];
819
+ }
820
+ }
821
+ if (baseName.includes('llava') || baseName.includes('vision')) {
822
+ return [Chat, Streaming, Vision];
823
+ }
824
+ // 4. 最后兜底:provider 默认 + Chat
825
+ const out = new Set(providerCaps ?? []);
826
+ for (const c of DEFAULT_CAPABILITIES)
827
+ out.add(c);
828
+ if (isGemma4Audio)
829
+ out.add(Audio);
830
+ return [...out];
831
+ }
832
+ /** 解析适配器级别默认能力(逗号/空格/换行分隔) */
833
+ function parseProviderCapabilities(raw) {
834
+ if (!raw || typeof raw !== 'string')
835
+ return [];
836
+ return raw
837
+ .split(/[,\s\n]/)
838
+ .map(s => s.trim())
839
+ .filter(Boolean);
840
+ }
841
+ // ===== 插件入口 =====
842
+ /** 解析自定义模型列表:支持逗号分隔和换行分隔 */
843
+ function parseCustomModels(raw) {
844
+ if (!raw || typeof raw !== 'string')
845
+ return [];
846
+ return raw
847
+ .split(/[,\n]/)
848
+ .map(s => s.trim())
849
+ .filter(Boolean);
850
+ }
851
+ /** 解析能力覆盖 textarea:每行 `<modelId>: cap1,cap2,...` */
852
+ function parseModelCapabilities(raw) {
853
+ const out = new Map();
854
+ if (!raw || typeof raw !== 'string')
855
+ return out;
856
+ for (const line of raw.split(/\r?\n/)) {
857
+ const trimmed = line.trim();
858
+ if (!trimmed || trimmed.startsWith('#'))
859
+ continue;
860
+ const colonIdx = trimmed.indexOf(':');
861
+ if (colonIdx < 0)
862
+ continue;
863
+ const modelId = trimmed.slice(0, colonIdx).trim();
864
+ const caps = trimmed
865
+ .slice(colonIdx + 1)
866
+ .split(',')
867
+ .map(s => s.trim())
868
+ .filter(Boolean);
869
+ if (modelId && caps.length > 0)
870
+ out.set(modelId, caps);
871
+ }
872
+ return out;
873
+ }
874
+ // ===== Per-model handle:每个 model 独立的 LLMModel entry =====
875
+ class OllamaModelHandle {
876
+ client;
877
+ id;
878
+ providerId;
879
+ contextLength;
880
+ maxOutputTokens;
881
+ defaultThinking;
882
+ refresh;
883
+ capabilities;
884
+ constructor(client, id, providerId, contextLength, maxOutputTokens, defaultThinking,
885
+ /** Provider 级共享的 refresh 闭包;webui 按 contextId 找到任一 entry 调一次即可。 */
886
+ refresh,
887
+ /** 该 model 的能力元数据(供 media 发现/下拉展示读取,非 DI 选择机制)。 */
888
+ capabilities) {
889
+ this.client = client;
890
+ this.id = id;
891
+ this.providerId = providerId;
892
+ this.contextLength = contextLength;
893
+ this.maxOutputTokens = maxOutputTokens;
894
+ this.defaultThinking = defaultThinking;
895
+ this.refresh = refresh;
896
+ this.capabilities = capabilities;
897
+ }
898
+ chat(request) {
899
+ return this.client.chat(this.id, request, this.defaultThinking);
900
+ }
901
+ chatStream(request) {
902
+ return this.client.chatStream(this.id, request, this.defaultThinking);
903
+ }
904
+ }
905
+ export async function apply(ctx, config) {
906
+ const ollamaConfig = {
907
+ baseUrl: config.baseUrl ?? 'http://localhost:11434',
908
+ customModels: parseCustomModels(config.customModels),
909
+ modelCapabilities: parseModelCapabilities(config.modelCapabilities),
910
+ providerCapabilities: parseProviderCapabilities(config.providerCapabilities),
911
+ timeout: config.timeout ?? 120,
912
+ temperature: config.temperature ?? 0.7,
913
+ maxTokens: config.maxTokens ?? 4096,
914
+ contextLength: config.contextLength ?? 8192,
915
+ keepAlive: config.keepAlive ?? '5m',
916
+ thinking: config.thinking !== false,
917
+ };
918
+ const client = new OllamaClient(ollamaConfig, ctx.logger, createProcessGateway(ctx));
919
+ const baseLabel = `Ollama (${ollamaConfig.baseUrl.replace(/^https?:\/\//, '')})`;
920
+ // 已注册 model entry 的句柄表:modelId → dispose(来自 ctx.provide 返回值)
921
+ const registered = new Map();
922
+ // 前置声明:refresh 闭包稍后定义,但每个 handle 在创建时就需要它的引用
923
+ // 用一层间接调用以打破环依赖;handle.refresh() 实际转发到此变量。
924
+ let refreshFn = async () => ({
925
+ added: [],
926
+ removed: [],
927
+ total: registered.size,
928
+ });
929
+ const refresh = () => refreshFn();
930
+ function registerOne(modelId, detected) {
931
+ if (registered.has(modelId))
932
+ return;
933
+ const capabilities = resolveCapabilities(modelId, ollamaConfig.modelCapabilities.get(modelId), ollamaConfig.providerCapabilities, detected);
934
+ const handle = new OllamaModelHandle(client, modelId, ctx.id, ollamaConfig.contextLength, ollamaConfig.maxTokens, ollamaConfig.thinking, refresh, capabilities);
935
+ const dispose = ctx.provide('llm', handle, {
936
+ label: `${baseLabel} / ${modelId}`,
937
+ entryId: `${ctx.id}/${modelId}`,
938
+ });
939
+ registered.set(modelId, dispose);
940
+ }
941
+ function unregisterOne(modelId) {
942
+ const d = registered.get(modelId);
943
+ if (!d)
944
+ return;
945
+ try {
946
+ d();
947
+ }
948
+ catch (err) {
949
+ ctx.logger.warn(`卸载 model entry "${modelId}" 失败: ${err}`);
950
+ }
951
+ registered.delete(modelId);
952
+ }
953
+ async function discoverAllModelIds() {
954
+ const remoteIds = await client.fetchRemoteModelIds();
955
+ const remoteSet = new Set(remoteIds);
956
+ for (const cm of ollamaConfig.customModels) {
957
+ if (remoteSet.has(cm)) {
958
+ ctx.logger.warn(`自定义模型 "${cm}" 与自动发现的模型重复,请在配置中去重`);
959
+ }
960
+ }
961
+ return [...remoteIds, ...ollamaConfig.customModels.filter(id => !remoteSet.has(id))];
962
+ }
963
+ // 初次注册
964
+ const initialIds = await discoverAllModelIds();
965
+ if (initialIds.length === 0) {
966
+ ctx.logger.warn(`Ollama 已连接: ${ollamaConfig.baseUrl},但未发现任何可用模型;不注册任何 LLM entry`);
967
+ }
968
+ else {
969
+ // 并行查每个模型的真实能力(顺序保留→注册顺序稳定→优先级稳定);失败者回退家族表。
970
+ const detectedCaps = await Promise.all(initialIds.map(id => client.fetchModelCapabilities(id)));
971
+ for (let i = 0; i < initialIds.length; i++)
972
+ registerOne(initialIds[i], detectedCaps[i]);
973
+ ctx.logger.info(`Ollama 已连接: ${ollamaConfig.baseUrl},注册 ${initialIds.length} 个 model entry`);
974
+ }
975
+ // 装配 refresh 真实实现:webui 触发时无需重启插件,按 diff 增删 entries。
976
+ // 同 provider 下所有 OllamaModelHandle 共享同一份 refresh(通过 refreshFn 间接转发)。
977
+ refreshFn = async () => {
978
+ const next = await discoverAllModelIds();
979
+ const nextSet = new Set(next);
980
+ const added = [];
981
+ const removed = [];
982
+ for (const id of next) {
983
+ if (!registered.has(id)) {
984
+ registerOne(id, await client.fetchModelCapabilities(id));
985
+ added.push(id);
986
+ }
987
+ }
988
+ for (const id of [...registered.keys()]) {
989
+ if (!nextSet.has(id)) {
990
+ unregisterOne(id);
991
+ removed.push(id);
992
+ }
993
+ }
994
+ if (added.length || removed.length) {
995
+ ctx.logger.info(`Ollama 模型列表已刷新: +${added.length} (${added.join(',') || '-'}) / -${removed.length} (${removed.join(',') || '-'}) / 现共 ${registered.size}`);
996
+ }
997
+ else {
998
+ ctx.logger.debug(`Ollama 模型列表已刷新: 无变化 (共 ${registered.size})`);
999
+ }
1000
+ return { added, removed, total: registered.size };
1001
+ };
1002
+ }
1003
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@aalis/plugin-llm-ollama",
3
+ "version": "0.9.0",
4
+ "license": "MIT",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/AalisLabs/Aalis.git",
8
+ "directory": "packages/plugin-llm-ollama"
9
+ },
10
+ "author": "Ace Nyan <ace@acenyan.com>",
11
+ "bugs": {
12
+ "url": "https://github.com/AalisLabs/Aalis/issues"
13
+ },
14
+ "homepage": "https://github.com/AalisLabs/Aalis#readme",
15
+ "description": "Ollama 本地 LLM 提供者",
16
+ "type": "module",
17
+ "keywords": [
18
+ "aalis",
19
+ "aalis-plugin"
20
+ ],
21
+ "main": "dist/index.js",
22
+ "types": "dist/index.d.ts",
23
+ "files": [
24
+ "dist"
25
+ ],
26
+ "dependencies": {
27
+ "@aalis/schema-config": ">=0.9.0 <1.0.0",
28
+ "@aalis/api-llm": ">=0.9.0 <1.0.0",
29
+ "@aalis/schema-message": ">=0.5.1 <1.0.0",
30
+ "@aalis/api-process": ">=0.5.0 <1.0.0",
31
+ "@aalis/util-network-guard": ">=0.5.1 <1.0.0"
32
+ },
33
+ "devDependencies": {
34
+ "@types/node": "^22.0.0",
35
+ "typescript": "^5.7.0",
36
+ "@aalis/core": "0.10.0",
37
+ "@aalis/api-tools": "0.5.1"
38
+ },
39
+ "peerDependencies": {
40
+ "@aalis/core": ">=0.2.0 <1.0.0"
41
+ },
42
+ "aalis": {
43
+ "service": {
44
+ "optional": [
45
+ "process"
46
+ ],
47
+ "provides": [
48
+ "llm"
49
+ ]
50
+ }
51
+ },
52
+ "scripts": {
53
+ "build": "tsc",
54
+ "dev": "tsc --watch"
55
+ }
56
+ }