@useago/sdk 1.4.4 → 1.5.2
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/CHANGELOG.md +63 -1
- package/dist/AgoClient-5VGybmvz.cjs +8 -0
- package/dist/AgoClient-DXrH2AMi.js +964 -0
- package/dist/angular.cjs +1 -1
- package/dist/angular.d.cts +124 -5
- package/dist/angular.d.ts +124 -5
- package/dist/angular.js +5 -1
- package/dist/autoContinue-CC8K9mBU.js +63 -0
- package/dist/autoContinue-CP9pJR-V.cjs +1 -0
- package/dist/{createConversationSession-CUkNp6mZ.cjs → createConversationSession-0WTqcCLK.cjs} +1 -1
- package/dist/{createConversationSession-QIBN0gLx.js → createConversationSession-DPrrr70o.js} +1 -1
- package/dist/createFormCollector-1GKKwQV_.cjs +1 -0
- package/dist/{createFormCollector-F3YJfsbg.js → createFormCollector-DYh90kiG.js} +97 -91
- package/dist/devtools.d.cts +82 -5
- package/dist/devtools.d.ts +82 -5
- package/dist/functions-CPs7omgM.cjs +1 -0
- package/dist/helpers.cjs +1 -1
- package/dist/helpers.d.cts +5 -0
- package/dist/helpers.d.ts +5 -0
- package/dist/helpers.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +147 -7
- package/dist/index.d.ts +147 -7
- package/dist/index.js +45 -43
- package/dist/react.cjs +3 -3
- package/dist/react.d.cts +191 -21
- package/dist/react.d.ts +191 -21
- package/dist/react.js +666 -529
- package/dist/testing.cjs +1 -1
- package/dist/testing.d.cts +82 -5
- package/dist/testing.d.ts +82 -5
- package/dist/testing.js +1 -1
- package/dist/vue.cjs +1 -1
- package/dist/vue.d.cts +82 -5
- package/dist/vue.d.ts +82 -5
- package/dist/vue.js +1 -1
- package/dist/widget.cjs +4 -4
- package/dist/widget.d.cts +82 -5
- package/dist/widget.d.ts +82 -5
- package/dist/widget.js +437 -423
- package/llms-full.txt +100 -6
- package/package.json +1 -1
- package/dist/AgoClient-CLmtYTJx.cjs +0 -8
- package/dist/AgoClient-Ozz2b1dQ.js +0 -912
- package/dist/createFormCollector-DHT1ObOb.cjs +0 -1
- package/dist/functions-Djnq-JAo.cjs +0 -1
- package/dist/rolldown-runtime-16Nf8qvH.cjs +0 -1
- /package/dist/{createMockClient-BSr-UV8R.cjs → createMockClient-C-wrjb2C.cjs} +0 -0
- /package/dist/{createMockClient-bAZ9KBHC.js → createMockClient-we-XoPom.js} +0 -0
- /package/dist/{functions-CApuQZ2b.js → functions-tzyOZNp6.js} +0 -0
package/llms-full.txt
CHANGED
|
@@ -1086,6 +1086,7 @@ ago.getMessages(conversationId)
|
|
|
1086
1086
|
ago.registerFunction(definition) // or (name, handler, schema)
|
|
1087
1087
|
ago.unregisterFunction(name)
|
|
1088
1088
|
ago.registerNavigationFunction(navigate, routes)
|
|
1089
|
+
ago.enableAutoContinueAfterNavigation(options?) // returns a disable fn
|
|
1089
1090
|
ago.registerPageStateFunction(controls, opts?) / ago.unregisterPageStateFunction(functionName?)
|
|
1090
1091
|
|
|
1091
1092
|
ago.submitToolCallForm(toolCallId, formData)
|
|
@@ -1131,6 +1132,14 @@ this.ago.registerNavigationFunction((path) => router.navigateByUrl(path), [
|
|
|
1131
1132
|
]);
|
|
1132
1133
|
```
|
|
1133
1134
|
|
|
1135
|
+
To make "go to page B and change X" work in one user message, enable
|
|
1136
|
+
auto-continue once (e.g. in the root component) and disable it on teardown:
|
|
1137
|
+
|
|
1138
|
+
```ts
|
|
1139
|
+
private stopAutoContinue = this.ago.enableAutoContinueAfterNavigation();
|
|
1140
|
+
// ngOnDestroy: this.stopAutoContinue();
|
|
1141
|
+
```
|
|
1142
|
+
|
|
1134
1143
|
Register page state, the mirror of navigation (change the current page's state
|
|
1135
1144
|
and read it back):
|
|
1136
1145
|
|
|
@@ -1295,6 +1304,17 @@ Per framework:
|
|
|
1295
1304
|
| Vue | `useAgoFunction(name, options)` (auto-cleanup) |
|
|
1296
1305
|
| Angular | `agoService.registerFunction(def)` |
|
|
1297
1306
|
|
|
1307
|
+
### Keep the number of functions low
|
|
1308
|
+
|
|
1309
|
+
You can send up to **30** client functions with a message. Above that, the
|
|
1310
|
+
request is rejected.
|
|
1311
|
+
|
|
1312
|
+
Stay well under the limit whenever you can. The more functions the agent has to
|
|
1313
|
+
choose from, the harder it becomes to pick the right one: past **10** functions
|
|
1314
|
+
in a single message, expect the agent to call the wrong function or miss the
|
|
1315
|
+
right one more often. Register only the functions relevant to the current page
|
|
1316
|
+
or state, and unregister the ones that no longer apply.
|
|
1317
|
+
|
|
1298
1318
|
### Navigation shortcut
|
|
1299
1319
|
|
|
1300
1320
|
A common case (letting the agent move the user around) has a dedicated helper
|
|
@@ -1387,16 +1407,29 @@ function AppShell() {
|
|
|
1387
1407
|
}
|
|
1388
1408
|
```
|
|
1389
1409
|
|
|
1410
|
+
Outside React, the same behavior ships as a framework-agnostic helper. Attach it
|
|
1411
|
+
once per client; it returns a detach function:
|
|
1412
|
+
|
|
1413
|
+
```ts
|
|
1414
|
+
import { attachAutoContinueAfterNavigation } from "@useago/sdk";
|
|
1415
|
+
|
|
1416
|
+
const detach = attachAutoContinueAfterNavigation(client);
|
|
1417
|
+
```
|
|
1418
|
+
|
|
1419
|
+
Angular wraps it as `agoService.enableAutoContinueAfterNavigation(options?)`,
|
|
1420
|
+
which also returns the disable function (call it in `ngOnDestroy`).
|
|
1421
|
+
|
|
1390
1422
|
How the gap is bridged depends on the client-functions mode:
|
|
1391
1423
|
|
|
1392
|
-
- **Pause mode** (
|
|
1424
|
+
- **Pause mode** (the default, `clientFunctionsMode: "pause"` —
|
|
1393
1425
|
needs a backend with pause/resume support): the backend pauses the turn on the
|
|
1394
1426
|
navigation call. The SDK submits the function result and resumes the SAME turn
|
|
1395
1427
|
via `POST /messages/{id}/continue`; the hook only delays that resume until the
|
|
1396
1428
|
destination's `useAgoPageState` registered. No extra prompt, no second turn,
|
|
1397
1429
|
and the agent sees the real function results.
|
|
1398
1430
|
|
|
1399
|
-
- **Placeholder mode** (legacy
|
|
1431
|
+
- **Placeholder mode** (legacy, `clientFunctionsMode: "placeholder"`, also what
|
|
1432
|
+
older backends without pause/resume support fall back to): when the navigating turn ends, the hook
|
|
1400
1433
|
waits for the destination page to register, then sends a continuation message
|
|
1401
1434
|
with `{ hidden: true }` — kept in the model's context, never displayed
|
|
1402
1435
|
(`useMessages` and `ChatWidget` filter hidden messages). Without backend
|
|
@@ -1404,8 +1437,11 @@ How the gap is bridged depends on the client-functions mode:
|
|
|
1404
1437
|
|
|
1405
1438
|
A paused turn also survives a full page reload: after `getConversation(...)`,
|
|
1406
1439
|
call `client.resumePendingClientFunctions(conversation)` to re-run the waiting
|
|
1407
|
-
functions, submit their results, and resume the turn (opt-in
|
|
1408
|
-
navigation on reload navigates again).
|
|
1440
|
+
functions, submit their results, and resume the turn (opt-in, re-running a
|
|
1441
|
+
navigation on reload navigates again). A call gated by the approval policy (see
|
|
1442
|
+
below) is not re-run on reload either: `resumePendingClientFunctions` holds it
|
|
1443
|
+
for `approveFunction` / `rejectFunction` and keeps the turn paused, exactly as on
|
|
1444
|
+
the live stream.
|
|
1409
1445
|
|
|
1410
1446
|
### Observe invocations
|
|
1411
1447
|
|
|
@@ -1418,6 +1454,37 @@ client.on("function:result", ({ result, error }) =>
|
|
|
1418
1454
|
);
|
|
1419
1455
|
```
|
|
1420
1456
|
|
|
1457
|
+
### Approval gate (ask before running)
|
|
1458
|
+
|
|
1459
|
+
In pause mode you can hold a client function call until the user approves it.
|
|
1460
|
+
Set `approvalPolicy` on the config to gate calls by name (or anything on the
|
|
1461
|
+
invocation), or mark a single function with `requiresApproval: true`. The two OR
|
|
1462
|
+
together.
|
|
1463
|
+
|
|
1464
|
+
```ts
|
|
1465
|
+
const client = new AgoClient({
|
|
1466
|
+
baseUrl: "https://playground.api.useago.com",
|
|
1467
|
+
agent: "your-agent",
|
|
1468
|
+
// Return true for calls the user must approve first.
|
|
1469
|
+
approvalPolicy: (inv) => inv.functionName === "deleteAccount",
|
|
1470
|
+
});
|
|
1471
|
+
|
|
1472
|
+
client.on("function:awaiting-approval", ({ invocationId, functionName }) => {
|
|
1473
|
+
// Show your UI, then decide:
|
|
1474
|
+
if (userSaidYes) client.approveFunction(invocationId); // runs it, resumes the turn
|
|
1475
|
+
else client.rejectFunction(invocationId); // submits a rejection, agent sees the decline
|
|
1476
|
+
});
|
|
1477
|
+
```
|
|
1478
|
+
|
|
1479
|
+
A gated call stays at `WAITING_CLIENT`: the handler does not run and nothing is
|
|
1480
|
+
submitted until `approveFunction(invocationId)`. `rejectFunction(invocationId)`
|
|
1481
|
+
submits `{ approved: false, reason: "user_rejected" }` so the agent knows the
|
|
1482
|
+
user declined, then lets the turn resume. This is a no-op in placeholder mode
|
|
1483
|
+
(there is no paused turn to hold onto), so the call runs normally.
|
|
1484
|
+
|
|
1485
|
+
In React, `useAgoActivity` surfaces awaiting items with ready-made `approve` /
|
|
1486
|
+
`reject` controls (see the [React guide](../frameworks/react.md)).
|
|
1487
|
+
|
|
1421
1488
|
---
|
|
1422
1489
|
|
|
1423
1490
|
## Pre-built helpers
|
|
@@ -1496,9 +1563,35 @@ interface ContextEntry {
|
|
|
1496
1563
|
name?: string; // human label, e.g. "Order detail"
|
|
1497
1564
|
description?: string; // what this context represents
|
|
1498
1565
|
data?: Record<string, unknown>; // structured data for the AI
|
|
1566
|
+
stable?: boolean; // constant for the whole conversation (see below)
|
|
1499
1567
|
}
|
|
1500
1568
|
```
|
|
1501
1569
|
|
|
1570
|
+
### Stable context (prompt caching)
|
|
1571
|
+
|
|
1572
|
+
By default an entry is re-sent next to every new user message, which is right
|
|
1573
|
+
for data that changes as the user acts (a cart, the current page). If an
|
|
1574
|
+
entry's content never changes during a conversation (a schema, a capability
|
|
1575
|
+
list, static instructions), mark it `stable: true`: the backend pins it right
|
|
1576
|
+
after the system prompt, where LLM providers cache it across turns instead of
|
|
1577
|
+
re-processing it on every message.
|
|
1578
|
+
|
|
1579
|
+
```ts
|
|
1580
|
+
client.setContext("catalog", {
|
|
1581
|
+
name: "Product catalog",
|
|
1582
|
+
description: "The products the agent can talk about",
|
|
1583
|
+
data: { products: PRODUCTS },
|
|
1584
|
+
stable: true, // content is identical on every message
|
|
1585
|
+
});
|
|
1586
|
+
```
|
|
1587
|
+
|
|
1588
|
+
Only mark an entry stable when its content is byte-identical on every message.
|
|
1589
|
+
A "stable" entry that changes between messages invalidates the provider's
|
|
1590
|
+
cache for the whole conversation history, which costs more than leaving the
|
|
1591
|
+
flag off. Form collectors do this automatically: the form's schema is
|
|
1592
|
+
registered as a stable entry and only the live values/missing state is sent
|
|
1593
|
+
per message.
|
|
1594
|
+
|
|
1502
1595
|
### Dynamic context
|
|
1503
1596
|
|
|
1504
1597
|
A function evaluated on every send, perfect for data outside your render state
|
|
@@ -1586,6 +1679,7 @@ const final = await client.waitFor("message:complete", { timeout: 10_000 });
|
|
|
1586
1679
|
| `toolCall:received` | `ToolCallData` |
|
|
1587
1680
|
| `toolCall:form` | `ToolCallData` (only when the tool call is a form) |
|
|
1588
1681
|
| `function:invoke` | `{ invocationId, functionName, arguments, conversationId }` |
|
|
1682
|
+
| `function:awaiting-approval` | `{ invocationId, functionName, arguments, conversationId }`: a client function call is held pending user approval (pause mode + an `approvalPolicy`/`requiresApproval` match). The turn stays at `WAITING_CLIENT`; call `approveFunction(invocationId)` to run it and resume, or `rejectFunction(invocationId)` to decline. See [Approval gate](functions-and-context.md#approval-gate-ask-before-running) |
|
|
1589
1683
|
| `function:result` | `{ invocationId, result, error? }` |
|
|
1590
1684
|
| `form:submitted` | `{ name, values, result }`: a form collector submitted successfully; `result` is the submit response (the third-party API's answer) |
|
|
1591
1685
|
| `form:error` | `{ name, values, error }`: a form collector submit failed at the network/server level (HTTP non-2xx or a thrown handler/fetch). Validation pre-checks (missing fields, no submit target) do not fire this |
|
|
@@ -1720,7 +1814,7 @@ interface AgoConfig {
|
|
|
1720
1814
|
userJwt?: string; // Authorization: Bearer <jwt>, authenticated users
|
|
1721
1815
|
debug?: boolean; // enable verbose console logging
|
|
1722
1816
|
warnOnEmptyReply?: boolean; // default true; see "Empty replies" below
|
|
1723
|
-
clientFunctionsMode?: "placeholder" | "pause"; // default "
|
|
1817
|
+
clientFunctionsMode?: "placeholder" | "pause"; // default "pause"
|
|
1724
1818
|
maxFunctionResultBytes?: number; // default 50000; cap on client function results
|
|
1725
1819
|
}
|
|
1726
1820
|
```
|
|
@@ -1735,7 +1829,7 @@ interface AgoConfig {
|
|
|
1735
1829
|
| `userJwt` | — | `Authorization: Bearer …` | For authenticated sessions. |
|
|
1736
1830
|
| `debug` | — | — | Turns on the SDK's logger. |
|
|
1737
1831
|
| `warnOnEmptyReply` | — | — | Default `true`: warn on the console (once per conversation) when a reply completes empty, usually an unknown `agent` slug. The [`message:empty` event](events-and-streaming.md#events) fires regardless. |
|
|
1738
|
-
| `clientFunctionsMode` | — | `client_functions_mode` in the body | `"pause"
|
|
1832
|
+
| `clientFunctionsMode` | — | `client_functions_mode` in the body | Default `"pause"`: the agent stops on client function call(s) and resumes the SAME turn once the results are submitted (the SDK submits and resumes automatically; see the [`message:waiting-client` event](events-and-streaming.md#events)). Needs a backend with pause/resume support; older backends ignore the flag and fall back to placeholder behavior. Legacy `"placeholder"`: the turn continues on a placeholder and results are only visible on later turns. Per-message override via `sendMessage(..., { clientFunctionsMode })`. |
|
|
1739
1833
|
| `maxFunctionResultBytes` | — | — | Default `50000`. Client function results larger than this (serialized) are replaced with a truncated preview before reaching the LLM. Override per function with `maxResultBytes`; see [result size limit](functions-and-context.md#result-size-limit). |
|
|
1740
1834
|
|
|
1741
1835
|
---
|
package/package.json
CHANGED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
var d=class extends Error{constructor(e,t,n){super(e),this.code=t,this.statusCode=n,this.name="AgoError"}},f=class A extends d{constructor(t,n,i,s,o,a){super(t,n,i),this.type=s,this.param=o,this.docUrl=a,this.name="AgoApiError"}static fromResponse(t,n){const i=t.error;return new A(i.doc_url?`${i.message} See ${i.doc_url}`:i.message,i.code,n,i.type,i.param,i.doc_url)}},g=class extends d{constructor(e,t){super(e,"network_error"),this.originalError=t,this.name="AgoNetworkError"}},v=class extends d{constructor(e,t="stream_error"){super(e,t),this.name="AgoStreamError"}},b=class extends d{constructor(e,t,n){super(e,"function_error"),this.functionName=t,this.originalError=n,this.name="AgoFunctionError"}},P=class{constructor(e=!1){this.enabled=e}enable(){this.enabled=!0}disable(){this.enabled=!1}log(...e){this.enabled&&console.log("[AGO SDK]",...e)}warn(...e){this.enabled&&console.warn("[AGO SDK]",...e)}error(...e){console.error("[AGO SDK]",...e)}debug(...e){this.enabled&&console.debug("[AGO SDK]",...e)}},l=new P,S="ago_widget_id";function O(){if(typeof localStorage<"u"){const t=localStorage.getItem(S);if(t)return t}const e=typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`ago-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,12)}`;if(typeof localStorage<"u")try{localStorage.setItem(S,e)}catch{}return e}var j=class{constructor(e){this.baseUrl=e.baseUrl.replace(/\/$/,""),this.headers={"X-User-Anon-Id":e.widgetId||O()},e.userEmail&&(this.headers["X-User-Email"]=e.userEmail),e.userJwt&&(this.headers.Authorization=`Bearer ${e.userJwt}`),e.permission&&(this.headers["X-Widget-Permission"]=e.permission)}updateConfig(e){e.baseUrl&&(this.baseUrl=e.baseUrl.replace(/\/$/,"")),e.widgetId&&(this.headers["X-User-Anon-Id"]=e.widgetId),e.userEmail&&(this.headers["X-User-Email"]=e.userEmail),e.userJwt&&(this.headers.Authorization=`Bearer ${e.userJwt}`),e.permission!==void 0&&(e.permission?this.headers["X-Widget-Permission"]=e.permission:delete this.headers["X-Widget-Permission"])}async get(e){return this.request("GET",e)}async post(e,t){return this.request("POST",e,t)}async postStream(e,t){const n=`${this.baseUrl}${e}`;l.debug("POST (stream)",n,t);try{const i=await fetch(n,{method:"POST",headers:{...this.headers,"Content-Type":"application/json"},body:t?JSON.stringify(t):void 0});return i.ok||await this.handleErrorResponse(i),i}catch(i){throw i instanceof f?i:new g(`Network error: ${i instanceof Error?i.message:"Unknown error"}. Check that \`baseUrl\` is reachable and includes the protocol (https://).`,i instanceof Error?i:void 0)}}async postFormData(e,t){const n=`${this.baseUrl}${e}`;l.debug("POST (formData)",n);const i={...this.headers};try{const s=await fetch(n,{method:"POST",headers:i,body:t});return s.ok||await this.handleErrorResponse(s),s}catch(s){throw s instanceof f?s:new g(`Network error: ${s instanceof Error?s.message:"Unknown error"}. Check that \`baseUrl\` is reachable and includes the protocol (https://).`,s instanceof Error?s:void 0)}}async request(e,t,n){const i=`${this.baseUrl}${t}`;l.debug(e,i,n);try{const s=await fetch(i,{method:e,headers:{...this.headers,"Content-Type":"application/json"},body:n?JSON.stringify(n):void 0});return s.ok||await this.handleErrorResponse(s),s.status===204?void 0:s.json()}catch(s){throw s instanceof f?s:new g(`Network error: ${s instanceof Error?s.message:"Unknown error"}. Check that \`baseUrl\` is reachable and includes the protocol (https://).`,s instanceof Error?s:void 0)}}async handleErrorResponse(e){let t;try{t=await e.json()}catch{}if(t?.error)throw f.fromResponse(t,e.status);let n="";throw e.status===401||e.status===403?n=" Check `userJwt` (and that it has not expired).":e.status===404&&(n=" Check that `baseUrl` points at your AGO API root."),new f(`HTTP ${e.status}: ${e.statusText}.${n}`,"http_error",e.status,"api_error")}},D=5e4,M=2e4,B=2e3,k=class{constructor(e){this.functions=new Map,this.defaultMaxResultBytes=e?.maxResultBytes??D}setDefaultMaxResultBytes(e){this.defaultMaxResultBytes=e}register(e,t,n){if(typeof e=="object"){const{name:a,handler:r,description:c,parameters:u,maxResultBytes:h}=e;return this.register(a,r,{description:c,parameters:u,maxResultBytes:h})}const i=e;if(!t||!n)throw new d(`registerFunction("${i}"): both a handler and a schema are required. Pass them as arguments or use the single-object form: registerFunction({ name, parameters, handler }).`,"function_invalid_registration");this.functions.has(i)&&l.warn(`Function "${i}" is being overwritten`);const{maxResultBytes:s,...o}=n;this.functions.set(i,{schema:{...o,name:i},handler:t,maxResultBytes:s}),l.log(`Registered function: ${i}`)}unregister(e){const t=this.functions.delete(e);return t&&l.log(`Unregistered function: ${e}`),t}get(e){return this.functions.get(e)}has(e){return this.functions.has(e)}getSchemas(){return Array.from(this.functions.values()).map(e=>e.schema)}async execute(e,t){const n=this.functions.get(e);if(!n)throw new b(`Function "${e}" is not registered`,e);l.log(`Executing function: ${e}`,t);try{const i=await n.handler(t);return l.log(`Function ${e} completed:`,i),this.guardResultSize(e,i,n.maxResultBytes)}catch(i){throw l.error(`Function ${e} failed:`,i),new b(`Function "${e}" execution failed: ${i instanceof Error?i.message:"Unknown error"}`,e,i instanceof Error?i:void 0)}}guardResultSize(e,t,n){let i;try{i=JSON.stringify(t)}catch{return t}if(i===void 0)return t;const s=new TextEncoder().encode(i).length,o=n??this.defaultMaxResultBytes;return s>o?(l.warn(`Function "${e}" result is ${s} bytes, over the ${o}-byte limit; a truncated preview was sent to the agent instead. Return fewer fields, paginate, or raise maxResultBytes for this function.`),{truncated:!0,originalBytes:s,maxBytes:o,preview:i.slice(0,B),hint:`The result of "${e}" exceeded the ${o}-byte limit and was truncated. Request less data (use limit or filter parameters if available), or tell the user the result is too large to process.`}):(s>M&&l.warn(`Function "${e}" returned a large result (${Math.round(s/1024)} KB). Large results consume LLM context: return fewer fields, paginate, or push the data to the UI and return a summary.`),t)}clear(){this.functions.clear(),l.log("Cleared all registered functions")}get size(){return this.functions.size}},F=class{constructor(){this.entries=new Map,this.dynamicProviders=new Map}set(e,t){this.entries.set(e,t),l.log(`ClientContext set: ${e}`)}remove(e){const t=this.entries.delete(e);return t&&l.log(`ClientContext removed: ${e}`),t}addDynamicProvider(e,t){this.dynamicProviders.set(e,t),l.log(`DynamicContext provider added: ${e}`)}removeDynamicProvider(e){const t=this.dynamicProviders.delete(e);return t&&l.log(`DynamicContext provider removed: ${e}`),t}getSnapshot(){if(this.entries.size===0&&this.dynamicProviders.size===0)return null;const e={};for(const[t,n]of this.entries)e[t]=n;for(const[t,n]of this.dynamicProviders)try{const i=n();i&&(e[t]=i)}catch(i){l.error(`DynamicContext provider "${t}" threw:`,i)}return Object.keys(e).length===0?null:{entries:e}}clear(){this.entries.clear(),this.dynamicProviders.clear(),l.log("ClientContext cleared")}};function C(e){return e===null||typeof e!="object"?JSON.stringify(e)??"null":Array.isArray(e)?`[${e.map(C).join(",")}]`:`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${C(e[t])}`).join(",")}}`}var I=class{constructor(e){this.callbacks=e,this.buffer="",this.message={},this.toolCalls=[],this.sources=[],this.followUpReplies=[],this.isFirstChunk=!0,this.answerCompleteEmitted=!1,this.waitingClientEmitted=!1,this.firedClientFunctions=new Set}async processStream(e){if(!e.body)throw new v("Response has no body. The endpoint did not return a stream: check that `baseUrl` points at an AGO API and nothing (proxy, mock) strips the SSE body.","stream_no_body");const t=e.body.getReader(),n=new TextDecoder;try{for(;;){const{done:i,value:s}=await t.read();if(i)break;const o=n.decode(s,{stream:!0});this.buffer+=o,this.processBuffer()}return this.buffer.trim()&&this.processBuffer(),this.buildFinalMessage()}catch(i){const s=i instanceof Error?i:new v("Stream processing failed mid-flight. The connection may have dropped; retry the message.");throw this.callbacks.onError?.(s),s}finally{t.releaseLock()}}processBuffer(){const e=this.buffer.split(`
|
|
2
|
-
|
|
3
|
-
`);this.buffer=e.pop()||"";for(const t of e){if(!t.trim())continue;const n=t.split(`
|
|
4
|
-
`);for(const i of n)if(!i.startsWith(": ")&&i.startsWith("data: ")){const s=i.slice(6);try{const o=JSON.parse(s);this.handleChunk(o)}catch(o){l.warn("Failed to parse SSE data:",s,o)}}}}handleChunk(e){if(this.callbacks.onRawChunk?.(e),e.message_id&&!this.message.id&&(this.message.id=e.message_id),e.thread?.id&&(this.message.conversationId=e.thread.id,this.isFirstChunk&&this.message.id&&(this.isFirstChunk=!1,this.callbacks.onStart?.({conversationId:this.message.conversationId,messageId:this.message.id}))),e.content!==void 0&&(this.message.content=(this.message.content||"")+e.content,this.message.conversationId&&this.message.id&&this.callbacks.onChunk?.({content:e.content,conversationId:this.message.conversationId,messageId:this.message.id})),e.full_content!==void 0&&(this.message.content=e.full_content),e.status&&(this.message.status=e.status),e.agent&&(this.message.agent={id:e.agent.id,name:e.agent.name,displayName:e.agent.display_name}),e.knowledge_sources&&(this.sources=e.knowledge_sources.map(t=>{const n=t.knowledge_document;return{id:n.id,title:n.title,url:n.use_external_link?n.external_link_url:n.internal_link_url}})),e.type==="client_function"&&e.function_name){const t=`${e.function_name}::${C(e.arguments??{})}`;this.firedClientFunctions.has(t)||(this.firedClientFunctions.add(t),this.callbacks.onClientFunction?.({invocationId:e.id||"",functionName:e.function_name,arguments:e.arguments||{},conversationId:this.message.conversationId||""}))}if(e.tool_call_data&&e.type&&e.type!=="client_function"){const t=this.parseToolCall(e);this.callbacks.onToolCall?.(t);const n=this.toolCalls.findIndex(i=>i.id===t.id);n>=0?this.toolCalls[n]=t:this.toolCalls.push(t)}e.follow_up_replies&&(this.followUpReplies=e.follow_up_replies),this.message.status==="DONE"&&!this.answerCompleteEmitted&&this.message.id&&(this.answerCompleteEmitted=!0,this.callbacks.onAnswerComplete?.(this.buildMessage())),this.message.status==="WAITING_CLIENT"&&!this.waitingClientEmitted&&this.message.id&&(this.waitingClientEmitted=!0,this.callbacks.onWaitingClient?.({conversationId:this.message.conversationId||"",messageId:this.message.id,waitingToolCallIds:e.waiting_tool_call_ids??[]}))}parseToolCall(e){return{id:e.id||"",type:e.type||"status_message",status:e.status||"unknown",toolName:e.tool_name||"",toolDisplayName:e.tool_display_name,message:e.message,formSchema:e.form_schema,data:e.data,functionName:e.function_name,arguments:e.arguments}}buildMessage(){return{id:this.message.id||"",conversationId:this.message.conversationId||"",content:this.message.content||"",role:"assistant",status:this.message.status||"DONE",agent:this.message.agent,sources:this.sources.length>0?this.sources:void 0,toolCalls:this.toolCalls.length>0?this.toolCalls:void 0,followUpReplies:this.followUpReplies.length>0?this.followUpReplies:void 0,createdAt:new Date}}buildFinalMessage(){const e=this.buildMessage();return e.status!=="WAITING_CLIENT"&&this.callbacks.onComplete?.(e),e}};function L(e){const t=e.message.toLowerCase();return t.includes("load failed")||t.includes("failed to fetch")||t.includes("network")||t.includes("abort")}var G=new Set(["image/jpeg","image/png","image/gif","image/webp","image/bmp","image/tiff"]);function U(e){if(!e)return;const t=typeof window<"u"&&window.location?window.location.href:"https://ago.local/";try{const n=new URL(e,t);if(n.protocol==="http:"||n.protocol==="https:"||n.protocol==="blob:")return e}catch{}}function W(e){return e.isSafeImage===!0&&typeof e.contentType=="string"&&e.contentType.startsWith("image/")&&U(e.url)!==void 0}function z(e){if(e==null||e<0)return"";if(e<1024)return`${e} B`;const t=e/1024;return t<1024?`${t.toFixed(1)} KB`:`${(t/1024).toFixed(1)} MB`}function J(e){return{id:String(e.id??""),name:typeof e.name=="string"&&e.name?e.name:"file",contentType:typeof e.content_type=="string"?e.content_type:void 0,fileSize:typeof e.file_size=="number"?e.file_size:void 0,url:typeof e.file_url=="string"?e.file_url:void 0,isSafeImage:e.is_safe_image===!0}}function q(e){return e.map((t,n)=>({id:`local-${n}-${t.name}`,name:t.name,contentType:t.type||void 0,fileSize:t.size,url:typeof URL<"u"&&URL.createObjectURL?URL.createObjectURL(t):void 0,isSafeImage:G.has(t.type)}))}var N=class{constructor(){this.handlers=new Map}on(e,t){this.handlers.has(e)||this.handlers.set(e,new Set),this.handlers.get(e).add(t)}off(e,t){const n=this.handlers.get(e);n&&n.delete(t)}emit(e,t){const n=this.handlers.get(e);n&&n.forEach(i=>{try{i(t)}catch(s){console.error(`Error in event handler for ${String(e)}:`,s)}})}once(e,t){const n=(i=>{this.off(e,n),t(i)});this.on(e,n)}waitFor(e,t){return new Promise((n,i)=>{let s;const o=(a=>{s&&clearTimeout(s),n(a)});this.once(e,o),t?.timeout&&(s=setTimeout(()=>{this.off(e,o),i(new Error(`waitFor("${String(e)}") timed out after ${t.timeout}ms`))},t.timeout))})}removeAllListeners(e){e?this.handlers.delete(e):this.handlers.clear()}},$='`baseUrl` is required, e.g. new AgoClient({ baseUrl: "https://YOUR-DOMAIN.api.useago.com" }). Try the live demo endpoint https://playground.api.useago.com. See docs/general/configuration.md#error-codes (config_missing_base_url).',H=/^[a-z][a-z0-9+.-]*:\/\//i,x=!1;function E(e,t="AgoClient"){if(typeof e!="object"||e===null)throw new d(`${t}: ${$}`,"config_missing_base_url");const n=e.baseUrl;if(typeof n!="string"||n.trim()==="")throw new d(`${t}: ${$}`,"config_missing_base_url");!n.startsWith("/")&&!H.test(n)&&(x||(x=!0,console.warn(`[AGO] ${t}: \`baseUrl\` has no protocol and is not a relative path (config_suspect_base_url). Requests will fail: Node throws a URL parse error, browsers fetch it as a relative path. Use "https://..." (or a "/path" for a same-origin proxy).`)))}function K(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function w(e){return e.split("/").filter(t=>t.startsWith(":")).map(t=>t.slice(1))}function X(e,t){const n=[];return{path:e.split("/").map(i=>{if(!i.startsWith(":"))return i;const s=i.slice(1),o=t[s];return o==null||o===""?(n.push(s),i):encodeURIComponent(String(o))}).join("/"),missing:n}}function Y(e,t){const n=t.find(s=>s.path===e);if(n)return n;const i=t.find(s=>{if(!s.path.includes(":"))return!1;const o="^"+s.path.split("/").map(a=>a.startsWith(":")?"[^/]+":K(a)).join("/")+"/?$";return new RegExp(o).test(e)});return i||t.filter(s=>s.path!=="/"&&e.startsWith(s.path)).sort((s,o)=>o.path.length-s.path.length)[0]}var V=class T{constructor(t){this.warnedEmptyConversations=new Set,this.pendingResumes=new Map,this.resumeGate=null,E(t,"AgoClient"),this.config=t,this.httpClient=new j(t),this.functionRegistry=new k({maxResultBytes:t.maxFunctionResultBytes}),this.contextRegistry=new F,this.eventEmitter=new N,t.debug&&l.enable(),l.log("AgoClient initialized")}async sendMessage(t,n){const i=this.functionRegistry.getSchemas(),s=this.contextRegistry.getSnapshot(),o=this.config.agent||this.config.defaultAgentId,a=this.resolveClientFunctionsMode(n),r={content:t,conversation_id:n?.conversationId,agent_id:n?.agentId||o};i.length>0&&(r.client_functions=i,a==="pause"&&(r.client_functions_mode=a)),s&&(r.client_context=s),n?.hidden&&(r.hidden=!0);let c;if(n?.files&&n.files.length>0){const u=new FormData;u.append("content",t),n.conversationId&&u.append("conversation_id",n.conversationId),(n.agentId||o)&&u.append("agent_id",n.agentId||o||""),i.length>0&&(u.append("client_functions",JSON.stringify(i)),a==="pause"&&u.append("client_functions_mode",a)),s&&u.append("client_context",JSON.stringify(s)),n.hidden&&u.append("hidden","true");for(const h of n.files)u.append("files",h);c=await this.httpClient.postFormData("/api/sdk/v1/messages",u)}else c=await this.httpClient.postStream("/api/sdk/v1/messages",r);return this.processSSEResponse(c)}async processSSEResponse(t){let n=!1;const i=await new I({onRawChunk:s=>{this.eventEmitter.emit("stream:message",s)},onStart:s=>{this.eventEmitter.emit("message:start",s)},onChunk:s=>{this.eventEmitter.emit("message:chunk",s)},onToolCall:s=>{this.eventEmitter.emit("toolCall:received",s),s.type==="form"&&this.eventEmitter.emit("toolCall:form",s)},onClientFunction:async s=>{n=!0,this.eventEmitter.emit("function:invoke",s),await this.handleClientFunctionInvocation(s)},onAnswerComplete:s=>{this.eventEmitter.emit("message:answer-complete",s)},onWaitingClient:s=>{this.eventEmitter.emit("message:waiting-client",s),this.markResumeSignal(s.messageId,s.conversationId,"waitingConfirmed")},onComplete:s=>{this.eventEmitter.emit("message:complete",s)},onError:s=>{this.eventEmitter.emit("message:error",{error:s.message,code:s instanceof d?s.code:void 0})}}).processStream(t);return i.status!=="WAITING_CLIENT"&&this.maybeFlagEmptyReply(i,n),i}resolveClientFunctionsMode(t){return t?.clientFunctionsMode??this.config.clientFunctionsMode??"placeholder"}registerResumeGate(t){return this.resumeGate=t,()=>{this.resumeGate===t&&(this.resumeGate=null)}}async continueMessage(t){const n=this.functionRegistry.getSchemas(),i=this.contextRegistry.getSnapshot(),s={};n.length>0&&(s.client_functions=n),i&&(s.client_context=i);const o=await this.httpClient.postStream(`/api/sdk/v1/messages/${t}/continue`,s);return this.processSSEResponse(o)}markResumeSignal(t,n,i){if(!t)return;const s=this.pendingResumes.get(t)??{conversationId:n,waitingConfirmed:!1,resultsReady:!1,started:!1};s[i]=!0,n&&(s.conversationId=n),this.pendingResumes.set(t,s),!(!s.waitingConfirmed||!s.resultsReady||s.started)&&(s.started=!0,this.runAutoResume(t,s.conversationId))}async runAutoResume(t,n){try{this.resumeGate&&await this.resumeGate({conversationId:n,messageId:t})}catch(i){l.warn("Resume gate threw; resuming anyway:",i)}this.pendingResumes.delete(t);try{await this.continueMessage(t)}catch(i){l.warn("Auto-resume of paused turn failed:",i)}}maybeFlagEmptyReply(t,n){t.status==="DONE"&&(t.content??"").trim()===""&&!n&&!(t.toolCalls&&t.toolCalls.length>0)&&!(t.followUpReplies&&t.followUpReplies.length>0)&&setTimeout(()=>{if(this.eventEmitter.emit("message:empty",{conversationId:t.conversationId??"",messageId:t.id??""}),this.config.warnOnEmptyReply===!1)return;const i=t.conversationId||"(no conversation)";if(this.warnedEmptyConversations.has(i))return;this.warnedEmptyConversations.add(i);const s=this.config.agent||this.config.defaultAgentId;t.id?console.warn("[AGO] Reply completed with empty content. Possible causes: "+(s?`the agent "${s}" may not exist for this tenant, `:"an unknown `agent` slug, ")+"or the agent replied with no text. Listen for the `message:empty` event to handle this in your app; silence this warning with `warnOnEmptyReply: false`."):console.warn("[AGO] The stream completed without any message data. Possible causes: "+(s?`the agent "${s}" may not exist for this tenant, or `:"")+"`baseUrl` does not point at an AGO endpoint that returns server-sent events. Listen for the `message:empty` event to handle this in your app; silence this warning with `warnOnEmptyReply: false`.")},0)}async handleClientFunctionInvocation(t){let n,i;try{n=await this.functionRegistry.execute(t.functionName,t.arguments)}catch(s){i=s instanceof Error?s.message:"Unknown error",l.error("Client function execution failed:",s)}if(t.invocationId)try{const s=await this.submitToolCallForm(t.invocationId,{result:n,error:i,_type:"client_function_result"});s?.resume?.ready&&this.markResumeSignal(s.resume.message_id,t.conversationId,"resultsReady")}catch(s){l.error("Failed to submit function result:",s)}this.eventEmitter.emit("function:result",{invocationId:t.invocationId,result:n,error:i})}async getConversations(){return(await this.httpClient.get("/api/sdk/v1/conversations")).items.map(t=>({id:t.id,title:t.title,lastMessageDate:new Date(t.last_message_date)}))}async getConversation(t){const n=await this.httpClient.get(`/api/sdk/v1/conversations/${t}`),i={id:n.id,title:n.title,lastMessageDate:new Date(n.last_message_date),messages:n.messages.map(s=>({id:s.id,conversationId:n.id,content:s.content,role:s.role,status:s.status,createdAt:new Date(s.created_at),hidden:s.hidden,toolCalls:T.mapPersistedToolCalls(s.tool_call_data),attachments:s.attachments&&s.attachments.length>0?s.attachments.map(J):void 0}))};return this.eventEmitter.emit("conversation:loaded",i),i}static mapPersistedToolCalls(t){if(!(!t||t.length===0))return t.map(n=>({id:String(n.id??""),type:n.type??"status_message",status:String(n.status??"unknown"),toolName:n.tool_name??"",toolDisplayName:n.tool_display_name,message:n.message,formSchema:n.form_schema,data:n.data,functionName:n.function_name,arguments:n.arguments}))}async getMessages(t){return(await this.getConversation(t)).messages||[]}async resumePendingClientFunctions(t){const n=[...t.messages??[]].reverse().find(r=>r.role==="assistant"&&r.status==="WAITING_CLIENT");if(!n)return null;const i=(n.toolCalls??[]).filter(r=>r.type==="client_function"&&r.status==="waiting_input"&&r.functionName),s=new Set(this.functionRegistry.getSchemas().map(r=>r.name)),o=i.filter(r=>!s.has(r.functionName));if(o.length>0)return l.warn("Cannot resume paused turn: function(s) not registered on this page:",o.map(r=>r.functionName)),null;let a=i.length===0;for(const r of i){let c,u;try{c=await this.functionRegistry.execute(r.functionName,r.arguments??{})}catch(h){u=h instanceof Error?h.message:"Unknown error",l.error("Client function execution failed:",h)}a=(await this.submitToolCallForm(r.id,{result:c,error:u,_type:"client_function_result"}))?.resume?.ready??a}return a?this.continueMessage(n.id):null}async submitToolCallForm(t,n){return this.httpClient.post(`/api/sdk/v1/tool-calls/${t}/submit`,{formData:n})}async confirmToolCall(t){await this.httpClient.post(`/api/tool-calls/${t}/confirm/`)}async rejectToolCall(t){await this.httpClient.post(`/api/tool-calls/${t}/reject/`)}async getFormCollector(t){const n=await this.httpClient.get(`/api/sdk/v1/forms/${encodeURIComponent(t)}`);return{name:n.name,description:n.description,schema:n.schema,submit:n.submit??void 0}}async submitFormCollector(t,n){return this.httpClient.post("/api/sdk/v1/forms/submit",{name:t,values:n})}async submitFeedback(t,n){await this.httpClient.post(`/api/sdk/v1/messages/${t}/feedback`,{rating:n})}registerFunction(t,n,i){typeof t=="object"?this.functionRegistry.register(t):this.functionRegistry.register(t,n,i)}register(t){if(Array.isArray(t))for(const n of t)this.functionRegistry.register(n);else this.functionRegistry.register(t)}unregisterFunction(t){return this.functionRegistry.unregister(t)}getRegisteredFunctions(){return this.functionRegistry.getSchemas()}registerNavigationFunction(t,n){const i=n.map(r=>r.name),s=n.map(r=>{const c=w(r.path),u=c.length>0?` (requires ${c.map(h=>`"${h}"`).join(", ")})`:"";return`- "${r.name}"${u}: ${r.description}`}).join(`
|
|
5
|
-
`),o=new Map;for(const r of n)for(const c of w(r.path))o.set(c,[...o.get(c)??[],r.name]);const a={page:{type:"string",description:"The page to navigate to",enum:i}};for(const[r,c]of o){if(r==="page"){l.error('registerNavigationFunction: a ":page" placeholder collides with the "page" argument and is ignored. Rename the placeholder.');continue}a[r]={type:"string",description:`Value for ":${r}" in the page path. Required when page is ${c.map(u=>`"${u}"`).join(" or ")}.`}}this.registerFunction("navigateToPage",async r=>{const c=r.page,u=n.find(m=>m.name===c);if(!u)return{success:!1,error:`Unknown page: ${c}`};let h={};if(typeof r.params=="string")try{h=JSON.parse(r.params)}catch{}else r.params&&typeof r.params=="object"&&(h=r.params);const _={};for(const m of w(u.path))_[m]=r[m]??h[m];const{path:R,missing:p}=X(u.path,_);if(p.length>0){const m=p.map(y=>`"${y}": "..."`).join(", ");return{success:!1,error:`Page "${c}" needs ${p.map(y=>`"${y}"`).join(", ")}. Retry with { "page": "${c}", ${m} }.`}}return t(R),{success:!0,navigatedTo:R}},{description:`Navigate the user to a page in the application. Available pages:
|
|
6
|
-
${s}`,parameters:{type:"object",properties:a,required:["page"]}}),this.addDynamicContext("current-page",()=>{if(typeof window>"u"||!window.location)return null;const r=window.location.href,c=typeof document<"u"?document.title:void 0,u=Y(window.location.pathname,n),h={url:r};return u&&(h.page=u.name),c&&(h.title=c),{name:"Current page",description:"The page the user is currently viewing.",data:h}})}unregisterNavigationFunction(){this.unregisterFunction("navigateToPage"),this.removeDynamicContext("current-page")}registerPageStateFunction(t,n){const i=n?.functionName??"setPageState",s=new Map(t.map(a=>[a.name,a])),o=t.map(a=>`- "${a.name}": ${a.description}`).join(`
|
|
7
|
-
`);this.registerFunction(i,async a=>{const r={};for(const[c,u]of Object.entries(a)){if(u===void 0)continue;const h=s.get(c);h&&(await h.set(u),r[c]=u)}return{success:!0,applied:r}},{description:`Change the state of the current page. Set ONLY the controls the user explicitly asked for; leave the others unset. Available controls:
|
|
8
|
-
${o}`,parameters:{type:"object",properties:Object.fromEntries(t.map(a=>[a.name,{...a.schema,description:a.description}]))}}),this.addDynamicContext(`page-state:${i}`,()=>{const a=t.filter(c=>typeof c.get=="function");if(a.length===0)return null;const r={};for(const c of a)r[c.name]=c.get();return{name:"Page state",description:"Current, editable state of the page the user is viewing.",data:r}})}unregisterPageStateFunction(t){const n=t??"setPageState";this.unregisterFunction(n),this.removeDynamicContext(`page-state:${n}`)}setContext(t,n){this.contextRegistry.set(t,n),this.notifyContextChanged()}removeContext(t){const n=this.contextRegistry.remove(t);return n&&this.notifyContextChanged(),n}addDynamicContext(t,n){this.contextRegistry.addDynamicProvider(t,n),this.notifyContextChanged()}removeDynamicContext(t){const n=this.contextRegistry.removeDynamicProvider(t);return n&&this.notifyContextChanged(),n}notifyContextChanged(){this.eventEmitter.emit("context:changed",this.contextRegistry.getSnapshot())}emitFormEvent(t,n){this.eventEmitter.emit(t,n)}enableAutoPageContext(){this.addDynamicContext("browser-page",()=>{const t=typeof window<"u"?window.location.href:void 0,n=typeof document<"u"?document.title:void 0;return!t&&!n?null:{name:"Browser page",description:"Current page the user is viewing",data:{url:t,title:n}}})}getContextSnapshot(){return this.contextRegistry.getSnapshot()}on(t,n){this.eventEmitter.on(t,n)}off(t,n){this.eventEmitter.off(t,n)}once(t,n){this.eventEmitter.once(t,n)}waitFor(t,n){return this.eventEmitter.waitFor(t,n)}updateConfig(t){const n={};for(const[s,o]of Object.entries(t))o!==void 0&&(n[s]=o);const i={...this.config,...n};E(i,"AgoClient.updateConfig"),this.config=i,this.httpClient.updateConfig(n),n.debug!==void 0&&(n.debug?l.enable():l.disable()),n.maxFunctionResultBytes!==void 0&&this.functionRegistry.setDefaultMaxResultBytes(n.maxFunctionResultBytes)}destroy(){this.eventEmitter.removeAllListeners(),this.functionRegistry.clear(),this.contextRegistry.clear(),this.pendingResumes.clear(),this.resumeGate=null,l.log("AgoClient destroyed")}};Object.defineProperty(exports,"AgoApiError",{enumerable:!0,get:function(){return f}});Object.defineProperty(exports,"AgoClient",{enumerable:!0,get:function(){return V}});Object.defineProperty(exports,"AgoError",{enumerable:!0,get:function(){return d}});Object.defineProperty(exports,"AgoFunctionError",{enumerable:!0,get:function(){return b}});Object.defineProperty(exports,"AgoNetworkError",{enumerable:!0,get:function(){return g}});Object.defineProperty(exports,"AgoStreamError",{enumerable:!0,get:function(){return v}});Object.defineProperty(exports,"ClientContextRegistry",{enumerable:!0,get:function(){return F}});Object.defineProperty(exports,"EventEmitter",{enumerable:!0,get:function(){return N}});Object.defineProperty(exports,"FunctionRegistry",{enumerable:!0,get:function(){return k}});Object.defineProperty(exports,"SSEHandler",{enumerable:!0,get:function(){return I}});Object.defineProperty(exports,"attachmentsFromFiles",{enumerable:!0,get:function(){return q}});Object.defineProperty(exports,"canInlineImage",{enumerable:!0,get:function(){return W}});Object.defineProperty(exports,"formatFileSize",{enumerable:!0,get:function(){return z}});Object.defineProperty(exports,"isStreamNetworkError",{enumerable:!0,get:function(){return L}});Object.defineProperty(exports,"logger",{enumerable:!0,get:function(){return l}});Object.defineProperty(exports,"safeAttachmentUrl",{enumerable:!0,get:function(){return U}});Object.defineProperty(exports,"validateConfig",{enumerable:!0,get:function(){return E}});
|