@elizaos/plugin-lmstudio 2.0.3-beta.6 → 2.0.3-beta.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/browser/index.browser.js +849 -0
  2. package/dist/browser/index.browser.js.map +17 -0
  3. package/dist/browser/index.d.ts +2 -0
  4. package/dist/cjs/index.d.ts +2 -0
  5. package/dist/cjs/index.node.cjs +879 -0
  6. package/dist/cjs/index.node.cjs.map +17 -0
  7. package/dist/node/auto-enable.d.ts +3 -0
  8. package/dist/node/auto-enable.d.ts.map +1 -0
  9. package/dist/node/index.browser.d.ts +8 -0
  10. package/dist/node/index.browser.d.ts.map +1 -0
  11. package/dist/node/index.d.ts +2 -0
  12. package/dist/node/index.d.ts.map +1 -0
  13. package/dist/node/index.node.d.ts +8 -0
  14. package/dist/node/index.node.d.ts.map +1 -0
  15. package/dist/node/index.node.js +849 -0
  16. package/dist/node/index.node.js.map +17 -0
  17. package/dist/node/models/embedding.d.ts +17 -0
  18. package/dist/node/models/embedding.d.ts.map +1 -0
  19. package/dist/node/models/index.d.ts +3 -0
  20. package/dist/node/models/index.d.ts.map +1 -0
  21. package/dist/node/models/text.d.ts +39 -0
  22. package/dist/node/models/text.d.ts.map +1 -0
  23. package/dist/node/plugin.d.ts +13 -0
  24. package/dist/node/plugin.d.ts.map +1 -0
  25. package/dist/node/types/index.d.ts +37 -0
  26. package/dist/node/types/index.d.ts.map +1 -0
  27. package/dist/node/utils/client.d.ts +17 -0
  28. package/dist/node/utils/client.d.ts.map +1 -0
  29. package/dist/node/utils/config.d.ts +37 -0
  30. package/dist/node/utils/config.d.ts.map +1 -0
  31. package/dist/node/utils/detect.d.ts +43 -0
  32. package/dist/node/utils/detect.d.ts.map +1 -0
  33. package/dist/node/utils/index.d.ts +4 -0
  34. package/dist/node/utils/index.d.ts.map +1 -0
  35. package/dist/node/utils/model-usage.d.ts +22 -0
  36. package/dist/node/utils/model-usage.d.ts.map +1 -0
  37. package/dist/node/vitest.config.d.ts +3 -0
  38. package/dist/node/vitest.config.d.ts.map +1 -0
  39. package/package.json +4 -4
