@automattic/agenttic-client
Version:
A TypeScript client library for A2A (Agent2Agent) protocol communication
2,032 lines (2,031 loc) • 55.5 kB
JavaScript
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";