@umituz/web-ai 1.2.0 → 1.4.0

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
@@ -322,6 +322,31 @@ function aiErrorStatus(code) {
322
322
  return AI_ERROR_STATUS[code];
323
323
  }
324
324
 
325
+ // src/core/errors/ai-failure.ts
326
+ var TYPE_TO_CODE = {
327
+ ["INVALID_API_KEY" /* INVALID_API_KEY */]: "invalid_key",
328
+ ["MISSING_CONFIG" /* MISSING_CONFIG */]: "missing_key",
329
+ ["NETWORK_ERROR" /* NETWORK_ERROR */]: "network",
330
+ ["ABORT_ERROR" /* ABORT_ERROR */]: "timeout",
331
+ ["RATE_LIMIT_ERROR" /* RATE_LIMIT_ERROR */]: "rate_limited",
332
+ ["SERVER_ERROR" /* SERVER_ERROR */]: "upstream_error",
333
+ ["CLIENT_ERROR" /* CLIENT_ERROR */]: "invalid_request",
334
+ ["UNKNOWN_ERROR" /* UNKNOWN_ERROR */]: "upstream_error"
335
+ };
336
+ function aiFailureOf(error) {
337
+ if (error instanceof AiError) {
338
+ return { code: error.code, status: AI_ERROR_STATUS[error.code], message: error.userMessage };
339
+ }
340
+ if (error instanceof AIError) {
341
+ const code = TYPE_TO_CODE[error.type];
342
+ return { code, status: AI_ERROR_STATUS[code], message: CODE_MESSAGES[code] };
343
+ }
344
+ if (error instanceof Error && error.name === "AbortError") {
345
+ return { code: "timeout", status: AI_ERROR_STATUS.timeout, message: CODE_MESSAGES.timeout };
346
+ }
347
+ return { code: "upstream_error", status: AI_ERROR_STATUS.upstream_error, message: CODE_MESSAGES.upstream_error };
348
+ }
349
+
325
350
  // src/core/executor/retry-executor.strategy.ts
