UNPKG

@automattic/agenttic-client

Version:

A TypeScript client library for A2A (Agent2Agent) protocol communication

2,032 lines (2,031 loc) 55.5 kB
var Rt = Object.defineProperty; var Et = (t, e, s) => e in t ? Rt(t, e, { enumerable: !0, configurable: !0, writable: !0, value: s }) : t[e] = s; var Z = (t, e, s) => Et(t, typeof e != "symbol" ? e + "" : e, s); import { useMemo as pt, useCallback as $, useState as yt, useRef as Ot, useEffect as tt } from "react"; import ut from "@wordpress/api-fetch"; const R = (t, ...e) => { _t() && console.log(`[agenttic-client] ${t}`, ...e); }; function _t() { var t; return typeof globalThis < "u" && "window" in globalThis && ((t = globalThis.window) == null ? void 0 : t.DEBUG) === "agenttic-client"; } function wt(t) { return JSON.stringify(t, null, 2); } function dt(t, ...e) { console.log(`[agenttic-client] ${t}`, ...e); } function Ae(t) { return pt(() => t ? { getClientContext: () => { try { return t() || {}; } catch (n) { return R("Error getting client context: %O", n), {}; } } } : void 0, [t]); } function ot({ getClientTools: t, executeTool: e, getAbilities: s }) { const n = $(async () => { const o = []; if (t) try { const c = await t(); o.push(...c); } catch (c) { R("Error getting available tools: %O", c); } return o; }, [t]), a = $( async (o, c) => { if (!e) throw new Error("No executeTool callback provided"); try { return await e(o, c); } catch (i) { throw R("Error executing tool %s: %O", o, i), i; } }, [e] ); return pt(() => { if (!t && !s) return; const o = {}; return t && (o.getAvailableTools = n), e && (o.executeTool = a), s && (o.getAbilities = s), o; }, [ n, a, t, e, s ]); } function Se(t, e) { return ot({ getClientTools: t, executeTool: e, getAbilities: void 0 }); } function ve(t) { return ot({ getClientTools: void 0, executeTool: void 0, getAbilities: t }); } function ke(t) { const { getClientTools: e, executeTool: s, getAbilities: n } = t; if (!e && !n) throw new Error( "At least one of getClientTools or getAbilities must be provided to useClientToolsWithAbilities." ); if (e && !s) throw new Error( "executeTool is required when providing getClientTools." ); return ot({ getClientTools: e, executeTool: s, getAbilities: n }); } function rt() { const t = "abcdefghijklmnopqrstuvwxyz0123456789"; let e = ""; for (let s = 0; s < 8; s++) e += t.charAt(Math.floor(Math.random() * t.length)); return e; } function q() { return rt(); } function Pt() { return `req-${rt()}`; } function Nt() { return `task-${rt()}`; } function It(t, e) { return { type: "text", text: t, ...e && { metadata: e } }; } function qt(t, e = "message/send", s = !1) { const n = { jsonrpc: "2.0", id: Pt(), method: e, params: { id: t.id || Nt(), ...t } }; return s && e === "message/stream" && (n.tokenStreaming = !0), n; } function D(t) { return !t || !t.parts || !Array.isArray(t.parts) ? "" : t.parts.filter((e) => e.type === "text").map((e) => e.text).join(" "); } function Ht(t) { return { type: "data", data: { toolId: t.id, toolName: t.name, description: t.description, inputSchema: t.input_schema }, metadata: {} }; } function $t(t) { return { type: "data", data: { name: t.name, label: t.label, description: t.description, category: t.category, input_schema: t.input_schema, output_schema: t.output_schema, meta: t.meta }, metadata: {} }; } function F(t) { return !t || !t.parts || !Array.isArray(t.parts) ? [] : t.parts.filter( (e) => e.type === "data" && "toolCallId" in e.data && "toolId" in e.data && "arguments" in e.data ); } function j(t, e, s, n) { return { type: "data", data: { toolCallId: t, toolId: e, result: s }, metadata: n ? { error: n } : void 0 }; } function Dt(t) { return { type: "data", data: { clientContext: t }, metadata: {} }; } function at(t, e) { const { contentType: s, ...n } = e || {}; return { role: "user", parts: [It(t, s ? { contentType: s } : void 0)], kind: "message", messageId: q(), metadata: { timestamp: Date.now(), ...n } }; } function W(t) { return { role: "agent", parts: [It(t)], kind: "message", messageId: q(), metadata: { timestamp: Date.now() } }; } function it(t) { return t && typeof t == "object" && "result" in t ? { result: t.result, returnToAgent: t.returnToAgent !== !1, // Default to true agentMessage: t.agentMessage // Pass through agentMessage if present } : { result: t, returnToAgent: !0 }; } function G(t, e = []) { return { role: "user", kind: "message", parts: [...e, ...t], messageId: q(), metadata: { timestamp: Date.now() } }; } function Re() { return new AbortController(); } async function Ft(t, e) { if (!e) return t; try { const s = []; if (e.getAvailableTools) { const n = await e.getAvailableTools(); if (n.length > 0) { const a = n.map(Ht); s.push(...a); } } if (e.getAbilities) { const n = await e.getAbilities(); if (n.length > 0) { const a = n.map($t); s.push(...a); } } return s.length === 0 ? t : { ...t, parts: [...t.parts, ...s] }; } catch (s) { return R("Warning: Failed to get tools: %s", s), t; } } function Ut(t, e) { if (!e) return t; try { const s = e.getClientContext(); if (!s || Object.keys(s).length === 0) return t; const n = Dt(s); return { ...t, parts: [...t.parts, n] }; } catch (s) { return R("Warning: Failed to get context: %s", s), t; } } async function jt(t, e, s) { let n = await Ft( t, e ); n = Ut( n, s ); const { metadata: a, ...r } = n; return r; } function Jt(t, e = "") { const s = [], n = e + t; let a = "", r = 0, o = 0; for (; o < n.length; ) { const i = n.indexOf( ` `, o ), f = i === -1 ? n.substring(o) : n.substring(o, i); if (f.startsWith("data:")) a !== "" && (a += ` `), a += f.substring( f.startsWith("data: ") ? 6 : 5 ); else if (f.trim() === "" && a) { try { s.push(JSON.parse(a)), r = i === -1 ? n.length : i + 1; } catch (u) { R("Failed to parse SSE event: %o", u), R("Problematic payload: %s", a); } a = ""; } i === -1 ? o = n.length : o = i + 1; } const c = n.substring(r); return { events: s, nextBuffer: c }; } async function* Kt(t, e = {}) { var f, u, p; const { supportDeltas: s = !1 } = e, n = t.getReader(), a = new TextDecoder(); let r = ""; const o = new Lt(); let c = null, i = null; try { for (; ; ) { const { done: g, value: h } = await n.read(); if (g) break; const M = a.decode(h, { stream: !0 }), { events: m, nextBuffer: l } = Jt(M, r); if (m && Array.isArray(m)) for (let y = 0; y < m.length; y++) { const d = m[y]; if (y > 0 && d.method === "message/delta" && typeof requestAnimationFrame < "u" && await new Promise((I) => { requestAnimationFrame(() => I(void 0)); }), d.error) throw new Error( `Streaming error: ${d.error.message}` ); if (s && d.method === "message/delta" && ((f = d.params) != null && f.delta)) { const I = d.params.delta; try { if (I.deltaType === "content" && (o.processContentDelta( I.content ), !c && d.params.id && (c = d.params.id), c)) { const k = o.getCurrentMessage(); yield { id: c, status: { state: "working", message: k }, final: !1, text: o.getTextContent() }; } } catch (k) { R("Failed to process delta: %o", k); } } else d.result && d.result.status ? (c = d.result.id, i = d.result.status, (o.getTextContent() || o.getCurrentMessage().parts.length > 0) && o.reset(), yield { id: d.result.id, status: d.result.status, final: d.result.status.state === "completed" || d.result.status.state === "failed" || d.result.status.state === "canceled", text: D( ((u = d.result.status) == null ? void 0 : u.message) || { role: "agent", parts: [] } ) }) : d.id && d.result && (c = d.result.id, d.result.status && (yield { id: d.result.id, status: d.result.status, final: d.result.status.state === "completed" || d.result.status.state === "failed" || d.result.status.state === "canceled", text: D( ((p = d.result.status) == null ? void 0 : p.message) || { role: "agent", parts: [] } ) })); } r = l; } } finally { n.releaseLock(); } } class Lt { constructor() { Z(this, "textContent", ""); Z(this, "toolCalls", /* @__PURE__ */ new Map()); } /** * Process a simple content delta (server's actual format) * @param content - The text content to append */ processContentDelta(e) { this.textContent += e; } /** * Process a delta message and accumulate the content (original format) * @param delta - The delta message to process */ processDelta(e) { switch (e.type) { case "content": this.textContent += e.content; break; case "tool_name": this.toolCalls.has(e.toolCallIndex) || this.toolCalls.set(e.toolCallIndex, { toolCallId: e.toolCallId, toolName: "", argumentFragments: [] }); const s = this.toolCalls.get(e.toolCallIndex); s.toolName += e.content; break; case "tool_argument": this.toolCalls.has(e.toolCallIndex) || this.toolCalls.set(e.toolCallIndex, { toolCallId: e.toolCallId, toolName: "", argumentFragments: [] }), this.toolCalls.get(e.toolCallIndex).argumentFragments.push(e.content); break; } } /** * Get the accumulated text content */ getTextContent() { return this.textContent; } /** * Get the current accumulated message * @param role - The role for the message (default: 'agent') */ getCurrentMessage(e = "agent") { const s = []; this.textContent && s.push({ type: "text", text: this.textContent }); for (const [n, a] of this.toolCalls) if (a.toolName) { const r = a.argumentFragments.join(""); let o = {}; if (r) try { o = JSON.parse(r); } catch { o = { _raw: r }; } s.push({ type: "data", data: { toolCallId: a.toolCallId, toolId: a.toolName, arguments: o } }); } return { role: e, parts: s, kind: "message", messageId: q() }; } /** * Reset the accumulator */ reset() { this.textContent = "", this.toolCalls.clear(); } } function Tt(t, e, s = "request") { throw clearTimeout(e), R("%s failed with error: %O", s, t), t instanceof Error && (R("Error message: %s", t.message), R("Error stack: %s", t.stack)), t; } function Ct(t, e = "request") { if (!t.ok) throw new Error(`HTTP error! status: ${t.status}`); } function Wt(t, e = "request") { if (t.error) throw new Error(`A2A ${e} error: ${t.error.message}`); if (!t.result) throw new Error(`No result in ${e} response`); return t.result; } function Bt(t, e = "streaming request") { if (Ct(t, e), !t.body) throw new Error(`No response body for ${e}`); } function xt(t, e = "request") { const s = new AbortController(); return { timeoutId: setTimeout( () => s.abort(), t ), controller: s }; } function Vt(t, e) { return `${t}/${e}`; } function zt(t, e, s, n) { R("Request: %s %s", t, e), R("Headers: %o", s), n && R("Body: %s", wt(n)); } async function Gt(t, e = !1) { const s = { "Content-Type": "application/json" }; if (e && (s.Accept = "text/event-stream"), t) { const n = await t(); return { ...s, ...n }; } return s; } function bt(t, e) { if (!e) return t; const s = new AbortController(), n = (a) => { s.signal.aborted || s.abort(a.reason); }; return t.aborted ? s.abort(t.reason) : t.addEventListener("abort", () => n(t), { once: !0 }), e.aborted ? s.abort(e.reason) : e.addEventListener("abort", () => n(e), { once: !0 }), s.signal; } function Mt(t, e, s) { return { method: "POST", headers: t, body: e, signal: s }; } async function Q(t, e, s, n, a, r) { const { message: o, sessionId: c, taskId: i, metadata: f } = t, { agentId: u, agentUrl: p, authProvider: g, proxy: h } = e, { isStreaming: M = !1, enableTokenStreaming: m = !1 } = s, l = c || r, y = Vt(p, u), d = await jt( o, n, a ), I = qt( { id: i, sessionId: l, message: d, metadata: f }, M ? "message/stream" : "message/send", m && M // Only enable token streaming if using SSE ), k = await Gt(g, M); return zt("POST", y, k, I), { request: I, headers: k, enhancedMessage: d, effectiveSessionId: l, fullAgentUrl: y }; } async function At(t, e, s = {}) { const { request: n, headers: a, fullAgentUrl: r } = t, { timeout: o } = e, { abortSignal: c } = s, { timeoutId: i, controller: f } = xt( o, "request" ), u = c ? bt(f.signal, c) : f.signal; try { const p = Mt( a, JSON.stringify(n), u ); R("Making request to %s with options: %O", r, { method: p.method, headers: p.headers }); const g = await fetch(r, p); clearTimeout(i), Ct(g, "request"); const h = await g.json(); return R( "Response from %s: %d %O", r, g.status, wt(h) ), Wt(h, "request"); } catch (p) { Tt(p, i, "request"); } } async function* St(t, e, s) { const { request: n, headers: a, fullAgentUrl: r } = t, { streamingTimeout: o = 6e4, abortSignal: c, enableTokenStreaming: i = !1 } = s, { timeoutId: f, controller: u } = xt( o, "streaming request" ), p = c ? bt(u.signal, c) : u.signal; try { const g = JSON.stringify(n), h = Mt(a, g, p), M = await fetch(r, h); if (clearTimeout(f), Bt(M, "streaming request"), !M.body) throw new Error( "Response body is null - server may not support streaming" ); const m = i && n.tokenStreaming === !0; yield* Kt(M.body, { supportDeltas: m }); } catch (g) { Tt(g, f, "streaming request"); } } const Qt = 12e4; async function X(t, e, s, n, a) { if (t.getAbilities) { const r = await t.getAbilities(); if (r.length > 0) for (const o of r) { const c = o.name.replace(/\//g, "__").replace(/-/g, "_"); if (e === c || e === o.name) { if (o.callback) try { return { result: await o.callback(s), returnToAgent: !0 }; } catch (i) { return R( "Error executing ability %s: %O", o.name, i ), { result: { error: i instanceof Error ? i.message : String(i), success: !1 }, returnToAgent: !0 }; } if (!o.callback && t.executeAbility) try { return { result: await t.executeAbility( o.name, s ), returnToAgent: !0 }; } catch (i) { return R( "Error executing ability %s: %O", o.name, i ), { result: { error: i instanceof Error ? i.message : String(i), success: !1 }, returnToAgent: !0 }; } throw new Error( `Ability ${o.name} has no callback and no handler` ); } } } if (t.executeTool) return await t.executeTool( e, s, n, a ); throw new Error( `No handler found for tool: ${e}. Tool provider must implement executeTool for non-ability tools.` ); } const lt = /* @__PURE__ */ new Map(); async function Xt(t, e) { if (!t || !e || !t.getAvailableTools) return !1; const s = F(e); if (s.length === 0) return !1; try { const n = await t.getAvailableTools(); for (const a of s) if (n.some( (o) => o.id === a.data.toolId )) return !0; } catch { return !1; } return !1; } function Yt() { lt.clear(); } function Zt(t) { return t.map((e) => { const s = e.data.toolCallId, n = lt.get(s); if (n && n.resolvedValue !== null) { const a = n.resolvedValue; return a.error ? j( s, e.data.toolId, void 0, a.error ) : j( s, e.data.toolId, a ); } return e; }); } async function vt(t, e, s) { const n = [], a = []; let r = !1; for (const o of t) { const { toolCallId: c, toolId: i, arguments: f } = o.data; try { const u = await X( e, i, f, s, c ), { result: p, returnToAgent: g, agentMessage: h } = it(u); g && (r = !0), h && a.push(W(h)), n.push( j( c, i, p ) ); } catch (u) { r = !0, n.push( j( c, i, void 0, u instanceof Error ? u.message : String(u) ) ); } } return { results: n, shouldReturnToAgent: r, agentMessages: a }; } function gt(t) { const e = []; for (const s of t) for (const n of s.parts) n.type === "text" ? e.push({ type: "data", data: { role: s.role, text: n.text } }) : n.type === "data" && e.push(n); return e; } async function et(t, e, s, n, a, r, o) { const i = await Q( { message: e, taskId: t, sessionId: void 0 // Use task's session }, s, { isStreaming: !1 }, n, a, r ); return await At(i, s, { abortSignal: o }); } async function ft(t, e, s, n, a, r, o, c, i = []) { const f = { message: e, taskId: t, sessionId: void 0 // Use task's session }, u = c || { isStreaming: !0 }, p = await Q( f, s, { ...u }, n, a, r ), g = St(p, s, { ...u, abortSignal: o }); return kt( g, n, a, s, r, !0, // withHistory i, // preserve conversation parts across continuation o, u // Pass through the same request options ); } async function* kt(t, e, s, n, a, r = !0, o = [], c, i) { var f, u, p, g, h, M, m, l, y, d, I, k; for await (const w of t) { if (yield w, w.status.state === "running" && w.status.message && e && await Xt( e, w.status.message )) { const P = F( w.status.message ); for (const T of P) { const { toolCallId: x, toolId: v, arguments: C } = T.data; X( e, v, C, (u = (f = w.status) == null ? void 0 : f.message) == null ? void 0 : u.messageId, x ).catch((S) => { console.error( `Tool execution failed for ${v}:`, S ); }); } yield { id: w.id, status: { state: "running", message: { role: "agent", kind: "message", parts: P, messageId: q() } }, final: !1, text: "" }; } if (w.status.state === "input-required" && w.status.message && e) { const P = F( w.status.message ); if (P.length > 0) { const T = []; let x = !1; const v = [], C = []; for (const S of P) { const { toolCallId: b, toolId: _, arguments: N } = S.data; try { const E = await X( e, _, N, (g = (p = w.status) == null ? void 0 : p.message) == null ? void 0 : g.messageId, b ), { result: A, returnToAgent: O, agentMessage: J } = it(E); if (O && (x = !0), J && C.push( W(J) ), A.result instanceof Promise) { const V = A.result, K = { promise: V, resolvedValue: null }; lt.set( b, K ), V.then((H) => { K.resolvedValue = H; }).catch((H) => { console.error( `Promise rejected for tool call ${b}:`, H ), K.resolvedValue = { error: H instanceof Error ? H.message : String(H) }; }); } const B = j( b, _, A ); T.push(B), v.push(B); } catch (E) { const A = j( b, _, void 0, E instanceof Error ? E.message : String(E) ); T.push(A), v.push(A); } } if (o.push(w.status.message), T.length > 0 && o.push({ role: "agent", kind: "message", parts: T, messageId: q() }), x) { const S = gt(o), b = G( [], // Empty array - tool results are already in historyDataParts S ); yield { id: w.id, status: { state: "working", message: b }, final: !1, text: "" }; const _ = await ft( w.id, b, n, e, s, a, c, i, o ); let N = null; for await (const O of _) O.final ? N = O : yield O; if (!N) throw new Error( "Continue task stream ended without final result" ); let E = (h = N.status) != null && h.message ? F( N.status.message ) : [], A = N; if (E.length > 0) for (yield { ...N, final: !1, text: D( ((M = N.status) == null ? void 0 : M.message) || { parts: [], messageId: q() } ) }; E.length > 0; ) { (m = A.status) != null && m.message && o.push( A.status.message ); const { results: O, shouldReturnToAgent: J } = await vt( E, e, (y = (l = A.status) == null ? void 0 : l.message) == null ? void 0 : y.messageId ); if (O.length > 0 && (yield { id: A.id, status: { state: "working", message: { role: "agent", kind: "message", parts: O, messageId: q() } // Simple message with just the results }, final: !1, text: "" }), J) { const B = r ? gt( o ) : [], V = G( O, B ), K = await ft( A.id, V, n, e, s, a, c, i, o ); let H = null; for await (const Y of K) Y.final ? H = Y : yield Y; if (!H) throw new Error( "Continue task stream ended without final result" ); A = H, E = (d = A.status) != null && d.message ? F( A.status.message ) : [], E.length > 0 && (yield { id: A.id, status: A.status, final: !1, text: D( ((I = A.status) == null ? void 0 : I.message) || { parts: [], messageId: q() } ) }); } else break; } yield { ...A, final: !0, text: D( ((k = A.status) == null ? void 0 : k.message) || { parts: [], messageId: q() } ) }; } else { const S = { ...w.status.message, parts: v }, b = { ...w, status: { ...w.status, message: S }, final: C.length === 0, // Only final if no agent messages to follow text: D(S) }; if (yield b, C.length > 0) { const _ = C.map((E) => D(E)).join(" "), N = W(_); yield { id: b.id, status: { state: "completed", message: N }, final: !0, text: _ }; } } } } } } function te(t) { const { agentId: e, agentUrl: s, authProvider: n, defaultSessionId: a, timeout: r = Qt, toolProvider: o, contextProvider: c, enableStreaming: i = !1 } = t, f = { agentId: e, agentUrl: s, authProvider: n, timeout: r }; return { async sendMessage(u) { var I, k; const { withHistory: p = !0, abortSignal: g } = u, h = u.sessionId || a || void 0, M = []; M.push(u.message); const m = await Q( u, f, { isStreaming: !1 }, o, c, h ); let l = await At( m, f, { abortSignal: g } ); const y = [], d = []; for (; l.status.message && o; ) { const w = F( l.status.message ); if (w.length === 0) break; y.push(...w); const P = []; let T = !1; for (const x of w) { const { toolCallId: v, toolId: C, arguments: S } = x.data; try { const b = await X( o, C, S ), { result: _, returnToAgent: N, agentMessage: E } = it(b); N && (T = !0), E && d.push( W(E) ); const A = j( v, C, _ ); P.push(A), y.push(A); } catch (b) { const _ = j( v, C, void 0, b instanceof Error ? b.message : String(b) ); P.push(_), y.push(_); } } if (M.push(l.status.message), T) { const x = G(P); l = await et( l.id, x, f, o, c, h, g ); } else break; } if (y.length > 0 && (I = l.status) != null && I.message) { const w = { ...l.status.message, parts: y }; l = { ...l, status: { ...l.status, message: w } }; } if (d.length > 0) { const w = d.map((T) => D(T)).join(" "), P = W(w); return { ...l, // Keep the enhanced message with tool results // The agent message will be handled separately by the caller text: w, agentMessage: P // Add this for the caller to handle }; } return { ...l, text: D( ((k = l.status) == null ? void 0 : k.message) || { parts: [], messageId: q() } ) }; }, async *sendMessageStream(u) { const { withHistory: p = !0, abortSignal: g, enableStreaming: h } = u, M = u.sessionId || a || void 0, m = h ?? i, l = []; l.push(u.message); const y = await Q( u, f, { isStreaming: !0, // Always use message/stream endpoint for SSE enableTokenStreaming: m }, o, c, M ), d = St( y, f, { enableTokenStreaming: m, // Token streaming is optional streamingTimeout: r, abortSignal: g } ); yield* kt( d, o, c, f, M, p, l, g, { isStreaming: !0, enableTokenStreaming: m, streamingTimeout: r } ); }, async continueTask(u, p, g) { var l; const h = at(p); let m = await et( u, h, f, o, c, g ); for (; m.status.state === "input-required" && m.status.message && o; ) { const y = F( m.status.message ); if (y.length === 0) break; const { results: d, shouldReturnToAgent: I } = await vt(y, o); if (I) { const k = G(d); m = await et( m.id, k, f, o, c, g ); } else break; } return { ...m, text: D( ((l = m.status) == null ? void 0 : l.message) || { parts: [], messageId: q() } ) }; }, async getTask(u) { throw new Error("getTask not implemented yet"); }, async cancelTask(u) { throw new Error("cancelTask not implemented yet"); } }; } const ct = "a8c_agenttic_conversation_history"; function ee(t) { var u, p; const e = t.parts.filter( (g) => g.type === "text" ), s = e.map((g) => g.text).join(` `), n = e.some( (g) => { var h; return ((h = g.metadata) == null ? void 0 : h.contentType) === "context"; } ) ? "context" : void 0, a = t.parts.filter( (g) => g.type === "data" && "toolCallId" in g.data && "arguments" in g.data ).map((g) => ({ toolCallId: g.data.toolCallId, toolId: g.data.toolId, arguments: g.data.arguments })), r = t.parts.filter( (g) => g.type === "data" && "toolCallId" in g.data && "result" in g.data ).map((g) => ({ toolCallId: g.data.toolCallId, result: g.data.result, error: g.data.error })), c = a.length > 0 || r.length > 0 ? "agent" : t.role, i = ((u = t.metadata) == null ? void 0 : u.timestamp) ?? Date.now(), f = ((p = t.metadata) == null ? void 0 : p.archived) ?? void 0; return { role: c, content: s || "(No text content)", timestamp: i, ...f !== void 0 && { archived: f }, ...n && { contentType: n }, ...a.length > 0 && { toolCalls: a }, ...r.length > 0 && { toolResults: r } }; } function se(t) { const e = []; if (t.content && t.content !== "(No text content)" && e.push({ type: "text", text: t.content, ...t.contentType && { metadata: { contentType: t.contentType } } }), t.toolCalls) for (const s of t.toolCalls) e.push({ type: "data", data: { toolCallId: s.toolCallId, toolId: s.toolId, arguments: s.arguments } }); if (t.toolResults) for (const s of t.toolResults) e.push({ type: "data", data: { toolCallId: s.toolCallId, result: s.result, ...s.error && { error: s.error } } }); return { role: t.role, kind: "message", parts: e, messageId: q(), metadata: { timestamp: t.timestamp, // only store archived if it was already present. ...t.archived !== void 0 && { archived: t.archived } } }; } const U = /* @__PURE__ */ new Map(), ne = 50; async function ae(t, e, s) { const n = s || t; if (U.set(n, [...e]), U.size > ne) { const a = U.keys().next().value; a && U.delete(a); } if (!(typeof sessionStorage > "u")) try { const a = { storageKey: n, messages: e.map(ee), lastUpdated: Date.now() }; sessionStorage.setItem( `${ct}_${n}`, JSON.stringify(a) ); } catch (a) { R( "Failed to store conversation in sessionStorage for key %s: %O", n, a ); } } async function oe(t, e) { const s = e || t; if (U.has(s)) return [...U.get(s)]; if (typeof sessionStorage > "u") return []; try { const n = sessionStorage.getItem( `${ct}_${s}` ); if (n) { const r = JSON.parse(n).messages.map(se); return U.set(s, r), [...r]; } } catch (n) { R( "Failed to load conversation from sessionStorage for key %s: %O", s, n ); } return []; } async function re(t, e) { const s = e || t; if (U.delete(s), !(typeof sessionStorage > "u")) try { sessionStorage.removeItem(`${ct}_${s}`); } catch (n) { R( "Failed to clear conversation from sessionStorage for key %s: %O", s, n ); } } function L(t) { const e = t.parts.filter((s) => s.type === "text" ? !0 : s.type === "data" ? "role" in s.data && "text" in s.data ? !1 : "toolCallId" in s.data && "arguments" in s.data || "toolCallId" in s.data && "result" in s.data : !0); return { ...t, parts: e, // Preserve metadata if it exists, otherwise add timestamp metadata: t.metadata || { timestamp: Date.now() } }; } function ie(t) { const e = []; for (const s of t) for (const n of s.parts) if (n.type === "text") e.push({ type: "data", data: { role: s.role, text: n.text } }); else if (n.type === "data") { if ("role" in n.data && "text" in n.data) continue; if ("toolCallId" in n.data && "arguments" in n.data) { e.push(n); continue; } if ("toolCallId" in n.data && "result" in n.data) { e.push(n); continue; } } return e; } function mt(t, e = []) { return { role: "user", parts: [ ...ie(e), { type: "text", text: t } ], kind: "message", messageId: q(), metadata: { timestamp: Date.now() } }; } function le(t) { return t != null && t.parts ? t.parts.filter( (e) => e.type === "data" && "toolCallId" in e.data && "result" in e.data ) : []; } async function ce(t) { const e = []; for (const s of t) if (s.parts && Array.isArray(s.parts)) if (s.parts.some( (a) => a.type === "data" && "toolCallId" in a.data && "result" in a.data )) { const a = Zt( s.parts ); e.push({ ...s, parts: a }); } else e.push(s); else e.push(s); return Yt(), e; } function ue() { const t = /* @__PURE__ */ new Map(); async function e(s, n) { const a = t.get(s); if (a != null && a.sessionId) try { await ae( a.sessionId, n, a.conversationStorageKey ); } catch (r) { dt( `Failed to persist conversation history for agent ${s}:`, r ); } } return { async createAgent(s, n) { if (t.has(s)) return t.get(s).client; const a = te(n), r = n.sessionId || null, o = n.conversationStorageKey; let c = []; if (r) try { c = await oe( r, o ); } catch (f) { dt( `Failed to load conversation history for agent ${s} with session ${r}:`, f ); } const i = { client: a, sessionId: r, conversationStorageKey: o, conversationHistory: c, currentAbortController: null }; return t.set(s, i), a; }, getAgent(s) { const n = t.get(s); return (n == null ? void 0 : n.client) || null; }, hasAgent(s) { return t.has(s); }, removeAgent(s) { return t.delete(s); }, async sendMessage(s, n, a = {}) { var m; const r = t.get(s); if (!r) throw new Error(`Agent with key "${s}" not found`); const { withHistory: o = !0, ...c } = a, { client: i, conversationHistory: f } = r, u = a.message || mt(n, f), p = await i.sendMessage({ message: u, withHistory: o, ...c }); let g = null; if ((m = p.status) != null && m.message) { const l = p.status.message.parts.filter( (d) => d.type === "data" && "toolCallId" in d.data && ("arguments" in d.data || "result" in d.data) ), y = p.status.message.parts.filter( (d) => d.type === "text" ); g = { role: "agent", kind: "message", parts: [...l, ...y], messageId: q(), metadata: { timestamp: Date.now() } }; } const h = [ ...f, // Store only the new content from the user message (without history parts) at(n), // Add complete agent response with tool calls/results if present ...g ? [L(g)] : [] ]; let M = h; if (p.agentMessage) { const l = L( p.agentMessage ); M = [ ...h, l ]; } return r.conversationHistory = M, o && await e( s, M ), p; }, async *sendMessageStream(s, n, a = {}) { var d, I, k, w, P, T; const r = t.get(s); if (!r) throw new Error(`Agent with key "${s}" not found`); const { withHistory: o = !0, abortSignal: c, metadata: i, ...f } = a, { client: u } = r, p = i ? (({ contentType: x, ...v }) => v)(i) : void 0, g = new AbortController(); r.currentAbortController = g, c && c.addEventListener( "abort", () => g.abort() ); let h = [ ...r.conversationHistory ], M = []; const m = await ce( h ); r.conversationHistory = m, h = m, o && await e( s, m ); const l = a.message || mt( n, m ); if (a.metadata && !a.message) { const { contentType: x, ...v } = a.metadata; if (x) { const C = l.parts[l.parts.length - 1]; C && C.type === "text" && (C.metadata = { ...C.metadata, contentType: x }); } Object.keys(v).length > 0 && (l.metadata = { ...l.metadata, ...v }); } const y = at(n, a.metadata); h = [ ...h, y ], r.conversationHistory = h, o && await e( s, h ); for await (const x of u.sendMessageStream({ message: l, withHistory: o, abortSignal: g.signal, ...f, ...p && Object.keys(p).length > 0 && { metadata: p } })) { if (((d = x.status) == null ? void 0 : d.state) === "input-required" && ((I = x.status) != null && I.message)) { M = F( x.status.message ).map( (S) => S.data.toolCallId ); const C = L( x.status.message ); h = [ ...h, C ], r.conversationHistory = h, o && await e( s, h ); } if (((k = x.status) == null ? void 0 : k.state) === "working" && ((w = x.status) != null && w.message) && !x.final) { const C = le( x.status.message ).filter( (S) => M.includes( S.data.toolCallId ) ); if (C.length > 0) { const S = { role: "agent", kind: "message", parts: C, messageId: q() }; h = [ ...h, L(S) ], r.conversationHistory = h, o && await e( s, h ); } } if (x.final && ((P = x.status) == null ? void 0 : P.state) !== "input-required") { M = []; let v = null; (T = x.status) != null && T.message && (v = L( x.status.message ), h = [ ...h, v ], r.conversationHistory = h, o && await e( s, h )); } yield x; } r.currentAbortController = null; }, async resetConversation(s) { const n = t.get(s); if (!n) throw new Error(`Agent with key "${s}" not found`); n.conversationHistory = [], n.sessionId && await re( n.sessionId, n.conversationStorageKey ); }, getConversationHistory(s) { const n = t.get(s); if (!n) throw new Error(`Agent with key "${s}" not found`); return [...n.conversationHistory]; }, abortCurrentRequest(s) { const n = t.get(s); if (!n) throw new Error(`Agent with key "${s}" not found`); n.currentAbortController && (n.currentAbortController.abort(), n.currentAbortController = null); }, clear() { t.clear(); } }; } const de = ue(); function st() { return de; } function ge() { const [t, e] = yt([]), s = $( (r) => { e((o) => { const c = o.findIndex( (i) => i.id === r.id ); if (c >= 0) { const i = [...o]; return i[c] = r, i; } return [...o, r]; }); }, [] ), n = $((r) => { e((o) => o.filter((c) => c.id !== r)); }, []), a = $(() => { e([]); }, []); return { registerMessageActions: s, unregisterMessageActions: n, clearAllMessageActions: a, registrations: t }; } function fe(t, e) { return e.flatMap((a) => typeof a.actions == "function" ? a.actions(t) : a.actions).filter((a) => !(a.condition && !a.condition(t))).map((a) => ({ id: a.id, label: a.label, icon: a.icon, onClick: a.onClick, tooltip: a.tooltip, disabled: a.disabled || !1, pressed: a.pressed, showLabel: a.showLabel })); } const nt = (t) => [...t].sort((e, s) => e.timestamp - s.timestamp), z = (t, e = []) => { var o, c; if (t.parts.some((i) => { if (i.type === "data") { const f = i.data; return f.toolCallId || f.toolId || f.result; } return !1; })) return null; const n = t.parts.map((i) => { var f; if (i.type === "text") return { type: ((f = i.metadata) == null ? void 0 : f.contentType) || "text", text: i.text }; if (i.type === "file") return { type: "image_url", image_url: i.file.uri || `data:${i.file.mimeType};base64,${i.file.bytes}` }; if (i.type === "data") { const u = i.data; return u.component && u.componentProps ? { type: "component", component: u.component, componentProps: u.componentProps } : { type: "text", text: JSON.stringify(u) }; } return { type: "text", text: "[Unsupported content]" }; }), a = ((o = t.metadata) == null ? void 0 : o.timestamp) ?? Date.now(), r = { id: t.messageId, role: t.role === "agent" ? "agent" : "user", content: n, timestamp: a, archived: !!((c = t.metadata) != null && c.archived), showIcon: t.role === "agent", icon: t.role === "agent" ? "assistant" : void 0 }; if (t.role === "agent" && e.length > 0) { const i = fe( r, e ); i.length > 0 && (r.actions = i); } return r; }, me = () => ({ getClientContext: () => ({}) }), he = () => ({ getAvailableTools: async () => [], executeTool: async () => ({ success: !0, result: "No tools available" }) }), pe = (t) => ["agentId", "agentUrl", "sessionId"].every((s) => { const n = t[s]; return typeof n == "string" && n.trim().length > 0; }); function Ee(t) { const e = { agentId: t.agentId, agentUrl: t.agentUrl, sessionId: t.sessionId }, s = pe(e), [n, a] = yt({ clientMessages: [], uiMessages: [], isProcessing: !1, error: s ? null : "Invalid agent configuration", suggestions: [] }), { registerMessageActions: r, unregisterMessageActions: o, clearAllMessageActions: c, registrations: i } = ge(), f = Ot(i); tt(() => { f.current = i; }, [i]), tt(() => { if (!s) return; (async () => { if (e.sessionId) { const l = st(), y = `${e.agentId}-${e.sessionId}`; l.hasAgent(y) || await l.createAgent(y, { agentId: e.agentId, agentUrl: e.agentUrl, sessionId: e.sessionId, contextProvider: t.contextProvider || me(), toolProvider: t.toolProvider || he(), authProvider: t.authProvider, enableStreaming: t.enableStreaming }); const d = l.getConversationHistory(y); a((I) => { const k = d.map( (w) => z( w, f.current ) ).filter((w) => w !== null); return { ...I, clientMessages: d, uiMessages: k }; }); } })(); }, [ e.sessionId, e.agentId, e.agentUrl, t.contextProvider, t.toolProvider, t.authProvider, t.enableStreaming, s ]); const u = $( async (m, l) => { var P; if (!s) throw new Error("Invalid agent configuration"); const y = st(), d = `${e.agentId}-${e.sessionId}`, I = Date.now(), k = (l == null ? void 0 : l.type) || "text", w = { id: `user-${I}`, role: "user", content: [{ type: k, text: m }], timestamp: I, archived: (l == null ? void 0 : l.archived) ?? !1, showIcon: !1 }; a((T) => ({ ...T, uiMessages: [...T.uiMessages, w], isProcessing: !0, error: null })); try { let T = null, x = !1; const v = {}; (l != null && l.archived || l != null && l.type) && (v.metadata = { ...(l == null ? void 0 : l.archived) && { archived: !0 }, ...(l == null ? void 0 : l.type) && { contentType: l.type } }); for await (const C of y.sendMessageStream( d, m, v )) { if (!C.final && C.text) if (T) a((S) => ({ ...S, uiMessages: S.uiMessages.map( (b) => b.id === T ? { ...b, content: [ { type: "text", text: C.text } ] } : b ) })); else { T = `agent-streaming-${Date.now()}`; const S = { id: T, role: "agent", content: [ { type: "text", text: C.text } ], timestamp: Date.now(), archived: !1, showIcon: !0, icon: "assistant" }; a((b) => ({ ...b, uiMessages: [ ...b.uiMessages, S ] })); } if (C.final && ((P = C.status) != null && P.message) && T) { x = !0; const S = T, b = z( C.status.message, f.current ); b && a((_) => { const N = _.uiMessages.map( (A) => A.id === S ? b : A ), E = y.getConversationHistory( d ); return { ..._, clientMessages: E, uiMessages: N, isProcessing: !1 }; }), T = null; } } if (!x) { const C = y.getConversationHistory(d); a((S) => { let b = S.uiMessages; T && (b = S.uiMessages.filter( (O) => O.id !== T )); const _ = C.map( (O) => z( O, f.current ) ).filter( (O) => O !== null ), N = new Set( C.map((O) => O.messageId) ), E = b.filter( (O) => { var J; return !N.has(O.id) && ((J = O.content[0]) == null ? void 0 : J.type) === "component";