@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.js CHANGED
@@ -1140,6 +1140,141 @@ var handleXAIStream = async (response, ctx) => {
1140
1140
  };
1141
1141
  };
1142
1142
 
1143
+ // src/providers/local.ts
1144
+ var DEFAULT_BASE_URL = "http://localhost:11434/v1";
1145
+ var appendToolCalls3 = (toolCalls, tcchunklist) => {
1146
+ for (const tcchunk of tcchunklist) {
1147
+ while (toolCalls.length <= tcchunk.index) {
1148
+ toolCalls.push({
1149
+ id: "",
1150
+ type: "function",
1151
+ function: { name: "", arguments: "" }
1152
+ });
1153
+ }
1154
+ const tc = toolCalls[tcchunk.index];
1155
+ tc.id += tcchunk.id || "";
1156
+ tc.function.name += tcchunk.function?.name || "";
1157
+ tc.function.arguments += tcchunk.function?.arguments || "";
1158
+ }
1159
+ return toolCalls;
1160
+ };
1161
+ var callLocal = async (config, ctx) => {
1162
+ const { model: model2, instructions, schema, apiKey, baseUrl } = config;
1163
+ const endpoint = baseUrl || DEFAULT_BASE_URL;
1164
+ const messages = [];
1165
+ if (instructions) {
1166
+ messages.push({ role: "system", content: instructions });
1167
+ }
1168
+ messages.push(...ctx.history);
1169
+ const body = {
1170
+ model: model2,
1171
+ messages,
1172
+ stream: !!ctx.stream
1173
+ };
1174
+ if (schema) {
1175
+ body.response_format = {
1176
+ type: "json_schema",
1177
+ json_schema: {
1178
+ name: schema.name,
1179
+ schema: { ...schema.schema, additionalProperties: false },
1180
+ strict: true
1181
+ }
1182
+ };
1183
+ }
1184
+ if (ctx.tools && ctx.tools.length > 0) {
1185
+ body.tools = ctx.tools;
1186
+ body.tool_choice = "auto";
1187
+ }
1188
+ const headers = {
1189
+ "Content-Type": "application/json"
1190
+ };
1191
+ if (apiKey) {
1192
+ headers["Authorization"] = `Bearer ${apiKey}`;
1193
+ }
1194
+ const response = await fetch(`${endpoint}/chat/completions`, {
1195
+ method: "POST",
1196
+ headers,
1197
+ body: JSON.stringify(body),
1198
+ signal: ctx.abortSignal
1199
+ });
1200
+ if (!response.ok) {
1201
+ const error = await response.text();
1202
+ throw new Error(`Local API error: ${error}`);
1203
+ }
1204
+ if (ctx.stream) {
1205
+ return handleLocalStream(response, ctx);
1206
+ }
1207
+ const data = await response.json();
1208
+ const choice = data.choices[0];
1209
+ const { message } = choice;
1210
+ const msg = {
1211
+ role: "assistant",
1212
+ content: message.content || ""
1213
+ };
1214
+ if (message.tool_calls) {
1215
+ msg.tool_calls = message.tool_calls;
1216
+ }
1217
+ return {
1218
+ ...ctx,
1219
+ lastResponse: msg,
1220
+ history: [...ctx.history, msg]
1221
+ };
1222
+ };
1223
+ var handleLocalStream = async (response, ctx) => {
1224
+ const reader = response.body.getReader();
1225
+ const decoder = new TextDecoder();
1226
+ let fullContent = "";
1227
+ let toolCalls = [];
1228
+ let buffer = "";
1229
+ try {
1230
+ while (true) {
1231
+ if (ctx.abortSignal?.aborted) {
1232
+ break;
1233
+ }
1234
+ const { done, value } = await reader.read();
1235
+ if (done) break;
1236
+ buffer += decoder.decode(value, { stream: true });
1237
+ const lines = buffer.split("\n");
1238
+ buffer = lines.pop() || "";
1239
+ for (const line of lines) {
1240
+ if (line.startsWith("data: ")) {
1241
+ const data = line.slice(6).trim();
1242
+ if (data === "[DONE]") continue;
1243
+ if (!data) continue;
1244
+ try {
1245
+ const parsed = JSON.parse(data);
1246
+ const delta = parsed.choices?.[0]?.delta;
1247
+ if (delta?.content) {
1248
+ fullContent += delta.content;
1249
+ if (ctx.stream) {
1250
+ ctx.stream({ type: "content", content: delta.content });
1251
+ }
1252
+ }
1253
+ if (delta?.tool_calls) {
1254
+ toolCalls = appendToolCalls3(toolCalls, delta.tool_calls);
1255
+ }
1256
+ } catch (e) {
1257
+ }
1258
+ }
1259
+ }
1260
+ }
1261
+ } finally {
1262
+ reader.releaseLock();
1263
+ }
1264
+ const msg = {
1265
+ role: "assistant",
1266
+ content: fullContent
1267
+ };
1268
+ if (toolCalls.length > 0) {
1269
+ msg.tool_calls = toolCalls;
1270
+ }
1271
+ return {
1272
+ ...ctx,
1273
+ lastResponse: msg,
1274
+ history: [...ctx.history, msg]
1275
+ };
1276
+ };
1277
+
1143
1278
  // src/providers/index.ts
1144
1279
  var callProvider = async (config, ctx) => {
1145
1280
  const { provider, model: model2 } = parseModelName(config.model);
@@ -1153,6 +1288,8 @@ var callProvider = async (config, ctx) => {
1153
1288
  return callGoogle(providerConfig, ctx);
1154
1289
  case "xai":
1155
1290
  return callXAI(providerConfig, ctx);
1291
+ case "local":
1292
+ return callLocal(providerConfig, ctx);
1156
1293
  case "huggingface":
1157
1294
  default:
1158
1295
  return callHuggingFace(providerConfig, ctx);