@threaded/ai 1.0.20 → 1.0.22

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/dist/index.cjs CHANGED
@@ -1213,6 +1213,141 @@ var handleXAIStream = async (response, ctx) => {
1213
1213
  };
1214
1214
  };
1215
1215
 
1216
+ // src/providers/local.ts
1217
+ var DEFAULT_BASE_URL = "http://localhost:11434/v1";
1218
+ var appendToolCalls3 = (toolCalls, tcchunklist) => {
1219
+ for (const tcchunk of tcchunklist) {
1220
+ while (toolCalls.length <= tcchunk.index) {
1221
+ toolCalls.push({
1222
+ id: "",
1223
+ type: "function",
1224
+ function: { name: "", arguments: "" }
1225
+ });
1226
+ }
1227
+ const tc = toolCalls[tcchunk.index];
1228
+ tc.id += tcchunk.id || "";
1229
+ tc.function.name += tcchunk.function?.name || "";
1230
+ tc.function.arguments += tcchunk.function?.arguments || "";
1231
+ }
1232
+ return toolCalls;
1233
+ };
1234
+ var callLocal = async (config, ctx) => {
1235
+ const { model: model2, instructions, schema, apiKey, baseUrl } = config;
1236
+ const endpoint = baseUrl || DEFAULT_BASE_URL;
1237
+ const messages = [];
1238
+ if (instructions) {
1239
+ messages.push({ role: "system", content: instructions });
1240
+ }
1241
+ messages.push(...ctx.history);
1242
+ const body = {
1243
+ model: model2,
1244
+ messages,
1245
+ stream: !!ctx.stream
1246
+ };
1247
+ if (schema) {
1248
+ body.response_format = {
1249
+ type: "json_schema",
1250
+ json_schema: {
1251
+ name: schema.name,
1252
+ schema: { ...schema.schema, additionalProperties: false },
1253
+ strict: true
1254
+ }
1255
+ };
1256
+ }
1257
+ if (ctx.tools && ctx.tools.length > 0) {
1258
+ body.tools = ctx.tools;
1259
+ body.tool_choice = "auto";
1260
+ }
1261
+ const headers = {
1262
+ "Content-Type": "application/json"
1263
+ };
1264
+ if (apiKey) {
1265
+ headers["Authorization"] = `Bearer ${apiKey}`;
1266
+ }
1267
+ const response = await fetch(`${endpoint}/chat/completions`, {
1268
+ method: "POST",
1269
+ headers,
1270
+ body: JSON.stringify(body),
1271
+ signal: ctx.abortSignal
1272
+ });
1273
+ if (!response.ok) {
1274
+ const error = await response.text();
1275
+ throw new Error(`Local API error: ${error}`);
1276
+ }
1277
+ if (ctx.stream) {
1278
+ return handleLocalStream(response, ctx);
1279
+ }
1280
+ const data = await response.json();
1281
+ const choice = data.choices[0];
1282
+ const { message } = choice;
1283
+ const msg = {
1284
+ role: "assistant",
1285
+ content: message.content || ""
1286
+ };
1287
+ if (message.tool_calls) {
1288
+ msg.tool_calls = message.tool_calls;
1289
+ }
1290
+ return {
1291
+ ...ctx,
1292
+ lastResponse: msg,
1293
+ history: [...ctx.history, msg]
1294
+ };
1295
+ };
1296
+ var handleLocalStream = async (response, ctx) => {
1297
+ const reader = response.body.getReader();
1298
+ const decoder = new TextDecoder();
1299
+ let fullContent = "";
1300
+ let toolCalls = [];
1301
+ let buffer = "";
1302
+ try {
1303
+ while (true) {
1304
+ if (ctx.abortSignal?.aborted) {
1305
+ break;
1306
+ }
1307
+ const { done, value } = await reader.read();
1308
+ if (done) break;
1309
+ buffer += decoder.decode(value, { stream: true });
1310
+ const lines = buffer.split("\n");
1311
+ buffer = lines.pop() || "";
1312
+ for (const line of lines) {
1313
+ if (line.startsWith("data: ")) {
1314
+ const data = line.slice(6).trim();
1315
+ if (data === "[DONE]") continue;
1316
+ if (!data) continue;
1317
+ try {
1318
+ const parsed = JSON.parse(data);
1319
+ const delta = parsed.choices?.[0]?.delta;
1320
+ if (delta?.content) {
1321
+ fullContent += delta.content;
1322
+ if (ctx.stream) {
1323
+ ctx.stream({ type: "content", content: delta.content });
1324
+ }
1325
+ }
1326
+ if (delta?.tool_calls) {
1327
+ toolCalls = appendToolCalls3(toolCalls, delta.tool_calls);
1328
+ }
1329
+ } catch (e) {
1330
+ }
1331
+ }
1332
+ }
1333
+ }
1334
+ } finally {
1335
+ reader.releaseLock();
1336
+ }
1337
+ const msg = {
1338
+ role: "assistant",
1339
+ content: fullContent
1340
+ };
1341
+ if (toolCalls.length > 0) {
1342
+ msg.tool_calls = toolCalls;
1343
+ }
1344
+ return {
1345
+ ...ctx,
1346
+ lastResponse: msg,
1347
+ history: [...ctx.history, msg]
1348
+ };
1349
+ };
1350
+
1216
1351
  // src/providers/index.ts
1217
1352
  var callProvider = async (config, ctx) => {
1218
1353
  const { provider, model: model2 } = parseModelName(config.model);
@@ -1226,6 +1361,8 @@ var callProvider = async (config, ctx) => {
1226
1361
  return callGoogle(providerConfig, ctx);
1227
1362
  case "xai":
1228
1363
  return callXAI(providerConfig, ctx);
1364
+ case "local":
1365
+ return callLocal(providerConfig, ctx);
1229
1366
  case "huggingface":
1230
1367
  default:
1231
1368
  return callHuggingFace(providerConfig, ctx);