@umituz/web-ai 1.0.9 → 1.0.10

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 (43) hide show
  1. package/dist/{AIErrors-CSk4nvN1.d.ts → AIErrors-TuSFl--T.d.ts} +1 -1
  2. package/dist/{AIErrors-Dq9o95R_.d.cts → AIErrors-_IyXRWj1.d.cts} +1 -1
  3. package/dist/{cancellation-error-CpkPd67D.d.cts → cancellation-error-_39nYWwz.d.cts} +3 -3
  4. package/dist/{cancellation-error-Ci8fQhNF.d.ts → cancellation-error-hYcE9AS9.d.ts} +3 -3
  5. package/dist/chat/index.d.cts +4 -4
  6. package/dist/chat/index.d.ts +4 -4
  7. package/dist/{chat.service-BRtiA7H9.d.cts → chat.service-8MaW9pum.d.cts} +2 -2
  8. package/dist/{chat.service-Cqga2h1e.d.ts → chat.service-B4Isrckn.d.ts} +2 -2
  9. package/dist/content/index.d.cts +7 -7
  10. package/dist/content/index.d.ts +7 -7
  11. package/dist/core/index.cjs +6 -4
  12. package/dist/core/index.cjs.map +1 -1
  13. package/dist/core/index.d.cts +7 -26
  14. package/dist/core/index.d.ts +7 -26
  15. package/dist/core/index.js +6 -4
  16. package/dist/core/index.js.map +1 -1
  17. package/dist/{create-ai-DW7eHMBF.d.ts → create-ai-D-oEWzf9.d.ts} +3 -3
  18. package/dist/{create-ai-DeOpUgZ-.d.cts → create-ai-DRysRImc.d.cts} +3 -3
  19. package/dist/hooks/index.d.cts +9 -9
  20. package/dist/hooks/index.d.ts +9 -9
  21. package/dist/{index-Ca5o4gBK.d.ts → index-1e91KRYU.d.ts} +1 -1
  22. package/dist/{index-itgxPeLz.d.cts → index-Dv8gRzAu.d.cts} +1 -1
  23. package/dist/{index-DDzvTDg0.d.ts → index-OhvYUTXf.d.cts} +1 -2
  24. package/dist/{index-DDzvTDg0.d.cts → index-OhvYUTXf.d.ts} +1 -2
  25. package/dist/index.cjs +305 -4
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.cts +11 -11
  28. package/dist/index.d.ts +11 -11
  29. package/dist/index.js +304 -5
  30. package/dist/index.js.map +1 -1
  31. package/dist/{provider.factory-CJuI08Xr.d.ts → provider.factory-B9RNUTYj.d.ts} +1 -1
  32. package/dist/{provider.factory-DG2CYFgh.d.cts → provider.factory-Ce6Een1G.d.cts} +1 -1
  33. package/dist/providers/index.cjs +381 -0
  34. package/dist/providers/index.cjs.map +1 -1
  35. package/dist/providers/index.d.cts +61 -11
  36. package/dist/providers/index.d.ts +61 -11
  37. package/dist/providers/index.js +380 -1
  38. package/dist/providers/index.js.map +1 -1
  39. package/dist/{requestQueue-D-RCbxuR.d.ts → requestQueue-AP6n_bRH.d.ts} +4 -4
  40. package/dist/{requestQueue-O6f8VBl5.d.cts → requestQueue-D89wx91Q.d.cts} +4 -4
  41. package/dist/{request-deduplicator.util-NDo0_n1y.d.cts → tool-call-accumulator-C7KhaXZA.d.cts} +20 -1
  42. package/dist/{request-deduplicator.util-NDo0_n1y.d.ts → tool-call-accumulator-C7KhaXZA.d.ts} +20 -1
  43. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import { P as ProviderHealth, T as TextRequest, G as GenerationResult, a as StructuredTextRequest, S as StructuredGeneration, d as StreamCallbacks, b as TextTier } from './index-DDzvTDg0.js';
