@stackfactor/agent-utils 1.2.20 → 1.3.1
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/README.md +68 -40
- package/dist/cjs/index.d.ts +2 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/langChain.d.ts +5 -62
- package/dist/cjs/langChain.d.ts.map +1 -1
- package/dist/cjs/langChain.js +50 -287
- package/dist/cjs/tavily.d.ts +91 -0
- package/dist/cjs/tavily.d.ts.map +1 -0
- package/dist/cjs/tavily.js +404 -0
- package/dist/esm/index.d.ts +2 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/langChain.d.ts +5 -62
- package/dist/esm/langChain.d.ts.map +1 -1
- package/dist/esm/langChain.js +50 -287
- package/dist/esm/tavily.d.ts +91 -0
- package/dist/esm/tavily.d.ts.map +1 -0
- package/dist/esm/tavily.js +395 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -40,7 +40,7 @@ When `expectsJsonResponse` is `true` (the default), JSON escape instructions are
|
|
|
40
40
|
| Parameter | Type | Default | Description |
|
|
41
41
|
| --------------------- | -------------------- | --------------- | -------------------------------------------------------------------------------------------------------- |
|
|
42
42
|
| `modelName` | `string` | — | Model identifier: `"gpt-4o"`, `"claude-3-5-sonnet"`, `"gemini-1.5-pro"`, `"deepseek-chat"`, `"kimi-k2-0905-preview"`, `"glm-4.6"`, etc. |
|
|
43
|
-
| `config` | `object` | — | API keys (`openAIAPIKey`, `anthropicAPIKey`, `googleAPIKey`, `deepSeekAPIKey`, `kimiAPIKey`, `glmAPIKey`), `temperature`, `agentic`, `recursionLimit`, `
|
|
43
|
+
| `config` | `object` | — | API keys (`openAIAPIKey`, `anthropicAPIKey`, `googleAPIKey`, `deepSeekAPIKey`, `kimiAPIKey`, `glmAPIKey`), `temperature`, `agentic`, `recursionLimit`, `tavily`, `tavilyAPIKey` |
|
|
44
44
|
| `prompt` | `string \| object[]` | — | Plain string or array of `{ role, content }` message objects |
|
|
45
45
|
| `onProgressReport` | `function \| null` | `null` | Async callback receiving `{ message, progress }` updates |
|
|
46
46
|
| `minPercent` | `number` | `0` | Lower bound for progress percentage |
|
|
@@ -91,7 +91,8 @@ Constructs a LangChain agent with a model, system prompt, and tools. When `onRep
|
|
|
91
91
|
| `systemPrompt` | `string` | — | System prompt describing agent behaviour |
|
|
92
92
|
| `tools` | `any[]` | `[]` | LangChain tool instances |
|
|
93
93
|
| `responseFormat` | `any` | — | Structured response format descriptor |
|
|
94
|
-
| `config` | `object` | — | API keys, temperature, etc.
|
|
94
|
+
| `config` | `object` | — | API keys, temperature, `tavily`, etc. |
|
|
95
|
+
| `usageTracker` | `object \| null` | `null` | Accumulator the Tavily tools bill credits and record sources into |
|
|
95
96
|
| `onReportProgress` | `Function \| null` | `null` | Progress callback |
|
|
96
97
|
| `minPercent` | `number` | `0` | Minimum reportable progress |
|
|
97
98
|
| `maxPercent` | `number` | `100` | Maximum reportable progress |
|
|
@@ -254,15 +255,27 @@ Shared constants used across the package.
|
|
|
254
255
|
|
|
255
256
|
---
|
|
256
257
|
|
|
257
|
-
## Web Search
|
|
258
|
+
## Web Search (Tavily)
|
|
258
259
|
|
|
259
|
-
Set `config.
|
|
260
|
+
Set `config.tavily` to give an agent the Tavily web tools. These run **client-side**: the model emits a tool call, this library performs the HTTP request, and the result is appended to the conversation. Only an agent loop can execute them, so **`config.agentic` must be `true`** — enabling `tavily` without it throws `BAD_REQUEST` rather than handing the model tools whose calls nothing answers.
|
|
260
261
|
|
|
261
|
-
|
|
|
262
|
-
|
|
|
263
|
-
|
|
|
264
|
-
|
|
|
265
|
-
|
|
|
262
|
+
| Tool | Arguments | Returns | Default |
|
|
263
|
+
| ------------- | -------------------------------- | ----------------------------------------------------------------------- | ------- |
|
|
264
|
+
| `web_search` | `query`, `maxResults?` | Snippets and URLs; no page content | **on** |
|
|
265
|
+
| `web_extract` | `urls[]`, `query?` | Page content — matching passages with a `query`, whole document without | **on** |
|
|
266
|
+
| `web_map` | `url`, `instructions?` | URLs only, no content | off |
|
|
267
|
+
| `web_crawl` | `url`, `instructions?`, `limit?` | Full content of every page visited | off |
|
|
268
|
+
|
|
269
|
+
No new dependency is added: all four endpoints are a single `POST`, issued with the runtime's own `fetch`.
|
|
270
|
+
|
|
271
|
+
### Both reading modes, one tool
|
|
272
|
+
|
|
273
|
+
`web_extract` covers whole-page and targeted reading through Tavily's own optional `query` field, so the model chooses per call:
|
|
274
|
+
|
|
275
|
+
- **`query` omitted** → the entire document.
|
|
276
|
+
- **`query` supplied** → only the matching chunks (`chunks_per_source`, default `3`).
|
|
277
|
+
|
|
278
|
+
Targeted extraction is dramatically cheaper in context and is usually sufficient; whole-document extraction is there for when the full structure matters. Splitting these into two tools would duplicate the description tokens on every request to express a distinction the API already makes with one optional field.
|
|
266
279
|
|
|
267
280
|
```typescript
|
|
268
281
|
const usageTracker = {};
|
|
@@ -270,52 +283,66 @@ const result = await langChain.runPromptWithModel(
|
|
|
270
283
|
"claude-opus-5",
|
|
271
284
|
{
|
|
272
285
|
anthropicAPIKey: "sk-ant-...",
|
|
273
|
-
"
|
|
274
|
-
|
|
286
|
+
tavilyAPIKey: "tvly-...",
|
|
287
|
+
agentic: true, // required
|
|
288
|
+
"tavily-credit-costs": 0.008, // USD per credit
|
|
289
|
+
tavily: {
|
|
290
|
+
tools: ["search", "extract", "map"],
|
|
291
|
+
includeDomains: ["sc.gov", "sc.edu"],
|
|
292
|
+
maxCharsPerUrl: 60000,
|
|
293
|
+
},
|
|
275
294
|
},
|
|
276
|
-
"What
|
|
295
|
+
"What are the SC procurement thresholds for sole-source awards?",
|
|
277
296
|
null, 0, 100, false, null, "StackFactor", [], usageTracker,
|
|
278
297
|
);
|
|
279
|
-
// usageTracker.tokens
|
|
280
|
-
// usageTracker.cost includes
|
|
281
|
-
// usageTracker.webSearchSources === [{ url: "https
|
|
298
|
+
// usageTracker.tokens.tavilyCredits === 4
|
|
299
|
+
// usageTracker.cost includes 4 * 0.008
|
|
300
|
+
// usageTracker.webSearchSources === [{ url: "https://...", title: "..." }, ...]
|
|
282
301
|
```
|
|
283
302
|
|
|
284
|
-
### `
|
|
303
|
+
### `TavilyConfig`
|
|
285
304
|
|
|
286
|
-
`
|
|
305
|
+
`tavily: true` uses the defaults below. Pass an object to configure it.
|
|
287
306
|
|
|
288
|
-
| Field
|
|
289
|
-
|
|
|
290
|
-
| `
|
|
291
|
-
| `
|
|
292
|
-
| `
|
|
293
|
-
| `
|
|
294
|
-
| `
|
|
295
|
-
| `
|
|
296
|
-
| `
|
|
297
|
-
| `
|
|
298
|
-
| `
|
|
307
|
+
| Field | Default | Description |
|
|
308
|
+
| ----------------- | ------------------------ | -------------------------------------------------------------------------------------------- |
|
|
309
|
+
| `tools` | `["search", "extract"]` | Which tools to expose; each one spends its description tokens on every request |
|
|
310
|
+
| `searchDepth` | Tavily's `"basic"` | `"basic" \| "advanced" \| "fast" \| "ultra-fast"` |
|
|
311
|
+
| `extractDepth` | Tavily's `"basic"` | `"advanced"` also pulls tables and embedded content, at double the credits |
|
|
312
|
+
| `maxResults` | `5` | Results per search |
|
|
313
|
+
| `chunksPerSource` | `3` | Relevant chunks per URL when a `query` is passed to `web_extract` |
|
|
314
|
+
| `maxCharsPerUrl` | `60000` | Per-URL cap before truncation (≈15k tokens) |
|
|
315
|
+
| `maxCharsTotal` | `150000` | Cap across one tool call (≈37k tokens) |
|
|
316
|
+
| `includeDomains` | — | Restrict `web_search` to these domains |
|
|
317
|
+
| `excludeDomains` | — | Exclude these domains from `web_search` |
|
|
318
|
+
| `crawlLimit` | `10` | Maximum pages one `web_crawl` or `web_map` call may return |
|
|
319
|
+
| `format` | `"markdown"` | `"markdown"` preserves table and heading structure at fewer tokens than the prose equivalent |
|
|
299
320
|
|
|
300
321
|
### Context management
|
|
301
322
|
|
|
302
|
-
|
|
323
|
+
Nothing sits between Tavily's response and the context window — there is no provider-side filtering here — so the caps above are the only thing standing between one `extract` call and a 100-page PDF. Three measures apply by default:
|
|
303
324
|
|
|
304
|
-
**
|
|
325
|
+
**Responses are stripped before the model sees them.** Tavily returns `score`, `published_date`, `favicon` and `id` alongside each result. None of it informs an answer, so only the title, URL and text are forwarded; the rest is dropped rather than billed as input tokens.
|
|
305
326
|
|
|
306
|
-
|
|
327
|
+
**`web_search` never requests page content.** `include_raw_content` is always `false`: search finds documents, `web_extract` reads them. Asking for full text at search time pays for every result to find one.
|
|
328
|
+
|
|
329
|
+
**Truncation is reported, never silent.** When a document exceeds `maxCharsPerUrl`, or a call exhausts `maxCharsTotal`, the payload says exactly what was cut:
|
|
330
|
+
|
|
331
|
+
```
|
|
332
|
+
[truncated: 60,000 of 412,336 characters shown — narrow the query or request fewer URLs to see the parts that matter]
|
|
333
|
+
```
|
|
307
334
|
|
|
308
|
-
|
|
335
|
+
A model that cannot tell it received half a regulation will reason over the half it got, which on a compliance corpus is worse than an error.
|
|
309
336
|
|
|
310
|
-
|
|
337
|
+
`web_crawl` is off by default for the same reason: it returns full content for every page it visits, and is the easiest way here to exhaust a context window. Prefer `web_map` to enumerate a site, then `web_extract` with a `query` on the few URLs that matter.
|
|
311
338
|
|
|
312
339
|
**Notes**
|
|
313
340
|
|
|
314
|
-
-
|
|
315
|
-
-
|
|
316
|
-
-
|
|
317
|
-
-
|
|
318
|
-
-
|
|
341
|
+
- Works with every supported provider, including DeepSeek, Kimi and GLM, which have no native web search of their own.
|
|
342
|
+
- Credits come from each response's own `usage` block rather than an estimate, and are accumulated on `usageTracker.tokens.tavilyCredits`, costed from the `tavily-credit-costs` constant (USD per credit; falls back to Tavily's list price of `0.008`).
|
|
343
|
+
- URLs are collected on `usageTracker.webSearchSources`, deduplicated across the whole run — Tavily's terms require citing the original sources when its content is shown to end users.
|
|
344
|
+
- Per-URL failures are surfaced in the tool result instead of being dropped, so a fetch failure is not mistaken for an absence of content.
|
|
345
|
+
- Tool calls honour the caller's abort signal, so a cancelled run stops paying for in-flight crawls.
|
|
319
346
|
|
|
320
347
|
---
|
|
321
348
|
|
|
@@ -359,9 +386,10 @@ The `config` object accepted by LangChain methods supports the following keys:
|
|
|
359
386
|
| `maxTokens` | `number` | Maximum output tokens (default: `16384` for Claude, `200000` for other providers). For Claude, values above `21333` automatically enable LangChain streaming to bypass the Anthropic SDK's 10-minute non-streaming guard. |
|
|
360
387
|
| `agentic` | `boolean` | Enable agentic mode in `runPromptWithModel` |
|
|
361
388
|
| `recursionLimit` | `number` | Max agent steps (default: `25`) |
|
|
362
|
-
| `
|
|
389
|
+
| `tavilyAPIKey` | `string` | Tavily API key; required when `tavily` is set |
|
|
390
|
+
| `tavily` | `boolean \| TavilyConfig` | Enable the Tavily web tools; requires `agentic: true` (see [Web Search (Tavily)](#web-search-tavily)) |
|
|
363
391
|
|
|
364
|
-
Per-model cost constants are read from the same object using flat keys: `<model>-input-token-costs`, `<model>-output-token-costs`, `<model>-image-input-token-costs`, `<model>-image-output-token-costs`, `<model>-character-costs` (all USD per million)
|
|
392
|
+
Per-model cost constants are read from the same object using flat keys: `<model>-input-token-costs`, `<model>-output-token-costs`, `<model>-image-input-token-costs`, `<model>-image-output-token-costs`, and `<model>-character-costs` (all USD per million). Tavily is billed separately via `tavily-credit-costs` (USD per credit).
|
|
365
393
|
|
|
366
394
|
---
|
|
367
395
|
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -9,7 +9,8 @@ export { constants };
|
|
|
9
9
|
export { errorHandling, AppError };
|
|
10
10
|
export type { ParsedError } from "./errorHandling.js";
|
|
11
11
|
export { langChain };
|
|
12
|
-
export type { UsageTracker
|
|
12
|
+
export type { UsageTracker } from "./langChain.js";
|
|
13
|
+
export type { TavilyConfig, TavilyToolName } from "./tavily.js";
|
|
13
14
|
export { logger };
|
|
14
15
|
export { serve };
|
|
15
16
|
export { callAgent };
|
package/dist/cjs/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,YAAY,CAAC;AACnC,OAAO,aAAa,EAAE,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC;AAEnC,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,YAAY,EAAE,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,YAAY,CAAC;AACnC,OAAO,aAAa,EAAE,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAC;AAEtD,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC;AAEnC,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAEhE,OAAO,EAAE,MAAM,EAAE,CAAC;AAElB,OAAO,EAAE,KAAK,EAAE,CAAC;AAEjB,OAAO,EAAE,SAAS,EAAE,CAAC;AAErB,OAAO,EAAE,UAAU,EAAE,CAAC;AAEtB,YAAY,EACV,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,WAAW,GACZ,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,cAAc,EAAE,CAAC"}
|
package/dist/cjs/langChain.d.ts
CHANGED
|
@@ -10,76 +10,19 @@ export type UsageTracker = {
|
|
|
10
10
|
[tokenKey: string]: number;
|
|
11
11
|
};
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* the rest of the non-text content blocks.
|
|
13
|
+
* URLs returned by the Tavily tools, deduplicated across every call in the
|
|
14
|
+
* run. Only present once a web tool has actually run. Tavily's terms require
|
|
15
|
+
* the original sources to be cited when its content is shown to end users, so
|
|
16
|
+
* they are surfaced here rather than left buried in the tool messages.
|
|
18
17
|
*/
|
|
19
18
|
webSearchSources?: {
|
|
20
19
|
url: string;
|
|
21
20
|
title?: string;
|
|
22
21
|
}[];
|
|
23
22
|
};
|
|
24
|
-
/**
|
|
25
|
-
* Caller-facing options for the providers' native web search tools. Enable web
|
|
26
|
-
* search by setting `config.webSearch` to `true` (provider defaults) or to one
|
|
27
|
-
* of these objects. Every field is optional and is only forwarded to the
|
|
28
|
-
* providers that accept it — see `buildWebSearchTool` for the mapping.
|
|
29
|
-
*/
|
|
30
|
-
export type WebSearchConfig = {
|
|
31
|
-
/** Anthropic only: hard cap on searches per request (`max_uses`). */
|
|
32
|
-
maxUses?: number;
|
|
33
|
-
/** Anthropic (`allowed_domains`) and OpenAI (`filters.allowed_domains`). */
|
|
34
|
-
allowedDomains?: string[];
|
|
35
|
-
/** Anthropic only (`blocked_domains`); cannot be combined with `allowedDomains`. */
|
|
36
|
-
blockedDomains?: string[];
|
|
37
|
-
/** Anthropic and OpenAI: approximate location used to localize results. */
|
|
38
|
-
userLocation?: {
|
|
39
|
-
city?: string;
|
|
40
|
-
region?: string;
|
|
41
|
-
/** Two-letter ISO 3166-1 alpha-2 code, e.g. `"US"`. */
|
|
42
|
-
country?: string;
|
|
43
|
-
/** IANA timezone ID, e.g. `"America/Los_Angeles"`. */
|
|
44
|
-
timezone?: string;
|
|
45
|
-
};
|
|
46
|
-
/**
|
|
47
|
-
* OpenAI only: how much of the context window search results may consume.
|
|
48
|
-
* OpenAI's default is `"medium"`; `"low"` minimizes context at some cost to
|
|
49
|
-
* answer quality, `"high"` is the expensive end.
|
|
50
|
-
*/
|
|
51
|
-
searchContextSize?: "low" | "medium" | "high";
|
|
52
|
-
/** Gemini only: RFC 3339 window the search is restricted to. */
|
|
53
|
-
timeRange?: {
|
|
54
|
-
startTime: string;
|
|
55
|
-
endTime: string;
|
|
56
|
-
};
|
|
57
|
-
/**
|
|
58
|
-
* Anthropic only: opt out of dynamic filtering by forcing the search to be
|
|
59
|
-
* called directly (`allowed_callers: ["direct"]`). Defaults to `true` on
|
|
60
|
-
* models that support it — see `supportsAnthropicDynamicFiltering`. Turning
|
|
61
|
-
* this off means every raw search result lands in the context window.
|
|
62
|
-
*/
|
|
63
|
-
dynamicFiltering?: boolean;
|
|
64
|
-
/**
|
|
65
|
-
* Anthropic only: whether search result blocks consumed by dynamic filtering
|
|
66
|
-
* are echoed back in the response. Defaults to `"excluded"`, which drops them
|
|
67
|
-
* and cuts the output tokens billed for content nothing downstream reads.
|
|
68
|
-
*/
|
|
69
|
-
responseInclusion?: "full" | "excluded";
|
|
70
|
-
/**
|
|
71
|
-
* Anthropic only: pin the dated tool version instead of letting
|
|
72
|
-
* `buildWebSearchTool` pick per model. `web_search_20250305` is basic search,
|
|
73
|
-
* `web_search_20260209` adds dynamic filtering, `web_search_20260318` adds
|
|
74
|
-
* response-inclusion control. Pinning a filtering version on a model that
|
|
75
|
-
* cannot do programmatic tool calling returns a 400 unless
|
|
76
|
-
* `dynamicFiltering: false` is also set.
|
|
77
|
-
*/
|
|
78
|
-
toolVersion?: string;
|
|
79
|
-
};
|
|
80
23
|
declare const _default: {
|
|
81
24
|
checkIfAIProviderConfigured: (config: any) => void;
|
|
82
|
-
createAgent: (name: string, modelName: string, systemPrompt: string, tools: any[], responseFormat: any, config: any) => any;
|
|
25
|
+
createAgent: (name: string, modelName: string, systemPrompt: string, tools: any[], responseFormat: any, config: any, usageTracker?: UsageTracker | null) => any;
|
|
83
26
|
runAgent: (agent: any, prompt: string, config: any, onProgress?: Function | null, usageTracker?: UsageTracker | null) => Promise<any>;
|
|
84
27
|
runPromptWithModel: (modelName: string, config: any, prompt: any, onProgressReport: any, minPercent?: number, maxPercent?: number, expectsJsonResponse?: boolean, schema?: any, agentName?: string, tools?: any[], usageTracker?: UsageTracker | null) => Promise<any>;
|
|
85
28
|
runPromptWithModelForImageGeneration: (modelName: string, config: any, prompt: string, options?: any, usageTracker?: UsageTracker | null) => Promise<any>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"langChain.d.ts","sourceRoot":"","sources":["../../src/langChain.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"langChain.d.ts","sourceRoot":"","sources":["../../src/langChain.ts"],"names":[],"mappings":"AA4GA;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE;QAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IACvC;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACtD,CAAC;;0CAE2C,GAAG,KAAG,IAAI;wBA6uB/C,MAAM,aACD,MAAM,gBACH,MAAM,SACb,GAAG,EAAE,kBACI,GAAG,UACX,GAAG,iBACG,YAAY,GAAG,IAAI,KAChC,GAAG;sBAoCG,GAAG,UACF,MAAM,UACN,GAAG,eACC,QAAQ,GAAG,IAAI,iBACb,YAAY,GAAG,IAAI,KAChC,OAAO,CAAC,GAAG,CAAC;oCAkYF,MAAM,UACT,GAAG,UACH,GAAG,oBACO,GAAG,eACT,MAAM,eACN,MAAM,wBACG,OAAO,WACpB,GAAG,cACA,MAAM,UACV,GAAG,EAAE,iBACE,YAAY,GAAG,IAAI,KAChC,OAAO,CAAC,GAAG,CAAC;sDA0tBF,MAAM,UACT,GAAG,UACH,MAAM,YACL,GAAG,iBACE,YAAY,GAAG,IAAI,KAChC,OAAO,CAAC,GAAG,CAAC;0CApgC8B,GAAG,KAAG,MAAM;+CA1tB9C,YAAY,GAAG,IAAI,GAAG,SAAS,aAC7B,MAAM,kBACD,MAAM,UACd,GAAG,KACV,IAAI;mCA0uBU,MAAM,mBACJ,MAAM,EAAE,KACxB,MAAM;;AA2iCT,wBASE"}
|