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