1
+ import { P as ProviderHealth, T as TextRequest, G as GenerationResult, a as StructuredTextRequest, S as StructuredGeneration, d as StreamCallbacks, b as TextTier } from './index-OhvYUTXf.js';
2
2
  import { T as TextGenerationRequest, I as ImageGenerationRequest, V as VideoGenerationRequest, G as GeneratedContent, a as ImageToVideoRequest, b as VideoToVideoRequest } from './ProviderConfig-DIFa9nmG.js';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { P as ProviderHealth, T as TextRequest, G as GenerationResult, a as StructuredTextRequest, S as StructuredGeneration, d as StreamCallbacks, b as TextTier } from './index-DDzvTDg0.cjs';
1
+ import { P as ProviderHealth, T as TextRequest, G as GenerationResult, a as StructuredTextRequest, S as StructuredGeneration, d as StreamCallbacks, b as TextTier } from './index-OhvYUTXf.cjs';
2
2
  import { T as TextGenerationRequest, I as ImageGenerationRequest, V as VideoGenerationRequest, G as GeneratedContent, a as ImageToVideoRequest, b as VideoToVideoRequest } from './ProviderConfig-DIFa9nmG.cjs';
3
3
 
4
4
  /**
@@ -246,6 +246,68 @@ async function extractErrorMessageFromResponse(response) {
246
246
  return buildHttpStatusFallback(response.status, response.statusText);
247
247
  }
248
248
 
249
+ // src/core/errors/unified-ai-error.ts
250
+ var STATUS_TO_CODE = {
251
+ 400: "invalid_request",
252
+ 401: "invalid_key",
253
+ 403: "invalid_key",
254
+ 404: "model_unavailable",
255
+ 413: "invalid_request",
256
+ 422: "invalid_request",
257
+ 429: "rate_limited",
258
+ 500: "upstream_error",
259
+ 502: "upstream_error",
260
+ 503: "capacity",
261
+ 504: "timeout"
262
+ };
263
+ var CODE_MESSAGES = {
264
+ invalid_key: "The provider rejected the configured API key.",
265
+ missing_key: "The provider is not configured with an API key.",
266
+ rate_limited: "The provider rate limit was reached. Try again shortly.",
267
+ capacity: "The provider is temporarily at capacity. Try again shortly.",
268
+ timeout: "The model took too long to respond.",
269
+ invalid_request: "The request was rejected by the provider.",
270
+ model_unavailable: "The requested model is not available.",
271
+ upstream_error: "The provider returned an unexpected error.",
272
+ network: "Could not reach the provider.",
273
+ cancelled: "Generation was cancelled."
274
+ };
275
+ var AiError = class extends Error {
276
+ code;
277
+ constructor(code, message) {
278
+ super(message ?? CODE_MESSAGES[code]);
279
+ this.name = "AiError";
280
+ this.code = code;
281
+ }
282
+ get userMessage() {
283
+ return this.message;
284
+ }
285
+ };
286
+ function isApiKeyRejection(provider) {
287
+ if (provider.code === "invalid_api_key") return true;
288
+ return provider.type === void 0;
289
+ }
290
+ function errorFromStatus(status, detail, provider) {
291
+ let code = STATUS_TO_CODE[status] ?? "upstream_error";
292
+ if (status === 403 && provider && !isApiKeyRejection(provider)) {
293
+ code = "model_unavailable";
294
+ }
295
+ return new AiError(code, detail ? `${CODE_MESSAGES[code]} (${detail})` : void 0);
296
+ }
297
+ function errorFromUnknown(err) {
298
+ if (err instanceof AiError) return err;
299
+ if (err instanceof Error) {
300
+ if (err.name === "TimeoutError" || err.name === "AbortError") {
301
+ return new AiError("timeout");
302
+ }
303
+ if (err.name === "TypeError") {
304
+ return new AiError("network");
305
+ }
306
+ return new AiError("upstream_error", err.message);
307
+ }
308
+ return new AiError("upstream_error");
309
+ }
310
+
249
311
  // src/providers/factory/provider.factory.ts
250
312
  var ProviderFactory = class {
251
313
  providers = /* @__PURE__ */ new Map();