326
351
  var RetryExecutor = class {
327
352
  constructor(retryManager2, options) {
@@ -932,6 +957,34 @@ function failoverCandidate(primary, fallback) {
932
957
  return fallback;
933
958
  }
934
959
 
960
+ // src/core/utils/title.ts
961
+ function deriveConversationTitle(content, options = {}) {
962
+ const fallback = options.fallback ?? "";
963
+ const maxChars = options.maxChars ?? 60;
964
+ const firstLine = content.split("\n").map((line) => line.trim()).find((line) => line.length > 0);
965
+ const cleaned = (firstLine ?? fallback).replace(/^#{1,6}\s+/, "").replace(/^[>*-]\s+/, "").replace(/\s+/g, " ");
966
+ if (cleaned.length === 0) return fallback;
967
+ return cleaned.length > maxChars ? `${cleaned.slice(0, maxChars).trimEnd()}\u2026` : cleaned;
968
+ }
969
+
970
+ // src/core/utils/allowance-window.ts
971
+ var DEFAULT_ALLOWANCE_WINDOW_MS = 36e5;
972
+ function createAllowanceWindow(options) {
973
+ const windowMs = options.windowMs ?? DEFAULT_ALLOWANCE_WINDOW_MS;
974
+ const buckets = /* @__PURE__ */ new Map();
975
+ return {
976
+ allow(key, now = Date.now()) {
977
+ const bucket = buckets.get(key);
978
+ if (bucket === void 0 || now - bucket.windowStart >= windowMs) {
979
+ buckets.set(key, { windowStart: now, count: 1 });
980
+ return true;
981
+ }
982
+ bucket.count += 1;
983
+ return bucket.count <= options.limit;
984
+ }
985
+ };
986
+ }
987
+
935
988
  // src/core/constants/protocol.constants.ts
936
989
  var SSE_PREFIX = "data: ";
937
990
  var SSE_DONE_MARKER = "[DONE]";
@@ -1311,6 +1364,11 @@ function planTaskFailure(task, errorDetail, backoffBaseMs, now = /* @__PURE__ */
1311
1364
  }
1312
1365
  };
1313
1366
  }
1367
+ var STUCK_TASK_THRESHOLD_MS = 15 * 60 * 1e3;
1368
+ function planStuckRecovery(task, now = /* @__PURE__ */ new Date(), thresholdMs = STUCK_TASK_THRESHOLD_MS) {
1369
+ if (now.getTime() - task.updatedAt.getTime() < thresholdMs) return null;
1370
+ return task.attempts >= task.maxAttempts ? { action: "fail" } : { action: "requeue" };
1371
+ }
1314
1372
 
1315
1373
  // src/core/sse/sse-response.service.ts
1316
1374
  var SSE_BRIDGE_EVENTS = {
@@ -1910,21 +1968,52 @@ async function readSseResponse(response, callbacks) {
1910
1968
  callbacks.onError?.("request_failed", "The server returned an empty stream.");
1911
1969
  return;
1912
1970
  }
1913
- const reader = response.body.getReader();
1971
+ for await (const event of iterateSseJson(response)) {
1972
+ if (event) dispatchSseEvent(event, callbacks);
1973
+ }
1974
+ }
1975
+ function dataPayloadOf(frame) {
1976
+ let data = null;
1977
+ for (const line of frame.split("\n")) {
1978
+ if (line.startsWith("data:")) {
1979
+ const payload = line.slice(5).trim();
1980
+ data = data === null ? payload : `${data}
1981
+ ${payload}`;
1982
+ }
1983
+ }
1984
+ return data !== null && data.length > 0 ? data : null;
1985
+ }
1986
+ async function* iterateSseData(source) {
1987
+ const body = source instanceof Response ? source.body : source;
1988
+ if (!body) {
1989
+ throw new Error("iterateSseData: the response has no body to read");
1990
+ }
1991
+ const reader = body.getReader();
1914
1992
  const decoder = new TextDecoder();
1915
1993
  let buffer = "";
1916
- while (true) {
1917
- const { done, value } = await reader.read();
1918
- if (done) break;
1919
- buffer += decoder.decode(value, { stream: true });
1920
- let separator = buffer.indexOf("\n\n");
1921
- while (separator !== -1) {
1922
- const rawEvent = buffer.slice(0, separator);
1923
- buffer = buffer.slice(separator + 2);
1924
- separator = buffer.indexOf("\n\n");
1925
- const event = parseSseEvent(rawEvent);
1926
- if (!event) continue;
1927
- dispatchSseEvent(event, callbacks);
1994
+ try {
1995
+ while (true) {
1996
+ const { done, value } = await reader.read();
1997
+ if (done) break;
1998
+ buffer += decoder.decode(value, { stream: true });
1999
+ let boundary = buffer.indexOf("\n\n");
2000
+ while (boundary !== -1) {
2001
+ const frame = buffer.slice(0, boundary);
2002
+ buffer = buffer.slice(boundary + 2);
2003
+ boundary = buffer.indexOf("\n\n");
2004
+ const data = dataPayloadOf(frame);
2005
+ if (data) yield data;
2006
+ }
2007
+ }
2008
+ } finally {
2009
+ await reader.cancel().catch(() => void 0);
2010
+ }
2011
+ }
2012
+ async function* iterateSseJson(source) {
2013
+ for await (const data of iterateSseData(source)) {
2014
+ try {
2015
+ yield JSON.parse(data);
2016
+ } catch {
1928
2017
  }
1929
2018
  }
1930
2019
  }
@@ -6014,6 +6103,14 @@ function resetProvider() {
6014
6103
  container?.groqHttpClient.reset();
6015
6104
  container = null;
6016
6105
  }
6106
+ function bootProvider(apiKey, options = {}) {
6107
+ if (!isValidApiKey(apiKey)) return null;
6108
+ return getProvider() ?? configureProvider({
6109
+ apiKey: apiKey.trim(),
6110
+ timeoutMs: options.timeoutMs ?? 3e4,
6111
+ textModel: options.textModel ?? GROQ_MODELS.GPT_OSS_120B
6112
+ });
6113
+ }
6017
6114
 
6018
6115
  // src/providers/workers-ai/workers-ai.speech.ts
6019
6116
  var WORKERS_AI_SPEECH_TIMEOUT_MS = 45e3;
@@ -8353,6 +8450,7 @@ exports.ChatService = ChatService;
8353
8450
  exports.CompositeExecutor = CompositeExecutor;
8354
8451
  exports.ContentCalendarService = ContentCalendarService;
8355
8452
  exports.DEFAULT_AI_IDENTITY = DEFAULT_AI_IDENTITY;
8453
+ exports.DEFAULT_ALLOWANCE_WINDOW_MS = DEFAULT_ALLOWANCE_WINDOW_MS;
8356
8454
  exports.DEFAULT_API_KEY_RULE = DEFAULT_API_KEY_RULE;
8357
8455
  exports.DEFAULT_BASE_URL = DEFAULT_BASE_URL;
8358
8456
  exports.DEFAULT_EMBED_BATCH_SIZE = DEFAULT_EMBED_BATCH_SIZE;
@@ -8429,6 +8527,7 @@ exports.SSE_BRIDGE_EVENTS = SSE_BRIDGE_EVENTS;
8429
8527
  exports.SSE_DONE_MARKER = SSE_DONE_MARKER;
8430
8528
  exports.SSE_PREFIX = SSE_PREFIX;
8431
8529
  exports.STATUS_TO_CODE = STATUS_TO_CODE;
8530
+ exports.STUCK_TASK_THRESHOLD_MS = STUCK_TASK_THRESHOLD_MS;
8432
8531
  exports.STYLE_PRESETS = STYLE_PRESETS;
8433
8532
  exports.SYSTEM_PROMPT_VERSION = SYSTEM_PROMPT_VERSION;
8434
8533
  exports.SeoService = SeoService;
@@ -8459,6 +8558,7 @@ exports.WorkersAIProvider = WorkersAIProvider;
8459
8558
  exports.accumulateReport = accumulateReport;
8460
8559
  exports.aiErrorMessage = aiErrorMessage;
8461
8560
  exports.aiErrorStatus = aiErrorStatus;
8561
+ exports.aiFailureOf = aiFailureOf;
8462
8562
  exports.apiKeyAvailable = apiKeyAvailable;
8463
8563
  exports.asObjectArray = asObjectArray;
8464
8564
  exports.asRecord = asRecord;
@@ -8467,6 +8567,7 @@ exports.asTrimmedOptionalString = asTrimmedOptionalString;
8467
8567
  exports.audioTranscriptionAdapterFor = audioTranscriptionAdapterFor;
8468
8568
  exports.batchEmbed = batchEmbed;
8469
8569
  exports.batchRequest = batchRequest;
8570
+ exports.bootProvider = bootProvider;
8470
8571
  exports.buildCacheKey = buildCacheKey;
8471
8572
  exports.buildContentRequest = buildContentRequest;
8472
8573
  exports.buildContext = buildContext;
@@ -8503,6 +8604,7 @@ exports.cosineSimilarity = cosineSimilarity;
8503
8604
  exports.countChanges = countChanges;
8504
8605
  exports.createAI = createAI;
8505
8606
  exports.createAdapterResolver = createAdapterResolver;
8607
+ exports.createAllowanceWindow = createAllowanceWindow;
8506
8608
  exports.createAnthropicAdapter = createAnthropicAdapter;
8507
8609
  exports.createAssistantMessage = createAssistantMessage;
8508
8610
  exports.createFalProvider = createFalProvider;
@@ -8527,6 +8629,7 @@ exports.debounce = debounce;
8527
8629
  exports.debounceManager = debounceManager;
8528
8630
  exports.defaultEffortForModel = defaultEffortForModel;
8529
8631
  exports.defaultSseDeltaExtractor = defaultSseDeltaExtractor;
8632
+ exports.deriveConversationTitle = deriveConversationTitle;
8530
8633
  exports.deriveSnippetTitle = deriveSnippetTitle;
8531
8634
  exports.describeAIErrorType = describeAIErrorType;
8532
8635
  exports.diffLines = diffLines;
@@ -8576,6 +8679,8 @@ exports.isTransientError = isTransientError;
8576
8679
  exports.isValidApiKey = isValidApiKey;
8577
8680
  exports.isValidJSON = isValidJSON;
8578
8681
  exports.isWithinWindow = isWithinWindow;
8682
+ exports.iterateSseData = iterateSseData;
8683
+ exports.iterateSseJson = iterateSseJson;
8579
8684
  exports.magnitude = magnitude;
8580
8685
  exports.mapAnthropicStopReason = mapAnthropicStopReason;
8581
8686
  exports.mergeTierOverrides = mergeTierOverrides;
@@ -8590,6 +8695,7 @@ exports.parseFalAudioOutput = parseFalAudioOutput;
8590
8695
  exports.parseFalImageOutput = parseFalImageOutput;
8591
8696
  exports.parseFalVideoOutput = parseFalVideoOutput;
8592
8697
  exports.parseSseEvent = parseSseEvent;
8698
+ exports.planStuckRecovery = planStuckRecovery;
8593
8699
  exports.planTaskFailure = planTaskFailure;
8594
8700
  exports.pollForResult = pollForResult;
8595
8701
  exports.promptToMessages = promptToMessages;