@adriangalilea/utils 1.15.0 → 2.0.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.
@@ -0,0 +1,504 @@
1
+ /**
2
+ * Multi-provider LLM caller with priority failover — the policy layer the
3
+ * Vercel AI SDK deliberately doesn't ship.
4
+ *
5
+ * The AI SDK owns the transport: HTTP, SSE parsing, provider dialects
6
+ * (OpenAI-compatible, Anthropic-messages, OpenRouter), tool calling,
7
+ * streaming. This module owns the policy on top:
8
+ *
9
+ * - **Priority failover across providers AND keys.** Several declarations
10
+ * may share one `id` to register multiple API keys for the same provider;
11
+ * on failure the loop prefers another healthy key of the same `id` before
12
+ * moving to the next `id` by priority.
13
+ * - **Per-key circuit breaker.** Failures cool a key down with exponential
14
+ * backoff (rate-limit / auth / transient classed separately), persisted in
15
+ * an optional {@link HealthStore} (Cloudflare KV satisfies it
16
+ * structurally). Without a store the loop degrades to per-request
17
+ * failover.
18
+ * - **Reset semantics for live previews.** A provider that dies mid-stream
19
+ * forfeits its output: the consumer gets `{kind: 'reset'}` (drop
20
+ * everything rendered so far) and the next candidate regenerates from
21
+ * scratch. Telegram draft previews repaint per frame, so a reset is one
22
+ * cheap frame.
23
+ * - **Usage accounting that feeds a ledger.** Tokens are summed across every
24
+ * billed attempt (a failover means more than one billed request).
25
+ * `costUsd` is the ACTUAL charge when the gateway reports one —
26
+ * OpenRouter's usage accounting (`providerMetadata.openrouter.usage.cost`)
27
+ * or a `cost` field on the provider's raw usage frame — never a price
28
+ * table estimate.
29
+ *
30
+ * Worker-safe: fetch/WebStreams only, no `node:*`. Peer deps: `ai`,
31
+ * `@ai-sdk/openai-compatible`, `@ai-sdk/anthropic`,
32
+ * `@openrouter/ai-sdk-provider` (install all four; they are small and the
33
+ * provider used is picked per {@link ProviderConfig.type} at runtime).
34
+ *
35
+ * @example one-shot with failover
36
+ * import { createLlm } from '@adriangalilea/utils/llm'
37
+ *
38
+ * const llm = createLlm({
39
+ * providers: [
40
+ * { id: 'openrouter', type: 'openrouter', apiKey, defaultModel: 'deepseek/deepseek-chat', priority: 0 },
41
+ * { id: 'deepseek', type: 'openai', baseUrl: 'https://api.deepseek.com', apiKey: key2, defaultModel: 'deepseek-chat', priority: 1 },
42
+ * ],
43
+ * health: env.KEY_HEALTH, // optional KV namespace
44
+ * })
45
+ * const { text, usage } = await llm.complete({ prompt })
46
+ *
47
+ * @example streaming with tools
48
+ * import { tool } from '@adriangalilea/utils/llm'
49
+ * import { z } from 'zod'
50
+ *
51
+ * const events = llm.stream({
52
+ * prompt,
53
+ * tools: { not_covered: tool({ description: '…', inputSchema: z.object({}) }) },
54
+ * })
55
+ * for await (const e of events) {
56
+ * if (e.kind === 'delta') draft.append(e.text)
57
+ * else if (e.kind === 'reset') draft.clear()
58
+ * else if (e.kind === 'tool-call') handle(e.toolName, e.input)
59
+ * }
60
+ */
61
+ import { createAnthropic } from "@ai-sdk/anthropic";
62
+ import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
63
+ import { createOpenRouter } from "@openrouter/ai-sdk-provider";
64
+ import { APICallError, streamText, } from "ai";
65
+ // One import surface for consumers: the tool helper and its types ride along.
66
+ export { jsonSchema, tool, } from "ai";
67
+ export class LlmError extends Error {
68
+ status;
69
+ constructor(message, status) {
70
+ super(message);
71
+ this.status = status;
72
+ this.name = "LlmError";
73
+ }
74
+ }
75
+ const DEFAULT_MAX_TOKENS = 4096;
76
+ const DEFAULT_TEMPERATURE = 0.7;
77
+ const REQUEST_TIMEOUT_MS = 120_000;
78
+ // ─── Circuit breaker ───────────────────────────────────────────────
79
+ // Base cool-down per failure class; the window grows exponentially with the
80
+ // consecutive failure count, capped at one hour. A key past its recovery time
81
+ // probes again; jitter spreads concurrent probes so a fleet doesn't hammer a
82
+ // just-recovered key in one synchronized burst.
83
+ const RATE_LIMIT_BASE_MS = 60_000; // 429: providers' rate windows are ~a minute
84
+ const TRANSIENT_BASE_MS = 30_000; // 5xx / timeout / network: usually clears quickly
85
+ const AUTH_BASE_MS = 300_000; // 401/403: a revoked key won't self-heal, start at 5 min
86
+ const BACKOFF_CAP_MS = 3_600_000;
87
+ const RECOVERY_JITTER_MS = 10_000;
88
+ // Classify a failed attempt by HTTP status. `client` (our own bad request,
89
+ // 4xx except 408/429) must not blacklist a healthy key.
90
+ function classifyError(e) {
91
+ const status = APICallError.isInstance(e)
92
+ ? e.statusCode
93
+ : e instanceof LlmError
94
+ ? e.status
95
+ : undefined;
96
+ if (status === undefined)
97
+ return "transient"; // network/DNS/TLS/timeout
98
+ if (status === 429)
99
+ return "rate_limited";
100
+ if (status === 401 || status === 403)
101
+ return "auth";
102
+ if (status >= 400 && status < 500 && status !== 408)
103
+ return "client";
104
+ return "transient";
105
+ }
106
+ // Stable, non-reversible fingerprint of an API key (FNV-1a → base36): health
107
+ // is tracked PER KEY without ever writing the secret into a store key or log.
108
+ function keyFingerprint(apiKey) {
109
+ let h = 0x811c9dc5;
110
+ for (let i = 0; i < apiKey.length; i++) {
111
+ h ^= apiKey.charCodeAt(i);
112
+ h = Math.imul(h, 0x01000193);
113
+ }
114
+ return (h >>> 0).toString(36);
115
+ }
116
+ const keyId = (p) => `${p.id}:${keyFingerprint(p.apiKey ?? "")}`;
117
+ // ─── The caller ────────────────────────────────────────────────────
118
+ export function createLlm(opts) {
119
+ return new Llm(opts);
120
+ }
121
+ export class Llm {
122
+ opts;
123
+ constructor(opts) {
124
+ this.opts = opts;
125
+ if (opts.providers.length === 0)
126
+ throw new LlmError("llm: no providers configured");
127
+ }
128
+ /** One-shot: run {@link stream} to completion and collect the pieces. */
129
+ async complete(req) {
130
+ let text = "";
131
+ let reasoning = "";
132
+ const toolCalls = [];
133
+ let usage = null;
134
+ for await (const event of this.stream(req)) {
135
+ if (event.kind === "delta")
136
+ text += event.text;
137
+ else if (event.kind === "reasoning")
138
+ reasoning += event.text;
139
+ else if (event.kind === "reset") {
140
+ text = "";
141
+ reasoning = "";
142
+ toolCalls.length = 0;
143
+ }
144
+ else if (event.kind === "tool-call")
145
+ toolCalls.push({ toolName: event.toolName, input: event.input });
146
+ else
147
+ usage = event.usage;
148
+ }
149
+ return { text: text.trim(), reasoning: reasoning.trim(), toolCalls, usage };
150
+ }
151
+ /**
152
+ * Stream one response with failover. Attempts candidates in priority order
153
+ * (healthy keys first, same-`id` siblings preferred after a failure); an
154
+ * attempt that fails after emitting output yields `reset` so the consumer
155
+ * starts over. Throws {@link LlmError} when every candidate is exhausted.
156
+ * An attempt that finishes with no text and no tool calls counts as failed
157
+ * — an empty completion is a provider bug, not an answer.
158
+ */
159
+ async *stream(req) {
160
+ if ((req.prompt === undefined) === (req.messages === undefined))
161
+ throw new LlmError("llm: pass exactly one of prompt/messages");
162
+ const errors = [];
163
+ const queue = await this.buildQueue(errors);
164
+ let preferId;
165
+ let totalPrompt = 0;
166
+ let totalCompletion = 0;
167
+ let totalCost;
168
+ while (queue.length > 0) {
169
+ let idx = 0;
170
+ if (preferId !== undefined) {
171
+ const sameIdx = queue.findIndex((c) => c.provider.id === preferId);
172
+ if (sameIdx !== -1)
173
+ idx = sameIdx;
174
+ }
175
+ const { provider, health } = queue.splice(idx, 1)[0];
176
+ const attempt = yield* this.runAttempt(provider, req);
177
+ if (attempt.usage) {
178
+ totalPrompt += attempt.usage.promptTokens;
179
+ totalCompletion += attempt.usage.completionTokens;
180
+ if (attempt.usage.costUsd !== undefined)
181
+ totalCost = (totalCost ?? 0) + attempt.usage.costUsd;
182
+ }
183
+ if (attempt.ok) {
184
+ // Recovery: DELETE the health key (absence == healthy), clearing the failure counter.
185
+ if (health)
186
+ await this.clearHealth(keyId(provider));
187
+ yield {
188
+ kind: "end",
189
+ usage: totalPrompt || totalCompletion || totalCost !== undefined
190
+ ? {
191
+ promptTokens: totalPrompt,
192
+ completionTokens: totalCompletion,
193
+ ...(totalCost !== undefined ? { costUsd: totalCost } : {}),
194
+ provider: provider.id,
195
+ model: provider.defaultModel,
196
+ }
197
+ : null,
198
+ };
199
+ return;
200
+ }
201
+ // The caller's own signal aborting is not a provider failure: don't
202
+ // penalize the key, don't sweep the remaining candidates with an
203
+ // already-dead signal.
204
+ if (req.abortSignal?.aborted)
205
+ throw new LlmError("llm: aborted");
206
+ const msg = attempt.error instanceof Error
207
+ ? attempt.error.message
208
+ : String(attempt.error);
209
+ errors.push(`${provider.id}: ${msg}`);
210
+ await this.recordFailure(keyId(provider), provider.id, health, classifyError(attempt.error), msg);
211
+ // Whatever this attempt painted is now stale; order a repaint before
212
+ // the next attempt streams a fresh response.
213
+ if (attempt.emitted)
214
+ yield { kind: "reset" };
215
+ preferId = provider.id;
216
+ }
217
+ if (errors.length === 0)
218
+ throw new LlmError("llm: all providers unavailable (disabled or cooling down after failures)");
219
+ throw new LlmError(`llm: all providers failed: ${errors.join("; ")}`);
220
+ }
221
+ // Stream one provider attempt, translating AI SDK parts to LlmStreamEvents.
222
+ async *runAttempt(provider, req) {
223
+ let emitted = false;
224
+ let sawContent = false;
225
+ let usage = null;
226
+ try {
227
+ const result = streamText({
228
+ model: this.modelFor(provider, req),
229
+ ...(req.prompt !== undefined
230
+ ? { prompt: req.prompt }
231
+ : { messages: req.messages }),
232
+ ...(req.instructions !== undefined
233
+ ? { instructions: req.instructions }
234
+ : {}),
235
+ temperature: resolveTemperature(provider),
236
+ maxOutputTokens: resolveMaxTokens(provider, req.maxTokens),
237
+ maxRetries: 0, // retry policy lives in the failover loop, not the transport
238
+ abortSignal: withTimeout(req.abortSignal, this.opts.requestTimeoutMs ?? REQUEST_TIMEOUT_MS),
239
+ ...(req.tools ? { tools: req.tools } : {}),
240
+ ...(req.toolChoice ? { toolChoice: req.toolChoice } : {}),
241
+ ...this.providerOptionsFor(provider, req),
242
+ });
243
+ for await (const part of result.stream) {
244
+ if (part.type === "text-delta") {
245
+ emitted = true;
246
+ sawContent = true;
247
+ yield { kind: "delta", text: part.text };
248
+ }
249
+ else if (part.type === "reasoning-delta") {
250
+ emitted = true;
251
+ yield { kind: "reasoning", text: part.text };
252
+ }
253
+ else if (part.type === "tool-call") {
254
+ sawContent = true;
255
+ yield {
256
+ kind: "tool-call",
257
+ toolName: part.toolName,
258
+ input: part.input,
259
+ };
260
+ }
261
+ else if (part.type === "finish-step") {
262
+ usage = {
263
+ promptTokens: part.usage.inputTokens ?? 0,
264
+ completionTokens: part.usage.outputTokens ?? 0,
265
+ ...(extractCost(part.providerMetadata, part.usage.raw) !== undefined
266
+ ? { costUsd: extractCost(part.providerMetadata, part.usage.raw) }
267
+ : {}),
268
+ };
269
+ }
270
+ else if (part.type === "error") {
271
+ // The AI SDK stream never throws; failures arrive as parts.
272
+ return { ok: false, emitted, error: part.error, usage };
273
+ }
274
+ else if (part.type === "abort") {
275
+ return {
276
+ ok: false,
277
+ emitted,
278
+ error: new LlmError("llm: aborted"),
279
+ usage,
280
+ };
281
+ }
282
+ }
283
+ }
284
+ catch (e) {
285
+ return { ok: false, emitted, error: e, usage };
286
+ }
287
+ if (!sawContent)
288
+ return {
289
+ ok: false,
290
+ emitted,
291
+ error: new LlmError("llm: empty completion"),
292
+ usage,
293
+ };
294
+ return { ok: true, emitted, usage };
295
+ }
296
+ // One AI SDK model instance per attempt, by wire dialect. An `openai`
297
+ // entry pointed at openrouter.ai is upgraded to the openrouter provider so
298
+ // legacy configs keep typed cost accounting.
299
+ modelFor(provider, req) {
300
+ const type = dialectOf(provider);
301
+ if (type === "openrouter") {
302
+ const openrouter = createOpenRouter({
303
+ ...(provider.apiKey ? { apiKey: provider.apiKey } : {}),
304
+ ...(provider.baseUrl ? { baseURL: provider.baseUrl } : {}),
305
+ });
306
+ return openrouter.chat(provider.defaultModel, {
307
+ usage: { include: true }, // OpenRouter usage accounting: actual billed cost on the final chunk
308
+ ...(provider.disableThinking
309
+ ? { reasoning: { enabled: false, effort: "none" } }
310
+ : {}),
311
+ ...(req.extraBody ? { extraBody: req.extraBody } : {}),
312
+ });
313
+ }
314
+ if (type === "anthropic") {
315
+ const anthropic = createAnthropic({
316
+ ...(provider.apiKey ? { apiKey: provider.apiKey } : {}),
317
+ ...(provider.baseUrl
318
+ ? { baseURL: normalizeAnthropicBase(provider.baseUrl) }
319
+ : {}),
320
+ });
321
+ return anthropic(provider.defaultModel);
322
+ }
323
+ if (!provider.baseUrl)
324
+ throw new LlmError(`llm: provider ${provider.id} (openai) requires baseUrl`);
325
+ const compat = createOpenAICompatible({
326
+ name: provider.id,
327
+ baseURL: normalizeOpenAiBase(provider.baseUrl),
328
+ ...(provider.apiKey ? { apiKey: provider.apiKey } : {}),
329
+ includeUsage: true, // stream_options usage frame
330
+ });
331
+ return compat.chatModel(provider.defaultModel);
332
+ }
333
+ // Dialect-specific request body knobs, keyed the way each provider expects:
334
+ // openai-compatible spreads providerOptions[name] raw into the JSON body,
335
+ // which carries both the disableThinking flag and the request's extraBody.
336
+ providerOptionsFor(provider, req) {
337
+ const type = dialectOf(provider);
338
+ if (type === "anthropic")
339
+ return provider.disableThinking
340
+ ? { providerOptions: { anthropic: { thinking: { type: "disabled" } } } }
341
+ : {};
342
+ if (type === "openai") {
343
+ const body = {
344
+ ...(provider.disableThinking ? { thinking: { type: "disabled" } } : {}),
345
+ ...req.extraBody,
346
+ };
347
+ return Object.keys(body).length > 0
348
+ ? { providerOptions: { [provider.id]: body } }
349
+ : {};
350
+ }
351
+ return {}; // openrouter: settings + extraBody ride the model instance in modelFor
352
+ }
353
+ // Ordered attemptable keys: available now first (priority order), then
354
+ // jitter-deferred recovering keys as a deterministic fallback. Disabled and
355
+ // misconfigured declarations are dropped with a recorded reason.
356
+ async buildQueue(errors) {
357
+ const sorted = [...this.opts.providers].sort((a, b) => (a.priority ?? 99) - (b.priority ?? 99));
358
+ const available = [];
359
+ const deferred = [];
360
+ for (const provider of sorted) {
361
+ if (provider.disabled)
362
+ continue;
363
+ if (!provider.id || !provider.defaultModel) {
364
+ errors.push(`${provider.id || "(no id)"}: missing id or defaultModel`);
365
+ continue;
366
+ }
367
+ if (Array.isArray(provider.models) &&
368
+ provider.models.length > 0 &&
369
+ !provider.models.includes(provider.defaultModel)) {
370
+ errors.push(`${provider.id}: defaultModel "${provider.defaultModel}" is not in models`);
371
+ continue;
372
+ }
373
+ const health = await this.getHealth(keyId(provider));
374
+ const state = healthState(health);
375
+ if (state === "down")
376
+ continue;
377
+ if (state === "probe-deferred")
378
+ deferred.push({ provider, health });
379
+ else
380
+ available.push({ provider, health });
381
+ }
382
+ return [...available, ...deferred];
383
+ }
384
+ // Health plumbing is advisory and best-effort: a KV hiccup (or no store at
385
+ // all) must never break a chat request.
386
+ async getHealth(storeKey) {
387
+ if (!this.opts.health)
388
+ return null;
389
+ try {
390
+ const raw = await this.opts.health.get(`health:${storeKey}`);
391
+ return raw ? JSON.parse(raw) : null;
392
+ }
393
+ catch {
394
+ return null;
395
+ }
396
+ }
397
+ async recordFailure(storeKey, label, prev, cls, errMsg) {
398
+ if (cls === "client") {
399
+ console.error(`[llm:health] ${label} rejected our request (${errMsg}); not marking unhealthy`);
400
+ return;
401
+ }
402
+ const now = Date.now();
403
+ const failures = (prev?.failures ?? 0) + 1;
404
+ const base = cls === "rate_limited"
405
+ ? RATE_LIMIT_BASE_MS
406
+ : cls === "auth"
407
+ ? AUTH_BASE_MS
408
+ : TRANSIENT_BASE_MS;
409
+ const backoff = Math.min(base * 2 ** (failures - 1), BACKOFF_CAP_MS);
410
+ const health = {
411
+ status: cls === "rate_limited" ? "rate_limited" : "failed",
412
+ updatedAt: now,
413
+ recoveryAt: now + backoff,
414
+ failures,
415
+ };
416
+ // TTL outlives the jittered recovery window so the failure counter keeps
417
+ // escalating a persistently-dead key, yet self-heals to "healthy" (key
418
+ // absent) if traffic stops.
419
+ const ttl = Math.ceil((backoff + RECOVERY_JITTER_MS) / 1000) + 60;
420
+ if (this.opts.health) {
421
+ try {
422
+ await this.opts.health.put(`health:${storeKey}`, JSON.stringify(health), { expirationTtl: ttl });
423
+ }
424
+ catch {
425
+ // best-effort
426
+ }
427
+ }
428
+ const until = new Date(health.recoveryAt).toISOString();
429
+ console.error(`[llm:health] ${label} ${cls} (${errMsg}); cooling down until ${until} (failure #${failures})`);
430
+ }
431
+ async clearHealth(storeKey) {
432
+ if (!this.opts.health)
433
+ return;
434
+ try {
435
+ await this.opts.health.delete(`health:${storeKey}`);
436
+ }
437
+ catch {
438
+ // best-effort
439
+ }
440
+ }
441
+ }
442
+ // The wire dialect actually used for an attempt: an `openai` entry pointed at
443
+ // openrouter.ai upgrades to the openrouter provider so legacy configs keep
444
+ // typed cost accounting.
445
+ function dialectOf(provider) {
446
+ return provider.type === "openai" &&
447
+ provider.baseUrl?.includes("openrouter.ai")
448
+ ? "openrouter"
449
+ : provider.type;
450
+ }
451
+ // 'available' = use/probe now; 'probe-deferred' = past recovery but jitter
452
+ // says wait (fallback tail); 'down' = still inside the cool-down window.
453
+ function healthState(health) {
454
+ if (!health)
455
+ return "available";
456
+ const now = Date.now();
457
+ if (now < health.recoveryAt)
458
+ return "down";
459
+ const jitter = Math.random() * RECOVERY_JITTER_MS;
460
+ return now >= health.recoveryAt + jitter ? "available" : "probe-deferred";
461
+ }
462
+ function resolveTemperature(provider) {
463
+ const preferred = [
464
+ provider.temperatures?.[provider.defaultModel],
465
+ provider.temperature,
466
+ ].find((t) => typeof t === "number" && Number.isFinite(t));
467
+ const base = preferred ?? DEFAULT_TEMPERATURE;
468
+ // Anthropic accepts [0, 1]; everything OpenAI-shaped accepts [0, 2].
469
+ const ceiling = provider.type === "anthropic" ? 1 : 2;
470
+ return Math.max(0, Math.min(base, ceiling));
471
+ }
472
+ function resolveMaxTokens(provider, requested) {
473
+ const ask = requested ?? DEFAULT_MAX_TOKENS;
474
+ return provider.maxTokens ? Math.min(ask, provider.maxTokens) : ask;
475
+ }
476
+ // Combine the caller's abort signal (client disconnect) with a hard per-attempt
477
+ // timeout so a stalled upstream can't wedge the request forever.
478
+ function withTimeout(external, ms) {
479
+ const timeout = AbortSignal.timeout(ms);
480
+ return external ? AbortSignal.any([external, timeout]) : timeout;
481
+ }
482
+ // The Anthropic provider appends /v1/messages relative to its base; tolerate a
483
+ // pasted base that already carries /v1 or trailing slashes.
484
+ function normalizeAnthropicBase(baseUrl) {
485
+ return baseUrl.replace(/\/+$/, "").replace(/\/v1$/, "");
486
+ }
487
+ // The OpenAI-compatible provider appends /chat/completions; tolerate a pasted
488
+ // full URL.
489
+ function normalizeOpenAiBase(baseUrl) {
490
+ return baseUrl.replace(/\/+$/, "").replace(/\/chat\/completions$/, "");
491
+ }
492
+ /**
493
+ * Actual billed cost for one attempt, when the gateway reports one. Typed via
494
+ * the OpenRouter provider's metadata; falls back to a numeric `cost` on the
495
+ * raw usage frame (OpenAI-compatible gateways that do usage accounting).
496
+ */
497
+ function extractCost(providerMetadata, rawUsage) {
498
+ const or = providerMetadata?.openrouter?.usage?.cost;
499
+ if (typeof or === "number")
500
+ return or;
501
+ const raw = rawUsage?.cost;
502
+ return typeof raw === "number" ? raw : undefined;
503
+ }
504
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/llm/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EACN,YAAY,EAGZ,UAAU,GAGV,MAAM,IAAI,CAAC;AAEZ,8EAA8E;AAC9E,OAAO,EACN,UAAU,EAIV,IAAI,GACJ,MAAM,IAAI,CAAC;AA6GZ,MAAM,OAAO,QAAS,SAAQ,KAAK;IAGxB;IAFV,YACC,OAAe,EACN,MAAe;QAExB,KAAK,CAAC,OAAO,CAAC,CAAC;QAFN,WAAM,GAAN,MAAM,CAAS;QAGxB,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACxB,CAAC;CACD;AA0BD,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAChC,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAChC,MAAM,kBAAkB,GAAG,OAAO,CAAC;AAEnC,sEAAsE;AACtE,4EAA4E;AAC5E,8EAA8E;AAC9E,6EAA6E;AAC7E,gDAAgD;AAEhD,MAAM,kBAAkB,GAAG,MAAM,CAAC,CAAC,6CAA6C;AAChF,MAAM,iBAAiB,GAAG,MAAM,CAAC,CAAC,kDAAkD;AACpF,MAAM,YAAY,GAAG,OAAO,CAAC,CAAC,yDAAyD;AACvF,MAAM,cAAc,GAAG,SAAS,CAAC;AACjC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAWlC,2EAA2E;AAC3E,wDAAwD;AACxD,SAAS,aAAa,CAAC,CAAU;IAChC,MAAM,MAAM,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC,CAAC,UAAU;QACd,CAAC,CAAC,CAAC,YAAY,QAAQ;YACtB,CAAC,CAAC,CAAC,CAAC,MAAM;YACV,CAAC,CAAC,SAAS,CAAC;IACd,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,WAAW,CAAC,CAAC,0BAA0B;IACxE,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,cAAc,CAAC;IAC1C,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,MAAM,CAAC;IACpD,IAAI,MAAM,IAAI,GAAG,IAAI,MAAM,GAAG,GAAG,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,QAAQ,CAAC;IACrE,OAAO,WAAW,CAAC;AACpB,CAAC;AAED,6EAA6E;AAC7E,8EAA8E;AAC9E,SAAS,cAAc,CAAC,MAAc;IACrC,IAAI,CAAC,GAAG,UAAU,CAAC;IACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAC1B,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;IAC9B,CAAC;IACD,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,KAAK,GAAG,CAAC,CAAiB,EAAU,EAAE,CAC3C,GAAG,CAAC,CAAC,EAAE,IAAI,cAAc,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,CAAC;AAE7C,sEAAsE;AAEtE,MAAM,UAAU,SAAS,CAAC,IAAgB;IACzC,OAAO,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC;AACtB,CAAC;AAmBD,MAAM,OAAO,GAAG;IACc;IAA7B,YAA6B,IAAgB;QAAhB,SAAI,GAAJ,IAAI,CAAY;QAC5C,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;YAC9B,MAAM,IAAI,QAAQ,CAAC,8BAA8B,CAAC,CAAC;IACrD,CAAC;IAED,yEAAyE;IACzE,KAAK,CAAC,QAAQ,CAAC,GAAgB;QAC9B,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,IAAI,SAAS,GAAG,EAAE,CAAC;QACnB,MAAM,SAAS,GAAkB,EAAE,CAAC;QACpC,IAAI,KAAK,GAAoB,IAAI,CAAC;QAClC,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;YAC5C,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO;gBAAE,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC;iBAC1C,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW;gBAAE,SAAS,IAAI,KAAK,CAAC,IAAI,CAAC;iBACxD,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBACjC,IAAI,GAAG,EAAE,CAAC;gBACV,SAAS,GAAG,EAAE,CAAC;gBACf,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC;YACtB,CAAC;iBAAM,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW;gBACpC,SAAS,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;;gBAC7D,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;QAC1B,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAC7E,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,CAAC,MAAM,CAAC,GAAgB;QAC7B,IAAI,CAAC,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC;YAC9D,MAAM,IAAI,QAAQ,CAAC,0CAA0C,CAAC,CAAC;QAEhE,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QAC5C,IAAI,QAA4B,CAAC;QACjC,IAAI,WAAW,GAAG,CAAC,CAAC;QACpB,IAAI,eAAe,GAAG,CAAC,CAAC;QACxB,IAAI,SAA6B,CAAC;QAElC,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,IAAI,GAAG,GAAG,CAAC,CAAC;YACZ,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC5B,MAAM,OAAO,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC;gBACnE,IAAI,OAAO,KAAK,CAAC,CAAC;oBAAE,GAAG,GAAG,OAAO,CAAC;YACnC,CAAC;YACD,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAErD,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;YACtD,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;gBACnB,WAAW,IAAI,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC;gBAC1C,eAAe,IAAI,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC;gBAClD,IAAI,OAAO,CAAC,KAAK,CAAC,OAAO,KAAK,SAAS;oBACtC,SAAS,GAAG,CAAC,SAAS,IAAI,CAAC,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC;YACvD,CAAC;YAED,IAAI,OAAO,CAAC,EAAE,EAAE,CAAC;gBAChB,sFAAsF;gBACtF,IAAI,MAAM;oBAAE,MAAM,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;gBACpD,MAAM;oBACL,IAAI,EAAE,KAAK;oBACX,KAAK,EACJ,WAAW,IAAI,eAAe,IAAI,SAAS,KAAK,SAAS;wBACxD,CAAC,CAAC;4BACA,YAAY,EAAE,WAAW;4BACzB,gBAAgB,EAAE,eAAe;4BACjC,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;4BAC1D,QAAQ,EAAE,QAAQ,CAAC,EAAE;4BACrB,KAAK,EAAE,QAAQ,CAAC,YAAY;yBAC5B;wBACF,CAAC,CAAC,IAAI;iBACR,CAAC;gBACF,OAAO;YACR,CAAC;YAED,oEAAoE;YACpE,iEAAiE;YACjE,uBAAuB;YACvB,IAAI,GAAG,CAAC,WAAW,EAAE,OAAO;gBAAE,MAAM,IAAI,QAAQ,CAAC,cAAc,CAAC,CAAC;YAEjE,MAAM,GAAG,GACR,OAAO,CAAC,KAAK,YAAY,KAAK;gBAC7B,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO;gBACvB,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAC1B,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,EAAE,KAAK,GAAG,EAAE,CAAC,CAAC;YACtC,MAAM,IAAI,CAAC,aAAa,CACvB,KAAK,CAAC,QAAQ,CAAC,EACf,QAAQ,CAAC,EAAE,EACX,MAAM,EACN,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC,EAC5B,GAAG,CACH,CAAC;YAEF,qEAAqE;YACrE,6CAA6C;YAC7C,IAAI,OAAO,CAAC,OAAO;gBAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;YAC7C,QAAQ,GAAG,QAAQ,CAAC,EAAE,CAAC;QACxB,CAAC;QAED,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YACtB,MAAM,IAAI,QAAQ,CACjB,0EAA0E,CAC1E,CAAC;QACH,MAAM,IAAI,QAAQ,CAAC,8BAA8B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACvE,CAAC;IAED,4EAA4E;IACpE,KAAK,CAAC,CAAC,UAAU,CACxB,QAAwB,EACxB,GAAgB;QAEhB,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,UAAU,GAAG,KAAK,CAAC;QACvB,IAAI,KAAK,GAAqB,IAAI,CAAC;QACnC,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,UAAU,CAAC;gBACzB,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC;gBACnC,GAAG,CAAC,GAAG,CAAC,MAAM,KAAK,SAAS;oBAC3B,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE;oBACxB,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,QAA0B,EAAE,CAAC;gBAChD,GAAG,CAAC,GAAG,CAAC,YAAY,KAAK,SAAS;oBACjC,CAAC,CAAC,EAAE,YAAY,EAAE,GAAG,CAAC,YAAY,EAAE;oBACpC,CAAC,CAAC,EAAE,CAAC;gBACN,WAAW,EAAE,kBAAkB,CAAC,QAAQ,CAAC;gBACzC,eAAe,EAAE,gBAAgB,CAAC,QAAQ,EAAE,GAAG,CAAC,SAAS,CAAC;gBAC1D,UAAU,EAAE,CAAC,EAAE,6DAA6D;gBAC5E,WAAW,EAAE,WAAW,CACvB,GAAG,CAAC,WAAW,EACf,IAAI,CAAC,IAAI,CAAC,gBAAgB,IAAI,kBAAkB,CAChD;gBACD,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC1C,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACzD,GAAG,IAAI,CAAC,kBAAkB,CAAC,QAAQ,EAAE,GAAG,CAAC;aACzC,CAAC,CAAC;YAEH,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;gBACxC,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;oBAChC,OAAO,GAAG,IAAI,CAAC;oBACf,UAAU,GAAG,IAAI,CAAC;oBAClB,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;gBAC1C,CAAC;qBAAM,IAAI,IAAI,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;oBAC5C,OAAO,GAAG,IAAI,CAAC;oBACf,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;gBAC9C,CAAC;qBAAM,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;oBACtC,UAAU,GAAG,IAAI,CAAC;oBAClB,MAAM;wBACL,IAAI,EAAE,WAAW;wBACjB,QAAQ,EAAE,IAAI,CAAC,QAAQ;wBACvB,KAAK,EAAE,IAAI,CAAC,KAAK;qBACjB,CAAC;gBACH,CAAC;qBAAM,IAAI,IAAI,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;oBACxC,KAAK,GAAG;wBACP,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,IAAI,CAAC;wBACzC,gBAAgB,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY,IAAI,CAAC;wBAC9C,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,SAAS;4BACnE,CAAC,CAAC,EAAE,OAAO,EAAE,WAAW,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;4BACjE,CAAC,CAAC,EAAE,CAAC;qBACN,CAAC;gBACH,CAAC;qBAAM,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;oBAClC,4DAA4D;oBAC5D,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC;gBACzD,CAAC;qBAAM,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;oBAClC,OAAO;wBACN,EAAE,EAAE,KAAK;wBACT,OAAO;wBACP,KAAK,EAAE,IAAI,QAAQ,CAAC,cAAc,CAAC;wBACnC,KAAK;qBACL,CAAC;gBACH,CAAC;YACF,CAAC;QACF,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACZ,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC;QAChD,CAAC;QACD,IAAI,CAAC,UAAU;YACd,OAAO;gBACN,EAAE,EAAE,KAAK;gBACT,OAAO;gBACP,KAAK,EAAE,IAAI,QAAQ,CAAC,uBAAuB,CAAC;gBAC5C,KAAK;aACL,CAAC;QACH,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IACrC,CAAC;IAED,sEAAsE;IACtE,2EAA2E;IAC3E,6CAA6C;IACrC,QAAQ,CAAC,QAAwB,EAAE,GAAgB;QAC1D,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;QACjC,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;YAC3B,MAAM,UAAU,GAAG,gBAAgB,CAAC;gBACnC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACvD,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC1D,CAAC,CAAC;YACH,OAAO,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE;gBAC7C,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,qEAAqE;gBAC/F,GAAG,CAAC,QAAQ,CAAC,eAAe;oBAC3B,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;oBACnD,CAAC,CAAC,EAAE,CAAC;gBACN,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACtD,CAAC,CAAC;QACJ,CAAC;QACD,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;YAC1B,MAAM,SAAS,GAAG,eAAe,CAAC;gBACjC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACvD,GAAG,CAAC,QAAQ,CAAC,OAAO;oBACnB,CAAC,CAAC,EAAE,OAAO,EAAE,sBAAsB,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE;oBACvD,CAAC,CAAC,EAAE,CAAC;aACN,CAAC,CAAC;YACH,OAAO,SAAS,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QACzC,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,OAAO;YACpB,MAAM,IAAI,QAAQ,CACjB,iBAAiB,QAAQ,CAAC,EAAE,4BAA4B,CACxD,CAAC;QACH,MAAM,MAAM,GAAG,sBAAsB,CAAC;YACrC,IAAI,EAAE,QAAQ,CAAC,EAAE;YACjB,OAAO,EAAE,mBAAmB,CAAC,QAAQ,CAAC,OAAO,CAAC;YAC9C,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACvD,YAAY,EAAE,IAAI,EAAE,6BAA6B;SACjD,CAAC,CAAC;QACH,OAAO,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;IAChD,CAAC;IAED,4EAA4E;IAC5E,0EAA0E;IAC1E,2EAA2E;IACnE,kBAAkB,CACzB,QAAwB,EACxB,GAAgB;QAEhB,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;QACjC,IAAI,IAAI,KAAK,WAAW;YACvB,OAAO,QAAQ,CAAC,eAAe;gBAC9B,CAAC,CAAC,EAAE,eAAe,EAAE,EAAE,SAAS,EAAE,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,EAAE;gBACxE,CAAC,CAAC,EAAE,CAAC;QACP,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvB,MAAM,IAAI,GAAG;gBACZ,GAAG,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACvE,GAAG,GAAG,CAAC,SAAS;aAChB,CAAC;YACF,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;gBAClC,CAAC,CAAC,EAAE,eAAe,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE;gBAC9C,CAAC,CAAC,EAAE,CAAC;QACP,CAAC;QACD,OAAO,EAAE,CAAC,CAAC,uEAAuE;IACnF,CAAC;IAED,uEAAuE;IACvE,4EAA4E;IAC5E,iEAAiE;IACzD,KAAK,CAAC,UAAU,CAAC,MAAgB;QACxC,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAC3C,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC,CACjD,CAAC;QACF,MAAM,SAAS,GAAgB,EAAE,CAAC;QAClC,MAAM,QAAQ,GAAgB,EAAE,CAAC;QACjC,KAAK,MAAM,QAAQ,IAAI,MAAM,EAAE,CAAC;YAC/B,IAAI,QAAQ,CAAC,QAAQ;gBAAE,SAAS;YAChC,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;gBAC5C,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,EAAE,IAAI,SAAS,8BAA8B,CAAC,CAAC;gBACvE,SAAS;YACV,CAAC;YACD,IACC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAC9B,QAAQ,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;gBAC1B,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,EAC/C,CAAC;gBACF,MAAM,CAAC,IAAI,CACV,GAAG,QAAQ,CAAC,EAAE,mBAAmB,QAAQ,CAAC,YAAY,oBAAoB,CAC1E,CAAC;gBACF,SAAS;YACV,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;YACrD,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC;YAClC,IAAI,KAAK,KAAK,MAAM;gBAAE,SAAS;YAC/B,IAAI,KAAK,KAAK,gBAAgB;gBAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;;gBAC/D,SAAS,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;QAC3C,CAAC;QACD,OAAO,CAAC,GAAG,SAAS,EAAE,GAAG,QAAQ,CAAC,CAAC;IACpC,CAAC;IAED,2EAA2E;IAC3E,wCAAwC;IAChC,KAAK,CAAC,SAAS,CAAC,QAAgB;QACvC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QACnC,IAAI,CAAC;YACJ,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,QAAQ,EAAE,CAAC,CAAC;YAC7D,OAAO,GAAG,CAAC,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAe,CAAC,CAAC,CAAC,IAAI,CAAC;QACpD,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,IAAI,CAAC;QACb,CAAC;IACF,CAAC;IAEO,KAAK,CAAC,aAAa,CAC1B,QAAgB,EAChB,KAAa,EACb,IAAsB,EACtB,GAAiB,EACjB,MAAc;QAEd,IAAI,GAAG,KAAK,QAAQ,EAAE,CAAC;YACtB,OAAO,CAAC,KAAK,CACZ,gBAAgB,KAAK,0BAA0B,MAAM,0BAA0B,CAC/E,CAAC;YACF,OAAO;QACR,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,QAAQ,GAAG,CAAC,IAAI,EAAE,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QAC3C,MAAM,IAAI,GACT,GAAG,KAAK,cAAc;YACrB,CAAC,CAAC,kBAAkB;YACpB,CAAC,CAAC,GAAG,KAAK,MAAM;gBACf,CAAC,CAAC,YAAY;gBACd,CAAC,CAAC,iBAAiB,CAAC;QACvB,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;QACrE,MAAM,MAAM,GAAc;YACzB,MAAM,EAAE,GAAG,KAAK,cAAc,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,QAAQ;YAC1D,SAAS,EAAE,GAAG;YACd,UAAU,EAAE,GAAG,GAAG,OAAO;YACzB,QAAQ;SACR,CAAC;QACF,yEAAyE;QACzE,uEAAuE;QACvE,4BAA4B;QAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,GAAG,kBAAkB,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAClE,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACtB,IAAI,CAAC;gBACJ,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CACzB,UAAU,QAAQ,EAAE,EACpB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EACtB,EAAE,aAAa,EAAE,GAAG,EAAE,CACtB,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACR,cAAc;YACf,CAAC;QACF,CAAC;QACD,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE,CAAC;QACxD,OAAO,CAAC,KAAK,CACZ,gBAAgB,KAAK,IAAI,GAAG,KAAK,MAAM,yBAAyB,KAAK,cAAc,QAAQ,GAAG,CAC9F,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,WAAW,CAAC,QAAgB;QACzC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO;QAC9B,IAAI,CAAC;YACJ,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,QAAQ,EAAE,CAAC,CAAC;QACrD,CAAC;QAAC,MAAM,CAAC;YACR,cAAc;QACf,CAAC;IACF,CAAC;CACD;AAED,8EAA8E;AAC9E,2EAA2E;AAC3E,yBAAyB;AACzB,SAAS,SAAS,CAAC,QAAwB;IAC1C,OAAO,QAAQ,CAAC,IAAI,KAAK,QAAQ;QAChC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,eAAe,CAAC;QAC3C,CAAC,CAAC,YAAY;QACd,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;AAClB,CAAC;AAED,2EAA2E;AAC3E,yEAAyE;AACzE,SAAS,WAAW,CACnB,MAAwB;IAExB,IAAI,CAAC,MAAM;QAAE,OAAO,WAAW,CAAC;IAChC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,IAAI,GAAG,GAAG,MAAM,CAAC,UAAU;QAAE,OAAO,MAAM,CAAC;IAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,kBAAkB,CAAC;IAClD,OAAO,GAAG,IAAI,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,gBAAgB,CAAC;AAC3E,CAAC;AAED,SAAS,kBAAkB,CAAC,QAAwB;IACnD,MAAM,SAAS,GAAG;QACjB,QAAQ,CAAC,YAAY,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC;QAC9C,QAAQ,CAAC,WAAW;KACpB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IACxE,MAAM,IAAI,GAAG,SAAS,IAAI,mBAAmB,CAAC;IAC9C,qEAAqE;IACrE,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACtD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED,SAAS,gBAAgB,CACxB,QAAwB,EACxB,SAAkB;IAElB,MAAM,GAAG,GAAG,SAAS,IAAI,kBAAkB,CAAC;IAC5C,OAAO,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AACrE,CAAC;AAED,gFAAgF;AAChF,iEAAiE;AACjE,SAAS,WAAW,CACnB,QAAiC,EACjC,EAAU;IAEV,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACxC,OAAO,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;AAClE,CAAC;AAED,+EAA+E;AAC/E,4DAA4D;AAC5D,SAAS,sBAAsB,CAAC,OAAe;IAC9C,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AACzD,CAAC;AAED,8EAA8E;AAC9E,YAAY;AACZ,SAAS,mBAAmB,CAAC,OAAe;IAC3C,OAAO,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,sBAAsB,EAAE,EAAE,CAAC,CAAC;AACxE,CAAC;AAED;;;;GAIG;AACH,SAAS,WAAW,CACnB,gBAAyB,EACzB,QAAiB;IAEjB,MAAM,EAAE,GACP,gBAGA,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,CAAC;IAC3B,IAAI,OAAO,EAAE,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAC;IACtC,MAAM,GAAG,GAAI,QAA2C,EAAE,IAAI,CAAC;IAC/D,OAAO,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;AAClD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adriangalilea/utils",
3
- "version": "1.15.0",
3
+ "version": "2.0.0",
4
4
  "description": "TypeScript utilities - logger, currency, formatter, GramIO bot plugins, and more",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -135,6 +135,10 @@
