@useago/sdk 1.0.0 → 1.0.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 CHANGED
@@ -1,97 +1,115 @@
1
1
  # @useago/sdk
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@useago/sdk.svg)](https://www.npmjs.com/package/@useago/sdk)
4
- [![license](https://img.shields.io/npm/l/@useago/sdk.svg)](./LICENSE)
5
4
  [![types](https://img.shields.io/npm/types/@useago/sdk.svg)](https://www.npmjs.com/package/@useago/sdk)
6
5
 
7
- Official JavaScript/TypeScript SDK for [AGO](https://useago.com) — embed AGO's AI
8
- agents directly inside your own app. Stream answers, let the agent call **your**
9
- client-side functions, navigate users around your UI, and feed it live context
10
- about what the user is doing.
6
+ **The agent layer for your frontend stack.** AGO's agents plug into React, Vue,
7
+ Angular or plain TypeScript like any other dependency: send a message, stream
8
+ the reply, and let the agent call **your** code and navigate **your** UI.
11
9
 
12
- Works with **plain JS/TS, React, Vue and Angular**. The core is framework-agnostic;
13
- each framework gets idiomatic bindings (hooks, composables, services) on top of the
14
- same `AgoClient`.
10
+ In two minutes you'll have a working chat on your page and an agent that can
11
+ navigate your app. The quickstart below uses **React**; every other stack gets
12
+ the same two steps through its own guide:
13
+
14
+ | Stack | Guide |
15
+ | --- | --- |
16
+ | <img src="https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons/react/react-original.svg" width="14" /> React | **you're reading it**, just scroll down |
17
+ | <img src="https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons/vuejs/vuejs-original.svg" width="14" /> Vue 3 | [Vue guide](docs/frameworks/vue.md) |
18
+ | <img src="https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons/angular/angular-original.svg" width="14" /> Angular | [Angular guide](docs/frameworks/angular.md) |
19
+ | <img src="https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons/typescript/typescript-original.svg" width="14" /> Plain JavaScript / TypeScript | [Core guide](docs/general/core.md) |
20
+ | <img src="https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons/html5/html5-original.svg" width="14" /> Any website, no build step (`<script>`) | [Widget guide](docs/general/widget.md) |
21
+
22
+ ## <img src="https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons/react/react-original.svg" width="22" /> Try it in 30 seconds
15
23
 
16
24
  ```bash
17
25
  npm install @useago/sdk
18
26
  ```
19
27
 
20
- 📚 **Full documentation:** [docs.useago.com](https://docs.useago.com) · the
21
- framework guides below are also published there.
28
+ The SDK has no framework dependency of its own. The React bindings need `react`
29
+ and `react-dom` (>=17): already there in an existing React app, otherwise
30
+ install them too.
31
+
32
+ ```tsx
33
+ // App.tsx
34
+ import { AgoProvider, ChatWidget } from "@useago/sdk/react";
35
+
36
+ export default function App() {
37
+ return (
38
+ <AgoProvider baseUrl="https://ago.api.useago.com" agent="generic-guide">
39
+ <ChatWidget title="AGO" welcomeMessage="Ask me anything!" height={500} />
40
+ </AgoProvider>
41
+ );
42
+ }
43
+ ```
22
44
 
23
- ---
45
+ Start your dev server. A chat panel renders on the page; type a message and
46
+ watch the reply stream in. That's a complete integration. (`generic-guide` is a
47
+ public demo agent; swap `baseUrl` and `agent` for your own once you have a tenant.)
24
48
 
25
- ## Quick start
49
+ ## Let the agent drive your existing routes
26
50
 
27
- Pick your stack — each guide is self-contained.
51
+ This is the part existing apps care about. You already have a router and pages;
52
+ describe them to the agent and *"show me my invoices"* actually navigates there.
53
+ One hook in the layout you already have, nothing to restructure:
28
54
 
29
- | Stack | Guide |
30
- | --- | --- |
31
- | Plain JavaScript / TypeScript | [docs/general/core.md](docs/general/core.md) |
32
- | React | [docs/frameworks/react.md](docs/frameworks/react.md) |
33
- | Vue 3 | [docs/frameworks/vue.md](docs/frameworks/vue.md) |
34
- | Angular | [docs/frameworks/angular.md](docs/frameworks/angular.md) |
35
- | Embeddable widget (`<script>`) | [docs/general/widget.md](docs/general/widget.md) |
55
+ ```tsx
56
+ import { Outlet, useNavigate } from "react-router-dom";
57
+ import { useAgoNavigation } from "@useago/sdk/react";
36
58
 
37
- Cross-cutting topics (apply to every framework):
59
+ // Your existing layout component. Only the hook is new.
60
+ function AppLayout() {
61
+ const navigate = useNavigate();
38
62
 
39
- - [**Client-side functions & helpers**](docs/general/functions-and-context.md#client-side-functions) — let the agent run code in the browser
40
- - [**Client context**](docs/general/functions-and-context.md#client-context) — tell the agent what the user is looking at
41
- - [**Events & streaming**](docs/general/events-and-streaming.md) — low-level hooks into the message stream
42
- - [**Testing**](docs/general/testing.md) — a mock client for unit tests
43
- - [**Configuration & auth**](docs/general/configuration.md) — every `AgoConfig` option, headers, errors
63
+ useAgoNavigation(navigate, [
64
+ { name: "dashboard", path: "/dashboard", description: "KPIs and recent activity" },
65
+ { name: "invoices", path: "/invoices", description: "List, search and download invoices" },
66
+ { name: "settings", path: "/settings", description: "Account, billing and team settings" },
67
+ ]);
44
68
 
45
- The 30-second version (vanilla):
69
+ return <Outlet />; // your existing routes render as before
70
+ }
71
+ ```
46
72
 
47
- ```ts
48
- import { AgoClient } from "@useago/sdk";
73
+ Each route needs a `name`, its existing `path`, and a `description` the agent
74
+ uses to pick the right page. It calls **your** `navigate` function, so route
75
+ guards, auth and layouts keep working exactly as they do today.
76
+ `react-router-dom` here is *your* router, not an SDK dependency:
77
+ `useAgoNavigation` accepts any `(path: string) => void` function.
49
78
 
50
- const ago = new AgoClient({ baseUrl: "https://YOUR-DOMAIN.useago.com" });
79
+ **Next: the [Getting started guide](docs/general/getting-started.md)** has both
80
+ examples assembled into a running app, plus everything else the SDK can do, in
81
+ about 5 minutes.
51
82
 
52
- ago.on("message:chunk", ({ content }) => process.stdout.write(content));
83
+ ## Or clone a running example
53
84
 
54
- const reply = await ago.sendMessage("What can you do?");
55
- console.log("\nDone:", reply.status);
85
+ ```bash
86
+ git clone https://github.com/useago/ago-sdk.git
87
+ cd ago-sdk && npm install && npm run build # build the SDK once
88
+ cd examples/simple-react
89
+ npm install && npm run dev
56
90
  ```
57
91
 
92
+ The examples ship pre-configured against the demo backend, so they answer
93
+ immediately. [`examples/`](examples/) has one per stack: React (with
94
+ react-router navigation), Vue, Angular, plain TypeScript, and no-build HTML.
95
+
58
96
  ---
59
97
 
60
- ## Feature matrix
61
-
62
- What ships out of the box for each entry point. The **core** (`@useago/sdk`)
63
- APIs are usable from *any* framework — the framework columns mark where a more
64
- idiomatic binding (hook / composable / service / component) is also provided.
65
-
66
- | Feature | Core (vanilla) | React | Vue | Angular |
67
- | --- | :---: | :---: | :---: | :---: |
68
- | Create client | `new AgoClient()` | `useAgo` / `<AgoProvider>` | `AgoPlugin` / `useAgo` | `provideAgo` / `AgoService` |
69
- | Zero-config auto-detect | ✅ `createAgo()` | ✅ | ✅ | ✅ |
70
- | Send message (streaming) | ✅ | ✅ `useChat`/`useMessages` | ✅ `useChat`/`useMessages` | ✅ `AgoService.sendMessage` |
71
- | File attachments | ✅ | ✅ | ✅ | ✅ |
72
- | List / load conversations | ✅ | ✅ `useConversation` | ✅ `useConversation` | ✅ `AgoService` |
73
- | All-in-one chat state | — | ✅ `useChat` | ✅ `useChat` | ➖ compose manually |
74
- | Pre-built `<ChatWidget>` UI | — | ✅ | ➖ see example | — |
75
- | Markdown / `<Message>` / `<ChatInput>` | — | ✅ | — | — |
76
- | Client-side functions | ✅ `registerFunction` | ✅ `useAgoFunction` | ✅ `useAgoFunction` | ✅ `AgoService` |
77
- | `defineFunction` / `withHandler` | ✅ | ✅ | ✅ | ✅ |
78
- | Pre-built helpers (`showToast`, …) | ✅ | ✅ `helpers` prop | ✅ | ✅ |
79
- | Navigation function | ✅ `registerNavigationFunction` | ✅ `useAgoNavigation` | ✅ `useAgoNavigation` | ✅ `AgoService` |
80
- | Client context | ✅ `setContext` / `addDynamicContext` | ✅ `useAgoContext` | ✅ core API | ✅ core API |
81
- | Auto page context | ✅ `enableAutoPageContext()` | ✅ `pageContext="auto"` | ✅ core API | ✅ core API |
82
- | Events (`on`/`off`/`once`/`waitFor`) | ✅ | ✅ (via client) | ✅ `useAgoEvents` | ✅ `messages$` Observables |
83
- | Streaming helpers / async generator | ✅ | ✅ | ✅ | ✅ |
84
- | Tool calls (form/confirm/reject) | ✅ | ✅ | ✅ | ✅ `AgoService` |
85
- | Message feedback | ✅ `submitFeedback` | ✅ | ✅ | ✅ `AgoService` |
86
- | Observable store | ✅ `createStore` | ✅ `useAgoStore` | ✅ `useAgoStore` | ➖ core API |
87
- | Dev panel / devtools | ✅ `initDevPanel` (`/devtools`) | ✅ | ✅ | ✅ |
88
- | Testing mock client | ✅ `createMockClient` | ✅ | ✅ | ✅ |
89
-
90
- Legend: ✅ first-class binding · ➖ supported via the core API, no dedicated sugar · — not applicable.
98
+ ## Docs
99
+
100
+ - [**Getting started**](docs/general/getting-started.md): send a message, wire the router, see the feature map
101
+ - [**Feature matrix**](docs/general/feature-matrix.md): everything that ships, per stack
102
+ - [**Functions & context**](docs/general/functions-and-context.md): let the agent run your code and see what the user sees
103
+ - [**Events & streaming**](docs/general/events-and-streaming.md): low-level hooks into the message stream
104
+ - [**Testing**](docs/general/testing.md): mock client for unit tests
105
+ - [**Configuration & auth**](docs/general/configuration.md): every `AgoConfig` option, headers, errors
106
+
107
+ Full documentation: [ago.mintlify.app](https://ago.mintlify.app/)
91
108
 
92
109
  ---
93
110
 
94
- ## Package entry points
111
+ <details>
112
+ <summary><strong>Package entry points</strong> (subpath exports)</summary>
95
113
 
96
114
  The package is published with several subpath exports so bundlers only pull in
97
115
  what you use:
@@ -104,20 +122,31 @@ what you use:
104
122
  | `@useago/sdk/angular` | Angular service and provider |
105
123
  | `@useago/sdk/helpers` | Pre-built client functions only |
106
124
  | `@useago/sdk/widget` | `window.AGO` widget config types |
107
- | `@useago/sdk/devtools` | `initDevPanel` — in-browser debug overlay (DOM/CSS) |
108
- | `@useago/sdk/testing` | `createMockClient` — mock client for tests |
125
+ | `@useago/sdk/devtools` | `initDevPanel`, an in-browser debug overlay (DOM/CSS) |
126
+ | `@useago/sdk/testing` | `createMockClient`, a mock client for tests |
109
127
 
110
128
  ESM and CJS builds are both shipped, with full TypeScript declarations.
111
129
 
112
- ---
130
+ </details>
113
131
 
114
- ## Requirements
132
+ ## Dependencies
115
133
 
116
- - A modern browser environment (uses `fetch` + `ReadableStream` for SSE) or Node 18+.
117
- - `react` / `react-dom` `>=17` for the React bindings (peer dependency, optional).
118
- - `vue` `>=3.3` for the Vue bindings (peer dependency, optional).
119
- - Angular bindings have **no** hard Angular dependency — they work with any DI container.
134
+ The core SDK depends on nothing but the platform: `fetch` and `ReadableStream`,
135
+ so any modern browser or Node 18+. Framework packages are **optional peer
136
+ dependencies**; you only need the one whose bindings you import:
137
+
138
+ | You import | Needs | Notes |
139
+ | --- | --- | --- |
140
+ | `@useago/sdk` (core, widget, helpers, testing) | nothing | works everywhere |
141
+ | `@useago/sdk/react` | `react` + `react-dom` `>=17` | already present in any React app |
142
+ | `@useago/sdk/vue` | `vue` `>=3.3` | already present in any Vue 3 app |
143
+ | `@useago/sdk/angular` | nothing | no hard Angular dependency, works with any DI container |
144
+
145
+ Your router (`react-router-dom`, `vue-router`, Angular Router) is **never** an
146
+ SDK dependency: the navigation helpers just take your navigate function.
147
+
148
+ ---
120
149
 
121
150
  ## License
122
151
 
123
- [Apache 2.0](./LICENSE) · [Documentation](https://docs.useago.com) · [Website](https://useago.com)
152
+ [Apache 2.0](./LICENSE) · [Documentation](https://ago.mintlify.app/) · [Website](https://useago.com)
@@ -1,6 +1,6 @@
1
1
  var u=class extends Error{constructor(e,t,s){super(e),this.code=t,this.statusCode=s,this.name="AgoError"}},h=class p extends u{constructor(t,s,r,n,o,a){super(t,s,r),this.type=n,this.param=o,this.docUrl=a,this.name="AgoApiError"}static fromResponse(t,s){const r=t.error;return new p(r.message,r.code,s,r.type,r.param,r.doc_url)}},d=class extends u{constructor(e,t){super(e,"network_error"),this.originalError=t,this.name="AgoNetworkError"}},g=class extends u{constructor(e){super(e,"stream_error"),this.name="AgoStreamError"}},m=class extends u{constructor(e,t,s){super(e,"function_error"),this.functionName=t,this.originalError=s,this.name="AgoFunctionError"}},_=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)}},i=new _,f="ago_widget_id";function S(){if(typeof localStorage<"u"){const t=localStorage.getItem(f);if(t)return t}const e=crypto.randomUUID();if(typeof localStorage<"u")try{localStorage.setItem(f,e)}catch{}return e}var k=class{constructor(e){this.baseUrl=e.baseUrl.replace(/\/$/,""),this.headers={"X-Widget-Id":e.widgetId||S()},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-Widget-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 s=`${this.baseUrl}${e}`;i.debug("POST (stream)",s,t);try{const r=await fetch(s,{method:"POST",headers:{...this.headers,"Content-Type":"application/json"},body:t?JSON.stringify(t):void 0});return r.ok||await this.handleErrorResponse(r),r}catch(r){throw r instanceof h?r:new d(`Network error: ${r instanceof Error?r.message:"Unknown error"}`,r instanceof Error?r:void 0)}}async postFormData(e,t){const s=`${this.baseUrl}${e}`;i.debug("POST (formData)",s);const r={...this.headers};try{const n=await fetch(s,{method:"POST",headers:r,body:t});return n.ok||await this.handleErrorResponse(n),n}catch(n){throw n instanceof h?n:new d(`Network error: ${n instanceof Error?n.message:"Unknown error"}`,n instanceof Error?n:void 0)}}async request(e,t,s){const r=`${this.baseUrl}${t}`;i.debug(e,r,s);try{const n=await fetch(r,{method:e,headers:{...this.headers,"Content-Type":"application/json"},body:s?JSON.stringify(s):void 0});return n.ok||await this.handleErrorResponse(n),n.status===204?void 0:n.json()}catch(n){throw n instanceof h?n:new d(`Network error: ${n instanceof Error?n.message:"Unknown error"}`,n instanceof Error?n:void 0)}}async handleErrorResponse(e){let t;try{t=await e.json()}catch{}throw t?.error?h.fromResponse(t,e.status):new h(`HTTP ${e.status}: ${e.statusText}`,"http_error",e.status,"api_error")}},y=class{constructor(){this.functions=new Map}register(e,t,s){if(typeof e=="object"){const{name:n,handler:o,description:a,parameters:c}=e;return this.register(n,o,{description:a,parameters:c})}const r=e;if(!t||!s)throw new Error("handler and schema are required");this.functions.has(r)&&i.warn(`Function "${r}" is being overwritten`),this.functions.set(r,{schema:{...s,name:r},handler:t}),i.log(`Registered function: ${r}`)}unregister(e){const t=this.functions.delete(e);return t&&i.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 s=this.functions.get(e);if(!s)throw new m(`Function "${e}" is not registered`,e);i.log(`Executing function: ${e}`,t);try{const r=await s.handler(t);return i.log(`Function ${e} completed:`,r),r}catch(r){throw i.error(`Function ${e} failed:`,r),new m(`Function "${e}" execution failed: ${r instanceof Error?r.message:"Unknown error"}`,e,r instanceof Error?r:void 0)}}clear(){this.functions.clear(),i.log("Cleared all registered functions")}get size(){return this.functions.size}},w=class{constructor(){this.entries=new Map,this.dynamicProviders=new Map}set(e,t){this.entries.set(e,t),i.log(`ClientContext set: ${e}`)}remove(e){const t=this.entries.delete(e);return t&&i.log(`ClientContext removed: ${e}`),t}addDynamicProvider(e,t){this.dynamicProviders.set(e,t),i.log(`DynamicContext provider added: ${e}`)}removeDynamicProvider(e){const t=this.dynamicProviders.delete(e);return t&&i.log(`DynamicContext provider removed: ${e}`),t}getSnapshot(){if(this.entries.size===0&&this.dynamicProviders.size===0)return null;const e={};for(const[t,s]of this.entries)e[t]=s;for(const[t,s]of this.dynamicProviders)try{const r=s();r&&(e[t]=r)}catch(r){i.error(`DynamicContext provider "${t}" threw:`,r)}return Object.keys(e).length===0?null:{entries:e}}clear(){this.entries.clear(),this.dynamicProviders.clear(),i.log("ClientContext cleared")}},v=class{constructor(e){this.callbacks=e,this.buffer="",this.message={},this.toolCalls=[],this.sources=[],this.followUpReplies=[],this.isFirstChunk=!0,this.answerCompleteEmitted=!1}async processStream(e){if(!e.body)throw new g("Response has no body");const t=e.body.getReader(),s=new TextDecoder;try{for(;;){const{done:r,value:n}=await t.read();if(r)break;const o=s.decode(n,{stream:!0});this.buffer+=o,this.processBuffer()}return this.buffer.trim()&&this.processBuffer(),this.buildFinalMessage()}catch(r){const n=r instanceof Error?r:new g("Stream processing failed");throw this.callbacks.onError?.(n),n}finally{t.releaseLock()}}processBuffer(){const e=this.buffer.split(`
2
2
 
3
3
  `);this.buffer=e.pop()||"";for(const t of e){if(!t.trim())continue;const s=t.split(`
4
- `);for(const r of s)if(!r.startsWith(": ")&&r.startsWith("data: ")){const n=r.slice(6);try{const o=JSON.parse(n);this.handleChunk(o)}catch(o){i.warn("Failed to parse SSE data:",n,o)}}}}handleChunk(e){if(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 s=t.knowledge_document;return{id:s.id,title:s.title,url:s.use_external_link?s.external_link_url:s.internal_link_url}})),e.type==="client_function"&&e.function_name&&this.callbacks.onClientFunction?.({invocationId:e.id||"",functionName:e.function_name,arguments:e.arguments||{},conversationId:this.message.conversationId||""}),e.tool_call_data&&e.type&&e.type!=="client_function"){const t=this.parseToolCall(e);this.callbacks.onToolCall?.(t);const s=this.toolCalls.findIndex(r=>r.id===t.id);s>=0?this.toolCalls[s]=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()))}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 this.callbacks.onComplete?.(e),e}};function x(e){const t=e.message.toLowerCase();return t.includes("load failed")||t.includes("failed to fetch")||t.includes("network")||t.includes("abort")}var C=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 s=this.handlers.get(e);s&&s.delete(t)}emit(e,t){const s=this.handlers.get(e);s&&s.forEach(r=>{try{r(t)}catch(n){console.error(`Error in event handler for ${String(e)}:`,n)}})}once(e,t){const s=(r=>{this.off(e,s),t(r)});this.on(e,s)}waitFor(e,t){return new Promise((s,r)=>{let n;const o=(a=>{n&&clearTimeout(n),s(a)});this.once(e,o),t?.timeout&&(n=setTimeout(()=>{this.off(e,o),r(new Error(`waitFor("${String(e)}") timed out after ${t.timeout}ms`))},t.timeout))})}removeAllListeners(e){e?this.handlers.delete(e):this.handlers.clear()}},A=class b{constructor(t){this.config=t,this.httpClient=new k(t),this.functionRegistry=new y,this.contextRegistry=new w,this.eventEmitter=new C,t.debug&&i.enable(),i.log("AgoClient initialized")}async sendMessage(t,s){const r=this.functionRegistry.getSchemas(),n=this.contextRegistry.getSnapshot(),o=this.config.agent||this.config.defaultAgentId,a={content:t,conversation_id:s?.conversationId,agent_id:s?.agentId||o};r.length>0&&(a.client_functions=r),n&&(a.client_context=n);let c;if(s?.files&&s.files.length>0){const l=new FormData;l.append("content",t),s.conversationId&&l.append("conversation_id",s.conversationId),(s.agentId||o)&&l.append("agent_id",s.agentId||o||""),r.length>0&&l.append("client_functions",JSON.stringify(r)),n&&l.append("client_context",JSON.stringify(n));for(const E of s.files)l.append("files",E);c=await this.httpClient.postFormData("/api/sdk/v1/messages",l)}else c=await this.httpClient.postStream("/api/sdk/v1/messages",a);return this.processSSEResponse(c)}async processSSEResponse(t){return new v({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=>{this.eventEmitter.emit("function:invoke",s),await this.handleClientFunctionInvocation(s)},onAnswerComplete:s=>{this.eventEmitter.emit("message:answer-complete",s)},onComplete:s=>{this.eventEmitter.emit("message:complete",s)},onError:s=>{this.eventEmitter.emit("message:error",{error:s.message})}}).processStream(t)}async handleClientFunctionInvocation(t){let s,r;try{s=await this.functionRegistry.execute(t.functionName,t.arguments)}catch(n){r=n instanceof Error?n.message:"Unknown error",i.error("Client function execution failed:",n)}if(t.invocationId)try{await this.submitToolCallForm(t.invocationId,{result:s,error:r,_type:"client_function_result"})}catch(n){i.error("Failed to submit function result:",n)}this.eventEmitter.emit("function:result",{invocationId:t.invocationId,result:s,error:r})}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 s=await this.httpClient.get(`/api/sdk/v1/conversations/${t}`),r={id:s.id,title:s.title,lastMessageDate:new Date(s.last_message_date),messages:s.messages.map(n=>({id:n.id,conversationId:s.id,content:n.content,role:n.role,status:n.status,createdAt:new Date(n.created_at),toolCalls:b.mapPersistedToolCalls(n.tool_call_data)}))};return this.eventEmitter.emit("conversation:loaded",r),r}static mapPersistedToolCalls(t){if(!(!t||t.length===0))return t.map(s=>({id:String(s.id??""),type:s.type??"status_message",status:String(s.status??"unknown"),toolName:s.tool_name??"",toolDisplayName:s.tool_display_name,message:s.message,formSchema:s.form_schema,data:s.data,functionName:s.function_name,arguments:s.arguments}))}async getMessages(t){return(await this.getConversation(t)).messages||[]}async submitToolCallForm(t,s){await this.httpClient.post(`/api/sdk/v1/tool-calls/${t}/submit`,{formData:s})}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 submitFormCollector(t,s){return this.httpClient.post("/api/sdk/v1/forms/submit",{destination:t,values:s})}async submitFeedback(t,s){await this.httpClient.post(`/api/sdk/v1/messages/${t}/feedback`,{rating:s})}registerFunction(t,s,r){typeof t=="object"?this.functionRegistry.register(t):this.functionRegistry.register(t,s,r)}register(t){if(Array.isArray(t))for(const s of t)this.functionRegistry.register(s);else this.functionRegistry.register(t)}unregisterFunction(t){return this.functionRegistry.unregister(t)}getRegisteredFunctions(){return this.functionRegistry.getSchemas()}registerNavigationFunction(t,s){const r=s.map(o=>o.name),n=s.map(o=>`- "${o.name}": ${o.description}`).join(`
4
+ `);for(const r of s)if(!r.startsWith(": ")&&r.startsWith("data: ")){const n=r.slice(6);try{const o=JSON.parse(n);this.handleChunk(o)}catch(o){i.warn("Failed to parse SSE data:",n,o)}}}}handleChunk(e){if(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 s=t.knowledge_document;return{id:s.id,title:s.title,url:s.use_external_link?s.external_link_url:s.internal_link_url}})),e.type==="client_function"&&e.function_name&&this.callbacks.onClientFunction?.({invocationId:e.id||"",functionName:e.function_name,arguments:e.arguments||{},conversationId:this.message.conversationId||""}),e.tool_call_data&&e.type&&e.type!=="client_function"){const t=this.parseToolCall(e);this.callbacks.onToolCall?.(t);const s=this.toolCalls.findIndex(r=>r.id===t.id);s>=0?this.toolCalls[s]=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()))}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 this.callbacks.onComplete?.(e),e}};function x(e){const t=e.message.toLowerCase();return t.includes("load failed")||t.includes("failed to fetch")||t.includes("network")||t.includes("abort")}var C=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 s=this.handlers.get(e);s&&s.delete(t)}emit(e,t){const s=this.handlers.get(e);s&&s.forEach(r=>{try{r(t)}catch(n){console.error(`Error in event handler for ${String(e)}:`,n)}})}once(e,t){const s=(r=>{this.off(e,s),t(r)});this.on(e,s)}waitFor(e,t){return new Promise((s,r)=>{let n;const o=(a=>{n&&clearTimeout(n),s(a)});this.once(e,o),t?.timeout&&(n=setTimeout(()=>{this.off(e,o),r(new Error(`waitFor("${String(e)}") timed out after ${t.timeout}ms`))},t.timeout))})}removeAllListeners(e){e?this.handlers.delete(e):this.handlers.clear()}},A=class b{constructor(t){this.config=t,this.httpClient=new k(t),this.functionRegistry=new y,this.contextRegistry=new w,this.eventEmitter=new C,t.debug&&i.enable(),i.log("AgoClient initialized")}async sendMessage(t,s){const r=this.functionRegistry.getSchemas(),n=this.contextRegistry.getSnapshot(),o=this.config.agent||this.config.defaultAgentId,a={content:t,conversation_id:s?.conversationId,agent_id:s?.agentId||o};r.length>0&&(a.client_functions=r),n&&(a.client_context=n);let c;if(s?.files&&s.files.length>0){const l=new FormData;l.append("content",t),s.conversationId&&l.append("conversation_id",s.conversationId),(s.agentId||o)&&l.append("agent_id",s.agentId||o||""),r.length>0&&l.append("client_functions",JSON.stringify(r)),n&&l.append("client_context",JSON.stringify(n));for(const E of s.files)l.append("files",E);c=await this.httpClient.postFormData("/api/sdk/v1/messages",l)}else c=await this.httpClient.postStream("/api/sdk/v1/messages",a);return this.processSSEResponse(c)}async processSSEResponse(t){return new v({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=>{this.eventEmitter.emit("function:invoke",s),await this.handleClientFunctionInvocation(s)},onAnswerComplete:s=>{this.eventEmitter.emit("message:answer-complete",s)},onComplete:s=>{this.eventEmitter.emit("message:complete",s)},onError:s=>{this.eventEmitter.emit("message:error",{error:s.message})}}).processStream(t)}async handleClientFunctionInvocation(t){let s,r;try{s=await this.functionRegistry.execute(t.functionName,t.arguments)}catch(n){r=n instanceof Error?n.message:"Unknown error",i.error("Client function execution failed:",n)}if(t.invocationId)try{await this.submitToolCallForm(t.invocationId,{result:s,error:r,_type:"client_function_result"})}catch(n){i.error("Failed to submit function result:",n)}this.eventEmitter.emit("function:result",{invocationId:t.invocationId,result:s,error:r})}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 s=await this.httpClient.get(`/api/sdk/v1/conversations/${t}`),r={id:s.id,title:s.title,lastMessageDate:new Date(s.last_message_date),messages:s.messages.map(n=>({id:n.id,conversationId:s.id,content:n.content,role:n.role,status:n.status,createdAt:new Date(n.created_at),toolCalls:b.mapPersistedToolCalls(n.tool_call_data)}))};return this.eventEmitter.emit("conversation:loaded",r),r}static mapPersistedToolCalls(t){if(!(!t||t.length===0))return t.map(s=>({id:String(s.id??""),type:s.type??"status_message",status:String(s.status??"unknown"),toolName:s.tool_name??"",toolDisplayName:s.tool_display_name,message:s.message,formSchema:s.form_schema,data:s.data,functionName:s.function_name,arguments:s.arguments}))}async getMessages(t){return(await this.getConversation(t)).messages||[]}async submitToolCallForm(t,s){await this.httpClient.post(`/api/sdk/v1/tool-calls/${t}/submit`,{formData:s})}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 s=await this.httpClient.get(`/api/sdk/v1/forms/${encodeURIComponent(t)}`);return{name:s.name,description:s.description,schema:s.schema,submit:s.submit??void 0}}async submitFormCollector(t,s){return this.httpClient.post("/api/sdk/v1/forms/submit",{destination:t,values:s})}async submitFeedback(t,s){await this.httpClient.post(`/api/sdk/v1/messages/${t}/feedback`,{rating:s})}registerFunction(t,s,r){typeof t=="object"?this.functionRegistry.register(t):this.functionRegistry.register(t,s,r)}register(t){if(Array.isArray(t))for(const s of t)this.functionRegistry.register(s);else this.functionRegistry.register(t)}unregisterFunction(t){return this.functionRegistry.unregister(t)}getRegisteredFunctions(){return this.functionRegistry.getSchemas()}registerNavigationFunction(t,s){const r=s.map(o=>o.name),n=s.map(o=>`- "${o.name}": ${o.description}`).join(`
5
5
  `);this.registerFunction("navigateToPage",async o=>{const a=o.page,c=s.find(l=>l.name===a);return c?(t(c.path),{success:!0,navigatedTo:c.path}):{success:!1,error:`Unknown page: ${a}`}},{description:`Navigate the user to a page in the application. Available pages:
6
6
  ${n}`,parameters:{type:"object",properties:{page:{type:"string",description:"The page to navigate to",enum:r}},required:["page"]}})}setContext(t,s){this.contextRegistry.set(t,s),this.notifyContextChanged()}removeContext(t){const s=this.contextRegistry.remove(t);return s&&this.notifyContextChanged(),s}addDynamicContext(t,s){this.contextRegistry.addDynamicProvider(t,s),this.notifyContextChanged()}removeDynamicContext(t){const s=this.contextRegistry.removeDynamicProvider(t);return s&&this.notifyContextChanged(),s}notifyContextChanged(){this.eventEmitter.emit("context:changed",this.contextRegistry.getSnapshot())}enableAutoPageContext(){this.addDynamicContext("browser-page",()=>{const t=typeof window<"u"?window.location.href:void 0,s=typeof document<"u"?document.title:void 0;return!t&&!s?null:{name:"Browser page",description:"Current page the user is viewing",data:{url:t,title:s}}})}getContextSnapshot(){return this.contextRegistry.getSnapshot()}on(t,s){this.eventEmitter.on(t,s)}off(t,s){this.eventEmitter.off(t,s)}once(t,s){this.eventEmitter.once(t,s)}waitFor(t,s){return this.eventEmitter.waitFor(t,s)}updateConfig(t){this.config={...this.config,...t},this.httpClient.updateConfig(t),t.debug!==void 0&&(t.debug?i.enable():i.disable())}destroy(){this.eventEmitter.removeAllListeners(),this.functionRegistry.clear(),this.contextRegistry.clear(),i.log("AgoClient destroyed")}};Object.defineProperty(exports,"AgoApiError",{enumerable:!0,get:function(){return h}});Object.defineProperty(exports,"AgoClient",{enumerable:!0,get:function(){return A}});Object.defineProperty(exports,"AgoError",{enumerable:!0,get:function(){return u}});Object.defineProperty(exports,"AgoFunctionError",{enumerable:!0,get:function(){return m}});Object.defineProperty(exports,"AgoNetworkError",{enumerable:!0,get:function(){return d}});Object.defineProperty(exports,"AgoStreamError",{enumerable:!0,get:function(){return g}});Object.defineProperty(exports,"ClientContextRegistry",{enumerable:!0,get:function(){return w}});Object.defineProperty(exports,"EventEmitter",{enumerable:!0,get:function(){return C}});Object.defineProperty(exports,"FunctionRegistry",{enumerable:!0,get:function(){return y}});Object.defineProperty(exports,"SSEHandler",{enumerable:!0,get:function(){return v}});Object.defineProperty(exports,"isStreamNetworkError",{enumerable:!0,get:function(){return x}});Object.defineProperty(exports,"logger",{enumerable:!0,get:function(){return i}});
@@ -14,11 +14,11 @@ var d = class extends Error {
14
14
  constructor(e, t) {
15
15
  super(e, "network_error"), this.originalError = t, this.name = "AgoNetworkError";
16
16
  }
17
- }, g = class extends d {
17
+ }, m = class extends d {
18
18
  constructor(e) {
19
19
  super(e, "stream_error"), this.name = "AgoStreamError";
20
20
  }
21
- }, m = class extends d {
21
+ }, g = class extends d {
22
22
  constructor(e, t, s) {
23
23
  super(e, "function_error"), this.functionName = t, this.originalError = s, this.name = "AgoFunctionError";
24
24
  }
@@ -133,10 +133,10 @@ var E = class {
133
133
  }
134
134
  register(e, t, s) {
135
135
  if (typeof e == "object") {
136
- const { name: i, handler: o, description: a, parameters: l } = e;
136
+ const { name: i, handler: o, description: a, parameters: c } = e;
137
137
  return this.register(i, o, {
138
138
  description: a,
139
- parameters: l
139
+ parameters: c
140
140
  });
141
141
  }
142
142
  const r = e;
@@ -164,13 +164,13 @@ var E = class {
164
164
  }
165
165
  async execute(e, t) {
166
166
  const s = this.functions.get(e);
167
- if (!s) throw new m(`Function "${e}" is not registered`, e);
167
+ if (!s) throw new g(`Function "${e}" is not registered`, e);
168
168
  n.log(`Executing function: ${e}`, t);
169
169
  try {
170
170
  const r = await s.handler(t);
171
171
  return n.log(`Function ${e} completed:`, r), r;
172
172
  } catch (r) {
173
- throw n.error(`Function ${e} failed:`, r), new m(`Function "${e}" execution failed: ${r instanceof Error ? r.message : "Unknown error"}`, e, r instanceof Error ? r : void 0);
173
+ throw n.error(`Function ${e} failed:`, r), new g(`Function "${e}" execution failed: ${r instanceof Error ? r.message : "Unknown error"}`, e, r instanceof Error ? r : void 0);
174
174
  }
175
175
  }
176
176
  clear() {
@@ -217,7 +217,7 @@ var E = class {
217
217
  this.callbacks = e, this.buffer = "", this.message = {}, this.toolCalls = [], this.sources = [], this.followUpReplies = [], this.isFirstChunk = !0, this.answerCompleteEmitted = !1;
218
218
  }
219
219
  async processStream(e) {
220
- if (!e.body) throw new g("Response has no body");
220
+ if (!e.body) throw new m("Response has no body");
221
221
  const t = e.body.getReader(), s = new TextDecoder();
222
222
  try {
223
223
  for (; ; ) {
@@ -228,7 +228,7 @@ var E = class {
228
228
  }
229
229
  return this.buffer.trim() && this.processBuffer(), this.buildFinalMessage();
230
230
  } catch (r) {
231
- const i = r instanceof Error ? r : new g("Stream processing failed");
231
+ const i = r instanceof Error ? r : new m("Stream processing failed");
232
232
  throw this.callbacks.onError?.(i), i;
233
233
  } finally {
234
234
  t.releaseLock();
@@ -376,14 +376,14 @@ var S = class {
376
376
  agent_id: s?.agentId || o
377
377
  };
378
378
  r.length > 0 && (a.client_functions = r), i && (a.client_context = i);
379
- let l;
379
+ let c;
380
380
  if (s?.files && s.files.length > 0) {
381
- const c = new FormData();
382
- c.append("content", t), s.conversationId && c.append("conversation_id", s.conversationId), (s.agentId || o) && c.append("agent_id", s.agentId || o || ""), r.length > 0 && c.append("client_functions", JSON.stringify(r)), i && c.append("client_context", JSON.stringify(i));
383
- for (const v of s.files) c.append("files", v);
384
- l = await this.httpClient.postFormData("/api/sdk/v1/messages", c);
385
- } else l = await this.httpClient.postStream("/api/sdk/v1/messages", a);
386
- return this.processSSEResponse(l);
381
+ const l = new FormData();
382
+ l.append("content", t), s.conversationId && l.append("conversation_id", s.conversationId), (s.agentId || o) && l.append("agent_id", s.agentId || o || ""), r.length > 0 && l.append("client_functions", JSON.stringify(r)), i && l.append("client_context", JSON.stringify(i));
383
+ for (const v of s.files) l.append("files", v);
384
+ c = await this.httpClient.postFormData("/api/sdk/v1/messages", l);
385
+ } else c = await this.httpClient.postStream("/api/sdk/v1/messages", a);
386
+ return this.processSSEResponse(c);
387
387
  }
388
388
  async processSSEResponse(t) {
389
389
  return new k({
@@ -483,6 +483,15 @@ var S = class {
483
483
  async rejectToolCall(t) {
484
484
  await this.httpClient.post(`/api/tool-calls/${t}/reject/`);
485
485
  }
486
+ async getFormCollector(t) {
487
+ const s = await this.httpClient.get(`/api/sdk/v1/forms/${encodeURIComponent(t)}`);
488
+ return {
489
+ name: s.name,
490
+ description: s.description,
491
+ schema: s.schema,
492
+ submit: s.submit ?? void 0
493
+ };
494
+ }
486
495
  async submitFormCollector(t, s) {
487
496
  return this.httpClient.post("/api/sdk/v1/forms/submit", {
488
497
  destination: t,
@@ -509,10 +518,10 @@ var S = class {
509
518
  const r = s.map((o) => o.name), i = s.map((o) => `- "${o.name}": ${o.description}`).join(`
510
519
  `);
511
520
  this.registerFunction("navigateToPage", async (o) => {
512
- const a = o.page, l = s.find((c) => c.name === a);
513
- return l ? (t(l.path), {
521
+ const a = o.page, c = s.find((l) => l.name === a);
522
+ return c ? (t(c.path), {
514
523
  success: !0,
515
- navigatedTo: l.path
524
+ navigatedTo: c.path
516
525
  }) : {
517
526
  success: !1,
518
527
  error: `Unknown page: ${a}`
@@ -590,7 +599,7 @@ export {
590
599
  _ as a,
591
600
  h as c,
592
601
  u as d,
593
- g as f,
602
+ m as f,
594
603
  x as i,
595
604
  d as l,
596
605
  S as n,
@@ -598,5 +607,5 @@ export {
598
607
  k as r,
599
608
  n as s,
600
609
  $ as t,
601
- m as u
610
+ g as u
602
611
  };
package/dist/angular.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("./AgoClient-CPqPT5s6.cjs");var n=class{constructor(e){this.client=new o.AgoClient(e),this.messages$=this.fromEvent("message:complete"),this.chunks$=this.fromEvent("message:chunk"),this.errors$=this.fromEvent("message:error"),this.messageStart$=this.fromEvent("message:start")}fromEvent(e){const t=this.client;return{subscribe(i){const s=r=>{i.next?.(r)};return t.on(e,s),{unsubscribe:()=>t.off(e,s)}}}}sendMessage(e,t){return this.client.sendMessage(e,t)}getConversations(){return this.client.getConversations()}getConversation(e){return this.client.getConversation(e)}getMessages(e){return this.client.getMessages(e)}submitToolCallForm(e,t){return this.client.submitToolCallForm(e,t)}confirmToolCall(e){return this.client.confirmToolCall(e)}rejectToolCall(e){return this.client.rejectToolCall(e)}submitFeedback(e,t){return this.client.submitFeedback(e,t)}registerFunction(e,t,i){typeof e=="object"?this.client.registerFunction(e):this.client.registerFunction(e,t,i)}unregisterFunction(e){return this.client.unregisterFunction(e)}registerNavigationFunction(e,t){this.client.registerNavigationFunction(e,t)}on(e,t){this.client.on(e,t)}off(e,t){this.client.off(e,t)}updateConfig(e){this.client.updateConfig(e)}getClient(){return this.client}destroy(){this.client.destroy()}};function c(e){return{provide:n,useValue:new n(e)}}exports.AgoService=n;exports.provideAgo=c;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("./AgoClient-0x2Du_62.cjs");var n=class{constructor(e){this.client=new o.AgoClient(e),this.messages$=this.fromEvent("message:complete"),this.chunks$=this.fromEvent("message:chunk"),this.errors$=this.fromEvent("message:error"),this.messageStart$=this.fromEvent("message:start")}fromEvent(e){const t=this.client;return{subscribe(i){const s=r=>{i.next?.(r)};return t.on(e,s),{unsubscribe:()=>t.off(e,s)}}}}sendMessage(e,t){return this.client.sendMessage(e,t)}getConversations(){return this.client.getConversations()}getConversation(e){return this.client.getConversation(e)}getMessages(e){return this.client.getMessages(e)}submitToolCallForm(e,t){return this.client.submitToolCallForm(e,t)}confirmToolCall(e){return this.client.confirmToolCall(e)}rejectToolCall(e){return this.client.rejectToolCall(e)}submitFeedback(e,t){return this.client.submitFeedback(e,t)}registerFunction(e,t,i){typeof e=="object"?this.client.registerFunction(e):this.client.registerFunction(e,t,i)}unregisterFunction(e){return this.client.unregisterFunction(e)}registerNavigationFunction(e,t){this.client.registerNavigationFunction(e,t)}on(e,t){this.client.on(e,t)}off(e,t){this.client.off(e,t)}updateConfig(e){this.client.updateConfig(e)}getClient(){return this.client}destroy(){this.client.destroy()}};function c(e){return{provide:n,useValue:new n(e)}}exports.AgoService=n;exports.provideAgo=c;
@@ -53,6 +53,13 @@ declare class AgoClient {
53
53
  * Reject a tool call
54
54
  */
55
55
  rejectToolCall(toolCallId: string): Promise<void>;
56
+ /**
57
+ * Fetch a backend-stored form collector definition by name (the single source
58
+ * of truth for the form's description, schema, and submit target). Used by
59
+ * `loadFormCollector` / the name-only form of `useFormCollector` so the schema
60
+ * lives in the backend instead of being hardcoded in client code.
61
+ */
62
+ getFormCollector(name: string): Promise<FormCollectorDefinition>;
56
63
  /**
57
64
  * Relay a completed form collector's values to a server-configured destination.
58
65
  *
@@ -477,6 +484,30 @@ export declare interface Conversation {
477
484
  */
478
485
  declare type DynamicContextProvider = () => ContextEntry | null | undefined;
479
486
 
487
+ /**
488
+ * The backend-stored shape returned by `GET /api/sdk/v1/forms/{name}` (see
489
+ * {@link AgoClient.getFormCollector}). Mirrors the persistable subset of
490
+ * {@link CreateFormCollectorOptions}: the `submit` here is never the client-only
491
+ * `handler` variant (a function can't be stored server-side).
492
+ */
493
+ declare interface FormCollectorDefinition<V = Record<string, unknown>> {
494
+ name: string;
495
+ description: string;
496
+ schema: FormCollectorSchema;
497
+ /** Server-stored submit target, if any. Absent means collect-only. */
498
+ submit?: SubmitConfig<V>;
499
+ }
500
+
501
+ /**
502
+ * Shape of a form's fields. Mirrors a client function's `parameters` (so the same
503
+ * object feeds the store, the update function, and the dynamic context). Additionally allows the SDK-only per-field `requiredWhen`, which {@link toWireParameters} removes before the schema reaches the LLM.
504
+ */
505
+ declare interface FormCollectorSchema {
506
+ type: "object";
507
+ properties: Record<string, FormFieldSchema>;
508
+ required?: string[];
509
+ }
510
+
480
511
  declare interface FormField {
481
512
  type: "string" | "number" | "boolean" | "array";
482
513
  title?: string;
@@ -485,6 +516,43 @@ declare interface FormField {
485
516
  default?: unknown;
486
517
  }
487
518
 
519
+ /**
520
+ * A field's conditional-requiredness rule. The field becomes required exactly
521
+ * when the controlling `property` matches `value` against the answers collected
522
+ * so far:
523
+ * - a single `value`, no `op` — equality (compared as strings);
524
+ * - a single `value` with `op` — numeric comparison (both sides coerced to numbers);
525
+ * - an array `value`, no `op` — "one of": matches when the property equals any
526
+ * listed value.
527
+ *
528
+ * SDK-only — it is stripped from the schema before it reaches the LLM tool
529
+ */
530
+ declare interface FormFieldCondition {
531
+ /** The controlling field whose value the rule tests. */
532
+ property: string;
533
+ /** Comparison operator; omitted means equality. Ignored when `value` is an array. */
534
+ op?: ">=" | "<=" | ">" | "<";
535
+ /**
536
+ * The value(s) to test the controlling field against. A single value is an
537
+ * equality (or, with `op`, a numeric comparison); an array is an "is one of"
538
+ * membership test, e.g. `value: ["1", "2", "3"]`.
539
+ */
540
+ value: string | number | Array<string | number>;
541
+ }
542
+
543
+ /** A single field's schema: the wire-legal keys plus the SDK-only `requiredWhen`. */
544
+ declare interface FormFieldSchema {
545
+ type: string;
546
+ description?: string;
547
+ enum?: string[];
548
+ default?: unknown;
549
+ /**
550
+ * Makes the field required only while this condition holds. Drives the dynamic
551
+ * `missing` list; stripped before the LLM tool — see {@link toWireParameters}.
552
+ */
553
+ requiredWhen?: FormFieldCondition;
554
+ }
555
+
488
556
  /**
489
557
  * Form schema for tool calls requiring user input
490
558
  */
@@ -541,6 +609,27 @@ declare interface SendMessageOptions {
541
609
  files?: File[];
542
610
  }
543
611
 
612
+ /**
613
+ * Where a completed form is sent.
614
+ * - `"https://..."` (a bare string) — shorthand for `{ via: "client", url }`: the browser
615
+ * POSTs the values to that URL.
616
+ * - `{ via: "client", url }` — same, written out.
617
+ * - `{ via: "client", handler }` — the browser runs your own submit logic.
618
+ * - `{ via: "backend", destination }` — the browser relays the values to the backend,
619
+ * which forwards them to the server-configured destination (URL + secret stay server-side).
620
+ * - `false` — collect only, no submit function.
621
+ */
622
+ declare type SubmitConfig<V = Record<string, unknown>> = string | {
623
+ via: "client";
624
+ url: string;
625
+ } | {
626
+ via: "client";
627
+ handler: (values: V) => Promise<unknown> | unknown;
628
+ } | {
629
+ via: "backend";
630
+ destination: string;
631
+ } | false;
632
+
544
633
  /**
545
634
  * Tool call data from SSE stream
546
635
  */