@@ -0,0 +1,879 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ function __accessProp(key) {
6
+ return this[key];
7
+ }
8
+ var __toCommonJS = (from) => {
9
+ var entry = (__moduleCache ??= new WeakMap).get(from), desc;
10
+ if (entry)
11
+ return entry;
12
+ entry = __defProp({}, "__esModule", { value: true });
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (var key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(entry, key))
16
+ __defProp(entry, key, {
17
+ get: __accessProp.bind(from, key),
18
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
19
+ });
20
+ }
21
+ __moduleCache.set(from, entry);
22
+ return entry;
23
+ };
24
+ var __moduleCache;
25
+ var __returnValue = (v) => v;
26
+ function __exportSetter(name, newValue) {
27
+ this[name] = __returnValue.bind(null, newValue);
28
+ }
29
+ var __export = (target, all) => {
30
+ for (var name in all)
31
+ __defProp(target, name, {
32
+ get: all[name],
33
+ enumerable: true,
34
+ configurable: true,
35
+ set: __exportSetter.bind(all, name)
36
+ });
37
+ };
38
+
39
+ // index.node.ts
40
+ var exports_index_node = {};
41
+ __export(exports_index_node, {
42
+ shouldAutoDetect: () => shouldAutoDetect,
43
+ parseModelsResponse: () => parseModelsResponse,
44
+ lmStudioPlugin: () => lmStudioPlugin,
45
+ getSmallModel: () => getSmallModel,
46
+ getSetting: () => getSetting,
47
+ getLargeModel: () => getLargeModel,
48
+ getEmbeddingModel: () => getEmbeddingModel,
49
+ getBaseURL: () => getBaseURL,
50
+ getApiKey: () => getApiKey,
51
+ getApiBase: () => getApiBase,
52
+ detectLMStudio: () => detectLMStudio,
53
+ default: () => index_node_default,
54
+ DEFAULT_LMSTUDIO_URL: () => DEFAULT_LMSTUDIO_URL
55
+ });
56
+ module.exports = __toCommonJS(exports_index_node);
57
+
58
+ // plugin.ts
59
+ var import_core4 = require("@elizaos/core");
60
+
61
+ // models/embedding.ts
62
+ var import_core2 = require("@elizaos/core");
63
+ var import_ai = require("ai");
64
+
65
+ // utils/client.ts
66
+ var import_openai_compatible = require("@ai-sdk/openai-compatible");
67
+
68
+ // utils/config.ts
69
+ var DEFAULT_LMSTUDIO_URL = "http://localhost:1234/v1";
70
+ function getEnvValue(key) {
71
+ if (typeof process === "undefined" || !process.env) {
72
+ return;
73
+ }
74
+ const value = process.env[key];
75
+ return value === undefined ? undefined : String(value);
76
+ }
77
+ function getSetting(runtime, key, defaultValue) {
78
+ const value = runtime.getSetting(key);
79
+ if (value !== undefined && value !== null) {
80
+ return String(value);
81
+ }
82
+ return getEnvValue(key) ?? defaultValue;
83
+ }
84
+ function getBaseURL(runtime) {
85
+ const raw = getSetting(runtime, "LMSTUDIO_BASE_URL") ?? DEFAULT_LMSTUDIO_URL;
86
+ const trimmed = raw.trim().replace(/\/+$/, "");
87
+ if (trimmed === "") {
88
+ return DEFAULT_LMSTUDIO_URL;
89
+ }
90
+ if (/\/v\d+$/.test(trimmed)) {
91
+ return trimmed;
92
+ }
93
+ return `${trimmed}/v1`;
94
+ }
95
+ function getApiBase(runtime) {
96
+ const baseURL = getBaseURL(runtime);
97
+ return baseURL.replace(/\/v\d+$/, "");
98
+ }
99
+ function getApiKey(runtime) {
100
+ const value = getSetting(runtime, "LMSTUDIO_API_KEY");
101
+ if (!value || value.trim() === "") {
102
+ return;
103
+ }
104
+ return value.trim();
105
+ }
106
+ function getSmallModel(runtime) {
107
+ return getSetting(runtime, "LMSTUDIO_SMALL_MODEL") ?? getSetting(runtime, "SMALL_MODEL") ?? undefined;
108
+ }
109
+ function getLargeModel(runtime) {
110
+ return getSetting(runtime, "LMSTUDIO_LARGE_MODEL") ?? getSetting(runtime, "LARGE_MODEL") ?? undefined;
111
+ }
112
+ function getEmbeddingModel(runtime) {
113
+ return getSetting(runtime, "LMSTUDIO_EMBEDDING_MODEL") ?? undefined;
114
+ }
115
+ function shouldAutoDetect(runtime) {
116
+ const value = getSetting(runtime, "LMSTUDIO_AUTO_DETECT", "true")?.trim().toLowerCase();
117
+ if (value === undefined || value === "") {
118
+ return true;
119
+ }
120
+ return value === "1" || value === "true" || value === "yes" || value === "on";
121
+ }
122
+
123
+ // utils/client.ts
124
+ function createLMStudioClient(runtime) {
125
+ const baseURL = getBaseURL(runtime);
126
+ const apiKey = getApiKey(runtime);
127
+ return import_openai_compatible.createOpenAICompatible({
128
+ name: "lmstudio",
129
+ baseURL,
130
+ ...apiKey ? { apiKey } : {},
131
+ ...runtime.fetch ? { fetch: runtime.fetch } : {},
132
+ includeUsage: true
133
+ });
134
+ }
135
+
136
+ // utils/model-usage.ts
137
+ var import_core = require("@elizaos/core");
138
+ function toFiniteNumber(value) {
139
+ if (typeof value !== "number" || !Number.isFinite(value)) {
140
+ return;
141
+ }
142
+ return Math.max(0, Math.round(value));
143
+ }
144
+ function normalizeTokenUsage(usage) {
145
+ if (!usage || typeof usage !== "object") {
146
+ return null;
147
+ }
148
+ const record = usage;
149
+ const promptTokens = toFiniteNumber(record.inputTokens ?? record.promptTokens);
150
+ const completionTokens = toFiniteNumber(record.outputTokens ?? record.completionTokens);
151
+ const totalTokens = toFiniteNumber(record.totalTokens);
152
+ if (promptTokens === undefined && completionTokens === undefined && totalTokens === undefined) {
153
+ return null;
154
+ }
155
+ const normalizedPromptTokens = promptTokens ?? (completionTokens === undefined && totalTokens !== undefined ? totalTokens : Math.max(0, (totalTokens ?? 0) - (completionTokens ?? 0)));
156
+ const normalizedCompletionTokens = completionTokens ?? Math.max(0, (totalTokens ?? normalizedPromptTokens) - normalizedPromptTokens);
157
+ return {
158
+ promptTokens: normalizedPromptTokens,
159
+ completionTokens: normalizedCompletionTokens,
160
+ totalTokens: totalTokens ?? normalizedPromptTokens + normalizedCompletionTokens
161
+ };
162
+ }
163
+ function estimateTokenCount(text) {
164
+ return text.length === 0 ? 0 : Math.ceil(text.length / 4);
165
+ }
166
+ function stringifyForUsage(value) {
167
+ if (typeof value === "string") {
168
+ return value;
169
+ }
170
+ try {
171
+ return JSON.stringify(value);
172
+ } catch {
173
+ return String(value);
174
+ }
175
+ }
176
+ function estimateUsage(prompt, response) {
177
+ const promptTokens = estimateTokenCount(prompt);
178
+ const completionTokens = estimateTokenCount(stringifyForUsage(response));
179
+ return {
180
+ promptTokens,
181
+ completionTokens,
182
+ totalTokens: promptTokens + completionTokens,
183
+ estimated: true
184
+ };
185
+ }
186
+ function estimateEmbeddingUsage(text) {
187
+ const promptTokens = estimateTokenCount(text);
188
+ return {
189
+ promptTokens,
190
+ completionTokens: 0,
191
+ totalTokens: promptTokens,
192
+ estimated: true
193
+ };
194
+ }
195
+ function emitModelUsed(runtime, type, model, usage) {
196
+ runtime.emitEvent(import_core.EventType.MODEL_USED, {
197
+ runtime,
198
+ source: "lmstudio",
199
+ provider: "lmstudio",
200
+ type,
201
+ model,
202
+ modelName: model,
203
+ tokens: {
204
+ prompt: usage.promptTokens,
205
+ completion: usage.completionTokens,
206
+ total: usage.totalTokens,
207
+ ...usage.estimated ? { estimated: true } : {}
208
+ },
209
+ ...usage.estimated ? { usageEstimated: true } : {}
210
+ });
211
+ }
212
+
213
+ // models/embedding.ts
214
+ var DEFAULT_ZERO_VECTOR_DIM = 1536;
215
+ function extractText(params) {
216
+ if (params === null) {
217
+ return "";
218
+ }
219
+ if (typeof params === "string") {
220
+ return params;
221
+ }
222
+ if (typeof params === "object" && typeof params.text === "string") {
223
+ return params.text;
224
+ }
225
+ return "";
226
+ }
227
+ async function handleTextEmbedding(runtime, params) {
228
+ const modelName = getEmbeddingModel(runtime);
229
+ if (!modelName) {
230
+ import_core2.logger.warn("[LMStudio] LMSTUDIO_EMBEDDING_MODEL not set — returning zero vector. Set it to a loaded embedding model in LM Studio.");
231
+ return new Array(DEFAULT_ZERO_VECTOR_DIM).fill(0);
232
+ }
233
+ let text = extractText(params);
234
+ const maxChars = 8000 * 4;
235
+ if (text.length > maxChars) {
236
+ import_core2.logger.warn(`[LMStudio] Embedding input too long (~${Math.ceil(text.length / 4)} tokens), truncating to ~8000 tokens`);
237
+ text = text.slice(0, maxChars);
238
+ }
239
+ const embeddingText = text || "test";
240
+ try {
241
+ const client = createLMStudioClient(runtime);
242
+ const { embedding, usage } = await import_ai.embed({
243
+ model: client.textEmbeddingModel(modelName),
244
+ value: embeddingText
245
+ });
246
+ emitModelUsed(runtime, import_core2.ModelType.TEXT_EMBEDDING, modelName, normalizeTokenUsage(usage) ?? estimateEmbeddingUsage(embeddingText));
247
+ return embedding;
248
+ } catch (error) {
249
+ import_core2.logger.error({ error }, "[LMStudio] Error generating embedding");
250
+ throw error;
251
+ }
252
+ }
253
+
254
+ // models/text.ts
255
+ var import_core3 = require("@elizaos/core");
256
+ var import_ai2 = require("ai");
257
+
258
+ // utils/detect.ts
259
+ function normalizeBaseURL(input) {
260
+ const raw = (input ?? DEFAULT_LMSTUDIO_URL).replace(/\/+$/, "");
261
+ if (/\/v\d+$/.test(raw)) {
262
+ return raw;
263
+ }
264
+ return `${raw}/v1`;
265
+ }
266
+ function parseModelsResponse(body) {
267
+ if (Array.isArray(body)) {
268
+ return body.filter((entry) => {
269
+ return Boolean(entry) && typeof entry.id === "string";
270
+ });
271
+ }
272
+ if (body && typeof body === "object") {
273
+ const shaped = body;
274
+ if (Array.isArray(shaped.data)) {
275
+ return shaped.data.filter((entry) => {
276
+ return Boolean(entry) && typeof entry.id === "string";
277
+ });
278
+ }
279
+ }
280
+ return null;
281
+ }
282
+ async function detectLMStudio(options = {}) {
283
+ const baseURL = normalizeBaseURL(options.baseURL);
284
+ const fetcher = options.fetcher ?? fetch;
285
+ const timeoutMs = options.timeoutMs ?? 1500;
286
+ const controller = new AbortController;
287
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
288
+ try {
289
+ const headers = { "Content-Type": "application/json" };
290
+ if (options.apiKey) {
291
+ headers.Authorization = `Bearer ${options.apiKey}`;
292
+ }
293
+ const response = await fetcher(`${baseURL}/models`, {
294
+ method: "GET",
295
+ headers,
296
+ signal: controller.signal
297
+ });
298
+ if (!response.ok) {
299
+ return {
300
+ available: false,
301
+ baseURL,
302
+ error: `HTTP ${response.status} ${response.statusText}`
303
+ };
304
+ }
305
+ const body = await response.json();
306
+ const models = parseModelsResponse(body);
307
+ if (!models) {
308
+ return {
309
+ available: false,
310
+ baseURL,
311
+ error: "unexpected /v1/models response shape"
312
+ };
313
+ }
314
+ return { available: true, baseURL, models };
315
+ } catch (err) {
316
+ const message = err instanceof Error ? err.message : String(err);
317
+ return { available: false, baseURL, error: message };
318
+ } finally {
319
+ clearTimeout(timer);
320
+ }
321
+ }
322
+
323
+ // models/text.ts
324
+ var TEXT_NANO_MODEL_TYPE = import_core3.ModelType.TEXT_NANO;
325
+ var TEXT_MEDIUM_MODEL_TYPE = import_core3.ModelType.TEXT_MEDIUM;
326
+ var TEXT_MEGA_MODEL_TYPE = import_core3.ModelType.TEXT_MEGA;
327
+ var RESPONSE_HANDLER_MODEL_TYPE = import_core3.ModelType.RESPONSE_HANDLER;
328
+ var ACTION_PLANNER_MODEL_TYPE = import_core3.ModelType.ACTION_PLANNER;
329
+ var _firstModelIdCache = new WeakMap;
330
+ async function resolveModelForType(runtime, modelType) {
331
+ if (modelType === import_core3.ModelType.TEXT_LARGE || modelType === TEXT_MEGA_MODEL_TYPE || modelType === ACTION_PLANNER_MODEL_TYPE) {
332
+ const large = getLargeModel(runtime);
333
+ if (large)
334
+ return large;
335
+ } else {
336
+ const small = getSmallModel(runtime);
337
+ if (small)
338
+ return small;
339
+ }
340
+ let pending = _firstModelIdCache.get(runtime);
341
+ if (!pending) {
342
+ pending = (async () => {
343
+ const result = await detectLMStudio({
344
+ baseURL: getBaseURL(runtime),
345
+ ...runtime.fetch ? { fetcher: runtime.fetch } : {}
346
+ });
347
+ if (!result.available || !result.models || result.models.length === 0) {
348
+ return null;
349
+ }
350
+ const first = result.models[0];
351
+ return first.id;
352
+ })();
353
+ _firstModelIdCache.set(runtime, pending);
354
+ }
355
+ const resolved = await pending;
356
+ if (resolved) {
357
+ return resolved;
358
+ }
359
+ throw new Error("[LMStudio] No model configured and `GET /v1/models` returned no entries. Set LMSTUDIO_SMALL_MODEL / LMSTUDIO_LARGE_MODEL or load a model in LM Studio.");
360
+ }
361
+ function summarizeAiSdkError(error, depth = 0) {
362
+ if (depth > 4) {
363
+ return { note: "max depth summarizing nested error" };
364
+ }
365
+ if (error == null) {
366
+ return { raw: String(error) };
367
+ }
368
+ if (typeof error !== "object") {
369
+ return { message: String(error) };
370
+ }
371
+ const e = error;
372
+ const out = {};
373
+ if (typeof e.name === "string")
374
+ out.errorName = e.name;
375
+ if (typeof e.message === "string")
376
+ out.message = e.message;
377
+ if (typeof e.url === "string")
378
+ out.requestUrl = e.url;
379
+ if (typeof e.statusCode === "number")
380
+ out.httpStatus = e.statusCode;
381
+ if (typeof e.responseBody === "string")
382
+ out.lmstudioResponseBody = e.responseBody;
383
+ if (e.cause != null && typeof e.cause === "object") {
384
+ out.cause = summarizeAiSdkError(e.cause, depth + 1);
385
+ }
386
+ return out;
387
+ }
388
+ function logTextFailure(phase, modelType, modelId, endpoint, error) {
389
+ import_core3.logger.error({
390
+ src: "plugin:lmstudio:text",
391
+ phase,
392
+ modelType,
393
+ modelId,
394
+ lmstudioBaseURL: endpoint,
395
+ ...summarizeAiSdkError(error)
396
+ }, `[LMStudio] ${phase} failed (${modelType}, model=${modelId}).`);
397
+ }
398
+ function buildStructuredOutput(responseSchema) {
399
+ if (responseSchema && typeof responseSchema === "object" && "responseFormat" in responseSchema && "parseCompleteOutput" in responseSchema) {
400
+ return responseSchema;
401
+ }
402
+ const schemaOptions = responseSchema && typeof responseSchema === "object" && "schema" in responseSchema ? responseSchema : { schema: responseSchema };
403
+ return import_ai2.Output.object({
404
+ schema: import_ai2.jsonSchema(schemaOptions.schema),
405
+ ...schemaOptions.name ? { name: schemaOptions.name } : {},
406
+ ...schemaOptions.description ? { description: schemaOptions.description } : {}
407
+ });
408
+ }
409
+ function serializeStructuredResult(result) {
410
+ if (result.output !== undefined && result.output !== null) {
411
+ return typeof result.output === "string" ? result.output : JSON.stringify(result.output);
412
+ }
413
+ const trimmed = result.text.trim();
414
+ if (trimmed)
415
+ return trimmed;
416
+ throw new Error("[LMStudio] Structured generation returned no text or output.");
417
+ }
418
+ function asRecord(value) {
419
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
420
+ }
421
+ function firstString(...values) {
422
+ for (const value of values) {
423
+ if (typeof value === "string" && value.length > 0) {
424
+ return value;
425
+ }
426
+ }
427
+ return;
428
+ }
429
+ function parseJsonIfPossible(value) {
430
+ if (typeof value !== "string") {
431
+ return value;
432
+ }
433
+ try {
434
+ return JSON.parse(value);
435
+ } catch {
436
+ return value;
437
+ }
438
+ }
439
+ function inferJsonSchemaType(schema, isRoot) {
440
+ if ("items" in schema && !("properties" in schema)) {
441
+ return "array";
442
+ }
443
+ if ("properties" in schema || "required" in schema || "additionalProperties" in schema || isRoot) {
444
+ return "object";
445
+ }
446
+ if (Array.isArray(schema.enum) && schema.enum.length > 0) {
447
+ const types = new Set(schema.enum.map((value) => typeof value));
448
+ if (types.size === 1) {
449
+ const [type] = [...types];
450
+ if (type === "string" || type === "number" || type === "boolean") {
451
+ return type;
452
+ }
453
+ }
454
+ }
455
+ return;
456
+ }
457
+ function sanitizeJsonSchema(schema, isRoot = false) {
458
+ if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
459
+ return { type: "object" };
460
+ }
461
+ const record = schema;
462
+ const sanitized = { ...record };
463
+ if (typeof sanitized.type !== "string") {
464
+ const inferredType = inferJsonSchemaType(sanitized, isRoot);
465
+ if (inferredType) {
466
+ sanitized.type = inferredType;
467
+ }
468
+ }
469
+ if (sanitized.properties && typeof sanitized.properties === "object" && !Array.isArray(sanitized.properties)) {
470
+ const properties = {};
471
+ for (const [key, value] of Object.entries(sanitized.properties)) {
472
+ properties[key] = sanitizeJsonSchema(value);
473
+ }
474
+ sanitized.properties = properties;
475
+ }
476
+ if (sanitized.items) {
477
+ sanitized.items = Array.isArray(sanitized.items) ? sanitized.items.map((item) => sanitizeJsonSchema(item)) : sanitizeJsonSchema(sanitized.items);
478
+ }
479
+ for (const unionKey of ["anyOf", "oneOf", "allOf"]) {
480
+ const value = sanitized[unionKey];
481
+ if (Array.isArray(value)) {
482
+ sanitized[unionKey] = value.map((item) => sanitizeJsonSchema(item));
483
+ }
484
+ }
485
+ return sanitized;
486
+ }
487
+ function normalizeNativeTools(tools) {
488
+ if (!tools) {
489
+ return;
490
+ }
491
+ if (!Array.isArray(tools)) {
492
+ return tools;
493
+ }
494
+ const toolSet = {};
495
+ for (const rawTool of tools) {
496
+ const tool = asRecord(rawTool);
497
+ const functionTool = asRecord(tool.function);
498
+ const name = firstString(tool.name, functionTool.name);
499
+ if (!name) {
500
+ throw new Error("[LMStudio] Native tool definition is missing a name.");
501
+ }
502
+ const description = firstString(tool.description, functionTool.description);
503
+ const rawSchema = tool.parameters ?? functionTool.parameters ?? { type: "object" };
504
+ const inputSchema = sanitizeJsonSchema(rawSchema, true);
505
+ toolSet[name] = {
506
+ ...description ? { description } : {},
507
+ inputSchema: import_ai2.jsonSchema(inputSchema)
508
+ };
509
+ }
510
+ return Object.keys(toolSet).length > 0 ? toolSet : undefined;
511
+ }
512
+ function normalizeToolChoice(toolChoice) {
513
+ if (!toolChoice) {
514
+ return;
515
+ }
516
+ if (typeof toolChoice === "string" && (toolChoice === "auto" || toolChoice === "none" || toolChoice === "required")) {
517
+ return toolChoice;
518
+ }
519
+ const choice = asRecord(toolChoice);
520
+ if (choice.type === "tool") {
521
+ const toolName = firstString(choice.toolName, choice.name);
522
+ if (toolName) {
523
+ return { type: "tool", toolName };
524
+ }
525
+ }
526
+ if (choice.type === "function") {
527
+ const fn = asRecord(choice.function);
528
+ const toolName = firstString(fn.name);
529
+ if (toolName) {
530
+ return { type: "tool", toolName };
531
+ }
532
+ }
533
+ return toolChoice;
534
+ }
535
+ function stringifyMessageContent(content) {
536
+ if (typeof content === "string")
537
+ return content;
538
+ if (content == null)
539
+ return "";
540
+ if (typeof content === "object") {
541
+ try {
542
+ return JSON.stringify(content);
543
+ } catch {
544
+ return "[unserializable content]";
545
+ }
546
+ }
547
+ return String(content);
548
+ }
549
+ function normalizeUserContent(content) {
550
+ if (Array.isArray(content)) {
551
+ return content;
552
+ }
553
+ return stringifyMessageContent(content);
554
+ }
555
+ function normalizeNativeMessage(message) {
556
+ const raw = asRecord(message);
557
+ if (raw.role === "system") {
558
+ return {
559
+ role: "system",
560
+ content: stringifyMessageContent(raw.content)
561
+ };
562
+ }
563
+ if (raw.role === "assistant") {
564
+ return {
565
+ role: "assistant",
566
+ content: typeof raw.content === "string" || Array.isArray(raw.content) ? raw.content : ""
567
+ };
568
+ }
569
+ if (raw.role === "tool") {
570
+ return {
571
+ role: "tool",
572
+ content: Array.isArray(raw.content) ? raw.content : [
573
+ {
574
+ type: "tool-result",
575
+ toolCallId: String(firstString(raw.toolCallId, raw.id) ?? "tool-call"),
576
+ toolName: String(firstString(raw.toolName, raw.name) ?? "tool"),
577
+ output: {
578
+ type: "text",
579
+ value: stringifyMessageContent(raw.content)
580
+ }
581
+ }
582
+ ]
583
+ };
584
+ }
585
+ return {
586
+ role: "user",
587
+ content: normalizeUserContent(raw.content)
588
+ };
589
+ }
590
+ function normalizeNativeMessages(messages) {
591
+ if (!Array.isArray(messages)) {
592
+ return;
593
+ }
594
+ return messages.map((m) => normalizeNativeMessage(m));
595
+ }
596
+ function mapToolCalls(toolCalls) {
597
+ if (!Array.isArray(toolCalls) || toolCalls.length === 0) {
598
+ return [];
599
+ }
600
+ const out = [];
601
+ for (const raw of toolCalls) {
602
+ const r = asRecord(raw);
603
+ const id = String(firstString(r.toolCallId, r.id) ?? "");
604
+ const name = String(firstString(r.toolName, r.name) ?? "").trim();
605
+ if (!name)
606
+ continue;
607
+ const rawInput = r.input ?? r.arguments ?? r.args;
608
+ let args;
609
+ if (typeof rawInput === "string") {
610
+ const parsed = parseJsonIfPossible(rawInput);
611
+ args = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : rawInput;
612
+ } else if (rawInput && typeof rawInput === "object" && !Array.isArray(rawInput)) {
613
+ args = rawInput;
614
+ } else {
615
+ args = {};
616
+ }
617
+ out.push({ id, name, arguments: args });
618
+ }
619
+ return out;
620
+ }
621
+ function buildNativeResultCast(result, modelName, usage) {
622
+ const payload = {
623
+ text: result.text,
624
+ toolCalls: mapToolCalls(result.toolCalls),
625
+ finishReason: String(result.finishReason),
626
+ usage,
627
+ providerMetadata: { modelName }
628
+ };
629
+ return payload;
630
+ }
631
+ function buildStreamResult(args) {
632
+ const streamResult = import_ai2.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 (err) {
653
+ logTextFailure("streamText.textStream", args.modelType, args.model, args.endpoint, err);
654
+ throw err;
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
+ async function handleTextWithModelType(runtime, modelType, params) {
671
+ const extended = params;
672
+ const responseSchema = extended.responseSchema;
673
+ const tools = normalizeNativeTools(extended.tools);
674
+ const {
675
+ prompt,
676
+ maxTokens = 8192,
677
+ temperature = 0.7,
678
+ frequencyPenalty = 0.7,
679
+ presencePenalty = 0.7
680
+ } = params;
681
+ let modelIdForLog = "";
682
+ const baseURL = getBaseURL(runtime);
683
+ try {
684
+ const client = createLMStudioClient(runtime);
685
+ const model = await resolveModelForType(runtime, modelType);
686
+ modelIdForLog = model;
687
+ import_core3.logger.log(`[LMStudio] Using ${modelType} model: ${model}`);
688
+ const system = import_core3.resolveEffectiveSystemPrompt({
689
+ params,
690
+ fallback: import_core3.buildCanonicalSystemPrompt({ character: runtime.character })
691
+ });
692
+ let outputSpec = responseSchema !== undefined && responseSchema !== null ? buildStructuredOutput(responseSchema) : undefined;
693
+ if (tools && outputSpec) {
694
+ import_core3.logger.debug("[LMStudio] tools and responseSchema both present — omitting structured output for this call.");
695
+ outputSpec = undefined;
696
+ }
697
+ const wireRaw = import_core3.dropDuplicateLeadingSystemMessage(extended.messages, system);
698
+ const normalizedMessages = normalizeNativeMessages(wireRaw);
699
+ const hasChatMessages = Array.isArray(normalizedMessages) && normalizedMessages.length > 0;
700
+ const toolChoice = tools ? normalizeToolChoice(extended.toolChoice) : undefined;
701
+ const shouldReturnNative = Boolean(hasChatMessages || tools || extended.toolChoice || outputSpec !== undefined);
702
+ const renderedPrompt = hasChatMessages ? "" : import_core3.renderChatMessagesForPrompt(params.messages, {
703
+ ...system ? { omitDuplicateSystem: system } : {}
704
+ }) ?? prompt ?? "";
705
+ const promptOrMessages = hasChatMessages ? { messages: normalizedMessages } : { prompt: renderedPrompt };
706
+ const resolvedStopSequences = Array.isArray(params.stopSequences) && params.stopSequences.length > 0 ? params.stopSequences : undefined;
707
+ const promptForUsageEstimate = hasChatMessages ? JSON.stringify(normalizedMessages) : renderedPrompt;
708
+ const baseArgs = {
709
+ model: client(model),
710
+ ...promptOrMessages,
711
+ ...system ? { system } : {},
712
+ temperature,
713
+ maxOutputTokens: maxTokens,
714
+ frequencyPenalty,
715
+ presencePenalty,
716
+ ...resolvedStopSequences ? { stopSequences: resolvedStopSequences } : {},
717
+ ...tools ? { tools, ...toolChoice ? { toolChoice } : {} } : {},
718
+ ...outputSpec ? { output: outputSpec } : {}
719
+ };
720
+ if (params.stream && !outputSpec && !(extended.toolChoice && !tools)) {
721
+ return buildStreamResult({
722
+ runtime,
723
+ modelType,
724
+ model,
725
+ endpoint: baseURL,
726
+ streamParams: baseArgs,
727
+ promptForEstimate: promptForUsageEstimate
728
+ });
729
+ }
730
+ const result = await import_ai2.generateText(baseArgs);
731
+ const usage = normalizeTokenUsage(result.usage) ?? estimateUsage(promptForUsageEstimate, result.text);
732
+ emitModelUsed(runtime, modelType, model, usage);
733
+ if (shouldReturnNative) {
734
+ if (outputSpec !== undefined) {
735
+ return serializeStructuredResult(result);
736
+ }
737
+ return buildNativeResultCast(result, model, usage);
738
+ }
739
+ return result.text;
740
+ } catch (error) {
741
+ logTextFailure("generateText", modelType, modelIdForLog || "(unknown)", baseURL, error);
742
+ throw error;
743
+ }
744
+ }
745
+ async function handleTextSmall(runtime, params) {
746
+ return handleTextWithModelType(runtime, import_core3.ModelType.TEXT_SMALL, params);
747
+ }
748
+ async function handleTextNano(runtime, params) {
749
+ return handleTextWithModelType(runtime, TEXT_NANO_MODEL_TYPE, params);
750
+ }
751
+ async function handleTextMedium(runtime, params) {
752
+ return handleTextWithModelType(runtime, TEXT_MEDIUM_MODEL_TYPE, params);
753
+ }
754
+ async function handleTextLarge(runtime, params) {
755
+ return handleTextWithModelType(runtime, import_core3.ModelType.TEXT_LARGE, params);
756
+ }
757
+ async function handleTextMega(runtime, params) {
758
+ return handleTextWithModelType(runtime, TEXT_MEGA_MODEL_TYPE, params);
759
+ }
760
+ async function handleResponseHandler(runtime, params) {
761
+ return handleTextWithModelType(runtime, RESPONSE_HANDLER_MODEL_TYPE, params);
762
+ }
763
+ async function handleActionPlanner(runtime, params) {
764
+ return handleTextWithModelType(runtime, ACTION_PLANNER_MODEL_TYPE, params);
765
+ }
766
+
767
+ // plugin.ts
768
+ function getProcessEnv() {
769
+ if (typeof process === "undefined" || !process.env) {
770
+ return {};
771
+ }
772
+ return process.env;
773
+ }
774
+ var env = getProcessEnv();
775
+ var TEXT_NANO_MODEL_TYPE2 = import_core4.ModelType.TEXT_NANO;
776
+ var TEXT_MEDIUM_MODEL_TYPE2 = import_core4.ModelType.TEXT_MEDIUM;
777
+ var TEXT_MEGA_MODEL_TYPE2 = import_core4.ModelType.TEXT_MEGA;
778
+ var RESPONSE_HANDLER_MODEL_TYPE2 = import_core4.ModelType.RESPONSE_HANDLER;
779
+ var ACTION_PLANNER_MODEL_TYPE2 = import_core4.ModelType.ACTION_PLANNER;
780
+ var lmStudioPlugin = {
781
+ name: "lmstudio",
782
+ description: "LM Studio provider for local LLM inference via the OpenAI-compatible API",
783
+ autoEnable: {
784
+ envKeys: ["LMSTUDIO_BASE_URL"],
785
+ shouldEnable: async () => {
786
+ try {
787
+ const result = await detectLMStudio({ timeoutMs: 750 });
788
+ return result.available;
789
+ } catch {
790
+ return false;
791
+ }
792
+ }
793
+ },
794
+ config: {
795
+ LMSTUDIO_BASE_URL: env.LMSTUDIO_BASE_URL ?? null,
796
+ LMSTUDIO_API_KEY: env.LMSTUDIO_API_KEY ?? null,
797
+ LMSTUDIO_SMALL_MODEL: env.LMSTUDIO_SMALL_MODEL ?? null,
798
+ LMSTUDIO_LARGE_MODEL: env.LMSTUDIO_LARGE_MODEL ?? null,
799
+ LMSTUDIO_EMBEDDING_MODEL: env.LMSTUDIO_EMBEDDING_MODEL ?? null,
800
+ LMSTUDIO_AUTO_DETECT: env.LMSTUDIO_AUTO_DETECT ?? null,
801
+ SMALL_MODEL: env.SMALL_MODEL ?? null,
802
+ LARGE_MODEL: env.LARGE_MODEL ?? null
803
+ },
804
+ async init(_config, runtime) {
805
+ const baseURL = getBaseURL(runtime);
806
+ if (!shouldAutoDetect(runtime)) {
807
+ import_core4.logger.debug("[LMStudio] LMSTUDIO_AUTO_DETECT disabled — skipping init probe.");
808
+ return;
809
+ }
810
+ const apiKey = getApiKey(runtime);
811
+ const result = await detectLMStudio({
812
+ baseURL,
813
+ ...apiKey ? { apiKey } : {},
814
+ ...runtime.fetch ? { fetcher: runtime.fetch } : {},
815
+ timeoutMs: 2000
816
+ });
817
+ if (!result.available) {
818
+ import_core4.logger.warn({ src: "plugin:lmstudio", baseURL, error: result.error }, "[LMStudio] /v1/models probe failed — plugin will only succeed once LM Studio is running.");
819
+ return;
820
+ }
821
+ const modelCount = result.models?.length ?? 0;
822
+ import_core4.logger.info(`[LMStudio] Detected ${modelCount} model${modelCount === 1 ? "" : "s"} at ${baseURL}`);
823
+ },
824
+ models: {
825
+ [import_core4.ModelType.TEXT_EMBEDDING]: async (runtime, params) => {
826
+ return handleTextEmbedding(runtime, params);
827
+ },
828
+ [TEXT_NANO_MODEL_TYPE2]: async (runtime, params) => {
829
+ return handleTextNano(runtime, params);
830
+ },
831
+ [import_core4.ModelType.TEXT_SMALL]: async (runtime, params) => {
832
+ return handleTextSmall(runtime, params);
833
+ },
834
+ [TEXT_MEDIUM_MODEL_TYPE2]: async (runtime, params) => {
835
+ return handleTextMedium(runtime, params);
836
+ },
837
+ [import_core4.ModelType.TEXT_LARGE]: async (runtime, params) => {
838
+ return handleTextLarge(runtime, params);
839
+ },
840
+ [TEXT_MEGA_MODEL_TYPE2]: async (runtime, params) => {
841
+ return handleTextMega(runtime, params);
842
+ },
843
+ [RESPONSE_HANDLER_MODEL_TYPE2]: async (runtime, params) => {
844
+ return handleResponseHandler(runtime, params);
845
+ },
846
+ [ACTION_PLANNER_MODEL_TYPE2]: async (runtime, params) => {
847
+ return handleActionPlanner(runtime, params);
848
+ }
849
+ },
850
+ tests: [
851
+ {
852
+ name: "lmstudio_plugin_tests",
853
+ tests: [
854
+ {
855
+ name: "lmstudio_test_models_endpoint",
856
+ fn: async (runtime) => {
857
+ const apiKey = getApiKey(runtime);
858
+ const result = await detectLMStudio({
859
+ baseURL: getBaseURL(runtime),
860
+ ...apiKey ? { apiKey } : {},
861
+ ...runtime.fetch ? { fetcher: runtime.fetch } : {}
862
+ });
863
+ if (!result.available) {
864
+ import_core4.logger.error({ result }, "[LMStudio] /v1/models probe failed");
865
+ return;
866
+ }
867
+ import_core4.logger.log({ models: result.models?.length ?? 0 }, "[LMStudio] /v1/models OK");
868
+ }
869
+ }
870
+ ]
871
+ }
872
+ ]
873
+ };
874
+ // index.node.ts
875
+ var defaultLMStudioPlugin = lmStudioPlugin;
876
+ var index_node_default = defaultLMStudioPlugin;
877
+
878
+ //# debugId=84CB05477B08554A64756E2164756E21
879
+ //# sourceMappingURL=index.node.cjs.map