@elizaos/plugin-ollama 2.0.0-alpha.8 → 2.0.0-beta.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/LICENSE +21 -0
- package/README.md +201 -0
- package/auto-enable.ts +17 -0
- package/dist/browser/index.browser.js +786 -152
- package/dist/browser/index.browser.js.map +10 -8
- package/dist/cjs/index.node.cjs +1003 -10
- package/dist/cjs/index.node.cjs.map +11 -4
- package/dist/node/auto-enable.d.ts +4 -0
- package/dist/node/auto-enable.d.ts.map +1 -0
- package/dist/node/generated/specs/specs.d.ts +1 -18
- package/dist/node/generated/specs/specs.d.ts.map +1 -1
- package/dist/node/index.browser.d.ts +6 -2
- package/dist/node/index.browser.d.ts.map +1 -1
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.node.d.ts +7 -0
- package/dist/node/index.node.d.ts.map +1 -0
- package/dist/node/index.node.js +1012 -5
- package/dist/node/index.node.js.map +11 -4
- package/dist/node/models/embedding.d.ts +7 -0
- package/dist/node/models/embedding.d.ts.map +1 -1
- package/dist/node/models/index.d.ts +0 -1
- package/dist/node/models/index.d.ts.map +1 -1
- package/dist/node/models/text.d.ts +82 -3
- package/dist/node/models/text.d.ts.map +1 -1
- package/dist/node/plugin.d.ts +34 -0
- package/dist/node/plugin.d.ts.map +1 -1
- package/dist/node/utils/ai-sdk-wire.d.ts +42 -0
- package/dist/node/utils/ai-sdk-wire.d.ts.map +1 -0
- package/dist/node/utils/config.d.ts +28 -3
- package/dist/node/utils/config.d.ts.map +1 -1
- package/dist/node/utils/index.d.ts +2 -0
- package/dist/node/utils/index.d.ts.map +1 -1
- package/dist/node/utils/modelUsage.d.ts +13 -0
- package/dist/node/utils/modelUsage.d.ts.map +1 -0
- package/dist/node/vitest.config.d.ts +3 -0
- package/dist/node/vitest.config.d.ts.map +1 -0
- package/package.json +38 -17
- package/dist/node/models/object.d.ts +0 -4
- package/dist/node/models/object.d.ts.map +0 -1
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
// plugin.ts
|
|
2
|
-
import { logger as
|
|
2
|
+
import { logger as logger4, ModelType as ModelType3 } from "@elizaos/core";
|
|
3
3
|
|
|
4
4
|
// models/embedding.ts
|
|
5
|
-
import { logger as logger2 } from "@elizaos/core";
|
|
5
|
+
import { logger as logger2, ModelType } from "@elizaos/core";
|
|
6
6
|
import { embed } from "ai";
|
|
7
|
-
import { createOllama } from "ollama-ai-provider";
|
|
7
|
+
import { createOllama } from "ollama-ai-provider-v2";
|
|
8
8
|
|
|
9
9
|
// utils/config.ts
|
|
10
10
|
var DEFAULT_OLLAMA_URL = "http://localhost:11434";
|
|
11
|
-
var DEFAULT_SMALL_MODEL = "
|
|
12
|
-
var DEFAULT_LARGE_MODEL = "
|
|
13
|
-
var DEFAULT_EMBEDDING_MODEL = "
|
|
11
|
+
var DEFAULT_SMALL_MODEL = "eliza-1-2b";
|
|
12
|
+
var DEFAULT_LARGE_MODEL = "eliza-1-9b";
|
|
13
|
+
var DEFAULT_EMBEDDING_MODEL = "eliza-1-2b";
|
|
14
14
|
function getEnvValue(key) {
|
|
15
15
|
if (typeof process === "undefined" || !process.env) {
|
|
16
16
|
return;
|
|
@@ -39,12 +39,108 @@ function getApiBase(runtime) {
|
|
|
39
39
|
function getSmallModel(runtime) {
|
|
40
40
|
return getSetting(runtime, "OLLAMA_SMALL_MODEL") || getSetting(runtime, "SMALL_MODEL") || DEFAULT_SMALL_MODEL;
|
|
41
41
|
}
|
|
42
|
+
function getNanoModel(runtime) {
|
|
43
|
+
return getSetting(runtime, "OLLAMA_NANO_MODEL") || getSetting(runtime, "NANO_MODEL") || getSmallModel(runtime);
|
|
44
|
+
}
|
|
45
|
+
function getMediumModel(runtime) {
|
|
46
|
+
return getSetting(runtime, "OLLAMA_MEDIUM_MODEL") || getSetting(runtime, "MEDIUM_MODEL") || getSmallModel(runtime);
|
|
47
|
+
}
|
|
42
48
|
function getLargeModel(runtime) {
|
|
43
49
|
return getSetting(runtime, "OLLAMA_LARGE_MODEL") || getSetting(runtime, "LARGE_MODEL") || DEFAULT_LARGE_MODEL;
|
|
44
50
|
}
|
|
51
|
+
function getMegaModel(runtime) {
|
|
52
|
+
return getSetting(runtime, "OLLAMA_MEGA_MODEL") || getSetting(runtime, "MEGA_MODEL") || getLargeModel(runtime);
|
|
53
|
+
}
|
|
54
|
+
function getResponseHandlerModel(runtime) {
|
|
55
|
+
return getSetting(runtime, "OLLAMA_RESPONSE_HANDLER_MODEL") || getSetting(runtime, "OLLAMA_SHOULD_RESPOND_MODEL") || getSetting(runtime, "RESPONSE_HANDLER_MODEL") || getSetting(runtime, "SHOULD_RESPOND_MODEL") || getNanoModel(runtime);
|
|
56
|
+
}
|
|
57
|
+
function getActionPlannerModel(runtime) {
|
|
58
|
+
return getSetting(runtime, "OLLAMA_ACTION_PLANNER_MODEL") || getSetting(runtime, "OLLAMA_PLANNER_MODEL") || getSetting(runtime, "ACTION_PLANNER_MODEL") || getSetting(runtime, "PLANNER_MODEL") || getMediumModel(runtime);
|
|
59
|
+
}
|
|
45
60
|
function getEmbeddingModel(runtime) {
|
|
46
61
|
return getSetting(runtime, "OLLAMA_EMBEDDING_MODEL") || DEFAULT_EMBEDDING_MODEL;
|
|
47
62
|
}
|
|
63
|
+
function isOllamaStructuredOutputDisabled(runtime) {
|
|
64
|
+
const v = getSetting(runtime, "OLLAMA_DISABLE_STRUCTURED_OUTPUT")?.trim().toLowerCase();
|
|
65
|
+
return v === "1" || v === "true" || v === "yes" || v === "on";
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// utils/modelUsage.ts
|
|
69
|
+
import { EventType } from "@elizaos/core";
|
|
70
|
+
function toFiniteNumber(value) {
|
|
71
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
return Math.max(0, Math.round(value));
|
|
75
|
+
}
|
|
76
|
+
function normalizeTokenUsage(usage) {
|
|
77
|
+
if (!usage || typeof usage !== "object") {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
const record = usage;
|
|
81
|
+
const promptTokens = toFiniteNumber(record.inputTokens ?? record.promptTokens);
|
|
82
|
+
const completionTokens = toFiniteNumber(record.outputTokens ?? record.completionTokens);
|
|
83
|
+
const totalTokens = toFiniteNumber(record.totalTokens);
|
|
84
|
+
if (promptTokens === undefined && completionTokens === undefined && totalTokens === undefined) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
const normalizedPromptTokens = promptTokens ?? (completionTokens === undefined && totalTokens !== undefined ? totalTokens : Math.max(0, (totalTokens ?? 0) - (completionTokens ?? 0)));
|
|
88
|
+
const normalizedCompletionTokens = completionTokens ?? Math.max(0, (totalTokens ?? normalizedPromptTokens) - normalizedPromptTokens);
|
|
89
|
+
return {
|
|
90
|
+
promptTokens: normalizedPromptTokens,
|
|
91
|
+
completionTokens: normalizedCompletionTokens,
|
|
92
|
+
totalTokens: totalTokens ?? normalizedPromptTokens + normalizedCompletionTokens
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function estimateTokenCount(text) {
|
|
96
|
+
return text.length === 0 ? 0 : Math.ceil(text.length / 4);
|
|
97
|
+
}
|
|
98
|
+
function stringifyForUsage(value) {
|
|
99
|
+
if (typeof value === "string") {
|
|
100
|
+
return value;
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
return JSON.stringify(value);
|
|
104
|
+
} catch {
|
|
105
|
+
return String(value);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function estimateUsage(prompt, response) {
|
|
109
|
+
const promptTokens = estimateTokenCount(prompt);
|
|
110
|
+
const completionTokens = estimateTokenCount(stringifyForUsage(response));
|
|
111
|
+
return {
|
|
112
|
+
promptTokens,
|
|
113
|
+
completionTokens,
|
|
114
|
+
totalTokens: promptTokens + completionTokens,
|
|
115
|
+
estimated: true
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function estimateEmbeddingUsage(text) {
|
|
119
|
+
const promptTokens = estimateTokenCount(text);
|
|
120
|
+
return {
|
|
121
|
+
promptTokens,
|
|
122
|
+
completionTokens: 0,
|
|
123
|
+
totalTokens: promptTokens,
|
|
124
|
+
estimated: true
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function emitModelUsed(runtime, type, model, usage) {
|
|
128
|
+
runtime.emitEvent(EventType.MODEL_USED, {
|
|
129
|
+
runtime,
|
|
130
|
+
source: "ollama",
|
|
131
|
+
provider: "ollama",
|
|
132
|
+
type,
|
|
133
|
+
model,
|
|
134
|
+
modelName: model,
|
|
135
|
+
tokens: {
|
|
136
|
+
prompt: usage.promptTokens,
|
|
137
|
+
completion: usage.completionTokens,
|
|
138
|
+
total: usage.totalTokens,
|
|
139
|
+
...usage.estimated ? { estimated: true } : {}
|
|
140
|
+
},
|
|
141
|
+
...usage.estimated ? { usageEstimated: true } : {}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
48
144
|
|
|
49
145
|
// models/availability.ts
|
|
50
146
|
import { logger } from "@elizaos/core";
|
|
@@ -101,7 +197,8 @@ async function handleTextEmbedding(runtime, params) {
|
|
|
101
197
|
model: ollama.embedding(modelName),
|
|
102
198
|
value: embeddingText
|
|
103
199
|
};
|
|
104
|
-
const { embedding } = await embed(embedParams);
|
|
200
|
+
const { embedding, usage } = await embed(embedParams);
|
|
201
|
+
emitModelUsed(runtime, ModelType.TEXT_EMBEDDING, modelName, normalizeTokenUsage(usage) ?? estimateEmbeddingUsage(embeddingText));
|
|
105
202
|
return embedding;
|
|
106
203
|
} catch (embeddingError) {
|
|
107
204
|
logger2.error({ error: embeddingError }, "Error generating embedding");
|
|
@@ -113,144 +210,626 @@ async function handleTextEmbedding(runtime, params) {
|
|
|
113
210
|
}
|
|
114
211
|
}
|
|
115
212
|
|
|
116
|
-
// models/
|
|
117
|
-
import {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
213
|
+
// models/text.ts
|
|
214
|
+
import {
|
|
215
|
+
buildCanonicalSystemPrompt,
|
|
216
|
+
dropDuplicateLeadingSystemMessage,
|
|
217
|
+
logger as logger3,
|
|
218
|
+
ModelType as ModelType2,
|
|
219
|
+
renderChatMessagesForPrompt,
|
|
220
|
+
resolveEffectiveSystemPrompt
|
|
221
|
+
} from "@elizaos/core";
|
|
222
|
+
import {
|
|
223
|
+
generateText,
|
|
224
|
+
jsonSchema as jsonSchema2,
|
|
225
|
+
Output,
|
|
226
|
+
streamText
|
|
227
|
+
} from "ai";
|
|
228
|
+
import { createOllama as createOllama2 } from "ollama-ai-provider-v2";
|
|
229
|
+
|
|
230
|
+
// utils/ai-sdk-wire.ts
|
|
231
|
+
import {
|
|
232
|
+
jsonSchema
|
|
233
|
+
} from "ai";
|
|
234
|
+
function normalizeNativeTools(tools) {
|
|
235
|
+
if (!tools) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
if (!Array.isArray(tools)) {
|
|
239
|
+
return tools;
|
|
240
|
+
}
|
|
241
|
+
const toolSet = {};
|
|
242
|
+
for (const rawTool of tools) {
|
|
243
|
+
const tool = asRecord(rawTool);
|
|
244
|
+
const functionTool = asRecord(tool.function);
|
|
245
|
+
const name = firstString(tool.name, functionTool.name);
|
|
246
|
+
if (!name) {
|
|
247
|
+
throw new Error("[Ollama] Native tool definition is missing a name.");
|
|
248
|
+
}
|
|
249
|
+
const description = firstString(tool.description, functionTool.description);
|
|
250
|
+
const rawSchema = tool.parameters ?? functionTool.parameters ?? { type: "object" };
|
|
251
|
+
const inputSchema = sanitizeJsonSchema(rawSchema, true);
|
|
252
|
+
toolSet[name] = {
|
|
253
|
+
...description ? { description } : {},
|
|
254
|
+
inputSchema: jsonSchema(inputSchema)
|
|
127
255
|
};
|
|
128
|
-
const { object } = await generateObject(generateParams);
|
|
129
|
-
return object;
|
|
130
|
-
} catch (error) {
|
|
131
|
-
logger3.error({ error }, "Error generating object");
|
|
132
|
-
return {};
|
|
133
256
|
}
|
|
257
|
+
return Object.keys(toolSet).length > 0 ? toolSet : undefined;
|
|
134
258
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
logger3.log(`[Ollama] Using OBJECT_SMALL model: ${model}`);
|
|
145
|
-
await ensureModelAvailable(model, baseURL, customFetch);
|
|
146
|
-
return await generateOllamaObject(ollama, model, params);
|
|
147
|
-
} catch (error) {
|
|
148
|
-
logger3.error({ error }, "Error in OBJECT_SMALL model");
|
|
149
|
-
return {};
|
|
259
|
+
function normalizeNativeMessages(messages) {
|
|
260
|
+
if (!Array.isArray(messages)) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
return messages.map((message) => normalizeNativeMessage(message));
|
|
264
|
+
}
|
|
265
|
+
function normalizeToolChoice(toolChoice) {
|
|
266
|
+
if (!toolChoice) {
|
|
267
|
+
return;
|
|
150
268
|
}
|
|
269
|
+
if (typeof toolChoice === "string" && (toolChoice === "auto" || toolChoice === "none" || toolChoice === "required")) {
|
|
270
|
+
return toolChoice;
|
|
271
|
+
}
|
|
272
|
+
const choice = asRecord(toolChoice);
|
|
273
|
+
if (choice.type === "tool") {
|
|
274
|
+
if (typeof choice.toolName === "string" && choice.toolName.length > 0) {
|
|
275
|
+
return toolChoice;
|
|
276
|
+
}
|
|
277
|
+
const toolName = firstString(choice.toolName, choice.name);
|
|
278
|
+
if (toolName) {
|
|
279
|
+
return { type: "tool", toolName };
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
if (choice.type === "function") {
|
|
283
|
+
const fn = asRecord(choice.function);
|
|
284
|
+
const toolName = firstString(fn.name);
|
|
285
|
+
if (toolName) {
|
|
286
|
+
return { type: "tool", toolName };
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
const namedTool = firstString(choice.name);
|
|
290
|
+
if (namedTool) {
|
|
291
|
+
return { type: "tool", toolName: namedTool };
|
|
292
|
+
}
|
|
293
|
+
return toolChoice;
|
|
151
294
|
}
|
|
152
|
-
|
|
295
|
+
function parseJsonIfPossible(value) {
|
|
296
|
+
if (typeof value !== "string") {
|
|
297
|
+
return value;
|
|
298
|
+
}
|
|
153
299
|
try {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
300
|
+
return JSON.parse(value);
|
|
301
|
+
} catch {
|
|
302
|
+
return value;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
function mapAiSdkToolCallsToCore(toolCalls) {
|
|
306
|
+
if (!Array.isArray(toolCalls) || toolCalls.length === 0) {
|
|
307
|
+
return [];
|
|
308
|
+
}
|
|
309
|
+
const out = [];
|
|
310
|
+
for (const tc of toolCalls) {
|
|
311
|
+
const mapped = mapOneToolCall(tc);
|
|
312
|
+
if (mapped) {
|
|
313
|
+
out.push(mapped);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return out;
|
|
317
|
+
}
|
|
318
|
+
function mapOneToolCall(tc) {
|
|
319
|
+
const r = asRecord(tc);
|
|
320
|
+
const id = String(firstString(r.toolCallId, r.id) ?? "");
|
|
321
|
+
const name = String(firstString(r.toolName, r.name) ?? "").trim();
|
|
322
|
+
if (!name) {
|
|
323
|
+
return null;
|
|
324
|
+
}
|
|
325
|
+
const rawInput = r.input ?? r.arguments ?? r.args;
|
|
326
|
+
let args;
|
|
327
|
+
if (typeof rawInput === "string") {
|
|
328
|
+
const parsed = parseJsonIfPossible(rawInput);
|
|
329
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
330
|
+
args = parsed;
|
|
331
|
+
} else {
|
|
332
|
+
args = rawInput;
|
|
333
|
+
}
|
|
334
|
+
} else if (rawInput && typeof rawInput === "object" && !Array.isArray(rawInput)) {
|
|
335
|
+
args = rawInput;
|
|
336
|
+
} else {
|
|
337
|
+
args = {};
|
|
338
|
+
}
|
|
339
|
+
return { id, name, arguments: args };
|
|
340
|
+
}
|
|
341
|
+
function normalizeNativeMessage(message) {
|
|
342
|
+
const raw = asRecord(message);
|
|
343
|
+
const providerOptions = asOptionalRecord(raw.providerOptions);
|
|
344
|
+
if (raw.role === "system") {
|
|
345
|
+
return {
|
|
346
|
+
role: "system",
|
|
347
|
+
content: stringifyMessageContent(raw.content),
|
|
348
|
+
...providerOptions ? { providerOptions } : {}
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
if (raw.role === "assistant") {
|
|
352
|
+
return {
|
|
353
|
+
role: "assistant",
|
|
354
|
+
content: normalizeAssistantContent(raw),
|
|
355
|
+
...providerOptions ? { providerOptions } : {}
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
if (raw.role === "tool") {
|
|
359
|
+
return {
|
|
360
|
+
role: "tool",
|
|
361
|
+
content: normalizeToolContent(raw),
|
|
362
|
+
...providerOptions ? { providerOptions } : {}
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
return {
|
|
366
|
+
role: "user",
|
|
367
|
+
content: normalizeUserContent(raw.content),
|
|
368
|
+
...providerOptions ? { providerOptions } : {}
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
function normalizeAssistantContent(message) {
|
|
372
|
+
const toolCalls = Array.isArray(message.toolCalls) ? message.toolCalls : [];
|
|
373
|
+
if (toolCalls.length === 0) {
|
|
374
|
+
if (Array.isArray(message.content) || typeof message.content === "string") {
|
|
375
|
+
return message.content;
|
|
376
|
+
}
|
|
377
|
+
return "";
|
|
378
|
+
}
|
|
379
|
+
const parts = [];
|
|
380
|
+
if (typeof message.content === "string" && message.content.length > 0) {
|
|
381
|
+
parts.push({ type: "text", text: message.content });
|
|
382
|
+
} else if (Array.isArray(message.content)) {
|
|
383
|
+
parts.push(...message.content);
|
|
384
|
+
}
|
|
385
|
+
for (const toolCall of toolCalls) {
|
|
386
|
+
const rawCall = asRecord(toolCall);
|
|
387
|
+
const rawFunction = asRecord(rawCall.function);
|
|
388
|
+
const toolCallId = firstString(rawCall.toolCallId, rawCall.id);
|
|
389
|
+
const toolName = firstString(rawCall.toolName, rawCall.name, rawFunction.name);
|
|
390
|
+
if (!toolCallId || !toolName) {
|
|
391
|
+
continue;
|
|
392
|
+
}
|
|
393
|
+
parts.push({
|
|
394
|
+
type: "tool-call",
|
|
395
|
+
toolCallId,
|
|
396
|
+
toolName,
|
|
397
|
+
input: parseToolCallInput(rawCall, rawFunction)
|
|
159
398
|
});
|
|
160
|
-
const model = getLargeModel(runtime);
|
|
161
|
-
logger3.log(`[Ollama] Using OBJECT_LARGE model: ${model}`);
|
|
162
|
-
await ensureModelAvailable(model, baseURL, customFetch);
|
|
163
|
-
return await generateOllamaObject(ollama, model, params);
|
|
164
|
-
} catch (error) {
|
|
165
|
-
logger3.error({ error }, "Error in OBJECT_LARGE model");
|
|
166
|
-
return {};
|
|
167
399
|
}
|
|
400
|
+
return parts;
|
|
401
|
+
}
|
|
402
|
+
function normalizeToolContent(message) {
|
|
403
|
+
if (Array.isArray(message.content)) {
|
|
404
|
+
return message.content;
|
|
405
|
+
}
|
|
406
|
+
const toolCallId = firstString(message.toolCallId, message.id) ?? "tool-call";
|
|
407
|
+
const toolName = firstString(message.toolName, message.name) ?? "tool";
|
|
408
|
+
const parsed = parseJsonIfPossible(message.content);
|
|
409
|
+
return [
|
|
410
|
+
{
|
|
411
|
+
type: "tool-result",
|
|
412
|
+
toolCallId,
|
|
413
|
+
toolName,
|
|
414
|
+
output: typeof parsed === "string" ? { type: "text", value: parsed } : { type: "json", value: parsed }
|
|
415
|
+
}
|
|
416
|
+
];
|
|
417
|
+
}
|
|
418
|
+
function normalizeUserContent(content) {
|
|
419
|
+
if (Array.isArray(content)) {
|
|
420
|
+
return content;
|
|
421
|
+
}
|
|
422
|
+
return stringifyMessageContent(content);
|
|
423
|
+
}
|
|
424
|
+
function stringifyMessageContent(content) {
|
|
425
|
+
if (typeof content === "string") {
|
|
426
|
+
return content;
|
|
427
|
+
}
|
|
428
|
+
if (content == null) {
|
|
429
|
+
return "";
|
|
430
|
+
}
|
|
431
|
+
return typeof content === "object" ? JSON.stringify(content) : String(content);
|
|
432
|
+
}
|
|
433
|
+
function parseToolCallInput(rawCall, rawFunction) {
|
|
434
|
+
if ("input" in rawCall) {
|
|
435
|
+
return rawCall.input;
|
|
436
|
+
}
|
|
437
|
+
return parseJsonIfPossible(rawCall.arguments ?? rawFunction.arguments ?? {});
|
|
438
|
+
}
|
|
439
|
+
function sanitizeJsonSchema(schema, isRoot = false) {
|
|
440
|
+
if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
|
|
441
|
+
return { type: "object" };
|
|
442
|
+
}
|
|
443
|
+
const record = schema;
|
|
444
|
+
const sanitized = { ...record };
|
|
445
|
+
if (typeof sanitized.type !== "string") {
|
|
446
|
+
const inferredType = inferJsonSchemaType(sanitized, isRoot);
|
|
447
|
+
if (inferredType) {
|
|
448
|
+
sanitized.type = inferredType;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
if (sanitized.properties && typeof sanitized.properties === "object" && !Array.isArray(sanitized.properties)) {
|
|
452
|
+
const properties = {};
|
|
453
|
+
for (const [key, value] of Object.entries(sanitized.properties)) {
|
|
454
|
+
properties[key] = sanitizeJsonSchema(value);
|
|
455
|
+
}
|
|
456
|
+
sanitized.properties = properties;
|
|
457
|
+
}
|
|
458
|
+
if (sanitized.items) {
|
|
459
|
+
sanitized.items = Array.isArray(sanitized.items) ? sanitized.items.map((item) => sanitizeJsonSchema(item)) : sanitizeJsonSchema(sanitized.items);
|
|
460
|
+
}
|
|
461
|
+
for (const unionKey of ["anyOf", "oneOf", "allOf"]) {
|
|
462
|
+
const value = sanitized[unionKey];
|
|
463
|
+
if (Array.isArray(value)) {
|
|
464
|
+
sanitized[unionKey] = value.map((item) => sanitizeJsonSchema(item));
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
return sanitized;
|
|
468
|
+
}
|
|
469
|
+
function inferJsonSchemaType(schema, isRoot) {
|
|
470
|
+
if ("items" in schema && !("properties" in schema)) {
|
|
471
|
+
return "array";
|
|
472
|
+
}
|
|
473
|
+
if ("properties" in schema || "required" in schema || "additionalProperties" in schema || isRoot) {
|
|
474
|
+
return "object";
|
|
475
|
+
}
|
|
476
|
+
if (Array.isArray(schema.enum) && schema.enum.length > 0) {
|
|
477
|
+
const types = new Set(schema.enum.map((value) => typeof value));
|
|
478
|
+
if (types.size === 1) {
|
|
479
|
+
const [type] = [...types];
|
|
480
|
+
if (type === "string" || type === "number" || type === "boolean") {
|
|
481
|
+
return type;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
function asRecord(value) {
|
|
488
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
489
|
+
}
|
|
490
|
+
function asOptionalRecord(value) {
|
|
491
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : undefined;
|
|
492
|
+
}
|
|
493
|
+
function firstString(...values) {
|
|
494
|
+
for (const value of values) {
|
|
495
|
+
if (typeof value === "string" && value.length > 0) {
|
|
496
|
+
return value;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
return;
|
|
168
500
|
}
|
|
169
501
|
|
|
170
502
|
// models/text.ts
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
503
|
+
var TEXT_NANO_MODEL_TYPE = ModelType2.TEXT_NANO ?? "TEXT_NANO";
|
|
504
|
+
var TEXT_MEDIUM_MODEL_TYPE = ModelType2.TEXT_MEDIUM ?? "TEXT_MEDIUM";
|
|
505
|
+
var TEXT_MEGA_MODEL_TYPE = ModelType2.TEXT_MEGA ?? "TEXT_MEGA";
|
|
506
|
+
var RESPONSE_HANDLER_MODEL_TYPE = ModelType2.RESPONSE_HANDLER ?? "RESPONSE_HANDLER";
|
|
507
|
+
var ACTION_PLANNER_MODEL_TYPE = ModelType2.ACTION_PLANNER ?? "ACTION_PLANNER";
|
|
508
|
+
function summarizeAiSdkErrorForLogs(error, depth = 0) {
|
|
509
|
+
if (depth > 4) {
|
|
510
|
+
return { note: "max depth summarizing nested error" };
|
|
511
|
+
}
|
|
512
|
+
if (error == null) {
|
|
513
|
+
return { raw: String(error) };
|
|
514
|
+
}
|
|
515
|
+
if (typeof error !== "object") {
|
|
516
|
+
return { message: String(error) };
|
|
517
|
+
}
|
|
518
|
+
const e = error;
|
|
519
|
+
const out = {};
|
|
520
|
+
if (typeof e.name === "string")
|
|
521
|
+
out.errorName = e.name;
|
|
522
|
+
if (typeof e.message === "string")
|
|
523
|
+
out.message = e.message;
|
|
524
|
+
if (typeof e.reason === "string")
|
|
525
|
+
out.reason = e.reason;
|
|
526
|
+
if (typeof e.url === "string")
|
|
527
|
+
out.requestUrl = e.url;
|
|
528
|
+
if (typeof e.statusCode === "number")
|
|
529
|
+
out.httpStatus = e.statusCode;
|
|
530
|
+
if (typeof e.responseBody === "string")
|
|
531
|
+
out.ollamaResponseBody = e.responseBody;
|
|
532
|
+
if (Array.isArray(e.errors)) {
|
|
533
|
+
out.attemptErrors = e.errors.map((sub, i) => ({
|
|
534
|
+
attempt: i + 1,
|
|
535
|
+
...summarizeAiSdkErrorForLogs(sub, depth + 1)
|
|
536
|
+
}));
|
|
191
537
|
}
|
|
538
|
+
if (e.cause != null && typeof e.cause === "object") {
|
|
539
|
+
out.cause = summarizeAiSdkErrorForLogs(e.cause, depth + 1);
|
|
540
|
+
}
|
|
541
|
+
return out;
|
|
192
542
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
|
|
543
|
+
function logOllamaTextFailure(phase, modelType, modelId, endpoint, error) {
|
|
544
|
+
logger3.error({
|
|
545
|
+
src: "plugin:ollama:text",
|
|
546
|
+
phase,
|
|
547
|
+
modelType,
|
|
548
|
+
modelId,
|
|
549
|
+
ollamaApiEndpoint: endpoint,
|
|
550
|
+
...summarizeAiSdkErrorForLogs(error)
|
|
551
|
+
}, `[Ollama] ${phase} failed (${modelType}, model=${modelId}). See ollamaResponseBody / attemptErrors for Ollama’s JSON (e.g. insufficient RAM, model missing).`);
|
|
552
|
+
}
|
|
553
|
+
function buildStructuredOutput(responseSchema) {
|
|
554
|
+
if (responseSchema && typeof responseSchema === "object" && "responseFormat" in responseSchema && "parseCompleteOutput" in responseSchema) {
|
|
555
|
+
return responseSchema;
|
|
556
|
+
}
|
|
557
|
+
const schemaOptions = responseSchema && typeof responseSchema === "object" && "schema" in responseSchema ? responseSchema : { schema: responseSchema };
|
|
558
|
+
return Output.object({
|
|
559
|
+
schema: jsonSchema2(schemaOptions.schema),
|
|
560
|
+
...schemaOptions.name ? { name: schemaOptions.name } : {},
|
|
561
|
+
...schemaOptions.description ? { description: schemaOptions.description } : {}
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
function serializeStructuredGenerateTextResult(result) {
|
|
565
|
+
if (result.output !== undefined && result.output !== null) {
|
|
566
|
+
return typeof result.output === "string" ? result.output : JSON.stringify(result.output);
|
|
567
|
+
}
|
|
568
|
+
const trimmed = result.text?.trim() ?? "";
|
|
569
|
+
if (trimmed)
|
|
570
|
+
return trimmed;
|
|
571
|
+
throw new Error("[Ollama] Structured generation returned no text or output.");
|
|
572
|
+
}
|
|
573
|
+
function buildNativeResultCast(result, modelName, usage) {
|
|
574
|
+
const payload = {
|
|
575
|
+
text: result.text,
|
|
576
|
+
toolCalls: mapAiSdkToolCallsToCore(result.toolCalls),
|
|
577
|
+
finishReason: String(result.finishReason ?? ""),
|
|
578
|
+
usage,
|
|
579
|
+
providerMetadata: { modelName }
|
|
580
|
+
};
|
|
581
|
+
return payload;
|
|
582
|
+
}
|
|
583
|
+
function buildOllamaStreamTextResult(args) {
|
|
584
|
+
const streamResult = streamText(args.streamParams);
|
|
585
|
+
const textPromise = Promise.resolve(streamResult.text).catch(() => "");
|
|
586
|
+
const finishReasonPromise = Promise.resolve(streamResult.finishReason).catch(() => {
|
|
587
|
+
return;
|
|
588
|
+
});
|
|
589
|
+
const usagePromise = Promise.resolve(streamResult.usage).then(async (usage) => {
|
|
590
|
+
const fullText = await textPromise;
|
|
591
|
+
const normalized = normalizeTokenUsage(usage) ?? estimateUsage(args.promptForEstimate, fullText);
|
|
592
|
+
emitModelUsed(args.runtime, args.modelType, args.model, normalized);
|
|
593
|
+
return normalized;
|
|
594
|
+
}).catch(() => {
|
|
595
|
+
return;
|
|
596
|
+
});
|
|
597
|
+
async function* textStreamWithUsage() {
|
|
598
|
+
let completed = false;
|
|
599
|
+
try {
|
|
600
|
+
for await (const chunk of streamResult.textStream) {
|
|
601
|
+
yield chunk;
|
|
602
|
+
}
|
|
603
|
+
completed = true;
|
|
604
|
+
} catch (streamErr) {
|
|
605
|
+
logOllamaTextFailure("streamText.textStream", String(args.modelType), args.model, args.endpoint, streamErr);
|
|
606
|
+
throw streamErr;
|
|
607
|
+
} finally {
|
|
608
|
+
if (completed) {
|
|
609
|
+
await usagePromise.catch(() => {
|
|
610
|
+
return;
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
return {
|
|
616
|
+
textStream: textStreamWithUsage(),
|
|
617
|
+
text: textPromise,
|
|
618
|
+
usage: usagePromise,
|
|
619
|
+
finishReason: finishReasonPromise
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
function stringifyPlannerToolArgs(arguments_) {
|
|
623
|
+
if (typeof arguments_ === "string") {
|
|
624
|
+
return arguments_;
|
|
625
|
+
}
|
|
626
|
+
return JSON.stringify(arguments_);
|
|
627
|
+
}
|
|
628
|
+
function buildOllamaStreamWithToolsResult(args) {
|
|
629
|
+
const streamResult = streamText(args.streamParams);
|
|
630
|
+
const sdkTextPromise = Promise.resolve(streamResult.text).catch(() => "");
|
|
631
|
+
const finishReasonPromise = Promise.resolve(streamResult.finishReason).catch(() => {
|
|
632
|
+
return;
|
|
633
|
+
});
|
|
634
|
+
const toolCallsPromise = Promise.resolve(streamResult.toolCalls).then((calls) => mapAiSdkToolCallsToCore(calls)).catch(() => []);
|
|
635
|
+
const usagePromise = Promise.resolve(streamResult.usage).then(async (usage) => {
|
|
636
|
+
const fullText = await sdkTextPromise;
|
|
637
|
+
const normalized = normalizeTokenUsage(usage) ?? estimateUsage(args.promptForEstimate, fullText);
|
|
638
|
+
emitModelUsed(args.runtime, args.modelType, args.model, normalized);
|
|
639
|
+
return normalized;
|
|
640
|
+
}).catch(() => {
|
|
641
|
+
return;
|
|
642
|
+
});
|
|
643
|
+
const isNativePlannerType = args.modelType === RESPONSE_HANDLER_MODEL_TYPE || args.modelType === ACTION_PLANNER_MODEL_TYPE;
|
|
644
|
+
const textPromise = isNativePlannerType ? toolCallsPromise.then(async (mapped) => {
|
|
645
|
+
const first = mapped[0];
|
|
646
|
+
if (first) {
|
|
647
|
+
return stringifyPlannerToolArgs(first.arguments);
|
|
648
|
+
}
|
|
649
|
+
return sdkTextPromise;
|
|
650
|
+
}) : sdkTextPromise;
|
|
651
|
+
async function* textStreamWithUsage() {
|
|
652
|
+
let completed = false;
|
|
653
|
+
try {
|
|
654
|
+
if (isNativePlannerType) {
|
|
655
|
+
for await (const _ of streamResult.textStream) {}
|
|
656
|
+
const mapped = await toolCallsPromise;
|
|
657
|
+
const first = mapped[0];
|
|
658
|
+
if (first) {
|
|
659
|
+
yield stringifyPlannerToolArgs(first.arguments);
|
|
660
|
+
}
|
|
661
|
+
} else {
|
|
662
|
+
for await (const chunk of streamResult.textStream) {
|
|
663
|
+
yield chunk;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
completed = true;
|
|
667
|
+
} catch (streamErr) {
|
|
668
|
+
logOllamaTextFailure("streamText.textStream", String(args.modelType), args.model, args.endpoint, streamErr);
|
|
669
|
+
throw streamErr;
|
|
670
|
+
} finally {
|
|
671
|
+
if (completed) {
|
|
672
|
+
await usagePromise.catch(() => {
|
|
673
|
+
return;
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
return {
|
|
679
|
+
textStream: textStreamWithUsage(),
|
|
680
|
+
text: textPromise,
|
|
681
|
+
usage: usagePromise,
|
|
682
|
+
finishReason: finishReasonPromise,
|
|
683
|
+
toolCalls: toolCallsPromise
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
function getModelNameForType(runtime, modelType) {
|
|
687
|
+
switch (modelType) {
|
|
688
|
+
case TEXT_NANO_MODEL_TYPE:
|
|
689
|
+
return getNanoModel(runtime);
|
|
690
|
+
case TEXT_MEDIUM_MODEL_TYPE:
|
|
691
|
+
return getMediumModel(runtime);
|
|
692
|
+
case ModelType2.TEXT_SMALL:
|
|
693
|
+
return getSmallModel(runtime);
|
|
694
|
+
case ModelType2.TEXT_LARGE:
|
|
695
|
+
return getLargeModel(runtime);
|
|
696
|
+
case TEXT_MEGA_MODEL_TYPE:
|
|
697
|
+
return getMegaModel(runtime);
|
|
698
|
+
case RESPONSE_HANDLER_MODEL_TYPE:
|
|
699
|
+
return getResponseHandlerModel(runtime);
|
|
700
|
+
case ACTION_PLANNER_MODEL_TYPE:
|
|
701
|
+
return getActionPlannerModel(runtime);
|
|
702
|
+
default:
|
|
703
|
+
return getLargeModel(runtime);
|
|
220
704
|
}
|
|
221
705
|
}
|
|
222
|
-
async function
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
}
|
|
706
|
+
async function handleTextWithModelType(runtime, modelType, params) {
|
|
707
|
+
const extended = params;
|
|
708
|
+
const structuredDisabled = isOllamaStructuredOutputDisabled(runtime);
|
|
709
|
+
let responseSchema = extended.responseSchema;
|
|
710
|
+
if (structuredDisabled && extended.responseSchema) {
|
|
711
|
+
logger3.debug("[Ollama] OLLAMA_DISABLE_STRUCTURED_OUTPUT is set — ignoring responseSchema for this call.");
|
|
712
|
+
responseSchema = undefined;
|
|
713
|
+
}
|
|
714
|
+
const tools = normalizeNativeTools(extended.tools);
|
|
715
|
+
const {
|
|
716
|
+
prompt,
|
|
717
|
+
maxTokens = 8192,
|
|
718
|
+
temperature = 0.7,
|
|
719
|
+
frequencyPenalty = 0.7,
|
|
720
|
+
presencePenalty = 0.7
|
|
721
|
+
} = params;
|
|
722
|
+
let modelIdForLog = "";
|
|
230
723
|
try {
|
|
231
|
-
const model = getLargeModel(runtime);
|
|
232
724
|
const baseURL = getBaseURL(runtime);
|
|
233
725
|
const customFetch = runtime.fetch ?? undefined;
|
|
234
|
-
const ollama =
|
|
726
|
+
const ollama = createOllama2({
|
|
235
727
|
fetch: customFetch,
|
|
236
728
|
baseURL
|
|
237
729
|
});
|
|
238
|
-
|
|
730
|
+
const model = getModelNameForType(runtime, modelType);
|
|
731
|
+
modelIdForLog = model;
|
|
732
|
+
logger3.log(`[Ollama] Using ${modelType} model: ${model}`);
|
|
239
733
|
await ensureModelAvailable(model, baseURL, customFetch);
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
734
|
+
const system = resolveEffectiveSystemPrompt({
|
|
735
|
+
params,
|
|
736
|
+
fallback: buildCanonicalSystemPrompt({ character: runtime.character })
|
|
737
|
+
});
|
|
738
|
+
let outputSpec = responseSchema !== undefined && responseSchema !== null ? buildStructuredOutput(responseSchema) : undefined;
|
|
739
|
+
if (tools && outputSpec) {
|
|
740
|
+
logger3.debug("[Ollama] tools and responseSchema both present — omitting structured output for this call.");
|
|
741
|
+
outputSpec = undefined;
|
|
742
|
+
}
|
|
743
|
+
const wireRaw = dropDuplicateLeadingSystemMessage(extended.messages, system);
|
|
744
|
+
const normalizedMessages = normalizeNativeMessages(wireRaw);
|
|
745
|
+
const hasChatMessages = Array.isArray(normalizedMessages) && normalizedMessages.length > 0;
|
|
746
|
+
const toolChoice = tools ? normalizeToolChoice(extended.toolChoice) : undefined;
|
|
747
|
+
const shouldReturnNative = Boolean(hasChatMessages || tools || extended.toolChoice || outputSpec !== undefined);
|
|
748
|
+
const renderedPrompt = hasChatMessages ? "" : renderChatMessagesForPrompt(params.messages, {
|
|
749
|
+
omitDuplicateSystem: system
|
|
750
|
+
}) ?? prompt ?? "";
|
|
751
|
+
const promptOrMessages = hasChatMessages ? { messages: normalizedMessages } : { prompt: renderedPrompt };
|
|
752
|
+
const resolvedStopSequences = Array.isArray(params.stopSequences) && params.stopSequences.length > 0 ? params.stopSequences : undefined;
|
|
753
|
+
const promptForUsageEstimate = hasChatMessages ? JSON.stringify(normalizedMessages) : renderedPrompt;
|
|
754
|
+
const baseGenerateArgs = {
|
|
755
|
+
model: ollama(model),
|
|
756
|
+
...promptOrMessages,
|
|
757
|
+
system,
|
|
243
758
|
temperature,
|
|
244
|
-
maxTokens,
|
|
759
|
+
maxOutputTokens: maxTokens,
|
|
245
760
|
frequencyPenalty,
|
|
246
761
|
presencePenalty,
|
|
247
|
-
stopSequences
|
|
248
|
-
|
|
762
|
+
...resolvedStopSequences ? { stopSequences: resolvedStopSequences } : {},
|
|
763
|
+
...tools ? { tools, ...toolChoice ? { toolChoice } : {} } : {},
|
|
764
|
+
...outputSpec ? { output: outputSpec } : {}
|
|
765
|
+
};
|
|
766
|
+
if (params.stream) {
|
|
767
|
+
if (tools) {
|
|
768
|
+
return buildOllamaStreamWithToolsResult({
|
|
769
|
+
runtime,
|
|
770
|
+
modelType,
|
|
771
|
+
model,
|
|
772
|
+
endpoint: baseURL,
|
|
773
|
+
streamParams: baseGenerateArgs,
|
|
774
|
+
promptForEstimate: promptForUsageEstimate
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
if (!extended.toolChoice) {
|
|
778
|
+
if (!outputSpec) {
|
|
779
|
+
return buildOllamaStreamTextResult({
|
|
780
|
+
runtime,
|
|
781
|
+
modelType,
|
|
782
|
+
model,
|
|
783
|
+
endpoint: baseURL,
|
|
784
|
+
streamParams: baseGenerateArgs,
|
|
785
|
+
promptForEstimate: promptForUsageEstimate
|
|
786
|
+
});
|
|
787
|
+
}
|
|
788
|
+
logger3.debug({ src: "plugin:ollama:text", modelType }, "[Ollama] stream=true with responseSchema (no tools) — using generateText. Why: ollama-ai-provider-v2 does not support structured JSON output on the streamText path for this adapter.");
|
|
789
|
+
} else {
|
|
790
|
+
logger3.debug({ src: "plugin:ollama:text", modelType }, "[Ollama] stream=true with toolChoice but no tools on wire — using generateText. Why: streamText+tools requires a ToolSet; callers should pass tools alongside toolChoice.");
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
const result = await generateText(baseGenerateArgs);
|
|
794
|
+
const usage = normalizeTokenUsage(result.usage) ?? estimateUsage(promptForUsageEstimate, result.text);
|
|
795
|
+
emitModelUsed(runtime, modelType, model, usage);
|
|
796
|
+
if (shouldReturnNative) {
|
|
797
|
+
if (outputSpec !== undefined) {
|
|
798
|
+
return serializeStructuredGenerateTextResult(result);
|
|
799
|
+
}
|
|
800
|
+
return buildNativeResultCast(result, model, usage);
|
|
801
|
+
}
|
|
802
|
+
return result.text;
|
|
249
803
|
} catch (error) {
|
|
250
|
-
|
|
804
|
+
let endpoint = "";
|
|
805
|
+
try {
|
|
806
|
+
endpoint = getBaseURL(runtime);
|
|
807
|
+
} catch {}
|
|
808
|
+
logOllamaTextFailure("generateText", String(modelType), modelIdForLog || "(unknown)", endpoint, error);
|
|
251
809
|
return "Error generating text. Please try again later.";
|
|
252
810
|
}
|
|
253
811
|
}
|
|
812
|
+
async function handleTextSmall(runtime, params) {
|
|
813
|
+
return handleTextWithModelType(runtime, ModelType2.TEXT_SMALL, params);
|
|
814
|
+
}
|
|
815
|
+
async function handleTextNano(runtime, params) {
|
|
816
|
+
return handleTextWithModelType(runtime, TEXT_NANO_MODEL_TYPE, params);
|
|
817
|
+
}
|
|
818
|
+
async function handleTextMedium(runtime, params) {
|
|
819
|
+
return handleTextWithModelType(runtime, TEXT_MEDIUM_MODEL_TYPE, params);
|
|
820
|
+
}
|
|
821
|
+
async function handleTextLarge(runtime, params) {
|
|
822
|
+
return handleTextWithModelType(runtime, ModelType2.TEXT_LARGE, params);
|
|
823
|
+
}
|
|
824
|
+
async function handleTextMega(runtime, params) {
|
|
825
|
+
return handleTextWithModelType(runtime, TEXT_MEGA_MODEL_TYPE, params);
|
|
826
|
+
}
|
|
827
|
+
async function handleResponseHandler(runtime, params) {
|
|
828
|
+
return handleTextWithModelType(runtime, RESPONSE_HANDLER_MODEL_TYPE, params);
|
|
829
|
+
}
|
|
830
|
+
async function handleActionPlanner(runtime, params) {
|
|
831
|
+
return handleTextWithModelType(runtime, ACTION_PLANNER_MODEL_TYPE, params);
|
|
832
|
+
}
|
|
254
833
|
|
|
255
834
|
// plugin.ts
|
|
256
835
|
var _globalThis = globalThis;
|
|
@@ -262,15 +841,39 @@ function getProcessEnv() {
|
|
|
262
841
|
return process.env;
|
|
263
842
|
}
|
|
264
843
|
var env = getProcessEnv();
|
|
844
|
+
var TEXT_NANO_MODEL_TYPE2 = ModelType3.TEXT_NANO ?? "TEXT_NANO";
|
|
845
|
+
var TEXT_MEDIUM_MODEL_TYPE2 = ModelType3.TEXT_MEDIUM ?? "TEXT_MEDIUM";
|
|
846
|
+
var TEXT_MEGA_MODEL_TYPE2 = ModelType3.TEXT_MEGA ?? "TEXT_MEGA";
|
|
847
|
+
var RESPONSE_HANDLER_MODEL_TYPE2 = ModelType3.RESPONSE_HANDLER ?? "RESPONSE_HANDLER";
|
|
848
|
+
var ACTION_PLANNER_MODEL_TYPE2 = ModelType3.ACTION_PLANNER ?? "ACTION_PLANNER";
|
|
265
849
|
var ollamaPlugin = {
|
|
266
850
|
name: "ollama",
|
|
267
851
|
description: "Ollama plugin for local LLM inference",
|
|
852
|
+
autoEnable: {
|
|
853
|
+
envKeys: ["OLLAMA_BASE_URL"]
|
|
854
|
+
},
|
|
268
855
|
config: {
|
|
269
856
|
OLLAMA_API_ENDPOINT: env.OLLAMA_API_ENDPOINT ?? null,
|
|
857
|
+
OLLAMA_NANO_MODEL: env.OLLAMA_NANO_MODEL ?? null,
|
|
270
858
|
OLLAMA_SMALL_MODEL: env.OLLAMA_SMALL_MODEL ?? null,
|
|
271
859
|
OLLAMA_MEDIUM_MODEL: env.OLLAMA_MEDIUM_MODEL ?? null,
|
|
272
860
|
OLLAMA_LARGE_MODEL: env.OLLAMA_LARGE_MODEL ?? null,
|
|
273
|
-
|
|
861
|
+
OLLAMA_MEGA_MODEL: env.OLLAMA_MEGA_MODEL ?? null,
|
|
862
|
+
OLLAMA_RESPONSE_HANDLER_MODEL: env.OLLAMA_RESPONSE_HANDLER_MODEL ?? null,
|
|
863
|
+
OLLAMA_SHOULD_RESPOND_MODEL: env.OLLAMA_SHOULD_RESPOND_MODEL ?? null,
|
|
864
|
+
OLLAMA_ACTION_PLANNER_MODEL: env.OLLAMA_ACTION_PLANNER_MODEL ?? null,
|
|
865
|
+
OLLAMA_PLANNER_MODEL: env.OLLAMA_PLANNER_MODEL ?? null,
|
|
866
|
+
NANO_MODEL: env.NANO_MODEL ?? null,
|
|
867
|
+
MEDIUM_MODEL: env.MEDIUM_MODEL ?? null,
|
|
868
|
+
SMALL_MODEL: env.SMALL_MODEL ?? null,
|
|
869
|
+
LARGE_MODEL: env.LARGE_MODEL ?? null,
|
|
870
|
+
MEGA_MODEL: env.MEGA_MODEL ?? null,
|
|
871
|
+
RESPONSE_HANDLER_MODEL: env.RESPONSE_HANDLER_MODEL ?? null,
|
|
872
|
+
SHOULD_RESPOND_MODEL: env.SHOULD_RESPOND_MODEL ?? null,
|
|
873
|
+
ACTION_PLANNER_MODEL: env.ACTION_PLANNER_MODEL ?? null,
|
|
874
|
+
PLANNER_MODEL: env.PLANNER_MODEL ?? null,
|
|
875
|
+
OLLAMA_EMBEDDING_MODEL: env.OLLAMA_EMBEDDING_MODEL ?? null,
|
|
876
|
+
OLLAMA_DISABLE_STRUCTURED_OUTPUT: env.OLLAMA_DISABLE_STRUCTURED_OUTPUT ?? null
|
|
274
877
|
},
|
|
275
878
|
async init(_config, runtime) {
|
|
276
879
|
const baseURL = getBaseURL(runtime);
|
|
@@ -278,7 +881,7 @@ var ollamaPlugin = {
|
|
|
278
881
|
if (!baseURL || baseURL === "http://localhost:11434/api") {
|
|
279
882
|
const endpoint = runtime.getSetting("OLLAMA_API_ENDPOINT");
|
|
280
883
|
if (!endpoint) {
|
|
281
|
-
|
|
884
|
+
logger4.warn("OLLAMA_API_ENDPOINT not set, using default localhost:11434");
|
|
282
885
|
}
|
|
283
886
|
}
|
|
284
887
|
try {
|
|
@@ -287,28 +890,37 @@ var ollamaPlugin = {
|
|
|
287
890
|
headers: { "Content-Type": "application/json" }
|
|
288
891
|
});
|
|
289
892
|
if (!response.ok) {
|
|
290
|
-
|
|
893
|
+
logger4.warn(`Ollama API validation failed: ${response.statusText}`);
|
|
291
894
|
}
|
|
292
895
|
} catch (fetchError) {
|
|
293
896
|
const message = fetchError instanceof Error ? fetchError.message : String(fetchError);
|
|
294
|
-
|
|
897
|
+
logger4.warn(`Ollama API validation error: ${message}`);
|
|
295
898
|
}
|
|
296
899
|
},
|
|
297
900
|
models: {
|
|
298
|
-
[
|
|
901
|
+
[ModelType3.TEXT_EMBEDDING]: async (runtime, params) => {
|
|
299
902
|
return handleTextEmbedding(runtime, params);
|
|
300
903
|
},
|
|
301
|
-
[
|
|
904
|
+
[TEXT_NANO_MODEL_TYPE2]: async (runtime, params) => {
|
|
905
|
+
return handleTextNano(runtime, params);
|
|
906
|
+
},
|
|
907
|
+
[ModelType3.TEXT_SMALL]: async (runtime, params) => {
|
|
302
908
|
return handleTextSmall(runtime, params);
|
|
303
909
|
},
|
|
304
|
-
[
|
|
910
|
+
[TEXT_MEDIUM_MODEL_TYPE2]: async (runtime, params) => {
|
|
911
|
+
return handleTextMedium(runtime, params);
|
|
912
|
+
},
|
|
913
|
+
[ModelType3.TEXT_LARGE]: async (runtime, params) => {
|
|
305
914
|
return handleTextLarge(runtime, params);
|
|
306
915
|
},
|
|
307
|
-
[
|
|
308
|
-
return
|
|
916
|
+
[TEXT_MEGA_MODEL_TYPE2]: async (runtime, params) => {
|
|
917
|
+
return handleTextMega(runtime, params);
|
|
918
|
+
},
|
|
919
|
+
[RESPONSE_HANDLER_MODEL_TYPE2]: async (runtime, params) => {
|
|
920
|
+
return handleResponseHandler(runtime, params);
|
|
309
921
|
},
|
|
310
|
-
[
|
|
311
|
-
return
|
|
922
|
+
[ACTION_PLANNER_MODEL_TYPE2]: async (runtime, params) => {
|
|
923
|
+
return handleActionPlanner(runtime, params);
|
|
312
924
|
}
|
|
313
925
|
},
|
|
314
926
|
tests: [
|
|
@@ -322,10 +934,10 @@ var ollamaPlugin = {
|
|
|
322
934
|
const apiBase = getApiBase(runtime);
|
|
323
935
|
const response = await fetch(`${apiBase}/api/tags`);
|
|
324
936
|
if (!response.ok) {
|
|
325
|
-
|
|
937
|
+
logger4.error(`Failed to validate Ollama API: ${response.statusText}`);
|
|
326
938
|
}
|
|
327
939
|
} catch (error) {
|
|
328
|
-
|
|
940
|
+
logger4.error({ error }, "Error in ollama_test_url_validation");
|
|
329
941
|
}
|
|
330
942
|
}
|
|
331
943
|
},
|
|
@@ -333,12 +945,13 @@ var ollamaPlugin = {
|
|
|
333
945
|
name: "ollama_test_text_embedding",
|
|
334
946
|
fn: async (runtime) => {
|
|
335
947
|
try {
|
|
336
|
-
const
|
|
948
|
+
const runModel = runtime.useModel.bind(runtime);
|
|
949
|
+
const embedding = await runModel(ModelType3.TEXT_EMBEDDING, {
|
|
337
950
|
text: "Hello, world!"
|
|
338
951
|
});
|
|
339
|
-
|
|
952
|
+
logger4.log({ embedding }, "Generated embedding");
|
|
340
953
|
} catch (error) {
|
|
341
|
-
|
|
954
|
+
logger4.error({ error }, "Error in test_text_embedding");
|
|
342
955
|
}
|
|
343
956
|
}
|
|
344
957
|
},
|
|
@@ -346,16 +959,17 @@ var ollamaPlugin = {
|
|
|
346
959
|
name: "ollama_test_text_large",
|
|
347
960
|
fn: async (runtime) => {
|
|
348
961
|
try {
|
|
349
|
-
const
|
|
962
|
+
const runModel = runtime.useModel.bind(runtime);
|
|
963
|
+
const text = await runModel(ModelType3.TEXT_LARGE, {
|
|
350
964
|
prompt: "What is the nature of reality in 10 words?"
|
|
351
965
|
});
|
|
352
966
|
if (text.length === 0) {
|
|
353
|
-
|
|
967
|
+
logger4.error("Failed to generate text");
|
|
354
968
|
return;
|
|
355
969
|
}
|
|
356
|
-
|
|
970
|
+
logger4.log({ text }, "Generated with test_text_large");
|
|
357
971
|
} catch (error) {
|
|
358
|
-
|
|
972
|
+
logger4.error({ error }, "Error in test_text_large");
|
|
359
973
|
}
|
|
360
974
|
}
|
|
361
975
|
},
|
|
@@ -363,46 +977,57 @@ var ollamaPlugin = {
|
|
|
363
977
|
name: "ollama_test_text_small",
|
|
364
978
|
fn: async (runtime) => {
|
|
365
979
|
try {
|
|
366
|
-
const
|
|
980
|
+
const runModel = runtime.useModel.bind(runtime);
|
|
981
|
+
const text = await runModel(ModelType3.TEXT_SMALL, {
|
|
367
982
|
prompt: "What is the nature of reality in 10 words?"
|
|
368
983
|
});
|
|
369
984
|
if (text.length === 0) {
|
|
370
|
-
|
|
985
|
+
logger4.error("Failed to generate text");
|
|
371
986
|
return;
|
|
372
987
|
}
|
|
373
|
-
|
|
988
|
+
logger4.log({ text }, "Generated with test_text_small");
|
|
374
989
|
} catch (error) {
|
|
375
|
-
|
|
990
|
+
logger4.error({ error }, "Error in test_text_small");
|
|
376
991
|
}
|
|
377
992
|
}
|
|
378
993
|
},
|
|
379
994
|
{
|
|
380
|
-
name: "
|
|
995
|
+
name: "ollama_test_structured_output_via_text_small",
|
|
381
996
|
fn: async (runtime) => {
|
|
382
997
|
try {
|
|
383
|
-
const
|
|
998
|
+
const runModel = runtime.useModel.bind(runtime);
|
|
999
|
+
const result = await runModel(ModelType3.TEXT_SMALL, {
|
|
384
1000
|
prompt: "Generate a JSON object representing a user profile with name, age, and hobbies",
|
|
385
1001
|
temperature: 0.7,
|
|
386
|
-
|
|
1002
|
+
responseSchema: {
|
|
1003
|
+
type: "object",
|
|
1004
|
+
properties: {
|
|
1005
|
+
name: { type: "string" },
|
|
1006
|
+
age: { type: "number" },
|
|
1007
|
+
hobbies: { type: "array", items: { type: "string" } }
|
|
1008
|
+
},
|
|
1009
|
+
required: ["name", "age", "hobbies"]
|
|
1010
|
+
}
|
|
387
1011
|
});
|
|
388
|
-
|
|
1012
|
+
logger4.log({ result }, "Generated structured output via TEXT_SMALL");
|
|
389
1013
|
} catch (error) {
|
|
390
|
-
|
|
1014
|
+
logger4.error({ error }, "Error in test_structured_output_via_text_small");
|
|
391
1015
|
}
|
|
392
1016
|
}
|
|
393
1017
|
},
|
|
394
1018
|
{
|
|
395
|
-
name: "
|
|
1019
|
+
name: "ollama_test_structured_output_via_text_large",
|
|
396
1020
|
fn: async (runtime) => {
|
|
397
1021
|
try {
|
|
398
|
-
const
|
|
1022
|
+
const runModel = runtime.useModel.bind(runtime);
|
|
1023
|
+
const result = await runModel(ModelType3.TEXT_LARGE, {
|
|
399
1024
|
prompt: "Generate a detailed JSON object representing a restaurant with name, cuisine type, menu items with prices, and customer reviews",
|
|
400
1025
|
temperature: 0.7,
|
|
401
|
-
|
|
1026
|
+
responseSchema: { type: "object" }
|
|
402
1027
|
});
|
|
403
|
-
|
|
1028
|
+
logger4.log({ result }, "Generated structured output via TEXT_LARGE");
|
|
404
1029
|
} catch (error) {
|
|
405
|
-
|
|
1030
|
+
logger4.error({ error }, "Error in test_structured_output_via_text_large");
|
|
406
1031
|
}
|
|
407
1032
|
}
|
|
408
1033
|
}
|
|
@@ -410,20 +1035,29 @@ var ollamaPlugin = {
|
|
|
410
1035
|
}
|
|
411
1036
|
]
|
|
412
1037
|
};
|
|
1038
|
+
// index.browser.ts
|
|
1039
|
+
var defaultOllamaPlugin = ollamaPlugin;
|
|
1040
|
+
var index_browser_default = defaultOllamaPlugin;
|
|
413
1041
|
export {
|
|
414
1042
|
ollamaPlugin,
|
|
1043
|
+
isOllamaStructuredOutputDisabled,
|
|
415
1044
|
getSmallModel,
|
|
416
1045
|
getSetting,
|
|
1046
|
+
getResponseHandlerModel,
|
|
1047
|
+
getNanoModel,
|
|
1048
|
+
getMegaModel,
|
|
1049
|
+
getMediumModel,
|
|
417
1050
|
getLargeModel,
|
|
418
1051
|
getEmbeddingModel,
|
|
419
1052
|
getBaseURL,
|
|
420
1053
|
getApiBase,
|
|
421
|
-
|
|
1054
|
+
getActionPlannerModel,
|
|
1055
|
+
index_browser_default as default,
|
|
422
1056
|
DEFAULT_SMALL_MODEL,
|
|
423
1057
|
DEFAULT_OLLAMA_URL,
|
|
424
1058
|
DEFAULT_LARGE_MODEL,
|
|
425
1059
|
DEFAULT_EMBEDDING_MODEL
|
|
426
1060
|
};
|
|
427
1061
|
|
|
428
|
-
//# debugId=
|
|
1062
|
+
//# debugId=A63C5405E663BB1264756E2164756E21
|
|
429
1063
|
//# sourceMappingURL=index.browser.js.map
|