@@ -4163,6 +4225,323 @@ function createOpenAiImageAdapter(config) {
4163
4225
  };
4164
4226
  }
4165
4227
 
4228
+ // src/core/sse/tool-call-accumulator.ts
4229
+ var ToolCallAccumulator = class {
4230
+ slots = /* @__PURE__ */ new Map();
4231
+ push(delta) {
4232
+ const index = delta.index ?? 0;
4233
+ const slot = this.slots.get(index) ?? { id: "", name: "", args: "" };
4234
+ if (delta.id) slot.id = delta.id;
4235
+ if (delta.function?.name) slot.name = delta.function.name;
4236
+ if (delta.function?.arguments) slot.args += delta.function.arguments;
4237
+ this.slots.set(index, slot);
4238
+ }
4239
+ finish() {
4240
+ return Array.from(this.slots.entries()).sort(([a], [b]) => a - b).map(([, slot]) => ({
4241
+ id: slot.id,
4242
+ name: slot.name,
4243
+ arguments: slot.args
4244
+ })).filter((call) => call.id.length > 0 || call.name.length > 0);
4245
+ }
4246
+ };
4247
+
4248
+ // src/providers/adapters/openai-compatible.adapter.ts
4249
+ function toWireMessage(message) {
4250
+ if (message.role === "tool") {
4251
+ return { role: "tool", content: message.content, tool_call_id: message.toolCallId ?? "" };
4252
+ }
4253
+ if (message.role === "assistant" && message.toolCalls && message.toolCalls.length > 0) {
4254
+ return {
4255
+ role: "assistant",
4256
+ content: message.content,
4257
+ tool_calls: message.toolCalls.map((call) => ({
4258
+ id: call.id,
4259
+ type: "function",
4260
+ function: { name: call.name, arguments: call.arguments }
4261
+ }))
4262
+ };
4263
+ }
4264
+ if (message.role === "user") return { role: "user", content: message.content };
4265
+ return { role: message.role, content: message.content };
4266
+ }
4267
+ function mergeImages(messages, images) {
4268
+ if (images.length === 0) return [...messages];
4269
+ const parts = images.map((image) => ({
4270
+ type: "image_url",
4271
+ image_url: { url: `data:${image.mimeType};base64,${image.dataBase64}` }
4272
+ }));
4273
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
4274
+ const message = messages[index];
4275
+ if (message.role !== "user") continue;
4276
+ const textParts = typeof message.content === "string" ? message.content.length > 0 ? [{ type: "text", text: message.content }] : [] : message.content;
4277
+ return [
4278
+ ...messages.slice(0, index),
4279
+ { role: "user", content: [...textParts, ...parts] },
4280
+ ...messages.slice(index + 1)
4281
+ ];
4282
+ }
4283
+ return [...messages, { role: "user", content: [...parts] }];
4284
+ }
4285
+ async function extractErrorDetail(response) {
4286
+ try {
4287
+ const body = await response.json();
4288
+ return body.error;
4289
+ } catch {
4290
+ return void 0;
4291
+ }
4292
+ }
4293
+ async function* parseSseEvent(rawEvent, toolCallAccumulator) {
4294
+ for (const line of rawEvent.split("\n")) {
4295
+ if (!line.startsWith("data:")) continue;
4296
+ const payload = line.slice(5).trim();
4297
+ if (payload.length === 0 || payload === "[DONE]") continue;
4298
+ let chunk;
4299
+ try {
4300
+ chunk = JSON.parse(payload);
4301
+ } catch {
4302
+ continue;
4303
+ }
4304
+ const delta = chunk.choices?.[0]?.delta;
4305
+ if (delta?.reasoning) {
4306
+ yield { type: "delta", channel: "reasoning", text: delta.reasoning };
4307
+ }
4308
+ if (delta?.content) {
4309
+ yield { type: "delta", channel: "answer", text: delta.content };
4310
+ }
4311
+ if (delta?.tool_calls) {
4312
+ for (const toolCallDelta of delta.tool_calls) toolCallAccumulator.push(toolCallDelta);
4313
+ }
4314
+ if (chunk.usage) {
4315
+ yield {
4316
+ type: "usage",
4317
+ usage: {
4318
+ inputTokens: chunk.usage.prompt_tokens ?? 0,
4319
+ outputTokens: chunk.usage.completion_tokens ?? 0,
4320
+ reasoningTokens: chunk.usage.completion_tokens_details?.reasoning_tokens
4321
+ }
4322
+ };
4323
+ }
4324
+ }
4325
+ }
4326
+ async function* parseSseStream(body) {
4327
+ const reader = body.getReader();
4328
+ const decoder = new TextDecoder();
4329
+ const toolCallAccumulator = new ToolCallAccumulator();
4330
+ let buffer = "";
4331
+ try {
4332
+ while (true) {
4333
+ const { done, value } = await reader.read();
4334
+ if (done) break;
4335
+ buffer += decoder.decode(value, { stream: true });
4336
+ let separator = buffer.indexOf("\n\n");
4337
+ while (separator !== -1) {
4338
+ const rawEvent = buffer.slice(0, separator);
4339
+ buffer = buffer.slice(separator + 2);
4340
+ separator = buffer.indexOf("\n\n");
4341
+ yield* parseSseEvent(rawEvent, toolCallAccumulator);
4342
+ }
4343
+ }
4344
+ } catch (err) {
4345
+ throw errorFromUnknown(err);
4346
+ } finally {
4347
+ reader.releaseLock();
4348
+ }
4349
+ const calls = toolCallAccumulator.finish();
4350
+ if (calls.length > 0) yield { type: "tool_calls", calls };
4351
+ }
4352
+ function createOpenAiCompatibleAdapter(config) {
4353
+ return {
4354
+ async *stream(req) {
4355
+ const timeout = AbortSignal.timeout(config.timeoutMs);
4356
+ const signal = req.signal ? AbortSignal.any([req.signal, timeout]) : timeout;
4357
+ let response;
4358
+ try {
4359
+ response = await fetch(`${config.baseUrl}/chat/completions`, {
4360
+ method: "POST",
4361
+ headers: {
4362
+ Authorization: `Bearer ${config.apiKey}`,
4363
+ "Content-Type": "application/json"
4364
+ },
4365
+ body: JSON.stringify({
4366
+ model: req.externalModelId,
4367
+ messages: mergeImages(req.messages.map(toWireMessage), req.images ?? []),
4368
+ temperature: req.temperature,
4369
+ max_completion_tokens: req.maxOutputTokens,
4370
+ top_p: req.topP,
4371
+ stream: true,
4372
+ stream_options: { include_usage: true },
4373
+ ...req.tools && req.tools.length > 0 ? {
4374
+ tools: req.tools.map((tool) => ({ type: "function", function: tool })),
4375
+ tool_choice: "auto"
4376
+ } : {}
4377
+ }),
4378
+ signal
4379
+ });
4380
+ } catch (err) {
4381
+ throw errorFromUnknown(err);
4382
+ }
4383
+ if (!response.ok || !response.body) {
4384
+ const detail = await extractErrorDetail(response);
4385
+ throw errorFromStatus(response.status, detail?.message, detail);
4386
+ }
4387
+ yield* parseSseStream(response.body);
4388
+ }
4389
+ };
4390
+ }
4391
+
4392
+ // src/providers/adapters/anthropic.adapter.ts
4393
+ var ANTHROPIC_VERSION = "2023-06-01";
4394
+ var ERROR_TYPE_TO_CODE = {
4395
+ invalid_request_error: "invalid_request",
4396
+ authentication_error: "invalid_key",
4397
+ permission_error: "invalid_key",
4398
+ not_found_error: "model_unavailable",
4399
+ request_too_large: "invalid_request",
4400
+ rate_limit_error: "rate_limited",
4401
+ overloaded_error: "capacity",
4402
+ api_error: "upstream_error"
4403
+ };
4404
+ function mergeImages2(messages, images) {
4405
+ if (images.length === 0) return [...messages];
4406
+ const blocks = images.map((image) => ({
4407
+ type: "image",
4408
+ source: { type: "base64", media_type: image.mimeType, data: image.dataBase64 }
4409
+ }));
4410
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
4411
+ const message = messages[index];
4412
+ if (message.role !== "user") continue;
4413
+ const textBlocks = typeof message.content === "string" ? message.content.length > 0 ? [{ type: "text", text: message.content }] : [] : message.content;
4414
+ return [
4415
+ ...messages.slice(0, index),
4416
+ { role: "user", content: [...textBlocks, ...blocks] },
4417
+ ...messages.slice(index + 1)
4418
+ ];
4419
+ }
4420
+ return [...messages, { role: "user", content: [...blocks] }];
4421
+ }
4422
+ async function extractErrorDetail2(response) {
4423
+ try {
4424
+ const body = await response.json();
4425
+ return body.error?.message;
4426
+ } catch {
4427
+ return void 0;
4428
+ }
4429
+ }
4430
+ function wireError(error) {
4431
+ const code = error.type && ERROR_TYPE_TO_CODE[error.type] || "upstream_error";
4432
+ return new AiError(code, error.message);
4433
+ }
4434
+ function* parseAnthropicEvent(rawEvent) {
4435
+ for (const line of rawEvent.split("\n")) {
4436
+ if (!line.startsWith("data:")) continue;
4437
+ const payload = line.slice(5).trim();
4438
+ if (payload.length === 0) continue;
4439
+ try {
4440
+ yield JSON.parse(payload);
4441
+ } catch {
4442
+ continue;
4443
+ }
4444
+ }
4445
+ }
4446
+ function mergeOutputTokens(previous, outputTokens) {
4447
+ return {
4448
+ inputTokens: previous?.inputTokens ?? 0,
4449
+ outputTokens,
4450
+ reasoningTokens: previous?.reasoningTokens
4451
+ };
4452
+ }
4453
+ async function* parseAnthropicStream(body) {
4454
+ const reader = body.getReader();
4455
+ const decoder = new TextDecoder();
4456
+ let buffer = "";
4457
+ let usage = null;
4458
+ let usageEmitted = false;
4459
+ const flushUsage = function* () {
4460
+ if (usage && !usageEmitted && (usage.inputTokens > 0 || usage.outputTokens > 0)) {
4461
+ usageEmitted = true;
4462
+ yield { type: "usage", usage };
4463
+ }
4464
+ };
4465
+ try {
4466
+ while (true) {
4467
+ const { done, value } = await reader.read();
4468
+ if (done) break;
4469
+ buffer += decoder.decode(value, { stream: true });
4470
+ let separator = buffer.indexOf("\n\n");
4471
+ while (separator !== -1) {
4472
+ const rawEvent = buffer.slice(0, separator);
4473
+ buffer = buffer.slice(separator + 2);
4474
+ separator = buffer.indexOf("\n\n");
4475
+ for (const event of parseAnthropicEvent(rawEvent)) {
4476
+ if (event.error) throw wireError(event.error);
4477
+ if (event.type === "message_start" && event.message?.usage) {
4478
+ usage = {
4479
+ inputTokens: event.message.usage.input_tokens ?? 0,
4480
+ outputTokens: 0,
4481
+ reasoningTokens: void 0
4482
+ };
4483
+ } else if (event.type === "message_delta" && event.usage) {
4484
+ usage = mergeOutputTokens(usage, event.usage.output_tokens ?? 0);
4485
+ } else if (event.type === "message_stop") {
4486
+ yield* flushUsage();
4487
+ } else if (event.delta?.type === "text_delta" && event.delta.text) {
4488
+ yield { type: "delta", channel: "answer", text: event.delta.text };
4489
+ } else if (event.delta?.type === "thinking_delta" && event.delta.thinking) {
4490
+ yield { type: "delta", channel: "reasoning", text: event.delta.thinking };
4491
+ }
4492
+ }
4493
+ }
4494
+ }
4495
+ yield* flushUsage();
4496
+ } catch (err) {
4497
+ throw err instanceof AiError ? err : errorFromUnknown(err);
4498
+ } finally {
4499
+ reader.releaseLock();
4500
+ }
4501
+ }
4502
+ function createAnthropicAdapter(config) {
4503
+ return {
4504
+ async *stream(req) {
4505
+ const timeout = AbortSignal.timeout(config.timeoutMs);
4506
+ const signal = req.signal ? AbortSignal.any([req.signal, timeout]) : timeout;
4507
+ const system = req.messages.filter((message) => message.role === "system").map((message) => message.content).join("\n\n");
4508
+ const messages = mergeImages2(
4509
+ req.messages.filter((message) => message.role !== "system").map((message) => {
4510
+ if (message.role === "user") return { role: "user", content: message.content };
4511
+ return { role: "assistant", content: message.content };
4512
+ }),
4513
+ req.images ?? []
4514
+ );
4515
+ let response;
4516
+ try {
4517
+ response = await fetch(`${config.baseUrl}/v1/messages`, {
4518
+ method: "POST",
4519
+ headers: {
4520
+ "x-api-key": config.apiKey,
4521
+ "anthropic-version": ANTHROPIC_VERSION,
4522
+ "Content-Type": "application/json"
4523
+ },
4524
+ body: JSON.stringify({
4525
+ model: req.externalModelId,
4526
+ messages,
4527
+ ...system.length > 0 ? { system } : {},
4528
+ max_tokens: req.maxOutputTokens,
4529
+ stream: true
4530
+ }),
4531
+ signal
4532
+ });
4533
+ } catch (err) {
4534
+ throw errorFromUnknown(err);
4535
+ }
4536
+ if (!response.ok || !response.body) {
4537
+ const detail = await extractErrorDetail2(response);
4538
+ throw errorFromStatus(response.status, detail);
4539
+ }
4540
+ yield* parseAnthropicStream(response.body);
4541
+ }
4542
+ };
4543
+ }
4544
+
4166
4545
  exports.ANTHROPIC_API_VERSION = ANTHROPIC_API_VERSION;
