@useago/sdk 1.0.3 → 1.0.5
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 +51 -3
- package/dist/AgoClient--y10UXUV.cjs +6 -0
- package/dist/{AgoClient-CBLJfu90.js → AgoClient-DYdIe_R4.js} +55 -44
- package/dist/angular.cjs +1 -1
- package/dist/angular.d.cts +49 -2
- package/dist/angular.d.ts +49 -2
- package/dist/angular.js +1 -1
- package/dist/{createConversationSession-D3aHSSir.js → createConversationSession-Boi0PjDU.js} +1 -1
- package/dist/{createConversationSession-CnIchjFa.cjs → createConversationSession-lJWANT6T.cjs} +1 -1
- package/dist/{createFormCollector-CyD7KnjG.js → createFormCollector-BUqSA2Qw.js} +1 -1
- package/dist/{createFormCollector-CQKfRjfj.cjs → createFormCollector-CSG5ioym.cjs} +1 -1
- package/dist/devtools.cjs +41 -27
- package/dist/devtools.d.cts +48 -0
- package/dist/devtools.d.ts +48 -0
- package/dist/devtools.js +98 -70
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +13 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +3 -3
- package/dist/react.cjs +1 -1
- package/dist/react.d.cts +49 -2
- package/dist/react.d.ts +49 -2
- package/dist/react.js +2 -2
- package/dist/testing.d.cts +48 -0
- package/dist/testing.d.ts +48 -0
- package/dist/vue.cjs +1 -1
- package/dist/vue.d.cts +49 -2
- package/dist/vue.d.ts +49 -2
- package/dist/vue.js +1 -1
- package/dist/widget.cjs +1 -1
- package/dist/widget.d.cts +48 -0
- package/dist/widget.d.ts +48 -0
- package/dist/widget.js +3 -3
- package/package.json +4 -4
- package/dist/AgoClient-nYVPdI5x.cjs +0 -6
package/README.md
CHANGED
|
@@ -22,12 +22,12 @@ the same two steps through its own guide:
|
|
|
22
22
|
## <img src="https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons/react/react-original.svg" width="22" /> Try it in 30 seconds
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
|
-
npm install @useago/sdk
|
|
25
|
+
npm install @useago/sdk react react-dom
|
|
26
26
|
```
|
|
27
27
|
|
|
28
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,
|
|
30
|
-
|
|
29
|
+
and `react-dom` (>=17): already there in an existing React app, so you can drop
|
|
30
|
+
them from the command above.
|
|
31
31
|
|
|
32
32
|
```tsx
|
|
33
33
|
// App.tsx
|
|
@@ -46,6 +46,11 @@ Start your dev server. A chat panel renders on the page; type a message and
|
|
|
46
46
|
watch the reply stream in. That's a complete integration. (`generic-guide` is a
|
|
47
47
|
public demo agent; swap `baseUrl` and `agent` for your own once you have a tenant.)
|
|
48
48
|
|
|
49
|
+
`ChatWidget` is the high-level component to get started in minutes. Everything it
|
|
50
|
+
does is also exposed through hooks and APIs (`useChat`, `useMessages`, the raw
|
|
51
|
+
client, events), so when you outgrow the default panel you can drop down and build
|
|
52
|
+
the exact experience you want. The example below renders one piece of that.
|
|
53
|
+
|
|
49
54
|
## Let the agent drive your existing routes
|
|
50
55
|
|
|
51
56
|
This is the part existing apps care about. You already have a router and pages;
|
|
@@ -76,6 +81,49 @@ guards, auth and layouts keep working exactly as they do today.
|
|
|
76
81
|
`react-router-dom` here is *your* router, not an SDK dependency:
|
|
77
82
|
`useAgoNavigation` accepts any `(path: string) => void` function.
|
|
78
83
|
|
|
84
|
+
## Show the source docs the agent retrieved
|
|
85
|
+
|
|
86
|
+
Each assistant message carries the knowledge sources it used in `m.sources`
|
|
87
|
+
(each one is `{ id, title, url? }`). Build your own chat with `useChat` and
|
|
88
|
+
render them as links to show the URL of every retrieved doc:
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
import { useChat } from "@useago/sdk/react";
|
|
92
|
+
|
|
93
|
+
function Chat() {
|
|
94
|
+
const { messages, sendMessage, isLoading } = useChat();
|
|
95
|
+
|
|
96
|
+
return (
|
|
97
|
+
<div>
|
|
98
|
+
{messages.map((m) => (
|
|
99
|
+
<div key={m.id}>
|
|
100
|
+
<p><b>{m.role}:</b> {m.content}</p>
|
|
101
|
+
|
|
102
|
+
{m.sources?.length ? (
|
|
103
|
+
<ul>
|
|
104
|
+
{m.sources.map((s) => (
|
|
105
|
+
<li key={s.id}>
|
|
106
|
+
{s.url ? (
|
|
107
|
+
<a href={s.url} target="_blank" rel="noreferrer">
|
|
108
|
+
{s.title || s.url}
|
|
109
|
+
</a>
|
|
110
|
+
) : (
|
|
111
|
+
s.title
|
|
112
|
+
)}
|
|
113
|
+
</li>
|
|
114
|
+
))}
|
|
115
|
+
</ul>
|
|
116
|
+
) : null}
|
|
117
|
+
</div>
|
|
118
|
+
))}
|
|
119
|
+
<button onClick={() => sendMessage("Hello!")} disabled={isLoading}>
|
|
120
|
+
Send
|
|
121
|
+
</button>
|
|
122
|
+
</div>
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
79
127
|
**Next: the [Getting started guide](docs/general/getting-started.md)** has both
|
|
80
128
|
examples assembled into a running app, plus everything else the SDK can do, in
|
|
81
129
|
about 5 minutes.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
var h=class extends Error{constructor(e,t,s){super(e),this.code=t,this.statusCode=s,this.name="AgoError"}},u=class b extends h{constructor(t,s,n,r,i,a){super(t,s,n),this.type=r,this.param=i,this.docUrl=a,this.name="AgoApiError"}static fromResponse(t,s){const n=t.error;return new b(n.doc_url?`${n.message} See ${n.doc_url}`:n.message,n.code,s,n.type,n.param,n.doc_url)}},d=class extends h{constructor(e,t){super(e,"network_error"),this.originalError=t,this.name="AgoNetworkError"}},g=class extends h{constructor(e,t="stream_error"){super(e,t),this.name="AgoStreamError"}},m=class extends h{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)}},o=new $,y="ago_widget_id";function x(){if(typeof localStorage<"u"){const t=localStorage.getItem(y);if(t)return t}const e=typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`ago-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,12)}`;if(typeof localStorage<"u")try{localStorage.setItem(y,e)}catch{}return e}var R=class{constructor(e){this.baseUrl=e.baseUrl.replace(/\/$/,""),this.headers={"X-User-Anon-Id":e.widgetId||x()},e.userEmail&&(this.headers["X-User-Email"]=e.userEmail),e.userJwt&&(this.headers.Authorization=`Bearer ${e.userJwt}`),e.permission&&(this.headers["X-Widget-Permission"]=e.permission)}updateConfig(e){e.baseUrl&&(this.baseUrl=e.baseUrl.replace(/\/$/,"")),e.widgetId&&(this.headers["X-User-Anon-Id"]=e.widgetId),e.userEmail&&(this.headers["X-User-Email"]=e.userEmail),e.userJwt&&(this.headers.Authorization=`Bearer ${e.userJwt}`),e.permission!==void 0&&(e.permission?this.headers["X-Widget-Permission"]=e.permission:delete this.headers["X-Widget-Permission"])}async get(e){return this.request("GET",e)}async post(e,t){return this.request("POST",e,t)}async postStream(e,t){const s=`${this.baseUrl}${e}`;o.debug("POST (stream)",s,t);try{const n=await fetch(s,{method:"POST",headers:{...this.headers,"Content-Type":"application/json"},body:t?JSON.stringify(t):void 0});return n.ok||await this.handleErrorResponse(n),n}catch(n){throw n instanceof u?n:new d(`Network error: ${n instanceof Error?n.message:"Unknown error"}. Check that \`baseUrl\` is reachable and includes the protocol (https://).`,n instanceof Error?n:void 0)}}async postFormData(e,t){const s=`${this.baseUrl}${e}`;o.debug("POST (formData)",s);const n={...this.headers};try{const r=await fetch(s,{method:"POST",headers:n,body:t});return r.ok||await this.handleErrorResponse(r),r}catch(r){throw r instanceof u?r:new d(`Network error: ${r instanceof Error?r.message:"Unknown error"}. Check that \`baseUrl\` is reachable and includes the protocol (https://).`,r instanceof Error?r:void 0)}}async request(e,t,s){const n=`${this.baseUrl}${t}`;o.debug(e,n,s);try{const r=await fetch(n,{method:e,headers:{...this.headers,"Content-Type":"application/json"},body:s?JSON.stringify(s):void 0});return r.ok||await this.handleErrorResponse(r),r.status===204?void 0:r.json()}catch(r){throw r instanceof u?r:new d(`Network error: ${r instanceof Error?r.message:"Unknown error"}. Check that \`baseUrl\` is reachable and includes the protocol (https://).`,r instanceof Error?r:void 0)}}async handleErrorResponse(e){let t;try{t=await e.json()}catch{}if(t?.error)throw u.fromResponse(t,e.status);let s="";throw e.status===401||e.status===403?s=" Check `userJwt` (and that it has not expired).":e.status===404&&(s=" Check that `baseUrl` points at your AGO API root."),new u(`HTTP ${e.status}: ${e.statusText}.${s}`,"http_error",e.status,"api_error")}},C=class{constructor(){this.functions=new Map}register(e,t,s){if(typeof e=="object"){const{name:r,handler:i,description:a,parameters:l}=e;return this.register(r,i,{description:a,parameters:l})}const n=e;if(!t||!s)throw new h(`registerFunction("${n}"): both a handler and a schema are required. Pass them as arguments or use the single-object form: registerFunction({ name, parameters, handler }).`,"function_invalid_registration");this.functions.has(n)&&o.warn(`Function "${n}" is being overwritten`),this.functions.set(n,{schema:{...s,name:n},handler:t}),o.log(`Registered function: ${n}`)}unregister(e){const t=this.functions.delete(e);return t&&o.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);o.log(`Executing function: ${e}`,t);try{const n=await s.handler(t);return o.log(`Function ${e} completed:`,n),n}catch(n){throw o.error(`Function ${e} failed:`,n),new m(`Function "${e}" execution failed: ${n instanceof Error?n.message:"Unknown error"}`,e,n instanceof Error?n:void 0)}}clear(){this.functions.clear(),o.log("Cleared all registered functions")}get size(){return this.functions.size}},E=class{constructor(){this.entries=new Map,this.dynamicProviders=new Map}set(e,t){this.entries.set(e,t),o.log(`ClientContext set: ${e}`)}remove(e){const t=this.entries.delete(e);return t&&o.log(`ClientContext removed: ${e}`),t}addDynamicProvider(e,t){this.dynamicProviders.set(e,t),o.log(`DynamicContext provider added: ${e}`)}removeDynamicProvider(e){const t=this.dynamicProviders.delete(e);return t&&o.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 n=s();n&&(e[t]=n)}catch(n){o.error(`DynamicContext provider "${t}" threw:`,n)}return Object.keys(e).length===0?null:{entries:e}}clear(){this.entries.clear(),this.dynamicProviders.clear(),o.log("ClientContext cleared")}};function f(e){return e===null||typeof e!="object"?JSON.stringify(e)??"null":Array.isArray(e)?`[${e.map(f).join(",")}]`:`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${f(e[t])}`).join(",")}}`}var _=class{constructor(e){this.callbacks=e,this.buffer="",this.message={},this.toolCalls=[],this.sources=[],this.followUpReplies=[],this.isFirstChunk=!0,this.answerCompleteEmitted=!1,this.firedClientFunctions=new Set}async processStream(e){if(!e.body)throw new g("Response has no body. The endpoint did not return a stream: check that `baseUrl` points at an AGO API and nothing (proxy, mock) strips the SSE body.","stream_no_body");const t=e.body.getReader(),s=new TextDecoder;try{for(;;){const{done:n,value:r}=await t.read();if(n)break;const i=s.decode(r,{stream:!0});this.buffer+=i,this.processBuffer()}return this.buffer.trim()&&this.processBuffer(),this.buildFinalMessage()}catch(n){const r=n instanceof Error?n:new g("Stream processing failed mid-flight. The connection may have dropped; retry the message.");throw this.callbacks.onError?.(r),r}finally{t.releaseLock()}}processBuffer(){const e=this.buffer.split(`
|
|
2
|
+
|
|
3
|
+
`);this.buffer=e.pop()||"";for(const t of e){if(!t.trim())continue;const s=t.split(`
|
|
4
|
+
`);for(const n of s)if(!n.startsWith(": ")&&n.startsWith("data: ")){const r=n.slice(6);try{const i=JSON.parse(r);this.handleChunk(i)}catch(i){o.warn("Failed to parse SSE data:",r,i)}}}}handleChunk(e){if(this.callbacks.onRawChunk?.(e),e.message_id&&!this.message.id&&(this.message.id=e.message_id),e.thread?.id&&(this.message.conversationId=e.thread.id,this.isFirstChunk&&this.message.id&&(this.isFirstChunk=!1,this.callbacks.onStart?.({conversationId:this.message.conversationId,messageId:this.message.id}))),e.content!==void 0&&(this.message.content=(this.message.content||"")+e.content,this.message.conversationId&&this.message.id&&this.callbacks.onChunk?.({content:e.content,conversationId:this.message.conversationId,messageId:this.message.id})),e.full_content!==void 0&&(this.message.content=e.full_content),e.status&&(this.message.status=e.status),e.agent&&(this.message.agent={id:e.agent.id,name:e.agent.name,displayName:e.agent.display_name}),e.knowledge_sources&&(this.sources=e.knowledge_sources.map(t=>{const 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){const t=`${e.function_name}::${f(e.arguments??{})}`;this.firedClientFunctions.has(t)||(this.firedClientFunctions.add(t),this.callbacks.onClientFunction?.({invocationId:e.id||"",functionName:e.function_name,arguments:e.arguments||{},conversationId:this.message.conversationId||""}))}if(e.tool_call_data&&e.type&&e.type!=="client_function"){const t=this.parseToolCall(e);this.callbacks.onToolCall?.(t);const s=this.toolCalls.findIndex(n=>n.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 I(e){const t=e.message.toLowerCase();return t.includes("load failed")||t.includes("failed to fetch")||t.includes("network")||t.includes("abort")}var S=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(n=>{try{n(t)}catch(r){console.error(`Error in event handler for ${String(e)}:`,r)}})}once(e,t){const s=(n=>{this.off(e,s),t(n)});this.on(e,s)}waitFor(e,t){return new Promise((s,n)=>{let r;const i=(a=>{r&&clearTimeout(r),s(a)});this.once(e,i),t?.timeout&&(r=setTimeout(()=>{this.off(e,i),n(new Error(`waitFor("${String(e)}") timed out after ${t.timeout}ms`))},t.timeout))})}removeAllListeners(e){e?this.handlers.delete(e):this.handlers.clear()}},w='`baseUrl` is required, e.g. new AgoClient({ baseUrl: "https://YOUR-DOMAIN.api.useago.com" }). Try the live demo endpoint https://playground.api.useago.com. See docs/general/configuration.md#error-codes (config_missing_base_url).',U=/^[a-z][a-z0-9+.-]*:\/\//i,v=!1;function p(e,t="AgoClient"){if(typeof e!="object"||e===null)throw new h(`${t}: ${w}`,"config_missing_base_url");const s=e.baseUrl;if(typeof s!="string"||s.trim()==="")throw new h(`${t}: ${w}`,"config_missing_base_url");!s.startsWith("/")&&!U.test(s)&&(v||(v=!0,console.warn(`[AGO] ${t}: \`baseUrl\` has no protocol and is not a relative path (config_suspect_base_url). Requests will fail: Node throws a URL parse error, browsers fetch it as a relative path. Use "https://..." (or a "/path" for a same-origin proxy).`)))}var F=class k{constructor(t){this.warnedEmptyConversations=new Set,p(t,"AgoClient"),this.config=t,this.httpClient=new R(t),this.functionRegistry=new C,this.contextRegistry=new E,this.eventEmitter=new S,t.debug&&o.enable(),o.log("AgoClient initialized")}async sendMessage(t,s){const n=this.functionRegistry.getSchemas(),r=this.contextRegistry.getSnapshot(),i=this.config.agent||this.config.defaultAgentId,a={content:t,conversation_id:s?.conversationId,agent_id:s?.agentId||i};n.length>0&&(a.client_functions=n),r&&(a.client_context=r);let l;if(s?.files&&s.files.length>0){const c=new FormData;c.append("content",t),s.conversationId&&c.append("conversation_id",s.conversationId),(s.agentId||i)&&c.append("agent_id",s.agentId||i||""),n.length>0&&c.append("client_functions",JSON.stringify(n)),r&&c.append("client_context",JSON.stringify(r));for(const A of s.files)c.append("files",A);l=await this.httpClient.postFormData("/api/sdk/v1/messages",c)}else l=await this.httpClient.postStream("/api/sdk/v1/messages",a);return this.processSSEResponse(l)}async processSSEResponse(t){let s=!1;const n=await new _({onRawChunk:r=>{this.eventEmitter.emit("stream:message",r)},onStart:r=>{this.eventEmitter.emit("message:start",r)},onChunk:r=>{this.eventEmitter.emit("message:chunk",r)},onToolCall:r=>{this.eventEmitter.emit("toolCall:received",r),r.type==="form"&&this.eventEmitter.emit("toolCall:form",r)},onClientFunction:async r=>{s=!0,this.eventEmitter.emit("function:invoke",r),await this.handleClientFunctionInvocation(r)},onAnswerComplete:r=>{this.eventEmitter.emit("message:answer-complete",r)},onComplete:r=>{this.eventEmitter.emit("message:complete",r)},onError:r=>{this.eventEmitter.emit("message:error",{error:r.message,code:r instanceof h?r.code:void 0})}}).processStream(t);return this.maybeFlagEmptyReply(n,s),n}maybeFlagEmptyReply(t,s){t.status==="DONE"&&(t.content??"").trim()===""&&!s&&!(t.toolCalls&&t.toolCalls.length>0)&&!(t.followUpReplies&&t.followUpReplies.length>0)&&setTimeout(()=>{if(this.eventEmitter.emit("message:empty",{conversationId:t.conversationId??"",messageId:t.id??""}),this.config.warnOnEmptyReply===!1)return;const n=t.conversationId||"(no conversation)";if(this.warnedEmptyConversations.has(n))return;this.warnedEmptyConversations.add(n);const r=this.config.agent||this.config.defaultAgentId;t.id?console.warn("[AGO] Reply completed with empty content. Possible causes: "+(r?`the agent "${r}" may not exist for this tenant, `:"an unknown `agent` slug, ")+"or the agent replied with no text. Listen for the `message:empty` event to handle this in your app; silence this warning with `warnOnEmptyReply: false`."):console.warn("[AGO] The stream completed without any message data. Possible causes: "+(r?`the agent "${r}" may not exist for this tenant, or `:"")+"`baseUrl` does not point at an AGO endpoint that returns server-sent events. Listen for the `message:empty` event to handle this in your app; silence this warning with `warnOnEmptyReply: false`.")},0)}async handleClientFunctionInvocation(t){let s,n;try{s=await this.functionRegistry.execute(t.functionName,t.arguments)}catch(r){n=r instanceof Error?r.message:"Unknown error",o.error("Client function execution failed:",r)}if(t.invocationId)try{await this.submitToolCallForm(t.invocationId,{result:s,error:n,_type:"client_function_result"})}catch(r){o.error("Failed to submit function result:",r)}this.eventEmitter.emit("function:result",{invocationId:t.invocationId,result:s,error:n})}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}`),n={id:s.id,title:s.title,lastMessageDate:new Date(s.last_message_date),messages:s.messages.map(r=>({id:r.id,conversationId:s.id,content:r.content,role:r.role,status:r.status,createdAt:new Date(r.created_at),toolCalls:k.mapPersistedToolCalls(r.tool_call_data)}))};return this.eventEmitter.emit("conversation:loaded",n),n}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",{name:t,values:s})}async submitFeedback(t,s){await this.httpClient.post(`/api/sdk/v1/messages/${t}/feedback`,{rating:s})}registerFunction(t,s,n){typeof t=="object"?this.functionRegistry.register(t):this.functionRegistry.register(t,s,n)}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 n=s.map(i=>i.name),r=s.map(i=>`- "${i.name}": ${i.description}`).join(`
|
|
5
|
+
`);this.registerFunction("navigateToPage",async i=>{const a=i.page,l=s.find(c=>c.name===a);return l?(t(l.path),{success:!0,navigatedTo:l.path}):{success:!1,error:`Unknown page: ${a}`}},{description:`Navigate the user to a page in the application. Available pages:
|
|
6
|
+
${r}`,parameters:{type:"object",properties:{page:{type:"string",description:"The page to navigate to",enum:n}},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){const s={};for(const[r,i]of Object.entries(t))i!==void 0&&(s[r]=i);const n={...this.config,...s};p(n,"AgoClient.updateConfig"),this.config=n,this.httpClient.updateConfig(s),s.debug!==void 0&&(s.debug?o.enable():o.disable())}destroy(){this.eventEmitter.removeAllListeners(),this.functionRegistry.clear(),this.contextRegistry.clear(),o.log("AgoClient destroyed")}};Object.defineProperty(exports,"AgoApiError",{enumerable:!0,get:function(){return u}});Object.defineProperty(exports,"AgoClient",{enumerable:!0,get:function(){return F}});Object.defineProperty(exports,"AgoError",{enumerable:!0,get:function(){return h}});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 E}});Object.defineProperty(exports,"EventEmitter",{enumerable:!0,get:function(){return S}});Object.defineProperty(exports,"FunctionRegistry",{enumerable:!0,get:function(){return C}});Object.defineProperty(exports,"SSEHandler",{enumerable:!0,get:function(){return _}});Object.defineProperty(exports,"isStreamNetworkError",{enumerable:!0,get:function(){return I}});Object.defineProperty(exports,"logger",{enumerable:!0,get:function(){return o}});Object.defineProperty(exports,"validateConfig",{enumerable:!0,get:function(){return p}});
|
|
@@ -2,27 +2,27 @@ var h = class extends Error {
|
|
|
2
2
|
constructor(e, t, s) {
|
|
3
3
|
super(e), this.code = t, this.statusCode = s, this.name = "AgoError";
|
|
4
4
|
}
|
|
5
|
-
}, d = class
|
|
5
|
+
}, d = class C extends h {
|
|
6
6
|
constructor(t, s, n, i, r, a) {
|
|
7
7
|
super(t, s, n), this.type = i, this.param = r, this.docUrl = a, this.name = "AgoApiError";
|
|
8
8
|
}
|
|
9
9
|
static fromResponse(t, s) {
|
|
10
10
|
const n = t.error;
|
|
11
|
-
return new
|
|
11
|
+
return new C(n.doc_url ? `${n.message} See ${n.doc_url}` : n.message, n.code, s, n.type, n.param, n.doc_url);
|
|
12
12
|
}
|
|
13
13
|
}, u = class extends h {
|
|
14
14
|
constructor(e, t) {
|
|
15
15
|
super(e, "network_error"), this.originalError = t, this.name = "AgoNetworkError";
|
|
16
16
|
}
|
|
17
|
-
},
|
|
17
|
+
}, g = class extends h {
|
|
18
18
|
constructor(e, t = "stream_error") {
|
|
19
19
|
super(e, t), this.name = "AgoStreamError";
|
|
20
20
|
}
|
|
21
|
-
},
|
|
21
|
+
}, f = class extends h {
|
|
22
22
|
constructor(e, t, s) {
|
|
23
23
|
super(e, "function_error"), this.functionName = t, this.originalError = s, this.name = "AgoFunctionError";
|
|
24
24
|
}
|
|
25
|
-
},
|
|
25
|
+
}, _ = class {
|
|
26
26
|
constructor(e = !1) {
|
|
27
27
|
this.enabled = e;
|
|
28
28
|
}
|
|
@@ -44,22 +44,22 @@ var h = class extends Error {
|
|
|
44
44
|
debug(...e) {
|
|
45
45
|
this.enabled && console.debug("[AGO SDK]", ...e);
|
|
46
46
|
}
|
|
47
|
-
}, o = new
|
|
48
|
-
function
|
|
47
|
+
}, o = new _(), p = "ago_widget_id";
|
|
48
|
+
function S() {
|
|
49
49
|
if (typeof localStorage < "u") {
|
|
50
|
-
const t = localStorage.getItem(
|
|
50
|
+
const t = localStorage.getItem(p);
|
|
51
51
|
if (t) return t;
|
|
52
52
|
}
|
|
53
53
|
const e = typeof crypto < "u" && typeof crypto.randomUUID == "function" ? crypto.randomUUID() : `ago-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 12)}`;
|
|
54
54
|
if (typeof localStorage < "u") try {
|
|
55
|
-
localStorage.setItem(
|
|
55
|
+
localStorage.setItem(p, e);
|
|
56
56
|
} catch {
|
|
57
57
|
}
|
|
58
58
|
return e;
|
|
59
59
|
}
|
|
60
|
-
var
|
|
60
|
+
var k = class {
|
|
61
61
|
constructor(e) {
|
|
62
|
-
this.baseUrl = e.baseUrl.replace(/\/$/, ""), this.headers = { "X-User-Anon-Id": e.widgetId ||
|
|
62
|
+
this.baseUrl = e.baseUrl.replace(/\/$/, ""), this.headers = { "X-User-Anon-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);
|
|
63
63
|
}
|
|
64
64
|
updateConfig(e) {
|
|
65
65
|
e.baseUrl && (this.baseUrl = e.baseUrl.replace(/\/$/, "")), e.widgetId && (this.headers["X-User-Anon-Id"] = e.widgetId), e.userEmail && (this.headers["X-User-Email"] = e.userEmail), e.userJwt && (this.headers.Authorization = `Bearer ${e.userJwt}`), e.permission !== void 0 && (e.permission ? this.headers["X-Widget-Permission"] = e.permission : delete this.headers["X-Widget-Permission"]);
|
|
@@ -129,7 +129,7 @@ var S = class {
|
|
|
129
129
|
let s = "";
|
|
130
130
|
throw e.status === 401 || e.status === 403 ? s = " Check `userJwt` (and that it has not expired)." : e.status === 404 && (s = " Check that `baseUrl` points at your AGO API root."), new d(`HTTP ${e.status}: ${e.statusText}.${s}`, "http_error", e.status, "api_error");
|
|
131
131
|
}
|
|
132
|
-
},
|
|
132
|
+
}, $ = class {
|
|
133
133
|
constructor() {
|
|
134
134
|
this.functions = /* @__PURE__ */ new Map();
|
|
135
135
|
}
|
|
@@ -166,13 +166,13 @@ var S = class {
|
|
|
166
166
|
}
|
|
167
167
|
async execute(e, t) {
|
|
168
168
|
const s = this.functions.get(e);
|
|
169
|
-
if (!s) throw new
|
|
169
|
+
if (!s) throw new f(`Function "${e}" is not registered`, e);
|
|
170
170
|
o.log(`Executing function: ${e}`, t);
|
|
171
171
|
try {
|
|
172
172
|
const n = await s.handler(t);
|
|
173
173
|
return o.log(`Function ${e} completed:`, n), n;
|
|
174
174
|
} catch (n) {
|
|
175
|
-
throw o.error(`Function ${e} failed:`, n), new
|
|
175
|
+
throw o.error(`Function ${e} failed:`, n), new f(`Function "${e}" execution failed: ${n instanceof Error ? n.message : "Unknown error"}`, e, n instanceof Error ? n : void 0);
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
clear() {
|
|
@@ -214,12 +214,16 @@ var S = class {
|
|
|
214
214
|
clear() {
|
|
215
215
|
this.entries.clear(), this.dynamicProviders.clear(), o.log("ClientContext cleared");
|
|
216
216
|
}
|
|
217
|
-
}
|
|
217
|
+
};
|
|
218
|
+
function m(e) {
|
|
219
|
+
return e === null || typeof e != "object" ? JSON.stringify(e) ?? "null" : Array.isArray(e) ? `[${e.map(m).join(",")}]` : `{${Object.keys(e).sort().map((t) => `${JSON.stringify(t)}:${m(e[t])}`).join(",")}}`;
|
|
220
|
+
}
|
|
221
|
+
var x = class {
|
|
218
222
|
constructor(e) {
|
|
219
|
-
this.callbacks = e, this.buffer = "", this.message = {}, this.toolCalls = [], this.sources = [], this.followUpReplies = [], this.isFirstChunk = !0, this.answerCompleteEmitted = !1;
|
|
223
|
+
this.callbacks = e, this.buffer = "", this.message = {}, this.toolCalls = [], this.sources = [], this.followUpReplies = [], this.isFirstChunk = !0, this.answerCompleteEmitted = !1, this.firedClientFunctions = /* @__PURE__ */ new Set();
|
|
220
224
|
}
|
|
221
225
|
async processStream(e) {
|
|
222
|
-
if (!e.body) throw new
|
|
226
|
+
if (!e.body) throw new g("Response has no body. The endpoint did not return a stream: check that `baseUrl` points at an AGO API and nothing (proxy, mock) strips the SSE body.", "stream_no_body");
|
|
223
227
|
const t = e.body.getReader(), s = new TextDecoder();
|
|
224
228
|
try {
|
|
225
229
|
for (; ; ) {
|
|
@@ -230,7 +234,7 @@ var S = class {
|
|
|
230
234
|
}
|
|
231
235
|
return this.buffer.trim() && this.processBuffer(), this.buildFinalMessage();
|
|
232
236
|
} catch (n) {
|
|
233
|
-
const i = n instanceof Error ? n : new
|
|
237
|
+
const i = n instanceof Error ? n : new g("Stream processing failed mid-flight. The connection may have dropped; retry the message.");
|
|
234
238
|
throw this.callbacks.onError?.(i), i;
|
|
235
239
|
} finally {
|
|
236
240
|
t.releaseLock();
|
|
@@ -258,7 +262,7 @@ var S = class {
|
|
|
258
262
|
}
|
|
259
263
|
}
|
|
260
264
|
handleChunk(e) {
|
|
261
|
-
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?.({
|
|
265
|
+
if (this.callbacks.onRawChunk?.(e), e.message_id && !this.message.id && (this.message.id = e.message_id), e.thread?.id && (this.message.conversationId = e.thread.id, this.isFirstChunk && this.message.id && (this.isFirstChunk = !1, this.callbacks.onStart?.({
|
|
262
266
|
conversationId: this.message.conversationId,
|
|
263
267
|
messageId: this.message.id
|
|
264
268
|
}))), e.content !== void 0 && (this.message.content = (this.message.content || "") + e.content, this.message.conversationId && this.message.id && this.callbacks.onChunk?.({
|
|
@@ -276,12 +280,16 @@ var S = class {
|
|
|
276
280
|
title: s.title,
|
|
277
281
|
url: s.use_external_link ? s.external_link_url : s.internal_link_url
|
|
278
282
|
};
|
|
279
|
-
})), e.type === "client_function" && e.function_name
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
283
|
+
})), e.type === "client_function" && e.function_name) {
|
|
284
|
+
const t = `${e.function_name}::${m(e.arguments ?? {})}`;
|
|
285
|
+
this.firedClientFunctions.has(t) || (this.firedClientFunctions.add(t), this.callbacks.onClientFunction?.({
|
|
286
|
+
invocationId: e.id || "",
|
|
287
|
+
functionName: e.function_name,
|
|
288
|
+
arguments: e.arguments || {},
|
|
289
|
+
conversationId: this.message.conversationId || ""
|
|
290
|
+
}));
|
|
291
|
+
}
|
|
292
|
+
if (e.tool_call_data && e.type && e.type !== "client_function") {
|
|
285
293
|
const t = this.parseToolCall(e);
|
|
286
294
|
this.callbacks.onToolCall?.(t);
|
|
287
295
|
const s = this.toolCalls.findIndex((n) => n.id === t.id);
|
|
@@ -322,11 +330,11 @@ var S = class {
|
|
|
322
330
|
return this.callbacks.onComplete?.(e), e;
|
|
323
331
|
}
|
|
324
332
|
};
|
|
325
|
-
function
|
|
333
|
+
function U(e) {
|
|
326
334
|
const t = e.message.toLowerCase();
|
|
327
335
|
return t.includes("load failed") || t.includes("failed to fetch") || t.includes("network") || t.includes("abort");
|
|
328
336
|
}
|
|
329
|
-
var
|
|
337
|
+
var R = class {
|
|
330
338
|
constructor() {
|
|
331
339
|
this.handlers = /* @__PURE__ */ new Map();
|
|
332
340
|
}
|
|
@@ -367,16 +375,16 @@ var $ = class {
|
|
|
367
375
|
removeAllListeners(e) {
|
|
368
376
|
e ? this.handlers.delete(e) : this.handlers.clear();
|
|
369
377
|
}
|
|
370
|
-
},
|
|
371
|
-
function
|
|
372
|
-
if (typeof e != "object" || e === null) throw new h(`${t}: ${
|
|
378
|
+
}, y = '`baseUrl` is required, e.g. new AgoClient({ baseUrl: "https://YOUR-DOMAIN.api.useago.com" }). Try the live demo endpoint https://playground.api.useago.com. See docs/general/configuration.md#error-codes (config_missing_base_url).', I = /^[a-z][a-z0-9+.-]*:\/\//i, w = !1;
|
|
379
|
+
function v(e, t = "AgoClient") {
|
|
380
|
+
if (typeof e != "object" || e === null) throw new h(`${t}: ${y}`, "config_missing_base_url");
|
|
373
381
|
const s = e.baseUrl;
|
|
374
|
-
if (typeof s != "string" || s.trim() === "") throw new h(`${t}: ${
|
|
375
|
-
!s.startsWith("/") && !I.test(s) && (
|
|
382
|
+
if (typeof s != "string" || s.trim() === "") throw new h(`${t}: ${y}`, "config_missing_base_url");
|
|
383
|
+
!s.startsWith("/") && !I.test(s) && (w || (w = !0, console.warn(`[AGO] ${t}: \`baseUrl\` has no protocol and is not a relative path (config_suspect_base_url). Requests will fail: Node throws a URL parse error, browsers fetch it as a relative path. Use "https://..." (or a "/path" for a same-origin proxy).`)));
|
|
376
384
|
}
|
|
377
|
-
var
|
|
385
|
+
var F = class b {
|
|
378
386
|
constructor(t) {
|
|
379
|
-
this.warnedEmptyConversations = /* @__PURE__ */ new Set(),
|
|
387
|
+
this.warnedEmptyConversations = /* @__PURE__ */ new Set(), v(t, "AgoClient"), this.config = t, this.httpClient = new k(t), this.functionRegistry = new $(), this.contextRegistry = new A(), this.eventEmitter = new R(), t.debug && o.enable(), o.log("AgoClient initialized");
|
|
380
388
|
}
|
|
381
389
|
async sendMessage(t, s) {
|
|
382
390
|
const n = this.functionRegistry.getSchemas(), i = this.contextRegistry.getSnapshot(), r = this.config.agent || this.config.defaultAgentId, a = {
|
|
@@ -389,7 +397,7 @@ var U = class C {
|
|
|
389
397
|
if (s?.files && s.files.length > 0) {
|
|
390
398
|
const c = new FormData();
|
|
391
399
|
c.append("content", t), s.conversationId && c.append("conversation_id", s.conversationId), (s.agentId || r) && c.append("agent_id", s.agentId || r || ""), n.length > 0 && c.append("client_functions", JSON.stringify(n)), i && c.append("client_context", JSON.stringify(i));
|
|
392
|
-
for (const
|
|
400
|
+
for (const E of s.files) c.append("files", E);
|
|
393
401
|
l = await this.httpClient.postFormData("/api/sdk/v1/messages", c);
|
|
394
402
|
} else l = await this.httpClient.postStream("/api/sdk/v1/messages", a);
|
|
395
403
|
return this.processSSEResponse(l);
|
|
@@ -397,6 +405,9 @@ var U = class C {
|
|
|
397
405
|
async processSSEResponse(t) {
|
|
398
406
|
let s = !1;
|
|
399
407
|
const n = await new x({
|
|
408
|
+
onRawChunk: (i) => {
|
|
409
|
+
this.eventEmitter.emit("stream:message", i);
|
|
410
|
+
},
|
|
400
411
|
onStart: (i) => {
|
|
401
412
|
this.eventEmitter.emit("message:start", i);
|
|
402
413
|
},
|
|
@@ -478,7 +489,7 @@ var U = class C {
|
|
|
478
489
|
role: i.role,
|
|
479
490
|
status: i.status,
|
|
480
491
|
createdAt: new Date(i.created_at),
|
|
481
|
-
toolCalls:
|
|
492
|
+
toolCalls: b.mapPersistedToolCalls(i.tool_call_data)
|
|
482
493
|
}))
|
|
483
494
|
};
|
|
484
495
|
return this.eventEmitter.emit("conversation:loaded", n), n;
|
|
@@ -619,24 +630,24 @@ ${i}`,
|
|
|
619
630
|
...this.config,
|
|
620
631
|
...s
|
|
621
632
|
};
|
|
622
|
-
|
|
633
|
+
v(n, "AgoClient.updateConfig"), this.config = n, this.httpClient.updateConfig(s), s.debug !== void 0 && (s.debug ? o.enable() : o.disable());
|
|
623
634
|
}
|
|
624
635
|
destroy() {
|
|
625
636
|
this.eventEmitter.removeAllListeners(), this.functionRegistry.clear(), this.contextRegistry.clear(), o.log("AgoClient destroyed");
|
|
626
637
|
}
|
|
627
638
|
};
|
|
628
639
|
export {
|
|
629
|
-
|
|
640
|
+
U as a,
|
|
630
641
|
o as c,
|
|
631
|
-
|
|
642
|
+
f as d,
|
|
632
643
|
u as f,
|
|
633
644
|
x as i,
|
|
634
645
|
d as l,
|
|
635
|
-
|
|
646
|
+
v as n,
|
|
636
647
|
A as o,
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
648
|
+
g as p,
|
|
649
|
+
R as r,
|
|
650
|
+
$ as s,
|
|
651
|
+
F as t,
|
|
641
652
|
h as u
|
|
642
653
|
};
|
package/dist/angular.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("./AgoClient
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("./AgoClient--y10UXUV.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;
|
package/dist/angular.d.cts
CHANGED
|
@@ -243,6 +243,13 @@ export declare interface AgoClientEvents {
|
|
|
243
243
|
conversationId: string;
|
|
244
244
|
messageId: string;
|
|
245
245
|
};
|
|
246
|
+
/**
|
|
247
|
+
* Every raw SSE message parsed off the stream, before the handler interprets it
|
|
248
|
+
* into the higher-level `message:*` / `toolCall:*` / `function:*` events. Carries
|
|
249
|
+
* the chunk verbatim so debugging tools (notably the dev panel) can log the exact
|
|
250
|
+
* wire payload. Heartbeat comments are not messages and don't fire this.
|
|
251
|
+
*/
|
|
252
|
+
"stream:message": SSEChunkData;
|
|
246
253
|
/**
|
|
247
254
|
* The main answer text is done (backend emitted `status: "DONE"`), but follow-up
|
|
248
255
|
* replies may still be pending. Fires once, before `message:complete`.
|
|
@@ -337,8 +344,7 @@ export declare interface AgoMessage {
|
|
|
337
344
|
createdAt: Date;
|
|
338
345
|
}
|
|
339
346
|
|
|
340
|
-
export declare
|
|
341
|
-
}
|
|
347
|
+
export declare type AgoProvideOptions = AgoConfig;
|
|
342
348
|
|
|
343
349
|
/**
|
|
344
350
|
* Angular-style service wrapping AgoClient.
|
|
@@ -651,6 +657,47 @@ declare interface SendMessageOptions {
|
|
|
651
657
|
files?: File[];
|
|
652
658
|
}
|
|
653
659
|
|
|
660
|
+
/**
|
|
661
|
+
* SSE stream chunk data
|
|
662
|
+
*/
|
|
663
|
+
declare interface SSEChunkData {
|
|
664
|
+
content?: string;
|
|
665
|
+
full_content?: string;
|
|
666
|
+
message_id?: string;
|
|
667
|
+
status?: MessageStatus;
|
|
668
|
+
thread?: {
|
|
669
|
+
id: string;
|
|
670
|
+
};
|
|
671
|
+
agent?: {
|
|
672
|
+
id: string;
|
|
673
|
+
name: string;
|
|
674
|
+
display_name?: string;
|
|
675
|
+
};
|
|
676
|
+
knowledge_sources?: Array<{
|
|
677
|
+
knowledge_document: {
|
|
678
|
+
id: string;
|
|
679
|
+
title: string;
|
|
680
|
+
use_external_link: boolean;
|
|
681
|
+
external_link_url?: string;
|
|
682
|
+
internal_link_url?: string;
|
|
683
|
+
};
|
|
684
|
+
position: number;
|
|
685
|
+
}>;
|
|
686
|
+
tool_call_data?: boolean;
|
|
687
|
+
type?: string;
|
|
688
|
+
id?: string;
|
|
689
|
+
tool_name?: string;
|
|
690
|
+
tool_display_name?: string;
|
|
691
|
+
function_name?: string;
|
|
692
|
+
arguments?: Record<string, unknown>;
|
|
693
|
+
form_schema?: FormSchema;
|
|
694
|
+
message?: string;
|
|
695
|
+
data?: Record<string, unknown>;
|
|
696
|
+
follow_up_replies?: string[];
|
|
697
|
+
satisfaction_feedback?: unknown;
|
|
698
|
+
ask_to_talk_to_human?: boolean;
|
|
699
|
+
}
|
|
700
|
+
|
|
654
701
|
/**
|
|
655
702
|
* Where a completed form is sent.
|
|
656
703
|
* - `"https://..."` (a bare string) — shorthand for `{ via: "client", url }`: the browser
|
package/dist/angular.d.ts
CHANGED
|
@@ -243,6 +243,13 @@ export declare interface AgoClientEvents {
|
|
|
243
243
|
conversationId: string;
|
|
244
244
|
messageId: string;
|
|
245
245
|
};
|
|
246
|
+
/**
|
|
247
|
+
* Every raw SSE message parsed off the stream, before the handler interprets it
|
|
248
|
+
* into the higher-level `message:*` / `toolCall:*` / `function:*` events. Carries
|
|
249
|
+
* the chunk verbatim so debugging tools (notably the dev panel) can log the exact
|
|
250
|
+
* wire payload. Heartbeat comments are not messages and don't fire this.
|
|
251
|
+
*/
|
|
252
|
+
"stream:message": SSEChunkData;
|
|
246
253
|
/**
|
|
247
254
|
* The main answer text is done (backend emitted `status: "DONE"`), but follow-up
|
|
248
255
|
* replies may still be pending. Fires once, before `message:complete`.
|
|
@@ -337,8 +344,7 @@ export declare interface AgoMessage {
|
|
|
337
344
|
createdAt: Date;
|
|
338
345
|
}
|
|
339
346
|
|
|
340
|
-
export declare
|
|
341
|
-
}
|
|
347
|
+
export declare type AgoProvideOptions = AgoConfig;
|
|
342
348
|
|
|
343
349
|
/**
|
|
344
350
|
* Angular-style service wrapping AgoClient.
|
|
@@ -651,6 +657,47 @@ declare interface SendMessageOptions {
|
|
|
651
657
|
files?: File[];
|
|
652
658
|
}
|
|
653
659
|
|
|
660
|
+
/**
|
|
661
|
+
* SSE stream chunk data
|
|
662
|
+
*/
|
|
663
|
+
declare interface SSEChunkData {
|
|
664
|
+
content?: string;
|
|
665
|
+
full_content?: string;
|
|
666
|
+
message_id?: string;
|
|
667
|
+
status?: MessageStatus;
|
|
668
|
+
thread?: {
|
|
669
|
+
id: string;
|
|
670
|
+
};
|
|
671
|
+
agent?: {
|
|
672
|
+
id: string;
|
|
673
|
+
name: string;
|
|
674
|
+
display_name?: string;
|
|
675
|
+
};
|
|
676
|
+
knowledge_sources?: Array<{
|
|
677
|
+
knowledge_document: {
|
|
678
|
+
id: string;
|
|
679
|
+
title: string;
|
|
680
|
+
use_external_link: boolean;
|
|
681
|
+
external_link_url?: string;
|
|
682
|
+
internal_link_url?: string;
|
|
683
|
+
};
|
|
684
|
+
position: number;
|
|
685
|
+
}>;
|
|
686
|
+
tool_call_data?: boolean;
|
|
687
|
+
type?: string;
|
|
688
|
+
id?: string;
|
|
689
|
+
tool_name?: string;
|
|
690
|
+
tool_display_name?: string;
|
|
691
|
+
function_name?: string;
|
|
692
|
+
arguments?: Record<string, unknown>;
|
|
693
|
+
form_schema?: FormSchema;
|
|
694
|
+
message?: string;
|
|
695
|
+
data?: Record<string, unknown>;
|
|
696
|
+
follow_up_replies?: string[];
|
|
697
|
+
satisfaction_feedback?: unknown;
|
|
698
|
+
ask_to_talk_to_human?: boolean;
|
|
699
|
+
}
|
|
700
|
+
|
|
654
701
|
/**
|
|
655
702
|
* Where a completed form is sent.
|
|
656
703
|
* - `"https://..."` (a bare string) — shorthand for `{ via: "client", url }`: the browser
|
package/dist/angular.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as o } from "./AgoClient-
|
|
1
|
+
import { t as o } from "./AgoClient-DYdIe_R4.js";
|
|
2
2
|
var n = class {
|
|
3
3
|
constructor(t) {
|
|
4
4
|
this.client = new o(t), this.messages$ = this.fromEvent("message:complete"), this.chunks$ = this.fromEvent("message:chunk"), this.errors$ = this.fromEvent("message:error"), this.messageStart$ = this.fromEvent("message:start");
|
package/dist/{createConversationSession-D3aHSSir.js → createConversationSession-Boi0PjDU.js}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as d } from "./createFormCollector-
|
|
1
|
+
import { i as d } from "./createFormCollector-BUqSA2Qw.js";
|
|
2
2
|
var f = "ago_widget_id", g = "ago_last_thread", y = 7200 * 1e3;
|
|
3
3
|
function v() {
|
|
4
4
|
return typeof crypto < "u" && typeof crypto.randomUUID == "function" ? crypto.randomUUID() : "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (e) => {
|
package/dist/{createConversationSession-CnIchjFa.cjs → createConversationSession-lJWANT6T.cjs}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
const d=require("./createFormCollector-
|
|
1
|
+
const d=require("./createFormCollector-CSG5ioym.cjs");var f="ago_widget_id",g="ago_last_thread",y=7200*1e3;function v(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{const r=Math.floor(Math.random()*16);return(e==="x"?r:r&3|8).toString(16)})}function _(e={}){const r=e.key??f,i=e.threadKey??g,u=e.ttlMs??y,l=e.storage??(typeof localStorage<"u"?localStorage:void 0);let n=e.widgetId??"";if(!n&&l)try{n=l.getItem(r)??""}catch{}if(n||(n=v()),l)try{l.setItem(r,n)}catch{}const o=d.createStore({value:null,lastMessageAt:null},{key:i,storage:l}),c=o.get();c.value!==null&&s(c.lastMessageAt)&&o.set({value:null,lastMessageAt:null});function s(t){return t===null?!0:Number.isFinite(u)?Date.now()-t>u:!1}return{widgetId:n,key:r,getLastActiveThread(){const{value:t,lastMessageAt:a}=o.get();return t===null||s(a)?null:t},setActiveThread(t,a){const x=a==null?null:a instanceof Date?a.getTime():a;o.set({value:t,lastMessageAt:x})},clear(){o.set({value:null,lastMessageAt:null})}}}Object.defineProperty(exports,"createConversationSession",{enumerable:!0,get:function(){return _}});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const O=require("./AgoClient
|
|
1
|
+
const O=require("./AgoClient--y10UXUV.cjs");function _(o,e){const i=e?e.storage??(typeof localStorage<"u"?localStorage:void 0):void 0;let t=o;if(e&&i)try{const c=i.getItem(e.key);c!=null&&(t=JSON.parse(c))}catch{}const a=new Set,f=()=>a.forEach(c=>c(t));function d(){if(e&&i)try{i.setItem(e.key,JSON.stringify(t))}catch{}}return{get:()=>t,set:c=>{t=c,d(),f()},subscribe:c=>(a.add(c),()=>{a.delete(c)})}}var k=/^[a-zA-Z0-9_-]{1,40}$/,P=o=>o==null||o==="";function q(o,e){const i=e[o.property];if(P(i))return!1;if(Array.isArray(o.value))return o.value.some(f=>String(i)===String(f));if(!o.op)return String(i)===String(o.value);const t=Number(i),a=Number(o.value);if(Number.isNaN(t)||Number.isNaN(a))return!1;switch(o.op){case">=":return t>=a;case"<=":return t<=a;case">":return t>a;case"<":return t<a;default:return O.logger.warn(`Unknown requiredWhen op "${o.op}"; treating as not required.`),!1}}function p(o,e){const i=o.properties??{},t=new Set;for(const f of o.required??[]){const d=i[f]?.requiredWhen;(!d||q(d,e))&&t.add(f)}for(const[f,d]of Object.entries(i))d.requiredWhen&&q(d.requiredWhen,e)&&t.add(f);const a=[...t].filter(f=>P(e[f]));return{missing:a,complete:a.length===0}}function W(o){const e={};for(const[i,t]of Object.entries(o.properties??{}))e[i]={type:t.type,...t.description!=null&&{description:t.description},...t.enum&&{enum:t.enum},...t.default!==void 0&&{default:t.default}};return{type:"object",properties:e,required:[]}}function j(o){const{name:e,description:i,schema:t}=o;if(!k.test(e))throw new Error(`Invalid form collector name "${e}": must match ${k} (it becomes the update_/submit_ function names).`);const a=typeof o.submit=="string"?o.submit?{via:"client",url:o.submit}:!1:o.submit??!1,f=t.properties??{},d=r=>{const n={};for(const[u,s]of Object.entries(r)){const l=f[u];if(l)if(s==null)n[u]=s;else if(l.type==="number"||l.type==="integer"){const b=typeof s=="number"?s:Number(s);n[u]=Number.isNaN(b)?s:b}else l.type==="boolean"?n[u]=typeof s=="boolean"?s:s==="true"?!0:s==="false"?!1:!!s:n[u]=s}return n},c=o.initialValues??{},m=_({values:c,submitted:!1}),v=r=>{const n=m.get(),u={...n,values:{...n.values,...r}};return m.set(u),u};let h=null;const N=async()=>{const{values:r}=m.get(),{complete:n,missing:u}=p(t,r);if(!n)return{ok:!1,missing:u};if(!a)return{ok:!1,error:"No submit target configured for this form collector."};const s=r;try{let l;if(a.via==="client")if("handler"in a)l=await a.handler(s);else{const b=await fetch(a.url,{method:"POST",headers:{"Content-Type":"application/json"},credentials:"include",body:JSON.stringify(s)});if(!b.ok)return{ok:!1,error:`Submit failed: HTTP ${b.status}`};l=await b.json().catch(()=>{})}else{if(!h)return{ok:!1,error:"Backend submit requires install(client) (or useFormCollector) first."};l=await h.submitFormCollector(e,s)}return m.set({...m.get(),submitted:!0}),{ok:!0,result:l}}catch(l){const b=l instanceof Error?l.message:"Submit failed";return O.logger.error(`FormCollector "${e}" submit failed:`,l),{ok:!1,error:b}}},S={name:`update_${e}`,description:`Fill or update fields of the "${e}" form. ${i} Pass any subset of fields; call it repeatedly to fill the form as the user provides information. Returns the current values and which required fields are still missing.`,parameters:W(t),handler:r=>{const n=v(d(r)),{missing:u}=p(t,n.values);return{ok:!0,values:n.values,missing:u}}},g=[S];a&&g.push({name:`submit_${e}`,description:`Submit the completed "${e}" form. Only call this once every required field is collected and the user has confirmed. If fields are missing it returns them instead of submitting.`,parameters:{type:"object",properties:{}},handler:()=>N()});const T="client__",C=a?`submit_${e}`:null,E=r=>{const n=r.functionName??r.toolName;if(n)return n.startsWith(T)?n.slice(8):n},$=r=>{let n={...c},u=!1;for(const s of r){const l=E(s);l===S.name?s.arguments&&(n={...n,...d(s.arguments)}):C&&l===C&&s.status?.toLowerCase()==="done"&&(u=!0)}m.set({values:n,submitted:u})},y=`form:${e}`,w=()=>{const{values:r,submitted:n}=m.get(),{missing:u,complete:s}=p(t,r),l=a?` When nothing is missing and the user confirms, call submit_${e}.`:"",b=n?`The "${e}" form has been submitted.`:`You are currently collecting information from the user to fill the "${e}" form.`;return{name:`Form: ${e}`,description:`${b} ${i} There are conditionnals questions/values to collected, you can find this information with the requiredWhen field in the form. The form schema is the following: ${JSON.stringify(t)}. Data collected so far: ${JSON.stringify(r)}. Call update_${e} with any fields the user provides; ask only for what is still missing.${l}`,data:{values:r,missing:u,complete:s,submitted:n}}},F=r=>{$((r.messages??[]).flatMap(n=>n.toolCalls??[]))};return{name:e,store:m,functions:g,contextKey:y,contextProvider:w,install:r=>{h=r;for(const u of g)r.register(u);r.addDynamicContext(y,w);const n=m.subscribe(()=>r.notifyContextChanged());return r.on("conversation:loaded",F),()=>{n();for(const u of g)r.unregisterFunction(u.name);r.removeDynamicContext(y),r.off("conversation:loaded",F),h===r&&(h=null)}},hydrate:$,submit:N,getValues:()=>m.get().values,setValues:r=>{v(d(r))},reset:()=>{m.set({values:c,submitted:!1})},getStatus:()=>p(t,m.get().values)}}async function x(o,e){const i=await o.getFormCollector(e.name);return j({name:i.name,description:e.description??i.description,schema:e.schema??i.schema,submit:e.submit??i.submit,initialValues:e.initialValues})}Object.defineProperty(exports,"createFormCollector",{enumerable:!0,get:function(){return j}});Object.defineProperty(exports,"createStore",{enumerable:!0,get:function(){return _}});Object.defineProperty(exports,"deriveFormStatus",{enumerable:!0,get:function(){return p}});Object.defineProperty(exports,"loadFormCollector",{enumerable:!0,get:function(){return x}});
|