@useago/sdk 1.4.1 → 1.4.3
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 +4 -1
- package/dist/AgoClient-CMDVqNaH.cjs +8 -0
- package/dist/{AgoClient-BdtuHX7k.js → AgoClient-S8oeNnAE.js} +273 -157
- package/dist/angular.cjs +1 -1
- package/dist/angular.d.cts +121 -4
- package/dist/angular.d.ts +121 -4
- package/dist/angular.js +1 -1
- package/dist/{createConversationSession-B8zfTL78.cjs → createConversationSession-CmBq7uGi.cjs} +1 -1
- package/dist/{createConversationSession-CWpf4u6I.js → createConversationSession-DoUHdVNR.js} +1 -1
- package/dist/{createFormCollector-BB_l0Sia.cjs → createFormCollector-Bz_0IJ0Q.cjs} +1 -1
- package/dist/{createFormCollector-B4n0_diV.js → createFormCollector-vy-QvFja.js} +1 -1
- package/dist/createMockClient-BSr-UV8R.cjs +1 -0
- package/dist/{createMockClient-d-arlmCq.js → createMockClient-bAZ9KBHC.js} +18 -15
- package/dist/devtools.d.cts +120 -3
- package/dist/devtools.d.ts +120 -3
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +132 -3
- package/dist/index.d.ts +132 -3
- package/dist/index.js +4 -4
- package/dist/react.cjs +3 -3
- package/dist/react.d.cts +134 -9
- package/dist/react.d.ts +134 -9
- package/dist/react.js +419 -401
- package/dist/testing.cjs +1 -1
- package/dist/testing.d.cts +120 -3
- package/dist/testing.d.ts +120 -3
- package/dist/testing.js +1 -1
- package/dist/vue.cjs +1 -1
- package/dist/vue.d.cts +127 -4
- package/dist/vue.d.ts +127 -4
- package/dist/vue.js +1 -1
- package/dist/widget.cjs +3 -3
- package/dist/widget.d.cts +120 -3
- package/dist/widget.d.ts +120 -3
- package/dist/widget.js +120 -120
- package/package.json +1 -1
- package/dist/AgoClient-CRAnT4qE.cjs +0 -8
- package/dist/createMockClient-ucPENDzz.cjs +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -50,12 +50,45 @@ export declare class AgoClient {
|
|
|
50
50
|
private config;
|
|
51
51
|
/** Conversations already warned about an empty reply (one warning each). */
|
|
52
52
|
private warnedEmptyConversations;
|
|
53
|
+
/** Paused turns awaiting auto-resume, keyed by assistant message id. */
|
|
54
|
+
private pendingResumes;
|
|
55
|
+
/** App-provided gate deciding WHEN a paused turn resumes (see {@link registerResumeGate}). */
|
|
56
|
+
private resumeGate;
|
|
53
57
|
constructor(config: AgoConfig);
|
|
54
58
|
/**
|
|
55
59
|
* Send a message and receive a streaming response
|
|
56
60
|
*/
|
|
57
61
|
sendMessage(content: string, options?: SendMessageOptions): Promise<AgoMessage>;
|
|
58
62
|
private processSSEResponse;
|
|
63
|
+
private resolveClientFunctionsMode;
|
|
64
|
+
/**
|
|
65
|
+
* Register a gate deciding WHEN a paused turn resumes. The SDK still decides
|
|
66
|
+
* *whether* (it resumes once every waiting result is submitted); the gate only
|
|
67
|
+
* delays the continue call — e.g. `useAgoAutoContinueAfterNavigation` waits for
|
|
68
|
+
* the destination page to register its page state. One gate at a time (last
|
|
69
|
+
* registration wins). Returns an unregister function.
|
|
70
|
+
*/
|
|
71
|
+
registerResumeGate(gate: ResumeGate): () => void;
|
|
72
|
+
/**
|
|
73
|
+
* Resume a turn paused on client function results (`WAITING_CLIENT`).
|
|
74
|
+
*
|
|
75
|
+
* Sends the CURRENT page's registered functions and context — the page may
|
|
76
|
+
* have changed since the pause (that's the point of pausing on a navigation) —
|
|
77
|
+
* and streams the continuation through the same event pipeline as
|
|
78
|
+
* `sendMessage`, so `message:chunk` / `message:complete` (or another
|
|
79
|
+
* `message:waiting-client` for chained pauses) fire as usual.
|
|
80
|
+
*
|
|
81
|
+
* The SDK calls this automatically after submitting the waiting results; call
|
|
82
|
+
* it manually only for custom flows (e.g. after restoring a reloaded page via
|
|
83
|
+
* {@link resumePendingClientFunctions}).
|
|
84
|
+
*/
|
|
85
|
+
continueMessage(messageId: string): Promise<AgoMessage>;
|
|
86
|
+
/**
|
|
87
|
+
* Record one of the two auto-resume preconditions for a paused turn and fire
|
|
88
|
+
* the resume when both are in (see {@link PendingResume}).
|
|
89
|
+
*/
|
|
90
|
+
private markResumeSignal;
|
|
91
|
+
private runAutoResume;
|
|
59
92
|
/**
|
|
60
93
|
* Detect a reply that completed as DONE with no content and no activity —
|
|
61
94
|
* today's backend answers an unknown `agent` slug with an empty 200, which
|
|
@@ -88,9 +121,25 @@ export declare class AgoClient {
|
|
|
88
121
|
*/
|
|
89
122
|
getMessages(conversationId: string): Promise<AgoMessage[]>;
|
|
90
123
|
/**
|
|
91
|
-
*
|
|
124
|
+
* Resume a turn left paused on client function results by a page reload.
|
|
125
|
+
*
|
|
126
|
+
* A paused turn (pause mode) survives a full reload: the backend keeps the
|
|
127
|
+
* assistant message in `WAITING_CLIENT` with its waiting tool calls. After
|
|
128
|
+
* restoring the conversation (`getConversation`) and re-registering the page's
|
|
129
|
+
* functions, call this: it re-executes each waiting client function through the
|
|
130
|
+
* registry, submits the results, and continues the turn.
|
|
131
|
+
*
|
|
132
|
+
* Opt-in on purpose — re-running functions on reload can be surprising (e.g. a
|
|
133
|
+
* navigation function would navigate again), so the app decides. Returns the
|
|
134
|
+
* resumed turn's final message, or `null` when there was nothing to resume or
|
|
135
|
+
* some waiting function is not registered on this page.
|
|
92
136
|
*/
|
|
93
|
-
|
|
137
|
+
resumePendingClientFunctions(conversation: Conversation): Promise<AgoMessage | null>;
|
|
138
|
+
/**
|
|
139
|
+
* Submit form data for a tool call. The response's `resume` field (pause mode
|
|
140
|
+
* only) tells whether the paused turn is ready to be resumed.
|
|
141
|
+
*/
|
|
142
|
+
submitToolCallForm(toolCallId: string, formData: Record<string, unknown>): Promise<SubmitToolCallResult>;
|
|
94
143
|
/**
|
|
95
144
|
* Confirm a tool call
|
|
96
145
|
*/
|
|
@@ -163,6 +212,12 @@ export declare class AgoClient {
|
|
|
163
212
|
* the agent know *where* it is after it navigates (e.g. so auto-continuation
|
|
164
213
|
* can apply page state on the destination), not just how to navigate away.
|
|
165
214
|
*
|
|
215
|
+
* Routes may contain `:param` placeholders (`/users/:id`). Each distinct
|
|
216
|
+
* placeholder becomes a top-level string argument of `navigateToPage`
|
|
217
|
+
* (`{ page: "userDetail", id: "42" }`), so one route covers every detail
|
|
218
|
+
* page of an entity. Flat arguments only: nested object parameters are not
|
|
219
|
+
* reliably rendered to the model, so placeholders must not be named `page`.
|
|
220
|
+
*
|
|
166
221
|
* @param navigate - A callback that performs the navigation (e.g. react-router's navigate)
|
|
167
222
|
* @param routes - Map of route names to paths, with descriptions for the LLM
|
|
168
223
|
*/
|
|
@@ -330,6 +385,19 @@ export declare interface AgoClientEvents {
|
|
|
330
385
|
*/
|
|
331
386
|
"message:answer-complete": AgoMessage;
|
|
332
387
|
"message:complete": AgoMessage;
|
|
388
|
+
/**
|
|
389
|
+
* The turn paused on client function call(s) (pause mode): the stream closed
|
|
390
|
+
* with status `WAITING_CLIENT` instead of `DONE`. `message:complete` does NOT
|
|
391
|
+
* fire for this stream — it fires when the resumed turn concludes, so one
|
|
392
|
+
* logical turn still emits exactly one `message:complete`. The SDK submits the
|
|
393
|
+
* function results and resumes automatically; listen to this to know the agent
|
|
394
|
+
* is waiting on the page (e.g. to keep a "working…" indicator up).
|
|
395
|
+
*/
|
|
396
|
+
"message:waiting-client": {
|
|
397
|
+
conversationId: string;
|
|
398
|
+
messageId: string;
|
|
399
|
+
waitingToolCallIds: string[];
|
|
400
|
+
};
|
|
333
401
|
/**
|
|
334
402
|
* A reply finished as `DONE` with empty content and no tool calls, client
|
|
335
403
|
* functions, or follow-up replies — usually an unknown `agent` slug (the
|
|
@@ -417,6 +485,16 @@ export declare interface AgoConfig {
|
|
|
417
485
|
* event fires regardless of this setting.
|
|
418
486
|
*/
|
|
419
487
|
warnOnEmptyReply?: boolean;
|
|
488
|
+
/**
|
|
489
|
+
* How the agent loop treats client function calls (requires backend support):
|
|
490
|
+
* - `"placeholder"` (default): the turn continues immediately on a placeholder
|
|
491
|
+
* result; the real result is only visible to the agent on later turns.
|
|
492
|
+
* - `"pause"`: the turn stops on client function call(s) with status
|
|
493
|
+
* `WAITING_CLIENT`; once every result is submitted, the SDK resumes the SAME
|
|
494
|
+
* turn via `POST /messages/{id}/continue`, so the agent sees the real results.
|
|
495
|
+
* Older backends ignore the flag, so `"pause"` degrades to legacy behavior.
|
|
496
|
+
*/
|
|
497
|
+
clientFunctionsMode?: ClientFunctionsMode;
|
|
420
498
|
}
|
|
421
499
|
|
|
422
500
|
/**
|
|
@@ -694,6 +772,9 @@ export declare interface ClientFunctionSchema {
|
|
|
694
772
|
};
|
|
695
773
|
}
|
|
696
774
|
|
|
775
|
+
/** See {@link AgoConfig.clientFunctionsMode}. */
|
|
776
|
+
export declare type ClientFunctionsMode = "placeholder" | "pause";
|
|
777
|
+
|
|
697
778
|
/**
|
|
698
779
|
* A single piece of context the client wants the LLM to know about.
|
|
699
780
|
*/
|
|
@@ -1276,7 +1357,13 @@ declare class Logger {
|
|
|
1276
1357
|
|
|
1277
1358
|
export declare const logger: Logger;
|
|
1278
1359
|
|
|
1279
|
-
export declare type MessageStatus = "IN_PROGRESS" | "DONE" | "ERROR" | "TODO" | "CANCELED"
|
|
1360
|
+
export declare type MessageStatus = "IN_PROGRESS" | "DONE" | "ERROR" | "TODO" | "CANCELED"
|
|
1361
|
+
/**
|
|
1362
|
+
* The turn paused on client function call(s) (pause mode): the agent waits for
|
|
1363
|
+
* every waiting call to be submitted, then the turn resumes via
|
|
1364
|
+
* `continueMessage`. Not a final state.
|
|
1365
|
+
*/
|
|
1366
|
+
| "WAITING_CLIENT";
|
|
1280
1367
|
|
|
1281
1368
|
export declare interface MockAgoClient extends AgoClient {
|
|
1282
1369
|
/**
|
|
@@ -1386,6 +1473,17 @@ export declare interface RegisteredFunction {
|
|
|
1386
1473
|
handler: ClientFunctionHandler;
|
|
1387
1474
|
}
|
|
1388
1475
|
|
|
1476
|
+
/**
|
|
1477
|
+
* Hook run before a paused turn is resumed, so the app controls WHEN the
|
|
1478
|
+
* continuation fires (e.g. wait for the destination page to mount after a
|
|
1479
|
+
* navigation). It must resolve — throwing or hanging blocks the resume; on
|
|
1480
|
+
* timeout-style situations resolve anyway and let the agent conclude.
|
|
1481
|
+
*/
|
|
1482
|
+
export declare type ResumeGate = (info: {
|
|
1483
|
+
conversationId: string;
|
|
1484
|
+
messageId: string;
|
|
1485
|
+
}) => Promise<void> | void;
|
|
1486
|
+
|
|
1389
1487
|
/**
|
|
1390
1488
|
* Allow only URL schemes that are safe to put in an `<img src>` / `<a href>`.
|
|
1391
1489
|
* Presigned attachment URLs are `https:` and optimistic previews are `blob:`;
|
|
@@ -1417,6 +1515,8 @@ export declare interface SendMessageOptions {
|
|
|
1417
1515
|
* Requires backend support for the `hidden` flag; older backends ignore it.
|
|
1418
1516
|
*/
|
|
1419
1517
|
hidden?: boolean;
|
|
1518
|
+
/** Per-message override of {@link AgoConfig.clientFunctionsMode}. */
|
|
1519
|
+
clientFunctionsMode?: ClientFunctionsMode;
|
|
1420
1520
|
}
|
|
1421
1521
|
|
|
1422
1522
|
/**
|
|
@@ -1491,6 +1591,8 @@ export declare interface SSEChunkData {
|
|
|
1491
1591
|
follow_up_replies?: string[];
|
|
1492
1592
|
satisfaction_feedback?: unknown;
|
|
1493
1593
|
ask_to_talk_to_human?: boolean;
|
|
1594
|
+
/** Tool call ids still awaiting a client result, sent with the final `WAITING_CLIENT` event. */
|
|
1595
|
+
waiting_tool_call_ids?: string[];
|
|
1494
1596
|
}
|
|
1495
1597
|
|
|
1496
1598
|
/**
|
|
@@ -1505,6 +1607,7 @@ export declare class SSEHandler {
|
|
|
1505
1607
|
private followUpReplies;
|
|
1506
1608
|
private isFirstChunk;
|
|
1507
1609
|
private answerCompleteEmitted;
|
|
1610
|
+
private waitingClientEmitted;
|
|
1508
1611
|
private firedClientFunctions;
|
|
1509
1612
|
constructor(callbacks: SSEHandlerCallbacks);
|
|
1510
1613
|
/**
|
|
@@ -1547,6 +1650,17 @@ declare interface SSEHandlerCallbacks {
|
|
|
1547
1650
|
* with the message as it stands at that moment (no `followUpReplies` yet).
|
|
1548
1651
|
*/
|
|
1549
1652
|
onAnswerComplete?: (message: AgoMessage) => void;
|
|
1653
|
+
/**
|
|
1654
|
+
* The turn paused on client function call(s) (pause mode): the backend closed
|
|
1655
|
+
* the stream with `status: "WAITING_CLIENT"` and the tool call ids awaiting a
|
|
1656
|
+
* result. {@link onComplete} does NOT fire for this stream — the turn is not
|
|
1657
|
+
* over; it resumes in a separate request once every result is submitted.
|
|
1658
|
+
*/
|
|
1659
|
+
onWaitingClient?: (data: {
|
|
1660
|
+
conversationId: string;
|
|
1661
|
+
messageId: string;
|
|
1662
|
+
waitingToolCallIds: string[];
|
|
1663
|
+
}) => void;
|
|
1550
1664
|
onComplete?: (message: AgoMessage) => void;
|
|
1551
1665
|
onError?: (error: Error) => void;
|
|
1552
1666
|
}
|
|
@@ -1602,6 +1716,21 @@ export declare type SubmitConfig<V = Record<string, unknown>> = string | {
|
|
|
1602
1716
|
*/
|
|
1603
1717
|
export declare const submitForm: ClientFunctionDefinition;
|
|
1604
1718
|
|
|
1719
|
+
/**
|
|
1720
|
+
* Response of `POST /tool-calls/{id}/submit`. `resume` is only present when the
|
|
1721
|
+
* tool call belongs to a turn paused on client functions (pause mode): `ready`
|
|
1722
|
+
* flips to `true` once ALL waiting calls of that message are submitted, meaning
|
|
1723
|
+
* the turn can be resumed via `continueMessage(resume.message_id)`.
|
|
1724
|
+
*/
|
|
1725
|
+
export declare interface SubmitToolCallResult {
|
|
1726
|
+
status: string;
|
|
1727
|
+
result?: unknown;
|
|
1728
|
+
resume?: {
|
|
1729
|
+
message_id: string;
|
|
1730
|
+
ready: boolean;
|
|
1731
|
+
};
|
|
1732
|
+
}
|
|
1733
|
+
|
|
1605
1734
|
/**
|
|
1606
1735
|
* Tool call data from SSE stream
|
|
1607
1736
|
*/
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { a as h, c as A, d as y, f as C, i as E, l as S, m as b, o as v, p as F, r as M, s as I, t as k, u as T } from "./functions-CApuQZ2b.js";
|
|
2
|
-
import { _ as G, a as O, c as _, d as q, f as x, g as L, h as N, l as D, m as d, n as H, o as J, p as R, r as j, s as z, t as c, u as B } from "./AgoClient-
|
|
3
|
-
import { i as $, n as K, r as Q, t as V } from "./createFormCollector-
|
|
4
|
-
import { t as X } from "./createConversationSession-
|
|
5
|
-
import { t as Z } from "./createMockClient-
|
|
2
|
+
import { _ as G, a as O, c as _, d as q, f as x, g as L, h as N, l as D, m as d, n as H, o as J, p as R, r as j, s as z, t as c, u as B } from "./AgoClient-S8oeNnAE.js";
|
|
3
|
+
import { i as $, n as K, r as Q, t as V } from "./createFormCollector-vy-QvFja.js";
|
|
4
|
+
import { t as X } from "./createConversationSession-DoUHdVNR.js";
|
|
5
|
+
import { t as Z } from "./createMockClient-bAZ9KBHC.js";
|
|
6
6
|
import "./testing.js";
|
|
7
7
|
function oe(e) {
|
|
8
8
|
return e;
|
package/dist/react.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
2
|
-
`)?(0,o.jsx)("code",{style:{display:"block",background:"#f5f5f5",padding:"8px 12px",borderRadius:"6px",fontSize:"13px",overflowX:"auto",fontFamily:'"IBM Plex Mono", monospace'},...r,children:
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const W=require("./rolldown-runtime-16Nf8qvH.cjs"),F=require("./AgoClient-CMDVqNaH.cjs"),M=require("./createFormCollector-Bz_0IJ0Q.cjs"),V=require("./createMockClient-BSr-UV8R.cjs");let s=require("react");s=W.__toESM(s,1);let o=require("react/jsx-runtime"),P=require("react-markdown");P=W.__toESM(P,1);let T=require("remark-gfm");T=W.__toESM(T,1);function H(e){const[n,r]=(0,s.useState)(!1),t=(0,s.useRef)(null),a=(0,s.useMemo)(()=>{if(t.current&&(t.current.destroy(),t.current=null),!e)return null;const l=new F.AgoClient(e);return t.current=l,l},[e?.baseUrl,e?.widgetId]);return(0,s.useEffect)(()=>(r(!0),()=>{t.current?.destroy(),t.current=null}),[a]),(0,s.useEffect)(()=>{t.current&&e&&t.current.updateConfig({agent:e.agent,defaultAgentId:e.defaultAgentId,permission:e.permission,userEmail:e.userEmail,userJwt:e.userJwt,debug:e.debug,warnOnEmptyReply:e.warnOnEmptyReply})},[e?.agent,e?.defaultAgentId,e?.permission,e?.userEmail,e?.userJwt,e?.debug,e?.warnOnEmptyReply]),{client:a,isReady:n}}var D=(0,s.createContext)(null),Y=({children:e,client:n,tools:r,helpers:t,pageContext:a,...l})=>{const{client:d}=H(n?null:l),c=n||d;return(0,s.useEffect)(()=>{if(!(!r||r.length===0)){for(const p of r)c.register(p);return()=>{for(const p of r)c.unregisterFunction(p.name)}}},[c,r]),(0,s.useEffect)(()=>{if(!t)return;const p=[];return Promise.resolve().then(()=>require("./functions-Djnq-JAo.cjs")).then(u=>u.functions_exports).then(u=>{for(const[C,b]of Object.entries(t)){const I=u[C];if(!I){console.warn(`[AGO] Unknown helper: "${C}"`);continue}const g=b===!0?I:{...I,handler:b};c.register(g),p.push(g.name)}}),()=>{for(const u of p)c.unregisterFunction(u)}},[c,t]),(0,s.useEffect)(()=>{a==="auto"&&c.enableAutoPageContext()},[c,a]),(0,o.jsx)(D.Provider,{value:c,children:e})};function E(){const e=(0,s.useContext)(D);if(!e)throw new Error('useAgoClient must be used within an <AgoProvider>. Wrap your component tree with <AgoProvider baseUrl="...">.');return e}function _(){return(0,s.useContext)(D)}function L({client:e,conversationId:n}={}){const r=_(),t=e||r;if(!t)throw new Error("useMessages requires an AgoClient. Either pass it as options.client or wrap your app in <AgoProvider>.");const[a,l]=(0,s.useState)([]),[d,c]=(0,s.useState)(n),[p,u]=(0,s.useState)(!1),[C,b]=(0,s.useState)(null);(0,s.useEffect)(()=>{n&&n!==d&&(c(n),I(n))},[n]);const I=async g=>{try{l((await t.getMessages(g)).filter(m=>!m.hidden))}catch(m){b(m instanceof Error?m:new Error("Failed to load messages"))}};return(0,s.useEffect)(()=>{const g=f=>f==="IN_PROGRESS"||f==="WAITING_CLIENT",m=f=>{d||c(f.conversationId),u(!0),l(x=>{const v=x.findIndex(h=>h.id===f.messageId);return v>=0?x.map((h,N)=>N===v?{...h,status:"IN_PROGRESS"}:h):x.some(h=>h.role==="assistant"&&g(h.status))?x:[...x,{id:f.messageId,conversationId:f.conversationId,content:"",role:"assistant",status:"IN_PROGRESS",createdAt:new Date}]})},S=f=>{l(x=>{const v=x.findIndex(h=>h.id===f.messageId);return v<0?x:x.map((h,N)=>N===v?{...h,content:h.content+f.content}:h)})},w=f=>{l(x=>{let v=-1;for(let h=x.length-1;h>=0;h--)if(x[h].role==="assistant"&&g(x[h].status)){v=h;break}return v<0?x:[...x.slice(0,v),{...x[v],...f},...x.slice(v+1)]})},i=f=>{l(x=>{const v=x.findIndex(h=>h.id===f.id);return v>=0?[...x.slice(0,v),f,...x.slice(v+1)]:[...x,f]}),u(!1)},y=f=>{b(new Error(f.error)),u(!1)};return t.on("message:start",m),t.on("message:chunk",S),t.on("message:answer-complete",w),t.on("message:complete",i),t.on("message:error",y),()=>{t.off("message:start",m),t.off("message:chunk",S),t.off("message:answer-complete",w),t.off("message:complete",i),t.off("message:error",y)}},[t,d]),{messages:a,isLoading:p,error:C,sendMessage:(0,s.useCallback)(async(g,m)=>{u(!0),b(null);const S={id:`temp-${Date.now()}`,conversationId:d||"",content:g,role:"user",status:"DONE",attachments:m&&m.length>0?F.attachmentsFromFiles(m):void 0,createdAt:new Date},w={id:`temp-assistant-${Date.now()}`,conversationId:d||"",content:"",role:"assistant",status:"IN_PROGRESS",createdAt:new Date};l(i=>[...i,S,w]);try{const i=await t.sendMessage(g,{conversationId:d,files:m});return i.conversationId&&!d&&c(i.conversationId),l(y=>{const f=y.filter(v=>!v.id.startsWith("temp-")),x={...S,id:S.id.replace("temp-","user-"),conversationId:i.conversationId};return f.some(v=>v.id===i.id)?[...f,x].sort((v,h)=>new Date(v.createdAt).getTime()-new Date(h.createdAt).getTime()):[...f,x,i]}),i}catch(i){return b(i instanceof Error?i:new Error("Failed to send message")),u(!1),l(y=>y.filter(f=>!f.id.startsWith("temp-"))),null}},[t,d]),clearMessages:(0,s.useCallback)(()=>{l([]),c(void 0),b(null)},[]),conversationId:d}}var q=({onSend:e,disabled:n=!1,placeholder:r="Type a message...",allowFiles:t=!1,className:a=""})=>{const[l,d]=(0,s.useState)(""),[c,p]=(0,s.useState)([]),u=(0,s.useRef)(null),C=(0,s.useRef)(null),b=(0,s.useCallback)(()=>{const i=C.current;if(!i)return;const y=110;i.style.height="auto",i.style.height=`${Math.min(i.scrollHeight+2,y)}px`,i.style.overflowY=i.scrollHeight+2>y?"auto":"hidden"},[]),I=(0,s.useCallback)(i=>{i.preventDefault(),(l.trim()||c.length>0)&&(e(l.trim(),c.length>0?c:void 0),d(""),p([]),requestAnimationFrame(b))},[l,c,e,b]),g=(0,s.useCallback)(i=>{i.key==="Enter"&&!i.shiftKey&&(i.preventDefault(),I(i))},[I]),m=(0,s.useCallback)(i=>{const y=Array.from(i.target.files||[]);p(f=>[...f,...y])},[]),S=(0,s.useCallback)(i=>{p(y=>y.filter((f,x)=>x!==i))},[]),w=l.trim()||c.length>0;return(0,o.jsxs)("form",{onSubmit:I,className:`ago-chat-input ${a}`,style:{display:"flex",flexDirection:"column",gap:"8px",padding:"12px 16px",borderTop:"1px solid #dee3e8",backgroundColor:"#fff"},children:[c.length>0&&(0,o.jsx)("div",{className:"ago-chat-input__files",style:{display:"flex",flexWrap:"wrap",gap:"6px"},children:c.map((i,y)=>(0,o.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:"6px",padding:"4px 10px",backgroundColor:"#f0f2f5",borderRadius:"6px",fontSize:"12px",color:"#30373e"},children:[(0,o.jsx)("span",{style:{maxWidth:"120px",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:i.name}),(0,o.jsx)("button",{type:"button",onClick:()=>S(y),"aria-label":`Remove ${i.name}`,style:{border:"none",background:"none",cursor:"pointer",padding:"0",color:"#6b6d6f",fontSize:"14px",lineHeight:1},children:"×"})]},y))}),(0,o.jsxs)("div",{style:{display:"flex",gap:"8px",alignItems:"flex-end"},children:[t&&(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)("button",{type:"button",onClick:()=>u.current?.click(),disabled:n,"aria-label":"Attach file",style:{padding:"8px",border:"1px solid #dee3e8",borderRadius:"8px",backgroundColor:"#fff",cursor:n?"not-allowed":"pointer",color:"#6b6d6f",fontSize:"16px",lineHeight:1},children:"+"}),(0,o.jsx)("input",{ref:u,type:"file",multiple:!0,onChange:m,style:{display:"none"}})]}),(0,o.jsx)("textarea",{ref:C,value:l,onChange:i=>{d(i.target.value),b()},onKeyDown:g,placeholder:r,"aria-label":r,disabled:n,rows:1,style:{flex:1,padding:"10px 14px",border:"1px solid #dee3e8",borderRadius:"20px",resize:"none",outline:"none",boxSizing:"border-box",maxHeight:"110px",overflowY:"hidden",fontFamily:"inherit",fontSize:"16px",lineHeight:1.4,color:"#30373e",backgroundColor:"#f8f8f8",transition:"border-color 0.15s"},onFocus:i=>{i.currentTarget.style.borderColor="#1b5fc4"},onBlur:i=>{i.currentTarget.style.borderColor="#dee3e8"}}),(0,o.jsx)("button",{type:"submit",disabled:n||!w,style:{padding:"10px 18px",border:"none",borderRadius:"20px",backgroundColor:n||!w?"#b5bfc8":"#03182f",color:"#fff",cursor:n||!w?"not-allowed":"pointer",fontWeight:500,fontSize:"16px",transition:"background-color 0.15s"},children:"Send"})]})]})},X=({href:e,children:n,...r})=>(0,o.jsx)("a",{href:e,target:"_blank",rel:"noopener noreferrer",style:{color:"#1b5fc4",textDecoration:"underline"},...r,children:n}),Q=({children:e,...n})=>(0,o.jsx)("p",{style:{margin:"0 0 8px 0",lineHeight:"1.6"},...n,children:e}),R=(e,n)=>{const r=({children:t,...a})=>s.default.createElement(`h${e}`,{style:{margin:"16px 0 8px 0",fontSize:n,fontWeight:600,lineHeight:"1.3"},...a},t);return r.displayName=`MarkdownHeading${e}`,r},Z=({children:e,...n})=>(0,o.jsx)("ul",{style:{margin:"0 0 8px 0",paddingLeft:"20px",listStyleType:"disc",listStylePosition:"outside"},...n,children:e}),ee=({children:e,...n})=>(0,o.jsx)("ol",{style:{margin:"0 0 8px 0",paddingLeft:"20px",listStyleType:"decimal",listStylePosition:"outside"},...n,children:e}),te=({children:e,...n})=>(0,o.jsx)("li",{style:{display:"list-item",margin:"2px 0",lineHeight:"1.6"},...n,children:e}),ne=({className:e,children:n,...r})=>e!==void 0||String(n).includes(`
|
|
2
|
+
`)?(0,o.jsx)("code",{style:{display:"block",background:"#f5f5f5",padding:"8px 12px",borderRadius:"6px",fontSize:"13px",overflowX:"auto",fontFamily:'"IBM Plex Mono", monospace'},...r,children:n}):(0,o.jsx)("code",{style:{background:"#f0f2f5",padding:"2px 5px",borderRadius:"4px",fontSize:"13px",fontFamily:'"IBM Plex Mono", monospace'},...r,children:n}),re=({children:e,...n})=>(0,o.jsx)("pre",{style:{margin:"0 0 8px 0"},...n,children:e}),oe=({children:e,...n})=>(0,o.jsx)("blockquote",{style:{borderLeft:"4px solid #dee3e8",paddingLeft:"12px",margin:"0 0 8px 0",fontStyle:"italic",color:"#6b6d6f"},...n,children:e}),se=({children:e,...n})=>(0,o.jsx)("div",{style:{overflowX:"auto",margin:"0 0 8px 0"},children:(0,o.jsx)("table",{style:{borderCollapse:"collapse",width:"100%",fontSize:"13px"},...n,children:e})}),ae=({children:e,...n})=>(0,o.jsx)("th",{style:{border:"1px solid #dee3e8",padding:"6px 10px",textAlign:"left",backgroundColor:"#f5f7fa",fontWeight:600},...n,children:e}),ie=({children:e,...n})=>(0,o.jsx)("td",{style:{border:"1px solid #dee3e8",padding:"6px 10px"},...n,children:e}),le=({alt:e,...n})=>(0,o.jsx)("img",{alt:e??"",style:{maxWidth:"100%",borderRadius:"8px",margin:"4px 0"},...n}),ce=e=>(0,o.jsx)("hr",{style:{border:"none",borderTop:"1px solid #dee3e8",margin:"12px 0"},...e}),de={a:X,p:Q,h1:R(1,"20px"),h2:R(2,"18px"),h3:R(3,"16px"),h4:R(4,"15px"),h5:R(5,"14px"),h6:R(6,"13px"),ul:Z,ol:ee,li:te,code:ne,pre:re,blockquote:oe,table:se,th:ae,td:ie,img:le,hr:ce},ue=[T.default],$=({content:e})=>(0,o.jsx)(P.default,{remarkPlugins:ue,components:de,children:e}),fe=({attachment:e,isUser:n})=>{const r=F.safeAttachmentUrl(e.url);if(F.canInlineImage(e))return(0,o.jsx)("a",{href:r,target:"_blank",rel:"noopener noreferrer",style:{display:"inline-block",textDecoration:"none"},children:(0,o.jsx)("img",{src:r,alt:e.name,loading:"lazy",style:{maxWidth:"180px",maxHeight:"160px",objectFit:"cover",borderRadius:"10px",border:"1px solid #dee3e8",display:"block"}})});const t=F.formatFileSize(e.fileSize),a=(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)("span",{style:{fontSize:"16px",lineHeight:1,flexShrink:0},"aria-hidden":!0,children:"📄"}),(0,o.jsxs)("span",{style:{display:"flex",flexDirection:"column",minWidth:0},children:[(0,o.jsx)("span",{style:{overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",maxWidth:"160px"},title:e.name,children:e.name}),t&&(0,o.jsx)("span",{style:{fontSize:"11px",color:"#6b6d6f"},children:t})]})]}),l={display:"inline-flex",alignItems:"center",gap:"8px",padding:"8px 12px",borderRadius:"10px",border:"1px solid #dee3e8",backgroundColor:n?"rgba(255,255,255,0.12)":"#fff",color:n?"#fff":"#30373e",fontSize:"13px",textDecoration:"none",maxWidth:"220px"};return r?(0,o.jsx)("a",{href:r,target:"_blank",rel:"noopener noreferrer",style:l,children:a}):(0,o.jsx)("div",{style:l,children:a})},ge=({source:e,index:n})=>{const r=(0,o.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:"8px",width:"100%",minWidth:0},children:[(0,o.jsx)("div",{style:{flexShrink:0,width:"18px",height:"18px",borderRadius:"3px",border:"1px solid #1b5fc4",color:"#1b5fc4",fontSize:"11px",fontWeight:500,display:"flex",alignItems:"center",justifyContent:"center",backgroundColor:"#f0f4ff"},children:n+1}),(0,o.jsx)("div",{style:{fontSize:"12px",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",color:"#30373e"},title:e.title,children:e.title})]}),t={display:"flex",alignItems:"center",padding:"8px 10px",border:"1px solid #dee3e8",borderRadius:"8px",backgroundColor:"#fff",cursor:e.url?"pointer":"default",textDecoration:"none",color:"inherit",minWidth:0,transition:"border-color 0.15s"};return e.url?(0,o.jsx)("a",{href:e.url,target:"_blank",rel:"noopener noreferrer",style:t,onMouseEnter:a=>{a.currentTarget.style.borderColor="#1b5fc4"},onMouseLeave:a=>{a.currentTarget.style.borderColor="#dee3e8"},children:r}):(0,o.jsx)("div",{style:t,children:r})},pe=()=>(0,o.jsxs)("div",{style:{display:"flex",gap:"4px",padding:"4px 0"},children:[[0,1,2].map(e=>(0,o.jsx)("div",{style:{width:"6px",height:"6px",borderRadius:"50%",backgroundColor:"#b5bfc8",animation:"ago-pulse 1.2s ease-in-out infinite",animationDelay:`${e*.2}s`}},e)),(0,o.jsx)("style",{children:`
|
|
3
3
|
@keyframes ago-pulse {
|
|
4
4
|
0%, 80%, 100% { opacity: 0.3; transform: scale(0.8); }
|
|
5
5
|
40% { opacity: 1; transform: scale(1); }
|
|
6
6
|
}
|
|
7
|
-
`})]}),$=({message:e,className:t="",showAgentName:r=!1,isLast:n=!1,onFollowUpClick:a})=>{const l=e.role==="user",d=e.status==="IN_PROGRESS";return(0,o.jsxs)("div",{className:`ago-message ago-message--${e.role} ${t}`,style:{display:"flex",flexDirection:"column",alignItems:l?"flex-end":"flex-start",marginBottom:"16px"},children:[!l&&r&&e.agent&&(0,o.jsx)("div",{className:"ago-message__agent",style:{display:"flex",alignItems:"center",gap:"6px",fontSize:"13px",fontWeight:500,color:"#30373e",marginBottom:"6px",padding:"0 4px"},children:e.agent.displayName||e.agent.name}),!l&&e.sources&&e.sources.length>0&&(0,o.jsx)("div",{className:"ago-message__sources",style:{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"6px",marginBottom:"10px",width:"100%",maxWidth:"85%"},children:e.sources.map((c,p)=>(0,o.jsx)(ge,{source:c,index:p},c.id))}),e.attachments&&e.attachments.length>0&&(0,o.jsx)("div",{className:"ago-message__attachments",style:{display:"flex",flexWrap:"wrap",gap:"6px",marginBottom:"6px",justifyContent:l?"flex-end":"flex-start",maxWidth:"75%"},children:e.attachments.map(c=>(0,o.jsx)(fe,{attachment:c,isUser:l},c.id))}),(e.content||d)&&(0,o.jsx)("div",{className:"ago-message__content",style:{maxWidth:l?"75%":"100%",padding:l?"10px 14px":"2px 8px",borderRadius:l?"16px":"0",backgroundColor:l?"#03182f":"transparent",color:l?"#fff":"#30373e",wordBreak:"break-word",fontSize:"16px",lineHeight:"1.6"},children:e.content?(0,o.jsx)(q,{content:e.content}):d&&(0,o.jsx)(pe,{})}),n&&e.followUpReplies&&e.followUpReplies.length>0&&(0,o.jsx)("div",{className:"ago-message__followups",style:{display:"flex",flexWrap:"wrap",gap:"8px",marginTop:"10px"},children:e.followUpReplies.map((c,p)=>(0,o.jsx)("button",{type:"button",className:"ago-message__followup-btn",disabled:!a,onClick:a?()=>a(c):void 0,style:{minHeight:"36px",padding:"6px 14px",fontSize:"13px",borderRadius:"16px",border:"1px solid #dee3e8",backgroundColor:"#fff",color:"#30373e",cursor:a?"pointer":"default",transition:"border-color 0.15s"},onMouseEnter:u=>{u.currentTarget.style.borderColor="#1b5fc4"},onMouseLeave:u=>{u.currentTarget.style.borderColor="#dee3e8"},children:c},p))})]})},xe=({client:e,conversationId:t,title:r="Chat",welcomeMessage:n="Hello! How can I help you today?",placeholder:a="Type a message...",allowFiles:l=!1,height:d=500,logoUrl:c,showAgentName:p=!1,forms:u,onFollowUpClick:b,className:x="",onMessageSent:y,onMessageReceived:h})=>{const m=(0,s.useRef)(null),C=R(),v=e??C,{messages:i,isLoading:g,error:f,sendMessage:w}=z({client:e,conversationId:t});(0,s.useEffect)(()=>{if(!v||!u||u.length===0)return;let S=!1;const I=[];return Promise.all(u.map(j=>j.schema!=null?Promise.resolve(M.createFormCollector(j)):M.loadFormCollector(v,j))).then(j=>{if(!S)for(const V of j)I.push(V.install(v))}).catch(()=>{}),()=>{S=!0,I.forEach(j=>j())}},[v,u?JSON.stringify(u.map(S=>[S.name,S.schema??null,S.submit??!1,S.description??null])):""]),(0,s.useEffect)(()=>{m.current?.scrollIntoView({behavior:"smooth"})},[i]),(0,s.useEffect)(()=>{const S=i[i.length-1];S&&S.role==="assistant"&&S.status==="DONE"&&h&&h({id:S.id,content:S.content})},[i,h]);const k=async(S,I)=>{y?.(S),await w(S,I)},P=i[i.length-1],K=g&&P?.role==="assistant"&&P.status==="IN_PROGRESS",J=b===!1?void 0:b??(S=>k(S));return(0,o.jsxs)("div",{className:`ago-chat-widget ${x}`,style:{display:"flex",flexDirection:"column",height:typeof d=="number"?`${d}px`:d,border:"1px solid #dee3e8",borderRadius:"16px",overflow:"hidden",backgroundColor:"#fff",fontFamily:'"IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',textAlign:"left",boxShadow:"rgba(15, 15, 15, 0.08) 0px 2px 16px 0px"},children:[(0,o.jsxs)("div",{className:"ago-chat-widget__header",style:{padding:"14px 16px",borderBottom:"1px solid #dee3e8",backgroundColor:"#03182f",color:"#e8f0fe",display:"flex",alignItems:"center",gap:"10px"},children:[c&&(0,o.jsx)("img",{src:c,alt:"Logo",style:{height:"24px",width:"auto"}}),(0,o.jsx)("h3",{style:{margin:0,fontSize:"15px",fontWeight:600},children:r})]}),(0,o.jsxs)("div",{className:"ago-chat-widget__messages",role:"log","aria-live":"polite","aria-relevant":"additions text","aria-atomic":!1,style:{flex:1,overflow:"auto",padding:"16px",backgroundColor:"#fbfbfb"},children:[i.length===0?(0,o.jsx)("div",{style:{textAlign:"center",color:"#6b6d6f",padding:"24px 16px",fontSize:"16px",lineHeight:"1.5"},children:n}):i.map((S,I)=>(0,o.jsx)($,{message:S,showAgentName:p,isLast:I===i.length-1,onFollowUpClick:J},S.id)),f&&(0,o.jsx)("div",{role:"alert",style:{padding:"10px 14px",backgroundColor:"#fef2f2",color:"#dc2626",borderRadius:"12px",marginTop:"8px",fontSize:"13px",border:"1px solid #fecaca"},children:f.message}),(0,o.jsx)("div",{ref:m})]}),(0,o.jsx)(O,{onSend:k,disabled:K,placeholder:a,allowFiles:l})]})};function B({client:e,autoLoad:t=!0}={}){const r=R(),n=e||r;if(!n)throw new Error("useConversation requires an AgoClient. Either pass it as options.client or wrap your app in <AgoProvider>.");const[a,l]=(0,s.useState)([]),[d,c]=(0,s.useState)(null),[p,u]=(0,s.useState)(!1),[b,x]=(0,s.useState)(null),y=(0,s.useCallback)(async()=>{u(!0),x(null);try{l(await n.getConversations())}catch(C){x(C instanceof Error?C:new Error("Failed to load conversations"))}finally{u(!1)}},[n]),h=(0,s.useCallback)(async C=>{u(!0),x(null);try{c(await n.getConversation(C))}catch(v){x(v instanceof Error?v:new Error("Failed to load conversation"))}finally{u(!1)}},[n]),m=(0,s.useCallback)(()=>{c(null)},[]);return(0,s.useEffect)(()=>{t&&y()},[t,y]),{conversations:a,currentConversation:d,isLoading:p,error:b,selectConversation:h,startNewConversation:m,refreshConversations:y}}function me(e={}){const t=R(),r=e.client||t;if(!r)throw new Error("useChat requires an AgoClient. Either pass it as options.client or wrap your app in <AgoProvider>.");const n=z({client:r,conversationId:e.conversationId}),a=B({client:r,autoLoad:e.autoLoad});return{messages:n.messages,isLoading:n.isLoading,error:n.error||a.error,sendMessage:n.sendMessage,clearMessages:n.clearMessages,conversationId:n.conversationId,conversations:a.conversations,currentConversation:a.currentConversation,isConversationsLoading:a.isLoading,selectConversation:a.selectConversation,startNewConversation:a.startNewConversation,refreshConversations:a.refreshConversations}}function he(e,t){const r=E(),{name:n,description:a,parameters:l,handler:d}=typeof e=="string"?{name:e,...t}:e,c=(0,s.useRef)(d);c.current=d,(0,s.useEffect)(()=>{const p=u=>c.current(u);return r.registerFunction(n,p,{description:a,parameters:l}),()=>{r.unregisterFunction(n)}},[r,n,a,l])}function ye(e,t){const r=E(),n=(0,s.useRef)(e);n.current=e,(0,s.useEffect)(()=>(r.registerNavigationFunction(a=>n.current(a),t),()=>{r.unregisterNavigationFunction()}),[r,t])}function be(e,t){const r=E(),n=t?.functionName??"setPageState",a=(0,s.useRef)(e);a.current=e,(0,s.useEffect)(()=>{const l=a.current.map(d=>{const c=()=>a.current.find(p=>p.name===d.name)??d;return{name:d.name,description:d.description,schema:d.schema,get:d.get?()=>c().get?.():void 0,set:p=>c().set(p)}});return r.registerPageStateFunction(l,{functionName:n}),()=>{r.unregisterPageStateFunction(n)}},[r,n])}var ve="You have navigated the user to a new page. That page now exposes its editable state through the available setPageState function, and its current values in the page context. If the user's latest request also asked to change something on this page, call setPageState now to apply exactly those changes and nothing else. Otherwise, reply with a short confirmation only.";function W(e){return{navigationFunctions:e?.navigationFunctions??["navigateToPage"],pageStateFunctionName:e?.pageStateFunctionName??"setPageState",continuationPrompt:e?.continuationPrompt??ve,maxDepth:e?.maxDepth??1,readinessTimeoutMs:e?.readinessTimeoutMs??4e3,settleMs:e?.settleMs??150,enabled:e?.enabled??!0}}function Ce(e){const t=E(),r=(0,s.useRef)(W(e));r.current=W(e),(0,s.useEffect)(()=>{const n={navigated:!1,depth:0,runId:0,ourSendPending:!1},a=()=>t.getRegisteredFunctions().some(x=>x.name===r.current.pageStateFunctionName),l=x=>new Promise(y=>{let h=!1;const m=g=>{h||(h=!0,clearTimeout(i),t.off("context:changed",v),y(g))},C=()=>setTimeout(()=>m(x===n.runId&&a()),r.current.settleMs),v=()=>{if(x!==n.runId)return m(!1);a()&&(t.off("context:changed",v),C())},i=setTimeout(()=>m(!1),r.current.readinessTimeoutMs);a()?C():t.on("context:changed",v)}),d=async x=>{const y=++n.runId;if(!(!await l(y)||y!==n.runId)){n.depth+=1,n.ourSendPending=!0;try{await t.sendMessage(r.current.continuationPrompt,{conversationId:x,hidden:!0})}catch{n.ourSendPending=!1}}},c=x=>{r.current.navigationFunctions.includes(x.functionName)&&(n.navigated=!0)},p=()=>{n.ourSendPending||(n.depth=0,n.runId+=1)},u=x=>{n.ourSendPending=!1;const y=n.navigated;n.navigated=!1,r.current.enabled&&y&&(n.depth>=r.current.maxDepth||d(x.conversationId))},b=()=>{n.ourSendPending=!1};return t.on("function:invoke",c),t.on("message:start",p),t.on("message:complete",u),t.on("message:error",b),()=>{n.runId+=1,t.off("function:invoke",c),t.off("message:start",p),t.off("message:complete",u),t.off("message:error",b)}},[t])}function we(e,t){const r=E(),n=(0,s.useId)(),a=t??n,l=(0,s.useRef)(e);l.current=e;const d=typeof e=="function";(0,s.useEffect)(()=>{if(typeof l.current=="function"){const c=()=>l.current();return r.addDynamicContext(a,c),()=>{r.removeDynamicContext(a)}}return r.setContext(a,l.current),()=>{r.removeContext(a)}},[r,a,d,d?"":JSON.stringify(e)])}function U(e){return(0,s.useSyncExternalStore)(e.subscribe,e.get,e.get)}var L={missing:[],complete:!1};function Se(e){const t=E(),r=e.schema!=null,n=JSON.stringify(e.schema??null),a=e.submit,l=a?typeof a=="string"?`client:${a}`:a.via==="backend"?"backend":"handler"in a?"client:handler":`client:${a.url}`:"none",d=JSON.stringify(e.initialValues??null),c=(0,s.useMemo)(()=>r?M.createFormCollector(e):null,[r,e.name,n,l,d,e.autoSubmit]),[p,u]=(0,s.useState)({collector:null,loading:!r,error:null});(0,s.useEffect)(()=>{if(r)return;let g=!1;return u({collector:null,loading:!0,error:null}),M.loadFormCollector(t,e).then(f=>{g||u({collector:f,loading:!1,error:null})}).catch(f=>{g||u({collector:null,loading:!1,error:f instanceof Error?f:new Error(String(f))})}),()=>{g=!0}},[t,r,e.name,l,d,e.autoSubmit]);const b=r?c:p.collector,x=r?!1:p.loading,y=r?null:p.error;(0,s.useEffect)(()=>{if(b)return b.install(t)},[t,b]);const h=(0,s.useMemo)(()=>M.createStore({values:e.initialValues??{},submitted:!1}),[d]),m=U(b?.store??h),C=(0,s.useMemo)(()=>b?.getStatus()??L,[m,b]),v=(0,s.useMemo)(()=>({...m,...C}),[m,C]),i=(0,s.useMemo)(()=>({name:e.name,store:h,functions:[],contextKey:`form:${e.name}`,contextProvider:()=>({name:`Form: ${e.name}`,description:""}),install:()=>()=>{},hydrate:()=>{},submit:async()=>({ok:!1,error:"Form definition not loaded yet."}),getValues:()=>h.get().values,setValues:()=>{},reset:()=>{},getStatus:()=>L}),[e.name,h]);return{...b??i,state:v,loading:x,error:y}}exports.AgoProvider=Y;exports.ChatInput=O;exports.ChatWidget=xe;exports.Markdown=q;exports.Message=$;exports.createFormCollector=M.createFormCollector;exports.createMockClient=G.createMockClient;exports.deriveFormStatus=M.deriveFormStatus;exports.loadFormCollector=M.loadFormCollector;exports.useAgo=H;exports.useAgoAutoContinueAfterNavigation=Ce;exports.useAgoClient=E;exports.useAgoContext=we;exports.useAgoFunction=he;exports.useAgoNavigation=ye;exports.useAgoPageState=be;exports.useAgoStore=U;exports.useChat=me;exports.useConversation=B;exports.useFormCollector=Se;exports.useMessages=z;exports.useOptionalAgoClient=R;
|
|
7
|
+
`})]}),B=({message:e,className:n="",showAgentName:r=!1,isLast:t=!1,onFollowUpClick:a})=>{const l=e.role==="user",d=e.status==="IN_PROGRESS"||e.status==="WAITING_CLIENT";return(0,o.jsxs)("div",{className:`ago-message ago-message--${e.role} ${n}`,style:{display:"flex",flexDirection:"column",alignItems:l?"flex-end":"flex-start",marginBottom:"16px"},children:[!l&&r&&e.agent&&(0,o.jsx)("div",{className:"ago-message__agent",style:{display:"flex",alignItems:"center",gap:"6px",fontSize:"13px",fontWeight:500,color:"#30373e",marginBottom:"6px",padding:"0 4px"},children:e.agent.displayName||e.agent.name}),!l&&e.sources&&e.sources.length>0&&(0,o.jsx)("div",{className:"ago-message__sources",style:{display:"grid",gridTemplateColumns:"1fr 1fr",gap:"6px",marginBottom:"10px",width:"100%",maxWidth:"85%"},children:e.sources.map((c,p)=>(0,o.jsx)(ge,{source:c,index:p},c.id))}),e.attachments&&e.attachments.length>0&&(0,o.jsx)("div",{className:"ago-message__attachments",style:{display:"flex",flexWrap:"wrap",gap:"6px",marginBottom:"6px",justifyContent:l?"flex-end":"flex-start",maxWidth:"75%"},children:e.attachments.map(c=>(0,o.jsx)(fe,{attachment:c,isUser:l},c.id))}),(e.content||d)&&(0,o.jsx)("div",{className:"ago-message__content",style:{maxWidth:l?"75%":"100%",padding:l?"10px 14px":"2px 8px",borderRadius:l?"16px":"0",backgroundColor:l?"#03182f":"transparent",color:l?"#fff":"#30373e",wordBreak:"break-word",fontSize:"16px",lineHeight:"1.6"},children:e.content?(0,o.jsx)($,{content:e.content}):d&&(0,o.jsx)(pe,{})}),t&&e.followUpReplies&&e.followUpReplies.length>0&&(0,o.jsx)("div",{className:"ago-message__followups",style:{display:"flex",flexWrap:"wrap",gap:"8px",marginTop:"10px"},children:e.followUpReplies.map((c,p)=>(0,o.jsx)("button",{type:"button",className:"ago-message__followup-btn",disabled:!a,onClick:a?()=>a(c):void 0,style:{minHeight:"36px",padding:"6px 14px",fontSize:"13px",borderRadius:"16px",border:"1px solid #dee3e8",backgroundColor:"#fff",color:"#30373e",cursor:a?"pointer":"default",transition:"border-color 0.15s"},onMouseEnter:u=>{u.currentTarget.style.borderColor="#1b5fc4"},onMouseLeave:u=>{u.currentTarget.style.borderColor="#dee3e8"},children:c},p))})]})},xe=({client:e,conversationId:n,title:r="Chat",welcomeMessage:t="Hello! How can I help you today?",placeholder:a="Type a message...",allowFiles:l=!1,height:d=500,logoUrl:c,showAgentName:p=!1,forms:u,onFollowUpClick:C,className:b="",onMessageSent:I,onMessageReceived:g})=>{const m=(0,s.useRef)(null),S=_(),w=e??S,{messages:i,isLoading:y,error:f,sendMessage:x}=L({client:e,conversationId:n});(0,s.useEffect)(()=>{if(!w||!u||u.length===0)return;let k=!1;const A=[];return Promise.all(u.map(j=>j.schema!=null?Promise.resolve(M.createFormCollector(j)):M.loadFormCollector(w,j))).then(j=>{if(!k)for(const J of j)A.push(J.install(w))}).catch(()=>{}),()=>{k=!0,A.forEach(j=>j())}},[w,u?JSON.stringify(u.map(k=>[k.name,k.schema??null,k.submit??!1,k.description??null])):""]),(0,s.useEffect)(()=>{m.current?.scrollIntoView({behavior:"smooth"})},[i]),(0,s.useEffect)(()=>{const k=i[i.length-1];k&&k.role==="assistant"&&k.status==="DONE"&&g&&g({id:k.id,content:k.content})},[i,g]);const v=async(k,A)=>{I?.(k),await x(k,A)},h=i[i.length-1],N=y&&h?.role==="assistant"&&(h.status==="IN_PROGRESS"||h.status==="WAITING_CLIENT"),K=C===!1?void 0:C??(k=>v(k));return(0,o.jsxs)("div",{className:`ago-chat-widget ${b}`,style:{display:"flex",flexDirection:"column",height:typeof d=="number"?`${d}px`:d,border:"1px solid #dee3e8",borderRadius:"16px",overflow:"hidden",backgroundColor:"#fff",fontFamily:'"IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',textAlign:"left",boxShadow:"rgba(15, 15, 15, 0.08) 0px 2px 16px 0px"},children:[(0,o.jsxs)("div",{className:"ago-chat-widget__header",style:{padding:"14px 16px",borderBottom:"1px solid #dee3e8",backgroundColor:"#03182f",color:"#e8f0fe",display:"flex",alignItems:"center",gap:"10px"},children:[c&&(0,o.jsx)("img",{src:c,alt:"Logo",style:{height:"24px",width:"auto"}}),(0,o.jsx)("h3",{style:{margin:0,fontSize:"15px",fontWeight:600},children:r})]}),(0,o.jsxs)("div",{className:"ago-chat-widget__messages",role:"log","aria-live":"polite","aria-relevant":"additions text","aria-atomic":!1,style:{flex:1,overflow:"auto",padding:"16px",backgroundColor:"#fbfbfb"},children:[i.length===0?(0,o.jsx)("div",{style:{textAlign:"center",color:"#6b6d6f",padding:"24px 16px",fontSize:"16px",lineHeight:"1.5"},children:t}):i.map((k,A)=>(0,o.jsx)(B,{message:k,showAgentName:p,isLast:A===i.length-1,onFollowUpClick:K},k.id)),f&&(0,o.jsx)("div",{role:"alert",style:{padding:"10px 14px",backgroundColor:"#fef2f2",color:"#dc2626",borderRadius:"12px",marginTop:"8px",fontSize:"13px",border:"1px solid #fecaca"},children:f.message}),(0,o.jsx)("div",{ref:m})]}),(0,o.jsx)(q,{onSend:v,disabled:N,placeholder:a,allowFiles:l})]})};function G({client:e,autoLoad:n=!0}={}){const r=_(),t=e||r;if(!t)throw new Error("useConversation requires an AgoClient. Either pass it as options.client or wrap your app in <AgoProvider>.");const[a,l]=(0,s.useState)([]),[d,c]=(0,s.useState)(null),[p,u]=(0,s.useState)(!1),[C,b]=(0,s.useState)(null),I=(0,s.useCallback)(async()=>{u(!0),b(null);try{l(await t.getConversations())}catch(S){b(S instanceof Error?S:new Error("Failed to load conversations"))}finally{u(!1)}},[t]),g=(0,s.useCallback)(async S=>{u(!0),b(null);try{c(await t.getConversation(S))}catch(w){b(w instanceof Error?w:new Error("Failed to load conversation"))}finally{u(!1)}},[t]),m=(0,s.useCallback)(()=>{c(null)},[]);return(0,s.useEffect)(()=>{n&&I()},[n,I]),{conversations:a,currentConversation:d,isLoading:p,error:C,selectConversation:g,startNewConversation:m,refreshConversations:I}}function me(e={}){const n=_(),r=e.client||n;if(!r)throw new Error("useChat requires an AgoClient. Either pass it as options.client or wrap your app in <AgoProvider>.");const t=L({client:r,conversationId:e.conversationId}),a=G({client:r,autoLoad:e.autoLoad});return{messages:t.messages,isLoading:t.isLoading,error:t.error||a.error,sendMessage:t.sendMessage,clearMessages:t.clearMessages,conversationId:t.conversationId,conversations:a.conversations,currentConversation:a.currentConversation,isConversationsLoading:a.isLoading,selectConversation:a.selectConversation,startNewConversation:a.startNewConversation,refreshConversations:a.refreshConversations}}function he(e,n){const r=E(),{name:t,description:a,parameters:l,handler:d}=typeof e=="string"?{name:e,...n}:e,c=(0,s.useRef)(d);c.current=d,(0,s.useEffect)(()=>{const p=u=>c.current(u);return r.registerFunction(t,p,{description:a,parameters:l}),()=>{r.unregisterFunction(t)}},[r,t,a,l])}function ye(e,n){const r=E(),t=(0,s.useRef)(e);t.current=e,(0,s.useEffect)(()=>(r.registerNavigationFunction(a=>t.current(a),n),()=>{r.unregisterNavigationFunction()}),[r,n])}function be(e,n){const r=E(),t=n?.functionName??"setPageState",a=(0,s.useRef)(e);a.current=e,(0,s.useEffect)(()=>{const l=a.current.map(d=>{const c=()=>a.current.find(p=>p.name===d.name)??d;return{name:d.name,description:d.description,schema:d.schema,get:d.get?()=>c().get?.():void 0,set:p=>c().set(p)}});return r.registerPageStateFunction(l,{functionName:t}),()=>{r.unregisterPageStateFunction(t)}},[r,t])}var ve="You have navigated the user to a new page. That page now exposes its editable state through the available setPageState function, and its current values in the page context. If the user's latest request also asked to change something on this page, call setPageState now to apply exactly those changes and nothing else. Otherwise, reply with a short confirmation only.";function z(e){return{navigationFunctions:e?.navigationFunctions??["navigateToPage"],pageStateFunctionName:e?.pageStateFunctionName??"setPageState",continuationPrompt:e?.continuationPrompt??ve,maxDepth:e?.maxDepth??1,readinessTimeoutMs:e?.readinessTimeoutMs??4e3,settleMs:e?.settleMs??150,enabled:e?.enabled??!0}}function Ce(e){const n=E(),r=(0,s.useRef)(z(e));r.current=z(e),(0,s.useEffect)(()=>{const t={navigated:!1,pausedTurnNavigated:!1,depth:0,runId:0,ourSendPending:!1},a=()=>n.getRegisteredFunctions().some(g=>g.name===r.current.pageStateFunctionName),l=g=>new Promise(m=>{let S=!1;const w=x=>{S||(S=!0,clearTimeout(f),n.off("context:changed",y),m(x))},i=()=>setTimeout(()=>w(g===t.runId&&a()),r.current.settleMs),y=()=>{if(g!==t.runId)return w(!1);a()&&(n.off("context:changed",y),i())},f=setTimeout(()=>w(!1),r.current.readinessTimeoutMs);a()?i():n.on("context:changed",y)}),d=async g=>{const m=++t.runId;if(!(!await l(m)||m!==t.runId)){t.depth+=1,t.ourSendPending=!0;try{await n.sendMessage(r.current.continuationPrompt,{conversationId:g,hidden:!0})}catch{t.ourSendPending=!1}}},c=g=>{r.current.navigationFunctions.includes(g.functionName)&&(t.navigated=!0)},p=n.registerResumeGate(async()=>{r.current.enabled&&t.pausedTurnNavigated&&(t.pausedTurnNavigated=!1,await l(++t.runId))}),u=()=>{t.pausedTurnNavigated=t.navigated,t.navigated=!1},C=()=>{t.ourSendPending||(t.depth=0,t.runId+=1)},b=g=>{t.ourSendPending=!1;const m=t.navigated;t.navigated=!1,r.current.enabled&&m&&(t.depth>=r.current.maxDepth||d(g.conversationId))},I=()=>{t.ourSendPending=!1};return n.on("function:invoke",c),n.on("message:start",C),n.on("message:waiting-client",u),n.on("message:complete",b),n.on("message:error",I),()=>{t.runId+=1,p(),n.off("function:invoke",c),n.off("message:start",C),n.off("message:waiting-client",u),n.off("message:complete",b),n.off("message:error",I)}},[n])}function we(e,n){const r=E(),t=(0,s.useId)(),a=n??t,l=(0,s.useRef)(e);l.current=e;const d=typeof e=="function";(0,s.useEffect)(()=>{if(typeof l.current=="function"){const c=()=>l.current();return r.addDynamicContext(a,c),()=>{r.removeDynamicContext(a)}}return r.setContext(a,l.current),()=>{r.removeContext(a)}},[r,a,d,d?"":JSON.stringify(e)])}function U(e){return(0,s.useSyncExternalStore)(e.subscribe,e.get,e.get)}var O={missing:[],complete:!1};function Se(e){const n=E(),r=e.schema!=null,t=JSON.stringify(e.schema??null),a=e.submit,l=a?typeof a=="string"?`client:${a}`:a.via==="backend"?"backend":"handler"in a?"client:handler":`client:${a.url}`:"none",d=JSON.stringify(e.initialValues??null),c=(0,s.useMemo)(()=>r?M.createFormCollector(e):null,[r,e.name,t,l,d,e.autoSubmit]),[p,u]=(0,s.useState)({collector:null,loading:!r,error:null});(0,s.useEffect)(()=>{if(r)return;let y=!1;return u({collector:null,loading:!0,error:null}),M.loadFormCollector(n,e).then(f=>{y||u({collector:f,loading:!1,error:null})}).catch(f=>{y||u({collector:null,loading:!1,error:f instanceof Error?f:new Error(String(f))})}),()=>{y=!0}},[n,r,e.name,l,d,e.autoSubmit]);const C=r?c:p.collector,b=r?!1:p.loading,I=r?null:p.error;(0,s.useEffect)(()=>{if(C)return C.install(n)},[n,C]);const g=(0,s.useMemo)(()=>M.createStore({values:e.initialValues??{},submitted:!1}),[d]),m=U(C?.store??g),S=(0,s.useMemo)(()=>C?.getStatus()??O,[m,C]),w=(0,s.useMemo)(()=>({...m,...S}),[m,S]),i=(0,s.useMemo)(()=>({name:e.name,store:g,functions:[],contextKey:`form:${e.name}`,contextProvider:()=>({name:`Form: ${e.name}`,description:""}),install:()=>()=>{},hydrate:()=>{},submit:async()=>({ok:!1,error:"Form definition not loaded yet."}),getValues:()=>g.get().values,setValues:()=>{},reset:()=>{},getStatus:()=>O}),[e.name,g]);return{...C??i,state:w,loading:b,error:I}}exports.AgoProvider=Y;exports.ChatInput=q;exports.ChatWidget=xe;exports.Markdown=$;exports.Message=B;exports.createFormCollector=M.createFormCollector;exports.createMockClient=V.createMockClient;exports.deriveFormStatus=M.deriveFormStatus;exports.loadFormCollector=M.loadFormCollector;exports.useAgo=H;exports.useAgoAutoContinueAfterNavigation=Ce;exports.useAgoClient=E;exports.useAgoContext=we;exports.useAgoFunction=he;exports.useAgoNavigation=ye;exports.useAgoPageState=be;exports.useAgoStore=U;exports.useChat=me;exports.useConversation=G;exports.useFormCollector=Se;exports.useMessages=L;exports.useOptionalAgoClient=_;
|
package/dist/react.d.cts
CHANGED
|
@@ -58,12 +58,45 @@ declare class AgoClient {
|
|
|
58
58
|
private config;
|
|
59
59
|
/** Conversations already warned about an empty reply (one warning each). */
|
|
60
60
|
private warnedEmptyConversations;
|
|
61
|
+
/** Paused turns awaiting auto-resume, keyed by assistant message id. */
|
|
62
|
+
private pendingResumes;
|
|
63
|
+
/** App-provided gate deciding WHEN a paused turn resumes (see {@link registerResumeGate}). */
|
|
64
|
+
private resumeGate;
|
|
61
65
|
constructor(config: AgoConfig);
|
|
62
66
|
/**
|
|
63
67
|
* Send a message and receive a streaming response
|
|
64
68
|
*/
|
|
65
69
|
sendMessage(content: string, options?: SendMessageOptions): Promise<AgoMessage>;
|
|
66
70
|
private processSSEResponse;
|
|
71
|
+
private resolveClientFunctionsMode;
|
|
72
|
+
/**
|
|
73
|
+
* Register a gate deciding WHEN a paused turn resumes. The SDK still decides
|
|
74
|
+
* *whether* (it resumes once every waiting result is submitted); the gate only
|
|
75
|
+
* delays the continue call — e.g. `useAgoAutoContinueAfterNavigation` waits for
|
|
76
|
+
* the destination page to register its page state. One gate at a time (last
|
|
77
|
+
* registration wins). Returns an unregister function.
|
|
78
|
+
*/
|
|
79
|
+
registerResumeGate(gate: ResumeGate): () => void;
|
|
80
|
+
/**
|
|
81
|
+
* Resume a turn paused on client function results (`WAITING_CLIENT`).
|
|
82
|
+
*
|
|
83
|
+
* Sends the CURRENT page's registered functions and context — the page may
|
|
84
|
+
* have changed since the pause (that's the point of pausing on a navigation) —
|
|
85
|
+
* and streams the continuation through the same event pipeline as
|
|
86
|
+
* `sendMessage`, so `message:chunk` / `message:complete` (or another
|
|
87
|
+
* `message:waiting-client` for chained pauses) fire as usual.
|
|
88
|
+
*
|
|
89
|
+
* The SDK calls this automatically after submitting the waiting results; call
|
|
90
|
+
* it manually only for custom flows (e.g. after restoring a reloaded page via
|
|
91
|
+
* {@link resumePendingClientFunctions}).
|
|
92
|
+
*/
|
|
93
|
+
continueMessage(messageId: string): Promise<AgoMessage>;
|
|
94
|
+
/**
|
|
95
|
+
* Record one of the two auto-resume preconditions for a paused turn and fire
|
|
96
|
+
* the resume when both are in (see {@link PendingResume}).
|
|
97
|
+
*/
|
|
98
|
+
private markResumeSignal;
|
|
99
|
+
private runAutoResume;
|
|
67
100
|
/**
|
|
68
101
|
* Detect a reply that completed as DONE with no content and no activity —
|
|
69
102
|
* today's backend answers an unknown `agent` slug with an empty 200, which
|
|
@@ -96,9 +129,25 @@ declare class AgoClient {
|
|
|
96
129
|
*/
|
|
97
130
|
getMessages(conversationId: string): Promise<AgoMessage[]>;
|
|
98
131
|
/**
|
|
99
|
-
*
|
|
132
|
+
* Resume a turn left paused on client function results by a page reload.
|
|
133
|
+
*
|
|
134
|
+
* A paused turn (pause mode) survives a full reload: the backend keeps the
|
|
135
|
+
* assistant message in `WAITING_CLIENT` with its waiting tool calls. After
|
|
136
|
+
* restoring the conversation (`getConversation`) and re-registering the page's
|
|
137
|
+
* functions, call this: it re-executes each waiting client function through the
|
|
138
|
+
* registry, submits the results, and continues the turn.
|
|
139
|
+
*
|
|
140
|
+
* Opt-in on purpose — re-running functions on reload can be surprising (e.g. a
|
|
141
|
+
* navigation function would navigate again), so the app decides. Returns the
|
|
142
|
+
* resumed turn's final message, or `null` when there was nothing to resume or
|
|
143
|
+
* some waiting function is not registered on this page.
|
|
144
|
+
*/
|
|
145
|
+
resumePendingClientFunctions(conversation: Conversation): Promise<AgoMessage | null>;
|
|
146
|
+
/**
|
|
147
|
+
* Submit form data for a tool call. The response's `resume` field (pause mode
|
|
148
|
+
* only) tells whether the paused turn is ready to be resumed.
|
|
100
149
|
*/
|
|
101
|
-
submitToolCallForm(toolCallId: string, formData: Record<string, unknown>): Promise<
|
|
150
|
+
submitToolCallForm(toolCallId: string, formData: Record<string, unknown>): Promise<SubmitToolCallResult>;
|
|
102
151
|
/**
|
|
103
152
|
* Confirm a tool call
|
|
104
153
|
*/
|
|
@@ -171,6 +220,12 @@ declare class AgoClient {
|
|
|
171
220
|
* the agent know *where* it is after it navigates (e.g. so auto-continuation
|
|
172
221
|
* can apply page state on the destination), not just how to navigate away.
|
|
173
222
|
*
|
|
223
|
+
* Routes may contain `:param` placeholders (`/users/:id`). Each distinct
|
|
224
|
+
* placeholder becomes a top-level string argument of `navigateToPage`
|
|
225
|
+
* (`{ page: "userDetail", id: "42" }`), so one route covers every detail
|
|
226
|
+
* page of an entity. Flat arguments only: nested object parameters are not
|
|
227
|
+
* reliably rendered to the model, so placeholders must not be named `page`.
|
|
228
|
+
*
|
|
174
229
|
* @param navigate - A callback that performs the navigation (e.g. react-router's navigate)
|
|
175
230
|
* @param routes - Map of route names to paths, with descriptions for the LLM
|
|
176
231
|
*/
|
|
@@ -338,6 +393,19 @@ declare interface AgoClientEvents {
|
|
|
338
393
|
*/
|
|
339
394
|
"message:answer-complete": AgoMessage;
|
|
340
395
|
"message:complete": AgoMessage;
|
|
396
|
+
/**
|
|
397
|
+
* The turn paused on client function call(s) (pause mode): the stream closed
|
|
398
|
+
* with status `WAITING_CLIENT` instead of `DONE`. `message:complete` does NOT
|
|
399
|
+
* fire for this stream — it fires when the resumed turn concludes, so one
|
|
400
|
+
* logical turn still emits exactly one `message:complete`. The SDK submits the
|
|
401
|
+
* function results and resumes automatically; listen to this to know the agent
|
|
402
|
+
* is waiting on the page (e.g. to keep a "working…" indicator up).
|
|
403
|
+
*/
|
|
404
|
+
"message:waiting-client": {
|
|
405
|
+
conversationId: string;
|
|
406
|
+
messageId: string;
|
|
407
|
+
waitingToolCallIds: string[];
|
|
408
|
+
};
|
|
341
409
|
/**
|
|
342
410
|
* A reply finished as `DONE` with empty content and no tool calls, client
|
|
343
411
|
* functions, or follow-up replies — usually an unknown `agent` slug (the
|
|
@@ -425,6 +493,16 @@ export declare interface AgoConfig {
|
|
|
425
493
|
* event fires regardless of this setting.
|
|
426
494
|
*/
|
|
427
495
|
warnOnEmptyReply?: boolean;
|
|
496
|
+
/**
|
|
497
|
+
* How the agent loop treats client function calls (requires backend support):
|
|
498
|
+
* - `"placeholder"` (default): the turn continues immediately on a placeholder
|
|
499
|
+
* result; the real result is only visible to the agent on later turns.
|
|
500
|
+
* - `"pause"`: the turn stops on client function call(s) with status
|
|
501
|
+
* `WAITING_CLIENT`; once every result is submitted, the SDK resumes the SAME
|
|
502
|
+
* turn via `POST /messages/{id}/continue`, so the agent sees the real results.
|
|
503
|
+
* Older backends ignore the flag, so `"pause"` degrades to legacy behavior.
|
|
504
|
+
*/
|
|
505
|
+
clientFunctionsMode?: ClientFunctionsMode;
|
|
428
506
|
}
|
|
429
507
|
|
|
430
508
|
/**
|
|
@@ -675,6 +753,9 @@ declare interface ClientFunctionSchema {
|
|
|
675
753
|
};
|
|
676
754
|
}
|
|
677
755
|
|
|
756
|
+
/** See {@link AgoConfig.clientFunctionsMode}. */
|
|
757
|
+
declare type ClientFunctionsMode = "placeholder" | "pause";
|
|
758
|
+
|
|
678
759
|
/**
|
|
679
760
|
* A single piece of context the client wants the LLM to know about.
|
|
680
761
|
*/
|
|
@@ -995,7 +1076,13 @@ export declare interface MessageProps {
|
|
|
995
1076
|
onFollowUpClick?: (reply: string) => void;
|
|
996
1077
|
}
|
|
997
1078
|
|
|
998
|
-
declare type MessageStatus = "IN_PROGRESS" | "DONE" | "ERROR" | "TODO" | "CANCELED"
|
|
1079
|
+
declare type MessageStatus = "IN_PROGRESS" | "DONE" | "ERROR" | "TODO" | "CANCELED"
|
|
1080
|
+
/**
|
|
1081
|
+
* The turn paused on client function call(s) (pause mode): the agent waits for
|
|
1082
|
+
* every waiting call to be submitted, then the turn resumes via
|
|
1083
|
+
* `continueMessage`. Not a final state.
|
|
1084
|
+
*/
|
|
1085
|
+
| "WAITING_CLIENT";
|
|
999
1086
|
|
|
1000
1087
|
declare interface MockAgoClient extends AgoClient {
|
|
1001
1088
|
/**
|
|
@@ -1027,6 +1114,17 @@ declare interface MockAgoClientOptions {
|
|
|
1027
1114
|
|
|
1028
1115
|
declare type MockFn = (...args: any[]) => any;
|
|
1029
1116
|
|
|
1117
|
+
/**
|
|
1118
|
+
* Hook run before a paused turn is resumed, so the app controls WHEN the
|
|
1119
|
+
* continuation fires (e.g. wait for the destination page to mount after a
|
|
1120
|
+
* navigation). It must resolve — throwing or hanging blocks the resume; on
|
|
1121
|
+
* timeout-style situations resolve anyway and let the agent conclude.
|
|
1122
|
+
*/
|
|
1123
|
+
declare type ResumeGate = (info: {
|
|
1124
|
+
conversationId: string;
|
|
1125
|
+
messageId: string;
|
|
1126
|
+
}) => Promise<void> | void;
|
|
1127
|
+
|
|
1030
1128
|
/**
|
|
1031
1129
|
* Options for sending a message
|
|
1032
1130
|
*/
|
|
@@ -1044,6 +1142,8 @@ declare interface SendMessageOptions {
|
|
|
1044
1142
|
* Requires backend support for the `hidden` flag; older backends ignore it.
|
|
1045
1143
|
*/
|
|
1046
1144
|
hidden?: boolean;
|
|
1145
|
+
/** Per-message override of {@link AgoConfig.clientFunctionsMode}. */
|
|
1146
|
+
clientFunctionsMode?: ClientFunctionsMode;
|
|
1047
1147
|
}
|
|
1048
1148
|
|
|
1049
1149
|
/**
|
|
@@ -1085,6 +1185,8 @@ declare interface SSEChunkData {
|
|
|
1085
1185
|
follow_up_replies?: string[];
|
|
1086
1186
|
satisfaction_feedback?: unknown;
|
|
1087
1187
|
ask_to_talk_to_human?: boolean;
|
|
1188
|
+
/** Tool call ids still awaiting a client result, sent with the final `WAITING_CLIENT` event. */
|
|
1189
|
+
waiting_tool_call_ids?: string[];
|
|
1088
1190
|
}
|
|
1089
1191
|
|
|
1090
1192
|
/**
|
|
@@ -1130,6 +1232,21 @@ export declare type SubmitConfig<V = Record<string, unknown>> = string | {
|
|
|
1130
1232
|
destination?: string;
|
|
1131
1233
|
} | false;
|
|
1132
1234
|
|
|
1235
|
+
/**
|
|
1236
|
+
* Response of `POST /tool-calls/{id}/submit`. `resume` is only present when the
|
|
1237
|
+
* tool call belongs to a turn paused on client functions (pause mode): `ready`
|
|
1238
|
+
* flips to `true` once ALL waiting calls of that message are submitted, meaning
|
|
1239
|
+
* the turn can be resumed via `continueMessage(resume.message_id)`.
|
|
1240
|
+
*/
|
|
1241
|
+
declare interface SubmitToolCallResult {
|
|
1242
|
+
status: string;
|
|
1243
|
+
result?: unknown;
|
|
1244
|
+
resume?: {
|
|
1245
|
+
message_id: string;
|
|
1246
|
+
ready: boolean;
|
|
1247
|
+
};
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1133
1250
|
/**
|
|
1134
1251
|
* Tool call data from SSE stream
|
|
1135
1252
|
*/
|
|
@@ -1166,12 +1283,20 @@ export declare function useAgo(config: UseAgoOptions | null): {
|
|
|
1166
1283
|
* Auto-continue the agent after it navigates, so a "go to page B and change X"
|
|
1167
1284
|
* request completes in one user gesture. Mount this once inside `AgoProvider`.
|
|
1168
1285
|
*
|
|
1169
|
-
*
|
|
1170
|
-
*
|
|
1171
|
-
*
|
|
1172
|
-
*
|
|
1173
|
-
*
|
|
1174
|
-
*
|
|
1286
|
+
* Two mechanisms, picked by the turn's client-functions mode:
|
|
1287
|
+
*
|
|
1288
|
+
* - **Pause mode** (`clientFunctionsMode: "pause"`): the backend pauses the turn
|
|
1289
|
+
* on the navigation call (`message:waiting-client`) and the SDK resumes it once
|
|
1290
|
+
* the result is submitted. This hook only registers a *resume gate* that delays
|
|
1291
|
+
* the resume until the destination page's `useAgoPageState` registered (plus a
|
|
1292
|
+
* settle delay), so the continued turn ships the new page's `setPageState` and
|
|
1293
|
+
* current state. Same turn, no extra prompt, backend budget as the guardrail —
|
|
1294
|
+
* `continuationPrompt` and `maxDepth` are unused here.
|
|
1295
|
+
*
|
|
1296
|
+
* - **Placeholder mode** (legacy default): when the agent calls the navigation
|
|
1297
|
+
* function and that turn ends, this waits for the destination page's state to
|
|
1298
|
+
* register, then sends a hidden continuation message; the agent applies the
|
|
1299
|
+
* state in a second turn (requires backend support for the `hidden` flag).
|
|
1175
1300
|
*
|
|
1176
1301
|
* ```tsx
|
|
1177
1302
|
* function AppShell() {
|