4167
4546
  exports.ANTHROPIC_DEFAULT_MAX_TOKENS = ANTHROPIC_DEFAULT_MAX_TOKENS;
4168
4547
  exports.ANTHROPIC_MODELS = ANTHROPIC_MODELS;
@@ -4205,12 +4584,14 @@ exports.configureProvider = configureProvider;
4205
4584
  exports.consumeAnthropicStream = consumeAnthropicStream;
4206
4585
  exports.consumeGroqStream = consumeGroqStream;
4207
4586
  exports.createAI = createAI;
4587
+ exports.createAnthropicAdapter = createAnthropicAdapter;
4208
4588
  exports.createAssistantMessage = createAssistantMessage;
4209
4589
  exports.createFalProvider = createFalProvider;
4210
4590
  exports.createGeminiProvider = createGeminiProvider;
4211
4591
  exports.createGroqProvider = createGroqProvider;
4212
4592
  exports.createMessage = createMessage;
4213
4593
  exports.createOpenAiAudioTranscriptionAdapter = createOpenAiAudioTranscriptionAdapter;
4594
+ exports.createOpenAiCompatibleAdapter = createOpenAiCompatibleAdapter;
4214
4595
  exports.createOpenAiEmbeddingsAdapter = createOpenAiEmbeddingsAdapter;
4215
4596
  exports.createOpenAiImageAdapter = createOpenAiImageAdapter;
4216
4597
  exports.createOpenAiSpeechAdapter = createOpenAiSpeechAdapter;