135
135
  "./bot/user": {
136
136
  "types": "./dist/bot/user.d.ts",
137
137
  "default": "./dist/bot/user.js"
138
+ },
139
+ "./llm": {
140
+ "types": "./dist/llm/index.d.ts",
141
+ "default": "./dist/llm/index.js"
138
142
  }
139
143
  },
140
144
  "files": [
@@ -174,11 +178,16 @@
174
178
  "author": "Adrian Galilea <adriangalilea@gmail.com>",
175
179
  "license": "MIT",
176
180
  "devDependencies": {
181
+ "@ai-sdk/anthropic": "^4.0.12",
182
+ "@ai-sdk/openai-compatible": "^3.0.7",
177
183
  "@biomejs/biome": "2.4.15",
178
184
  "@gramio/format": "^0.8.0",
179
185
  "@gramio/session": "^0.2.0",
186
+ "@gramio/split": "^0.0.1",
180
187
  "@gramio/storage": "^2.0.1",
188
+ "@openrouter/ai-sdk-provider": "^3.0.0",
181
189
  "@types/node": "^24.3.0",
190
+ "ai": "^7.0.22",
182
191
  "gramio": "^0.12.0",
183
192
  "marked": "^15.0.11",
184
193
  "tsx": "^4.20.4",
@@ -189,9 +198,14 @@
189
198
  "@gramio/format": ">=0.8.0",
190
199
  "@gramio/session": ">=0.2.0",
191
200
  "@gramio/storage": ">=2.0.0",
192
- "gramio": ">=0.10.0",
201
+ "gramio": "^0.12.0",
193
202
  "marked": ">=12",
194
- "zod": ">=3.22"
203
+ "zod": ">=3.22",
204
+ "ai": "^7.0.0",
205
+ "@ai-sdk/anthropic": "^4.0.0",
206
+ "@ai-sdk/openai-compatible": "^3.0.0",
207
+ "@openrouter/ai-sdk-provider": "^3.0.0",
208
+ "@gramio/split": "^0.0.1"
195
209
  },
196
210
  "peerDependenciesMeta": {
197
211
  "@gramio/format": {
@@ -211,6 +225,21 @@
211
225
  },
212
226
  "zod": {
213
227
  "optional": true
228
+ },
229
+ "ai": {
230
+ "optional": true
231
+ },
232
+ "@ai-sdk/anthropic": {
233
+ "optional": true
234
+ },
235
+ "@ai-sdk/openai-compatible": {
236
+ "optional": true
237
+ },
238
+ "@openrouter/ai-sdk-provider": {
239
+ "optional": true
240
+ },
241
+ "@gramio/split": {
242
+ "optional": true
214
243
  }
215
244
  },
216
245
  "publishConfig": {