@aparte/runner-ag-ui 0.0.0-stage → 0.19.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 aparté
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,34 @@
1
- # Temporary Holding Version
1
+ # @aparte/runner-ag-ui
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Render an agent served over **[AG-UI](https://docs.ag-ui.com)** in aparté. The agent runs on
4
+ its own server, with its own tools: Agno, LangGraph, Mastra, CrewAI, Pydantic AI, CopilotKit's
5
+ runtime, or **TanStack AI**, whose chat route streams AG-UI. aparté draws its text, its reasoning,
6
+ its tool calls and its approvals, exactly as it draws a loop it runs itself.
7
+
8
+ ```bash
9
+ npm install @aparte/runner-ag-ui @aparte/core
10
+ ```
11
+
12
+ ```ts
13
+ import { AparteClient } from '@aparte/core';
14
+ import { createAgUiRunner } from '@aparte/runner-ag-ui';
15
+
16
+ const client = new AparteClient({
17
+ streamRunner: createAgUiRunner({ endpoint: '/agui' }),
18
+ });
19
+ client.start();
20
+ ```
21
+
22
+ - **Tools that need the page** (an `ask_user` you register with `registerTool`) go to the agent
23
+ as AG-UI frontend tools. When it calls one, the page runs it and the run resumes with the
24
+ result.
25
+ - **Approvals.** When the agent pauses on a call that needs a person (an AG-UI interrupt, such
26
+ as TanStack AI's `needsApproval`), the page asks through its usual approval panel, and the
27
+ answer resumes the run on the agent's server.
28
+ - **Its own state** (`STATE_*`, `CUSTOM`, sub-agents) is read and left alone in this version.
29
+
30
+ No AG-UI SDK is pulled in: the wire is plain JSON over Server-Sent Events, parsed here, with
31
+ `@aparte/core` as the only peer dependency.
32
+
33
+ > Part of the [aparté](https://github.com/apartejs/aparte) monorepo. ESM-only.
34
+ > See **Providers → AG-UI agents** and **TanStack AI** in the docs.
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @aparte/runner-ag-ui — render an agent served over AG-UI in aparté.
3
+ *
4
+ * The agent runs on its own server (Agno, LangGraph, Mastra, CrewAI, Pydantic AI,
5
+ * TanStack AI…), with its own tools; `AparteClient` draws its text, its tool rows and its
6
+ * approvals through the `streamRunner` seam, the way it draws a loop it runs itself.
7
+ */
8
+ export { createAgUiRunner } from './runner.js';
9
+ export type { AgUiRunnerOptions } from './runner.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,YAAY,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,423 @@
1
+ import { contentToText, uuid, AparteError, AparteErrorCode } from "@aparte/core";
2
+ function toAgUiMessages(messages) {
3
+ const out = [];
4
+ messages.forEach((m, index) => {
5
+ const id = `aparte-${index}`;
6
+ const content = contentToText(m.content);
7
+ if (m.role === "system" || m.role === "user") {
8
+ out.push({ id, role: m.role, content });
9
+ } else if (m.role === "assistant") {
10
+ out.push({
11
+ id,
12
+ role: "assistant",
13
+ ...content ? { content } : {},
14
+ ...m.toolCalls?.length ? {
15
+ toolCalls: m.toolCalls.map((call) => ({
16
+ id: call.id,
17
+ type: "function",
18
+ function: { name: call.name, arguments: JSON.stringify(call.input ?? {}) }
19
+ }))
20
+ } : {}
21
+ });
22
+ } else if (m.role === "tool" && m.toolCallId) {
23
+ out.push({ id, role: "tool", content, toolCallId: m.toolCallId });
24
+ }
25
+ });
26
+ return out;
27
+ }
28
+ function toAgUiTools(tools) {
29
+ return (tools ?? []).map((tool) => ({ name: tool.name, description: tool.description, parameters: tool.inputSchema }));
30
+ }
31
+ async function* readAgUiEvents(body, contentType) {
32
+ const ndjson = Boolean(contentType && /ndjson|jsonl/i.test(contentType));
33
+ const reader = body.getReader();
34
+ const decoder = new TextDecoder();
35
+ let buffer = "";
36
+ let data = [];
37
+ const parse = (text) => {
38
+ const trimmed = text.trim();
39
+ if (!trimmed || trimmed === "[DONE]") return void 0;
40
+ try {
41
+ const value = JSON.parse(trimmed);
42
+ return value && typeof value === "object" && typeof value.type === "string" ? value : void 0;
43
+ } catch {
44
+ return void 0;
45
+ }
46
+ };
47
+ const takeBlock = () => {
48
+ const event = parse(data.join("\n"));
49
+ data = [];
50
+ return event;
51
+ };
52
+ const line = (raw) => {
53
+ const text = raw.endsWith("\r") ? raw.slice(0, -1) : raw;
54
+ if (ndjson) return parse(text);
55
+ if (text === "") return takeBlock();
56
+ if (text.startsWith("data:")) data.push(text.slice(5).replace(/^ /, ""));
57
+ return void 0;
58
+ };
59
+ try {
60
+ for (; ; ) {
61
+ const { done, value } = await reader.read();
62
+ if (done) break;
63
+ buffer += decoder.decode(value, { stream: true });
64
+ let newline;
65
+ while ((newline = buffer.indexOf("\n")) !== -1) {
66
+ const event = line(buffer.slice(0, newline));
67
+ buffer = buffer.slice(newline + 1);
68
+ if (event) yield event;
69
+ }
70
+ }
71
+ buffer += decoder.decode();
72
+ if (buffer) {
73
+ const event = line(buffer);
74
+ if (event) yield event;
75
+ }
76
+ if (!ndjson) {
77
+ const event = takeBlock();
78
+ if (event) yield event;
79
+ }
80
+ } finally {
81
+ reader.releaseLock();
82
+ }
83
+ }
84
+ function readTicket(token) {
85
+ if (!token) return void 0;
86
+ try {
87
+ const ticket = JSON.parse(token);
88
+ return ticket && ticket.v === 1 && typeof ticket.threadId === "string" && typeof ticket.runId === "string" && Array.isArray(ticket.interrupts) ? ticket : void 0;
89
+ } catch {
90
+ return void 0;
91
+ }
92
+ }
93
+ function interruptKind(interrupt) {
94
+ if (interrupt.reason === "tool_call" || interrupt.reason === "confirmation") return "approval";
95
+ if (/client_tool/.test(interrupt.reason)) return "external";
96
+ return void 0;
97
+ }
98
+ function readUsage(value) {
99
+ const entries = (Array.isArray(value) ? value : value && typeof value === "object" ? [value] : []).filter((u) => Boolean(u) && typeof u === "object");
100
+ if (entries.length === 0) return void 0;
101
+ const sum = (key) => entries.reduce((n, u) => n + (typeof u[key] === "number" ? u[key] : 0), 0);
102
+ const cached = sum("cachedInputTokens");
103
+ return {
104
+ inputTokens: sum("inputTokens"),
105
+ outputTokens: sum("outputTokens"),
106
+ totalTokens: sum("totalTokens") || void 0,
107
+ ...cached ? { cacheReadTokens: cached } : {}
108
+ };
109
+ }
110
+ function addUsage(total, step) {
111
+ if (!step) return total;
112
+ if (!total) return step;
113
+ const cache = (total.cacheReadTokens ?? 0) + (step.cacheReadTokens ?? 0);
114
+ const sumTotal = (total.totalTokens ?? 0) + (step.totalTokens ?? 0);
115
+ return {
116
+ inputTokens: total.inputTokens + step.inputTokens,
117
+ outputTokens: total.outputTokens + step.outputTokens,
118
+ ...sumTotal ? { totalTokens: sumTotal } : {},
119
+ ...cache ? { cacheReadTokens: cache } : {}
120
+ };
121
+ }
122
+ function parseArgs(args) {
123
+ if (!args.trim()) return {};
124
+ try {
125
+ return JSON.parse(args);
126
+ } catch {
127
+ return { arguments: args };
128
+ }
129
+ }
130
+ function resultText(content) {
131
+ if (typeof content === "string") return content;
132
+ if (content === void 0 || content === null) return "";
133
+ return JSON.stringify(content);
134
+ }
135
+ function resumeItem(interrupt, outcome) {
136
+ if (!outcome) return { interruptId: interrupt.id, status: "cancelled" };
137
+ if (outcome.kind === "decision") {
138
+ return { interruptId: interrupt.id, status: "resolved", payload: { approved: outcome.approved } };
139
+ }
140
+ if (outcome.kind === "failed") {
141
+ return {
142
+ interruptId: interrupt.id,
143
+ status: "resolved",
144
+ payload: { error: outcome.error },
145
+ metadata: { tanstack: { state: "output-error" } }
146
+ };
147
+ }
148
+ return {
149
+ interruptId: interrupt.id,
150
+ status: "resolved",
151
+ payload: outcome.structuredContent !== void 0 ? outcome.structuredContent : outcome.content
152
+ };
153
+ }
154
+ function createAgUiRunner(options) {
155
+ return async (opts) => {
156
+ const doFetch = options.fetch ?? fetch;
157
+ const headers = typeof options.headers === "function" ? await options.headers() : options.headers ?? {};
158
+ const request = opts.baseRequest;
159
+ const ticket = readTicket(opts.deferral?.token);
160
+ const outcomes = opts.deferral?.outcomes ?? {};
161
+ const threadId = ticket?.threadId ?? (typeof options.threadId === "function" ? options.threadId(opts) : options.threadId) ?? `aparte-${uuid()}`;
162
+ const runId = `aparte-run-${uuid()}`;
163
+ const interrupted = new Set((ticket?.interrupts ?? []).map((i) => i.toolCallId));
164
+ const messages = toAgUiMessages(request.messages);
165
+ for (const [toolCallId, outcome] of Object.entries(outcomes)) {
166
+ if (interrupted.has(toolCallId) || outcome.kind === "decision") continue;
167
+ messages.push({
168
+ id: `aparte-result-${toolCallId}`,
169
+ role: "tool",
170
+ toolCallId,
171
+ content: outcome.kind === "failed" ? `Error: ${outcome.error}` : outcome.content
172
+ });
173
+ }
174
+ const resume = ticket?.interrupts.length ? ticket.interrupts.map((interrupt) => resumeItem(interrupt, outcomes[interrupt.toolCallId])) : void 0;
175
+ const body = {
176
+ threadId,
177
+ runId,
178
+ ...ticket ? { parentRunId: ticket.runId } : {},
179
+ state: {},
180
+ messages,
181
+ tools: toAgUiTools(request.tools),
182
+ context: options.context ?? [],
183
+ forwardedProps: options.forwardedProps ?? {},
184
+ ...resume ? { resume } : {}
185
+ };
186
+ const response = await doFetch(options.endpoint, {
187
+ method: "POST",
188
+ headers: { "Content-Type": "application/json", Accept: "text/event-stream", ...headers },
189
+ body: JSON.stringify(body),
190
+ signal: opts.signal,
191
+ ...options.credentials ? { credentials: options.credentials } : {}
192
+ });
193
+ if (!response.ok || !response.body) {
194
+ const text = await response.text().catch(() => "");
195
+ throw new AparteError(
196
+ text.trim().slice(0, 300) || `The agent endpoint answered HTTP ${response.status}.`,
197
+ AparteError.codeForStatus(response.status) ?? AparteErrorCode.PROVIDER_ERROR,
198
+ void 0,
199
+ void 0,
200
+ response.status
201
+ );
202
+ }
203
+ const history = new Map(request.messages.flatMap((m) => (m.toolCalls ?? []).map((c) => [c.id, { name: c.name, input: c.input ?? {} }])));
204
+ const known = new Set(history.keys());
205
+ const browserTools = new Set((request.tools ?? []).map((t) => t.name));
206
+ const calls = /* @__PURE__ */ new Map();
207
+ const started = /* @__PURE__ */ new Map();
208
+ const answered = /* @__PURE__ */ new Set();
209
+ const rejected = /* @__PURE__ */ new Set();
210
+ const settledByPage = /* @__PURE__ */ new Set();
211
+ let textOpen = false;
212
+ let usage;
213
+ let finished;
214
+ const emit = opts.emitter;
215
+ const startTool = (toolCallId) => {
216
+ const call = calls.get(toolCallId);
217
+ if (!call || started.has(toolCallId) || known.has(toolCallId)) return;
218
+ const input = parseArgs(call.args);
219
+ started.set(toolCallId, { name: call.name, input });
220
+ if (textOpen) {
221
+ emit({ type: "text-flush" });
222
+ textOpen = false;
223
+ }
224
+ emit({ type: "tool-start", toolCallId, name: call.name, input });
225
+ stepEnded = true;
226
+ };
227
+ let stepEnded = false;
228
+ const nextStep = () => {
229
+ if (!stepEnded) return;
230
+ stepEnded = false;
231
+ if (textOpen) {
232
+ emit({ type: "text-flush" });
233
+ textOpen = false;
234
+ }
235
+ emit({ type: "turn-start" });
236
+ };
237
+ const callOf = (interrupt) => {
238
+ const here = started.get(interrupt.toolCallId) ?? history.get(interrupt.toolCallId);
239
+ if (here) return here;
240
+ const streamed = calls.get(interrupt.toolCallId);
241
+ if (streamed) return { name: streamed.name, input: parseArgs(streamed.args) };
242
+ const meta = interrupt.metadata;
243
+ return { name: typeof meta?.toolName === "string" ? meta.toolName : "", input: meta?.input ?? {} };
244
+ };
245
+ let endedOnFinish = false;
246
+ let begun = false;
247
+ const begin = () => {
248
+ if (begun) return;
249
+ begun = true;
250
+ emit({ type: "run-start" });
251
+ emit({ type: "turn-start" });
252
+ for (const [toolCallId, outcome] of Object.entries(outcomes)) {
253
+ if (outcome.kind === "result") {
254
+ emit({
255
+ type: "tool-resolved",
256
+ toolCallId,
257
+ result: outcome.content,
258
+ ...outcome.structuredContent !== void 0 ? { structuredResult: outcome.structuredContent } : {}
259
+ });
260
+ settledByPage.add(toolCallId);
261
+ continue;
262
+ }
263
+ if (outcome.kind === "failed") {
264
+ emit({ type: "tool-failed", toolCallId, error: outcome.error });
265
+ settledByPage.add(toolCallId);
266
+ continue;
267
+ }
268
+ if (outcome.approved) {
269
+ emit({ type: "tool-approved", toolCallId });
270
+ } else {
271
+ const reason = outcome.reason?.trim() || (outcome.instruction ? `The user rejected this tool call and said: ${outcome.instruction}` : "Tool execution was rejected by the user.");
272
+ emit({ type: "tool-rejected", toolCallId, reason });
273
+ rejected.add(toolCallId);
274
+ }
275
+ }
276
+ };
277
+ for await (const event of readAgUiEvents(response.body, response.headers.get("content-type"))) {
278
+ begin();
279
+ if (/^(TEXT_MESSAGE|REASONING|TOOL_CALL)_/.test(event.type)) endedOnFinish = false;
280
+ switch (event.type) {
281
+ case "RUN_STARTED":
282
+ break;
283
+ case "TEXT_MESSAGE_START":
284
+ case "REASONING_START":
285
+ case "REASONING_MESSAGE_START":
286
+ nextStep();
287
+ break;
288
+ case "TEXT_MESSAGE_CONTENT":
289
+ case "TEXT_MESSAGE_CHUNK": {
290
+ const delta = typeof event["delta"] === "string" ? event["delta"] : "";
291
+ if (delta) {
292
+ nextStep();
293
+ emit({ type: "text-delta", delta });
294
+ textOpen = true;
295
+ }
296
+ break;
297
+ }
298
+ case "TEXT_MESSAGE_END": {
299
+ if (textOpen) {
300
+ emit({ type: "text-flush" });
301
+ textOpen = false;
302
+ }
303
+ break;
304
+ }
305
+ case "REASONING_MESSAGE_CONTENT":
306
+ case "REASONING_MESSAGE_CHUNK": {
307
+ const delta = typeof event["delta"] === "string" ? event["delta"] : "";
308
+ if (delta) {
309
+ nextStep();
310
+ emit({ type: "thinking-delta", delta });
311
+ }
312
+ break;
313
+ }
314
+ case "TOOL_CALL_START": {
315
+ const id = String(event["toolCallId"]);
316
+ calls.set(id, { name: String(event["toolCallName"] ?? ""), args: "" });
317
+ break;
318
+ }
319
+ case "TOOL_CALL_ARGS": {
320
+ const call = calls.get(String(event["toolCallId"]));
321
+ if (call && typeof event["delta"] === "string") call.args += event["delta"];
322
+ break;
323
+ }
324
+ case "TOOL_CALL_CHUNK": {
325
+ const id = typeof event["toolCallId"] === "string" ? event["toolCallId"] : [...calls.keys()].at(-1);
326
+ if (!id) break;
327
+ const call = calls.get(id) ?? { name: "", args: "" };
328
+ if (typeof event["toolCallName"] === "string" && event["toolCallName"]) call.name = event["toolCallName"];
329
+ if (typeof event["delta"] === "string") call.args += event["delta"];
330
+ calls.set(id, call);
331
+ break;
332
+ }
333
+ case "TOOL_CALL_END": {
334
+ startTool(String(event["toolCallId"]));
335
+ break;
336
+ }
337
+ case "TOOL_CALL_RESULT": {
338
+ const toolCallId = String(event["toolCallId"]);
339
+ startTool(toolCallId);
340
+ if (rejected.has(toolCallId) || settledByPage.has(toolCallId)) break;
341
+ answered.add(toolCallId);
342
+ const content = resultText(event["content"]);
343
+ const meta = event["metadata"];
344
+ if (meta?.tanstack?.state === "output-error") {
345
+ emit({ type: "tool-failed", toolCallId, error: content });
346
+ } else {
347
+ emit({ type: "tool-resolved", toolCallId, result: content });
348
+ }
349
+ break;
350
+ }
351
+ case "RUN_ERROR": {
352
+ throw new AparteError(
353
+ typeof event["message"] === "string" && event["message"] ? event["message"] : "The agent run failed.",
354
+ AparteErrorCode.PROVIDER_ERROR,
355
+ typeof event["code"] === "string" ? { code: event["code"] } : void 0
356
+ );
357
+ }
358
+ case "RUN_FINISHED": {
359
+ for (const id of calls.keys()) startTool(id);
360
+ if (textOpen) {
361
+ emit({ type: "text-flush" });
362
+ textOpen = false;
363
+ }
364
+ usage = addUsage(usage, readUsage(event["usage"]));
365
+ stepEnded = true;
366
+ endedOnFinish = true;
367
+ finished = {
368
+ runId: typeof event["runId"] === "string" ? event["runId"] : runId,
369
+ outcome: event["outcome"]
370
+ };
371
+ break;
372
+ }
373
+ }
374
+ }
375
+ if (opts.signal.aborted) return usage;
376
+ if (!finished) {
377
+ throw new AparteError("The agent stream ended without RUN_FINISHED.", AparteErrorCode.PROVIDER_ERROR);
378
+ }
379
+ if (!endedOnFinish) {
380
+ throw new AparteError("The agent stream was cut: it ended in the middle of a step, after a RUN_FINISHED.", AparteErrorCode.PROVIDER_ERROR);
381
+ }
382
+ if (textOpen) emit({ type: "text-flush" });
383
+ const pending = [];
384
+ const interrupts = [];
385
+ if (finished.outcome?.type === "interrupt") {
386
+ for (const interrupt of finished.outcome.interrupts ?? []) {
387
+ const kind = interruptKind(interrupt);
388
+ if (!kind || !interrupt.toolCallId) {
389
+ throw new AparteError(
390
+ `The agent paused for something aparté cannot answer yet (interrupt reason "${interrupt.reason}").`,
391
+ AparteErrorCode.PROVIDER_ERROR
392
+ );
393
+ }
394
+ const call = callOf(interrupt);
395
+ if (kind === "approval") {
396
+ emit({ type: "tool-awaiting-approval", toolCallId: interrupt.toolCallId, name: call.name, input: call.input });
397
+ }
398
+ interrupts.push({ id: interrupt.id, toolCallId: interrupt.toolCallId, kind });
399
+ pending.push({ toolCallId: interrupt.toolCallId, name: call.name, input: call.input, reason: kind });
400
+ }
401
+ } else {
402
+ const outcome = finished.outcome;
403
+ const named = Array.isArray(outcome?.pendingToolCallIds) ? new Set(outcome.pendingToolCallIds.filter((id) => typeof id === "string")) : void 0;
404
+ for (const [toolCallId, call] of started) {
405
+ if (answered.has(toolCallId)) continue;
406
+ const forPage = outcome?.type !== "cancelled" && (named ? named.has(toolCallId) : browserTools.has(call.name));
407
+ if (forPage) pending.push({ toolCallId, name: call.name, input: call.input, reason: "external" });
408
+ else emit({ type: "tool-aborted", toolCallId });
409
+ }
410
+ }
411
+ if (pending.length > 0) {
412
+ const next = { v: 1, threadId, runId: finished.runId, interrupts };
413
+ emit({ type: "run-suspended", pending, ...usage ? { usage } : {}, ticket: JSON.stringify(next) });
414
+ } else {
415
+ emit({ type: "run-done", ...usage ? { usage } : {} });
416
+ }
417
+ return usage;
418
+ };
419
+ }
420
+ export {
421
+ createAgUiRunner
422
+ };
423
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/messages.ts","../src/wire.ts","../src/runner.ts"],"sourcesContent":["import { contentToText } from '@aparte/core';\nimport type { AparteChatMessage, AparteTool } from '@aparte/core';\nimport type { AgUiMessage, AgUiRunAgentInput } from './wire.js';\n\n/**\n * aparté's history as `RunAgentInput.messages`. Every message gets an id (the protocol\n * requires one) that is stable across the runs of one turn — its position — so a resume\n * replays the same history the paused run saw. A call is `{ id, type: 'function',\n * function: { name, arguments } }` with the arguments as a JSON string, and a result is\n * a `tool` message naming its call. Content goes as text: an image part has no AG-UI\n * shape every agent reads, so it is left out rather than guessed.\n */\nexport function toAgUiMessages(messages: readonly AparteChatMessage[]): AgUiMessage[] {\n const out: AgUiMessage[] = [];\n messages.forEach((m, index) => {\n const id = `aparte-${index}`;\n const content = contentToText(m.content);\n if (m.role === 'system' || m.role === 'user') {\n out.push({ id, role: m.role, content });\n } else if (m.role === 'assistant') {\n out.push({\n id,\n role: 'assistant',\n ...(content ? { content } : {}),\n ...(m.toolCalls?.length\n ? {\n toolCalls: m.toolCalls.map((call) => ({\n id: call.id,\n type: 'function' as const,\n function: { name: call.name, arguments: JSON.stringify(call.input ?? {}) },\n })),\n }\n : {}),\n });\n } else if (m.role === 'tool' && m.toolCallId) {\n out.push({ id, role: 'tool', content, toolCallId: m.toolCallId });\n }\n });\n return out;\n}\n\n/** The page's tools as `RunAgentInput.tools`: the ones the agent may ask the browser to run. */\nexport function toAgUiTools(tools: readonly AparteTool[] | undefined): AgUiRunAgentInput['tools'] {\n return (tools ?? []).map((tool) => ({ name: tool.name, description: tool.description, parameters: tool.inputSchema }));\n}\n","/**\n * The AG-UI wire, as much of it as aparté reads — typed here rather than taken from\n * `@ag-ui/core`, whose client pulls rxjs, zod and protobuf into a bundle that only\n * needs to read JSON lines. Field names follow the protocol (docs.ag-ui.com, 1.0).\n */\n\n/** An interrupt an agent ends its run on (`RUN_FINISHED.outcome`). */\nexport interface AgUiInterrupt {\n id: string;\n /** `tool_call`, `confirmation`, `input_required`, or a producer's own string. */\n reason: string;\n message?: string;\n toolCallId?: string;\n responseSchema?: unknown;\n metadata?: Record<string, unknown>;\n}\n\n/** The events the runner maps; any other `type` is read and ignored. */\nexport type AgUiEvent =\n | { type: 'RUN_STARTED'; threadId?: string; runId?: string }\n | {\n type: 'RUN_FINISHED';\n threadId?: string;\n runId?: string;\n outcome?: { type: 'success' } | { type: 'interrupt'; interrupts: AgUiInterrupt[] };\n /** TanStack AI reports usage here, as an array. */\n usage?: unknown;\n }\n | { type: 'RUN_ERROR'; message?: string; code?: string }\n | { type: 'TEXT_MESSAGE_START'; messageId?: string; role?: string }\n | { type: 'TEXT_MESSAGE_CONTENT'; messageId?: string; delta?: string }\n | { type: 'TEXT_MESSAGE_END'; messageId?: string }\n | { type: 'TEXT_MESSAGE_CHUNK'; messageId?: string; role?: string; delta?: string }\n | { type: 'REASONING_MESSAGE_CONTENT'; messageId?: string; delta?: string }\n | { type: 'REASONING_MESSAGE_CHUNK'; messageId?: string; delta?: string }\n | { type: 'TOOL_CALL_START'; toolCallId: string; toolCallName: string; parentMessageId?: string }\n | { type: 'TOOL_CALL_ARGS'; toolCallId: string; delta?: string }\n | { type: 'TOOL_CALL_END'; toolCallId: string }\n | { type: 'TOOL_CALL_CHUNK'; toolCallId?: string; toolCallName?: string; delta?: string }\n | { type: 'TOOL_CALL_RESULT'; toolCallId: string; content?: unknown; metadata?: Record<string, unknown> };\n\n/** One message of `RunAgentInput.messages`. */\nexport type AgUiMessage =\n | { id: string; role: 'system'; content: string }\n | { id: string; role: 'user'; content: string }\n | {\n id: string;\n role: 'assistant';\n content?: string;\n toolCalls?: { id: string; type: 'function'; function: { name: string; arguments: string } }[];\n }\n | { id: string; role: 'tool'; content: string; toolCallId: string };\n\n/** One entry of `RunAgentInput.resume`: the answer to one interrupt. */\nexport interface AgUiResumeItem {\n interruptId: string;\n status: 'resolved' | 'cancelled';\n payload?: unknown;\n metadata?: Record<string, unknown>;\n}\n\n/** The request body an AG-UI agent endpoint takes. */\nexport interface AgUiRunAgentInput {\n threadId: string;\n runId: string;\n parentRunId?: string;\n state: Record<string, unknown>;\n messages: AgUiMessage[];\n tools: { name: string; description: string; parameters: unknown }[];\n context: { description: string; value: string }[];\n forwardedProps: Record<string, unknown>;\n resume?: AgUiResumeItem[];\n}\n\n/**\n * The events of an AG-UI response, in order. Server-Sent Events by default — each\n * `data:` block is one JSON event, comments and `event:` lines are skipped, and a\n * `[DONE]` sentinel ends nothing on its own. An NDJSON body (one event per line, the\n * other encoding TanStack AI serves) is read the same way. A block that is not JSON\n * is skipped: a proxy's keep-alive must not end the run.\n */\nexport async function* readAgUiEvents(\n body: ReadableStream<Uint8Array>,\n contentType: string | null,\n): AsyncGenerator<{ type: string } & Record<string, unknown>> {\n const ndjson = Boolean(contentType && /ndjson|jsonl/i.test(contentType));\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n let data: string[] = [];\n const parse = (text: string): ({ type: string } & Record<string, unknown>) | undefined => {\n const trimmed = text.trim();\n if (!trimmed || trimmed === '[DONE]') return undefined;\n try {\n const value = JSON.parse(trimmed) as unknown;\n return value && typeof value === 'object' && typeof (value as { type?: unknown }).type === 'string'\n ? value as { type: string } & Record<string, unknown>\n : undefined;\n } catch {\n return undefined;\n }\n };\n const takeBlock = () => {\n const event = parse(data.join('\\n'));\n data = [];\n return event;\n };\n const line = (raw: string) => {\n const text = raw.endsWith('\\r') ? raw.slice(0, -1) : raw;\n if (ndjson) return parse(text);\n if (text === '') return takeBlock();\n if (text.startsWith('data:')) data.push(text.slice(5).replace(/^ /, ''));\n // `event:`, `id:`, `retry:` and `:` comments: AG-UI carries the type in the JSON.\n return undefined;\n };\n try {\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n let newline: number;\n while ((newline = buffer.indexOf('\\n')) !== -1) {\n const event = line(buffer.slice(0, newline));\n buffer = buffer.slice(newline + 1);\n if (event) yield event;\n }\n }\n buffer += decoder.decode();\n if (buffer) {\n const event = line(buffer);\n if (event) yield event;\n }\n if (!ndjson) {\n const event = takeBlock();\n if (event) yield event;\n }\n } finally {\n reader.releaseLock();\n }\n}\n","import { AparteError, AparteErrorCode, uuid } from '@aparte/core';\nimport type {\n AparteChatRequest,\n AparteStreamRunEvent,\n AparteStreamRunner,\n AparteStreamRunOptions,\n} from '@aparte/core';\nimport { toAgUiMessages, toAgUiTools } from './messages.js';\nimport { readAgUiEvents } from './wire.js';\nimport type { AgUiInterrupt, AgUiMessage, AgUiResumeItem, AgUiRunAgentInput } from './wire.js';\n\ntype Suspended = Extract<AparteStreamRunEvent, { type: 'run-suspended' }>;\ntype PendingCall = Suspended['pending'][number];\ntype Usage = NonNullable<Extract<AparteStreamRunEvent, { type: 'run-done' }>['usage']>;\ntype Outcome = NonNullable<NonNullable<AparteStreamRunOptions['deferral']>['outcomes']>[string];\n\nexport interface AgUiRunnerOptions {\n /** The agent's AG-UI endpoint, e.g. Agno's `/agui`, or a TanStack AI chat route. */\n endpoint: string;\n /** Sent with every request; a function is called per request (a fresh token each time). */\n headers?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);\n /** @default the global `fetch` */\n fetch?: typeof fetch;\n /** For a cross-origin endpoint that authenticates by cookie. */\n credentials?: RequestCredentials;\n /**\n * The AG-UI thread a turn runs in. Give the conversation's id when the agent keeps\n * state per thread (Agno's session); a function receives the run's options. A paused\n * run is always resumed in its own thread, whatever this returns.\n * @default a new thread per turn — the agent gets the whole history every time\n */\n threadId?: string | ((opts: AparteStreamRunOptions) => string);\n /** `RunAgentInput.forwardedProps`: settings your agent reads from the request. */\n forwardedProps?: Record<string, unknown>;\n /** `RunAgentInput.context`: extra context entries for the agent. */\n context?: { description: string; value: string }[];\n}\n\n/**\n * What a paused run hands the page and gets back with the answers — `deferral.token`.\n * Opaque to the client; the runner reads it to resume in the same thread, after the\n * run it continues, with the interrupts it must answer.\n */\ninterface Ticket {\n v: 1;\n threadId: string;\n runId: string;\n interrupts: { id: string; toolCallId: string; kind: 'approval' | 'external' }[];\n}\n\nfunction readTicket(token: string | undefined): Ticket | undefined {\n if (!token) return undefined;\n try {\n const ticket = JSON.parse(token) as Ticket;\n return ticket && ticket.v === 1 && typeof ticket.threadId === 'string' && typeof ticket.runId === 'string'\n && Array.isArray(ticket.interrupts) ? ticket : undefined;\n } catch {\n return undefined;\n }\n}\n\n/** An interrupt's reason, as what the page must do about its call. */\nfunction interruptKind(interrupt: AgUiInterrupt): 'approval' | 'external' | undefined {\n if (interrupt.reason === 'tool_call' || interrupt.reason === 'confirmation') return 'approval';\n if (/client_tool/.test(interrupt.reason)) return 'external';\n return undefined;\n}\n\n/** Usage as AG-UI agents report it — an object, or TanStack AI's array of steps — summed. */\nfunction readUsage(value: unknown): Usage | undefined {\n const entries = (Array.isArray(value) ? value : value && typeof value === 'object' ? [value] : [])\n .filter((u): u is Record<string, unknown> => Boolean(u) && typeof u === 'object');\n if (entries.length === 0) return undefined;\n const sum = (key: string) => entries.reduce((n, u) => n + (typeof u[key] === 'number' ? u[key] as number : 0), 0);\n const cached = sum('cachedInputTokens');\n return {\n inputTokens: sum('inputTokens'),\n outputTokens: sum('outputTokens'),\n totalTokens: sum('totalTokens') || undefined,\n ...(cached ? { cacheReadTokens: cached } : {}),\n } as Usage;\n}\n\n/** Two usage reports as one: a TanStack AI run reports one per model step. */\nfunction addUsage(total: Usage | undefined, step: Usage | undefined): Usage | undefined {\n if (!step) return total;\n if (!total) return step;\n const cache = (total.cacheReadTokens ?? 0) + (step.cacheReadTokens ?? 0);\n const sumTotal = (total.totalTokens ?? 0) + (step.totalTokens ?? 0);\n return {\n inputTokens: total.inputTokens + step.inputTokens,\n outputTokens: total.outputTokens + step.outputTokens,\n ...(sumTotal ? { totalTokens: sumTotal } : {}),\n ...(cache ? { cacheReadTokens: cache } : {}),\n } as Usage;\n}\n\n/** A call's streamed arguments as its input: `{}` for none, the raw text when not JSON. */\nfunction parseArgs(args: string): unknown {\n if (!args.trim()) return {};\n try { return JSON.parse(args); } catch { return { arguments: args }; }\n}\n\n/** A tool result as the row shows it: text as is, anything else as JSON. */\nfunction resultText(content: unknown): string {\n if (typeof content === 'string') return content;\n if (content === undefined || content === null) return '';\n return JSON.stringify(content);\n}\n\n/** The answer a resumed interrupt carries, in the shape AG-UI (and TanStack AI) reads. */\nfunction resumeItem(interrupt: Ticket['interrupts'][number], outcome: Outcome | undefined): AgUiResumeItem {\n if (!outcome) return { interruptId: interrupt.id, status: 'cancelled' };\n if (outcome.kind === 'decision') {\n return { interruptId: interrupt.id, status: 'resolved', payload: { approved: outcome.approved } };\n }\n if (outcome.kind === 'failed') {\n return {\n interruptId: interrupt.id,\n status: 'resolved',\n payload: { error: outcome.error },\n metadata: { tanstack: { state: 'output-error' } },\n };\n }\n return {\n interruptId: interrupt.id,\n status: 'resolved',\n payload: outcome.structuredContent !== undefined ? outcome.structuredContent : outcome.content,\n };\n}\n\n/**\n * An `AparteStreamRunner` for an agent served over AG-UI — Agno, LangGraph, Mastra,\n * CrewAI, Pydantic AI, CopilotKit's runtime, TanStack AI. The agent runs on its server,\n * with its own tools; this runner turns its event stream into the rows, text and\n * approvals `AparteClient` draws.\n *\n * ```ts\n * const client = new AparteClient({ streamRunner: createAgUiRunner({ endpoint: '/agui' }) });\n * ```\n *\n * Tools the PAGE registers go to the agent as AG-UI frontend tools. When the agent calls\n * one — or pauses on a call that needs a person (an AG-UI interrupt) — the run ends on\n * `run-suspended`; the client runs the tool or asks through its approval panel, then\n * calls this runner again with the answers, which go back as `tool` messages or as one\n * `resume` batch for the interrupts.\n */\nexport function createAgUiRunner(options: AgUiRunnerOptions): AparteStreamRunner {\n return async (opts) => {\n const doFetch = options.fetch ?? fetch;\n const headers = typeof options.headers === 'function' ? await options.headers() : options.headers ?? {};\n const request = opts.baseRequest as AparteChatRequest;\n const ticket = readTicket(opts.deferral?.token);\n const outcomes = opts.deferral?.outcomes ?? {};\n const threadId = ticket?.threadId\n ?? (typeof options.threadId === 'function' ? options.threadId(opts) : options.threadId)\n ?? `aparte-${uuid()}`;\n const runId = `aparte-run-${uuid()}`;\n const interrupted = new Set((ticket?.interrupts ?? []).map((i) => i.toolCallId));\n\n // Answers to calls the agent left to the browser without an interrupt go back as\n // `tool` messages after the history; answers to interrupts go in one `resume`\n // batch, since the protocol refuses a partial one.\n const messages: AgUiMessage[] = toAgUiMessages(request.messages);\n for (const [toolCallId, outcome] of Object.entries(outcomes)) {\n if (interrupted.has(toolCallId) || outcome.kind === 'decision') continue;\n messages.push({\n id: `aparte-result-${toolCallId}`,\n role: 'tool',\n toolCallId,\n content: outcome.kind === 'failed' ? `Error: ${outcome.error}` : outcome.content,\n });\n }\n const resume = ticket?.interrupts.length\n ? ticket.interrupts.map((interrupt) => resumeItem(interrupt, outcomes[interrupt.toolCallId]))\n : undefined;\n\n const body: AgUiRunAgentInput = {\n threadId,\n runId,\n ...(ticket ? { parentRunId: ticket.runId } : {}),\n state: {},\n messages,\n tools: toAgUiTools(request.tools),\n context: options.context ?? [],\n forwardedProps: options.forwardedProps ?? {},\n ...(resume ? { resume } : {}),\n };\n const response = await doFetch(options.endpoint, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', Accept: 'text/event-stream', ...headers },\n body: JSON.stringify(body),\n signal: opts.signal,\n ...(options.credentials ? { credentials: options.credentials } : {}),\n });\n if (!response.ok || !response.body) {\n const text = await response.text().catch(() => '');\n throw new AparteError(\n text.trim().slice(0, 300) || `The agent endpoint answered HTTP ${response.status}.`,\n AparteError.codeForStatus(response.status) ?? AparteErrorCode.PROVIDER_ERROR,\n undefined, undefined, response.status,\n );\n }\n\n // Calls the history already declares: a resumed run answers them, it does not\n // start them again (no second row).\n const history = new Map(request.messages.flatMap((m) => (m.toolCalls ?? []).map((c) => [c.id, { name: c.name, input: c.input ?? {} }] as const)));\n const known = new Set(history.keys());\n const browserTools = new Set((request.tools ?? []).map((t) => t.name));\n const calls = new Map<string, { name: string; args: string }>();\n const started = new Map<string, { name: string; input: unknown }>();\n const answered = new Set<string>();\n const rejected = new Set<string>();\n const settledByPage = new Set<string>();\n let textOpen = false;\n let usage: Usage | undefined;\n let finished: { runId: string; outcome?: { type?: string; interrupts?: AgUiInterrupt[] } } | undefined;\n const emit = opts.emitter;\n\n const startTool = (toolCallId: string) => {\n const call = calls.get(toolCallId);\n if (!call || started.has(toolCallId) || known.has(toolCallId)) return;\n const input = parseArgs(call.args);\n started.set(toolCallId, { name: call.name, input });\n if (textOpen) { emit({ type: 'text-flush' }); textOpen = false; }\n emit({ type: 'tool-start', toolCallId, name: call.name, input });\n stepEnded = true;\n };\n\n // A model step ends on a tool call, or on a RUN_FINISHED (TanStack AI closes each\n // step with one). What the next step draws, its reasoning or its text, opens a new\n // turn, the way the in-page loop opens one per model call. Drawn into the old turn,\n // a second step's reasoning landed in the first step's thinking block, above the\n // tool row.\n let stepEnded = false;\n const nextStep = () => {\n if (!stepEnded) return;\n stepEnded = false;\n if (textOpen) { emit({ type: 'text-flush' }); textOpen = false; }\n emit({ type: 'turn-start' });\n };\n\n /** The call an interrupt is about: started in this run, else in the history, else as the interrupt describes it. */\n const callOf = (interrupt: AgUiInterrupt & { toolCallId: string }): { name: string; input: unknown } => {\n const here = started.get(interrupt.toolCallId) ?? history.get(interrupt.toolCallId);\n if (here) return here;\n const streamed = calls.get(interrupt.toolCallId);\n if (streamed) return { name: streamed.name, input: parseArgs(streamed.args) };\n // TanStack AI describes the call on the interrupt itself.\n const meta = interrupt.metadata as { toolName?: unknown; input?: unknown } | undefined;\n return { name: typeof meta?.toolName === 'string' ? meta.toolName : '', input: meta?.input ?? {} };\n };\n\n // A stream that closes between two steps is cut, not finished: TanStack AI sends a\n // RUN_FINISHED per step, so having seen one says nothing about the last.\n let endedOnFinish = false;\n\n // The run opens on its FIRST event, whatever it is: a resumed TanStack AI run sends\n // the approved call's TOOL_CALL_RESULT before RUN_STARTED, and settling that row\n // after its result put it back to pending. The answers this run carries settle\n // their rows before anything else.\n let begun = false;\n const begin = () => {\n if (begun) return;\n begun = true;\n emit({ type: 'run-start' });\n emit({ type: 'turn-start' });\n for (const [toolCallId, outcome] of Object.entries(outcomes)) {\n // A tool the PAGE ran: its row settles here, with the result the page holds —\n // a plain AG-UI agent never echoes a frontend tool's result, so nothing\n // else would, and an echo that does come is not drawn twice.\n if (outcome.kind === 'result') {\n emit({\n type: 'tool-resolved',\n toolCallId,\n result: outcome.content,\n ...(outcome.structuredContent !== undefined ? { structuredResult: outcome.structuredContent } : {}),\n });\n settledByPage.add(toolCallId);\n continue;\n }\n if (outcome.kind === 'failed') {\n emit({ type: 'tool-failed', toolCallId, error: outcome.error });\n settledByPage.add(toolCallId);\n continue;\n }\n if (outcome.approved) {\n emit({ type: 'tool-approved', toolCallId });\n } else {\n const reason = outcome.reason?.trim()\n || (outcome.instruction ? `The user rejected this tool call and said: ${outcome.instruction}` : 'Tool execution was rejected by the user.');\n emit({ type: 'tool-rejected', toolCallId, reason });\n rejected.add(toolCallId);\n }\n }\n };\n\n for await (const event of readAgUiEvents(response.body, response.headers.get('content-type'))) {\n begin();\n if (/^(TEXT_MESSAGE|REASONING|TOOL_CALL)_/.test(event.type)) endedOnFinish = false;\n switch (event.type) {\n case 'RUN_STARTED':\n break;\n case 'TEXT_MESSAGE_START':\n case 'REASONING_START':\n case 'REASONING_MESSAGE_START':\n nextStep();\n break;\n case 'TEXT_MESSAGE_CONTENT':\n case 'TEXT_MESSAGE_CHUNK': {\n const delta = typeof event['delta'] === 'string' ? event['delta'] : '';\n if (delta) { nextStep(); emit({ type: 'text-delta', delta }); textOpen = true; }\n break;\n }\n case 'TEXT_MESSAGE_END': {\n if (textOpen) { emit({ type: 'text-flush' }); textOpen = false; }\n break;\n }\n case 'REASONING_MESSAGE_CONTENT':\n case 'REASONING_MESSAGE_CHUNK': {\n const delta = typeof event['delta'] === 'string' ? event['delta'] : '';\n if (delta) { nextStep(); emit({ type: 'thinking-delta', delta }); }\n break;\n }\n case 'TOOL_CALL_START': {\n const id = String(event['toolCallId']);\n calls.set(id, { name: String(event['toolCallName'] ?? ''), args: '' });\n break;\n }\n case 'TOOL_CALL_ARGS': {\n const call = calls.get(String(event['toolCallId']));\n if (call && typeof event['delta'] === 'string') call.args += event['delta'];\n break;\n }\n case 'TOOL_CALL_CHUNK': {\n const id = typeof event['toolCallId'] === 'string' ? event['toolCallId'] : [...calls.keys()].at(-1);\n if (!id) break;\n const call = calls.get(id) ?? { name: '', args: '' };\n if (typeof event['toolCallName'] === 'string' && event['toolCallName']) call.name = event['toolCallName'];\n if (typeof event['delta'] === 'string') call.args += event['delta'];\n calls.set(id, call);\n break;\n }\n case 'TOOL_CALL_END': {\n startTool(String(event['toolCallId']));\n break;\n }\n case 'TOOL_CALL_RESULT': {\n const toolCallId = String(event['toolCallId']);\n startTool(toolCallId);\n if (rejected.has(toolCallId) || settledByPage.has(toolCallId)) break; // already settled\n answered.add(toolCallId);\n const content = resultText(event['content']);\n const meta = event['metadata'] as { tanstack?: { state?: unknown } } | undefined;\n if (meta?.tanstack?.state === 'output-error') {\n emit({ type: 'tool-failed', toolCallId, error: content });\n } else {\n emit({ type: 'tool-resolved', toolCallId, result: content });\n }\n break;\n }\n case 'RUN_ERROR': {\n throw new AparteError(\n typeof event['message'] === 'string' && event['message'] ? event['message'] : 'The agent run failed.',\n AparteErrorCode.PROVIDER_ERROR,\n typeof event['code'] === 'string' ? { code: event['code'] } : undefined,\n );\n }\n case 'RUN_FINISHED': {\n // Not the end of the stream: TanStack AI closes each model step with a\n // RUN_FINISHED of its own (`finishReason: tool_calls`), then streams the\n // tool results and the next step. The LAST one says how the run ended.\n for (const id of calls.keys()) startTool(id);\n if (textOpen) { emit({ type: 'text-flush' }); textOpen = false; }\n usage = addUsage(usage, readUsage(event['usage']));\n stepEnded = true;\n endedOnFinish = true;\n finished = {\n runId: typeof event['runId'] === 'string' ? event['runId'] : runId,\n outcome: event['outcome'] as { type?: string; interrupts?: AgUiInterrupt[] } | undefined,\n };\n break;\n }\n default:\n // STEP_*, STATE_*, MESSAGES_SNAPSHOT, ACTIVITY_*, RAW, CUSTOM, SUBAGENT_*:\n // agent state aparté does not draw.\n break;\n }\n }\n if (opts.signal.aborted) return usage;\n if (!finished) {\n throw new AparteError('The agent stream ended without RUN_FINISHED.', AparteErrorCode.PROVIDER_ERROR);\n }\n if (!endedOnFinish) {\n throw new AparteError('The agent stream was cut: it ended in the middle of a step, after a RUN_FINISHED.', AparteErrorCode.PROVIDER_ERROR);\n }\n if (textOpen) emit({ type: 'text-flush' });\n\n const pending: PendingCall[] = [];\n const interrupts: Ticket['interrupts'] = [];\n if (finished.outcome?.type === 'interrupt') {\n for (const interrupt of finished.outcome.interrupts ?? []) {\n const kind = interruptKind(interrupt);\n if (!kind || !interrupt.toolCallId) {\n throw new AparteError(\n `The agent paused for something aparté cannot answer yet (interrupt reason \"${interrupt.reason}\").`,\n AparteErrorCode.PROVIDER_ERROR,\n );\n }\n // A resumed run can pause again on a call an earlier run started (TanStack AI\n // asks to approve a client tool, then to run it): its name comes from there.\n const call = callOf(interrupt as AgUiInterrupt & { toolCallId: string });\n if (kind === 'approval') {\n emit({ type: 'tool-awaiting-approval', toolCallId: interrupt.toolCallId, name: call.name, input: call.input });\n }\n interrupts.push({ id: interrupt.id, toolCallId: interrupt.toolCallId, kind });\n pending.push({ toolCallId: interrupt.toolCallId, name: call.name, input: call.input, reason: kind });\n }\n } else {\n // Plain AG-UI: the calls left to the browser are the ones the agent names\n // (`pendingToolCallIds`, AG-UI 1.0), else the page's own tools nobody answered.\n // Any other call without a result has nobody left to answer it: its row stops\n // waiting rather than spinning after the run. A cancelled run leaves nothing.\n const outcome = finished.outcome as { type?: string; pendingToolCallIds?: unknown } | undefined;\n const named = Array.isArray(outcome?.pendingToolCallIds)\n ? new Set(outcome.pendingToolCallIds.filter((id): id is string => typeof id === 'string'))\n : undefined;\n for (const [toolCallId, call] of started) {\n if (answered.has(toolCallId)) continue;\n const forPage = outcome?.type !== 'cancelled' && (named ? named.has(toolCallId) : browserTools.has(call.name));\n if (forPage) pending.push({ toolCallId, name: call.name, input: call.input, reason: 'external' });\n else emit({ type: 'tool-aborted', toolCallId });\n }\n }\n if (pending.length > 0) {\n const next: Ticket = { v: 1, threadId, runId: finished.runId, interrupts };\n emit({ type: 'run-suspended', pending, ...(usage ? { usage } : {}), ticket: JSON.stringify(next) } as Suspended);\n } else {\n emit({ type: 'run-done', ...(usage ? { usage } : {}) });\n }\n return usage;\n };\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { AparteChatMessage, AparteTool } from '@aparte/core';
2
+ import type { AgUiMessage, AgUiRunAgentInput } from './wire.js';
3
+ /**
4
+ * aparté's history as `RunAgentInput.messages`. Every message gets an id (the protocol
5
+ * requires one) that is stable across the runs of one turn — its position — so a resume
6
+ * replays the same history the paused run saw. A call is `{ id, type: 'function',
7
+ * function: { name, arguments } }` with the arguments as a JSON string, and a result is
8
+ * a `tool` message naming its call. Content goes as text: an image part has no AG-UI
9
+ * shape every agent reads, so it is left out rather than guessed.
10
+ */
11
+ export declare function toAgUiMessages(messages: readonly AparteChatMessage[]): AgUiMessage[];
12
+ /** The page's tools as `RunAgentInput.tools`: the ones the agent may ask the browser to run. */
13
+ export declare function toAgUiTools(tools: readonly AparteTool[] | undefined): AgUiRunAgentInput['tools'];
14
+ //# sourceMappingURL=messages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAEhE;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,GAAG,WAAW,EAAE,CA2BpF;AAED,gGAAgG;AAChG,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,GAAG,SAAS,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAEhG"}
@@ -0,0 +1,43 @@
1
+ import type { AparteStreamRunner, AparteStreamRunOptions } from '@aparte/core';
2
+ export interface AgUiRunnerOptions {
3
+ /** The agent's AG-UI endpoint, e.g. Agno's `/agui`, or a TanStack AI chat route. */
4
+ endpoint: string;
5
+ /** Sent with every request; a function is called per request (a fresh token each time). */
6
+ headers?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
7
+ /** @default the global `fetch` */
8
+ fetch?: typeof fetch;
9
+ /** For a cross-origin endpoint that authenticates by cookie. */
10
+ credentials?: RequestCredentials;
11
+ /**
12
+ * The AG-UI thread a turn runs in. Give the conversation's id when the agent keeps
13
+ * state per thread (Agno's session); a function receives the run's options. A paused
14
+ * run is always resumed in its own thread, whatever this returns.
15
+ * @default a new thread per turn — the agent gets the whole history every time
16
+ */
17
+ threadId?: string | ((opts: AparteStreamRunOptions) => string);
18
+ /** `RunAgentInput.forwardedProps`: settings your agent reads from the request. */
19
+ forwardedProps?: Record<string, unknown>;
20
+ /** `RunAgentInput.context`: extra context entries for the agent. */
21
+ context?: {
22
+ description: string;
23
+ value: string;
24
+ }[];
25
+ }
26
+ /**
27
+ * An `AparteStreamRunner` for an agent served over AG-UI — Agno, LangGraph, Mastra,
28
+ * CrewAI, Pydantic AI, CopilotKit's runtime, TanStack AI. The agent runs on its server,
29
+ * with its own tools; this runner turns its event stream into the rows, text and
30
+ * approvals `AparteClient` draws.
31
+ *
32
+ * ```ts
33
+ * const client = new AparteClient({ streamRunner: createAgUiRunner({ endpoint: '/agui' }) });
34
+ * ```
35
+ *
36
+ * Tools the PAGE registers go to the agent as AG-UI frontend tools. When the agent calls
37
+ * one — or pauses on a call that needs a person (an AG-UI interrupt) — the run ends on
38
+ * `run-suspended`; the client runs the tool or asks through its approval panel, then
39
+ * calls this runner again with the answers, which go back as `tool` messages or as one
40
+ * `resume` batch for the interrupts.
41
+ */
42
+ export declare function createAgUiRunner(options: AgUiRunnerOptions): AparteStreamRunner;
43
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAGR,kBAAkB,EAClB,sBAAsB,EACzB,MAAM,cAAc,CAAC;AAUtB,MAAM,WAAW,iBAAiB;IAC9B,oFAAoF;IACpF,QAAQ,EAAE,MAAM,CAAC;IACjB,2FAA2F;IAC3F,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IACpG,kCAAkC;IAClC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,gEAAgE;IAChE,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,sBAAsB,KAAK,MAAM,CAAC,CAAC;IAC/D,kFAAkF;IAClF,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzC,oEAAoE;IACpE,OAAO,CAAC,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACtD;AA+FD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,GAAG,kBAAkB,CAuS/E"}
package/dist/wire.d.ts ADDED
@@ -0,0 +1,147 @@
1
+ /**
2
+ * The AG-UI wire, as much of it as aparté reads — typed here rather than taken from
3
+ * `@ag-ui/core`, whose client pulls rxjs, zod and protobuf into a bundle that only
4
+ * needs to read JSON lines. Field names follow the protocol (docs.ag-ui.com, 1.0).
5
+ */
6
+ /** An interrupt an agent ends its run on (`RUN_FINISHED.outcome`). */
7
+ export interface AgUiInterrupt {
8
+ id: string;
9
+ /** `tool_call`, `confirmation`, `input_required`, or a producer's own string. */
10
+ reason: string;
11
+ message?: string;
12
+ toolCallId?: string;
13
+ responseSchema?: unknown;
14
+ metadata?: Record<string, unknown>;
15
+ }
16
+ /** The events the runner maps; any other `type` is read and ignored. */
17
+ export type AgUiEvent = {
18
+ type: 'RUN_STARTED';
19
+ threadId?: string;
20
+ runId?: string;
21
+ } | {
22
+ type: 'RUN_FINISHED';
23
+ threadId?: string;
24
+ runId?: string;
25
+ outcome?: {
26
+ type: 'success';
27
+ } | {
28
+ type: 'interrupt';
29
+ interrupts: AgUiInterrupt[];
30
+ };
31
+ /** TanStack AI reports usage here, as an array. */
32
+ usage?: unknown;
33
+ } | {
34
+ type: 'RUN_ERROR';
35
+ message?: string;
36
+ code?: string;
37
+ } | {
38
+ type: 'TEXT_MESSAGE_START';
39
+ messageId?: string;
40
+ role?: string;
41
+ } | {
42
+ type: 'TEXT_MESSAGE_CONTENT';
43
+ messageId?: string;
44
+ delta?: string;
45
+ } | {
46
+ type: 'TEXT_MESSAGE_END';
47
+ messageId?: string;
48
+ } | {
49
+ type: 'TEXT_MESSAGE_CHUNK';
50
+ messageId?: string;
51
+ role?: string;
52
+ delta?: string;
53
+ } | {
54
+ type: 'REASONING_MESSAGE_CONTENT';
55
+ messageId?: string;
56
+ delta?: string;
57
+ } | {
58
+ type: 'REASONING_MESSAGE_CHUNK';
59
+ messageId?: string;
60
+ delta?: string;
61
+ } | {
62
+ type: 'TOOL_CALL_START';
63
+ toolCallId: string;
64
+ toolCallName: string;
65
+ parentMessageId?: string;
66
+ } | {
67
+ type: 'TOOL_CALL_ARGS';
68
+ toolCallId: string;
69
+ delta?: string;
70
+ } | {
71
+ type: 'TOOL_CALL_END';
72
+ toolCallId: string;
73
+ } | {
74
+ type: 'TOOL_CALL_CHUNK';
75
+ toolCallId?: string;
76
+ toolCallName?: string;
77
+ delta?: string;
78
+ } | {
79
+ type: 'TOOL_CALL_RESULT';
80
+ toolCallId: string;
81
+ content?: unknown;
82
+ metadata?: Record<string, unknown>;
83
+ };
84
+ /** One message of `RunAgentInput.messages`. */
85
+ export type AgUiMessage = {
86
+ id: string;
87
+ role: 'system';
88
+ content: string;
89
+ } | {
90
+ id: string;
91
+ role: 'user';
92
+ content: string;
93
+ } | {
94
+ id: string;
95
+ role: 'assistant';
96
+ content?: string;
97
+ toolCalls?: {
98
+ id: string;
99
+ type: 'function';
100
+ function: {
101
+ name: string;
102
+ arguments: string;
103
+ };
104
+ }[];
105
+ } | {
106
+ id: string;
107
+ role: 'tool';
108
+ content: string;
109
+ toolCallId: string;
110
+ };
111
+ /** One entry of `RunAgentInput.resume`: the answer to one interrupt. */
112
+ export interface AgUiResumeItem {
113
+ interruptId: string;
114
+ status: 'resolved' | 'cancelled';
115
+ payload?: unknown;
116
+ metadata?: Record<string, unknown>;
117
+ }
118
+ /** The request body an AG-UI agent endpoint takes. */
119
+ export interface AgUiRunAgentInput {
120
+ threadId: string;
121
+ runId: string;
122
+ parentRunId?: string;
123
+ state: Record<string, unknown>;
124
+ messages: AgUiMessage[];
125
+ tools: {
126
+ name: string;
127
+ description: string;
128
+ parameters: unknown;
129
+ }[];
130
+ context: {
131
+ description: string;
132
+ value: string;
133
+ }[];
134
+ forwardedProps: Record<string, unknown>;
135
+ resume?: AgUiResumeItem[];
136
+ }
137
+ /**
138
+ * The events of an AG-UI response, in order. Server-Sent Events by default — each
139
+ * `data:` block is one JSON event, comments and `event:` lines are skipped, and a
140
+ * `[DONE]` sentinel ends nothing on its own. An NDJSON body (one event per line, the
141
+ * other encoding TanStack AI serves) is read the same way. A block that is not JSON
142
+ * is skipped: a proxy's keep-alive must not end the run.
143
+ */
144
+ export declare function readAgUiEvents(body: ReadableStream<Uint8Array>, contentType: string | null): AsyncGenerator<{
145
+ type: string;
146
+ } & Record<string, unknown>>;
147
+ //# sourceMappingURL=wire.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wire.d.ts","sourceRoot":"","sources":["../src/wire.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,sEAAsE;AACtE,MAAM,WAAW,aAAa;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,iFAAiF;IACjF,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,wEAAwE;AACxE,MAAM,MAAM,SAAS,GACf;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1D;IACE,IAAI,EAAE,cAAc,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE;QAAE,IAAI,EAAE,SAAS,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,WAAW,CAAC;QAAC,UAAU,EAAE,aAAa,EAAE,CAAA;KAAE,CAAC;IACnF,mDAAmD;IACnD,KAAK,CAAC,EAAE,OAAO,CAAC;CACnB,GACC;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GACtD;IAAE,IAAI,EAAE,oBAAoB,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GACjE;IAAE,IAAI,EAAE,sBAAsB,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACpE;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,oBAAoB,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACjF;IAAE,IAAI,EAAE,2BAA2B,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACzE;IAAE,IAAI,EAAE,yBAAyB,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACvE;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/F;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9D;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACvF;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAC;AAE9G,+CAA+C;AAC/C,MAAM,MAAM,WAAW,GACjB;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC/C;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC7C;IACE,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,UAAU,CAAC;QAAC,QAAQ,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,EAAE,CAAC;CACjG,GACC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAExE,wEAAwE;AACxE,MAAM,WAAW,cAAc;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,UAAU,GAAG,WAAW,CAAC;IACjC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,sDAAsD;AACtD,MAAM,WAAW,iBAAiB;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAE,EAAE,CAAC;IACpE,OAAO,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAClD,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,MAAM,CAAC,EAAE,cAAc,EAAE,CAAC;CAC7B;AAED;;;;;;GAMG;AACH,wBAAuB,cAAc,CACjC,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC,EAChC,WAAW,EAAE,MAAM,GAAG,IAAI,GAC3B,cAAc,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAuD5D"}
package/package.json CHANGED
@@ -1,6 +1,66 @@
1
1
  {
2
2
  "name": "@aparte/runner-ag-ui",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.19.1",
4
+ "homepage": "https://apartejs.dev/providers/agent/ag-ui/",
5
+ "description": "Render an AG-UI agent in aparté — Agno, LangGraph, Mastra, CrewAI, Pydantic AI, TanStack AI: the agent runs on its server, aparté draws the chat, its tool calls and its approvals.",
6
+ "type": "module",
7
+ "sideEffects": false,
8
+ "main": "./dist/index.js",
9
+ "module": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "@aparte-workspace/source": "./src/index.ts",
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js",
16
+ "default": "./dist/index.js"
17
+ }
18
+ },
19
+ "files": [
20
+ "dist",
21
+ "README.md",
22
+ "LICENSE"
23
+ ],
24
+ "engines": {
25
+ "node": ">=18"
26
+ },
27
+ "peerDependencies": {
28
+ "@aparte/core": ">=0.19.1 <1.0.0"
29
+ },
30
+ "devDependencies": {
31
+ "@ag-ui/core": "^1.0.0",
32
+ "@tanstack/ai": "^0.68.0",
33
+ "@types/node": "^22.0.0",
34
+ "typescript": "^5.4.0",
35
+ "vite": "^6.0.0",
36
+ "@aparte/core": "0.19.1"
37
+ },
38
+ "keywords": [
39
+ "ai",
40
+ "agent",
41
+ "ag-ui",
42
+ "agno",
43
+ "langgraph",
44
+ "mastra",
45
+ "tanstack-ai",
46
+ "chat",
47
+ "runner"
48
+ ],
49
+ "license": "MIT",
50
+ "repository": {
51
+ "type": "git",
52
+ "url": "git+https://github.com/apartejs/aparte.git",
53
+ "directory": "packages/providers/agent/ag-ui"
54
+ },
55
+ "bugs": {
56
+ "url": "https://github.com/apartejs/aparte/issues"
57
+ },
58
+ "scripts": {
59
+ "dev": "vite",
60
+ "build": "vite build && tsc -b --emitDeclarationOnly --force",
61
+ "preview": "vite preview",
62
+ "test": "vitest",
63
+ "test:run": "vitest run",
64
+ "test:coverage": "vitest run --coverage"
65
+ }
6
66
  }