@assistant-ui/react-ag-ui 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/agUiExtras.js +1 -2
- package/dist/hooks.js +1 -2
- package/dist/runtime/AgUiThreadController.d.ts +11 -0
- package/dist/runtime/AgUiThreadController.d.ts.map +1 -1
- package/dist/runtime/AgUiThreadController.js +565 -89
- package/dist/runtime/AgUiThreadController.js.map +1 -1
- package/dist/runtime/adapter/conversions.d.ts +9 -1
- package/dist/runtime/adapter/conversions.d.ts.map +1 -1
- package/dist/runtime/adapter/conversions.js +194 -12
- package/dist/runtime/adapter/conversions.js.map +1 -1
- package/dist/runtime/adapter/replay-content.d.ts +9 -0
- package/dist/runtime/adapter/replay-content.d.ts.map +1 -0
- package/dist/runtime/adapter/replay-content.js +185 -0
- package/dist/runtime/adapter/replay-content.js.map +1 -0
- package/dist/runtime/adapter/run-aggregator.d.ts +1 -0
- package/dist/runtime/adapter/run-aggregator.d.ts.map +1 -1
- package/dist/runtime/adapter/run-aggregator.js +35 -14
- package/dist/runtime/adapter/run-aggregator.js.map +1 -1
- package/dist/runtime/adapter/subscriber.d.ts +0 -1
- package/dist/runtime/adapter/subscriber.d.ts.map +1 -1
- package/dist/runtime/adapter/subscriber.js +2 -10
- package/dist/runtime/adapter/subscriber.js.map +1 -1
- package/dist/runtime/adapter/tool-approval.d.ts +2 -0
- package/dist/runtime/adapter/tool-approval.d.ts.map +1 -1
- package/dist/runtime/adapter/tool-approval.js +23 -6
- package/dist/runtime/adapter/tool-approval.js.map +1 -1
- package/dist/runtime/agUiThreadState.d.ts +1 -1
- package/dist/runtime/agUiThreadState.d.ts.map +1 -1
- package/dist/runtime/agUiThreadState.js +3 -4
- package/dist/runtime/agUiThreadState.js.map +1 -1
- package/dist/runtime/event-parser.d.ts.map +1 -1
- package/dist/runtime/event-parser.js +2 -2
- package/dist/runtime/event-parser.js.map +1 -1
- package/dist/runtime/interrupt-internals.js +1 -2
- package/dist/runtime/logger.js +1 -2
- package/dist/runtime/mcp-tool-result.js +1 -2
- package/dist/runtime/types.d.ts +2 -0
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/types.js +3 -3
- package/dist/runtime/types.js.map +1 -1
- package/dist/useAgUiRuntime.js +1 -2
- package/package.json +6 -6
- package/src/runtime/AgUiThreadController.deferred-results.test.ts +548 -0
- package/src/runtime/AgUiThreadController.disconnect.test.ts +914 -0
- package/src/runtime/AgUiThreadController.interrupt-history.test.ts +392 -0
- package/src/runtime/AgUiThreadController.replay.test.ts +3939 -0
- package/src/runtime/AgUiThreadController.snapshot-head-move.test.ts +167 -0
- package/src/runtime/AgUiThreadController.subagent-snapshot.test.ts +854 -0
- package/src/runtime/AgUiThreadController.test.ts +119 -0
- package/src/runtime/AgUiThreadController.ts +1184 -136
- package/src/runtime/adapter/conversions.content.test.ts +242 -1
- package/src/runtime/adapter/conversions.subagent-messages.test.ts +550 -0
- package/src/runtime/adapter/conversions.ts +349 -28
- package/src/runtime/adapter/replay-content.test.ts +235 -0
- package/src/runtime/adapter/replay-content.ts +306 -0
- package/src/runtime/adapter/run-aggregator.metadata.test.ts +151 -0
- package/src/runtime/adapter/run-aggregator.ts +52 -9
- package/src/runtime/adapter/subscriber.test.ts +1 -1
- package/src/runtime/adapter/subscriber.ts +1 -6
- package/src/runtime/adapter/tool-approval.ts +41 -3
- package/src/runtime/agUiThreadState.test.ts +21 -2
- package/src/runtime/agUiThreadState.ts +12 -3
- package/src/runtime/event-parser.ts +3 -0
- package/src/runtime/types.ts +5 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { HttpAgent } from "@ag-ui/client";
|
|
3
|
+
import type { AppendMessage } from "@assistant-ui/core";
|
|
4
|
+
import { AgUiThreadController } from "./AgUiThreadController";
|
|
5
|
+
import { makeLogger } from "./logger";
|
|
6
|
+
|
|
7
|
+
const userMessage: AppendMessage = {
|
|
8
|
+
role: "user",
|
|
9
|
+
content: [{ type: "text", text: "hello" }],
|
|
10
|
+
attachments: [],
|
|
11
|
+
metadata: { custom: {} },
|
|
12
|
+
createdAt: new Date(0),
|
|
13
|
+
parentId: null,
|
|
14
|
+
sourceId: null,
|
|
15
|
+
runConfig: {},
|
|
16
|
+
startRun: true,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
type Wire = { messages: unknown[] };
|
|
20
|
+
|
|
21
|
+
function createController(events: (wire: Wire) => object[]) {
|
|
22
|
+
const agent = new HttpAgent({
|
|
23
|
+
url: "https://example.invalid",
|
|
24
|
+
fetch: async (_url: unknown, init: RequestInit) => {
|
|
25
|
+
const wire = { messages: JSON.parse(init.body as string).messages ?? [] };
|
|
26
|
+
return new Response(
|
|
27
|
+
events(wire)
|
|
28
|
+
.map((event) => `data: ${JSON.stringify(event)}\n\n`)
|
|
29
|
+
.join(""),
|
|
30
|
+
{ headers: { "Content-Type": "text/event-stream" } },
|
|
31
|
+
);
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
return new AgUiThreadController({
|
|
35
|
+
agent,
|
|
36
|
+
logger: makeLogger(),
|
|
37
|
+
showThinking: false,
|
|
38
|
+
onError: () => {},
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const start = { type: "RUN_STARTED", threadId: "thread", runId: "run" };
|
|
43
|
+
const answerText = [
|
|
44
|
+
{ type: "TEXT_MESSAGE_START", messageId: "answer", role: "assistant" },
|
|
45
|
+
{ type: "TEXT_MESSAGE_CONTENT", messageId: "answer", delta: "Let me check." },
|
|
46
|
+
{ type: "TEXT_MESSAGE_END", messageId: "answer" },
|
|
47
|
+
];
|
|
48
|
+
const answerRecord = {
|
|
49
|
+
id: "answer",
|
|
50
|
+
role: "assistant",
|
|
51
|
+
content: "Let me check.",
|
|
52
|
+
toolCalls: [
|
|
53
|
+
{
|
|
54
|
+
id: "task",
|
|
55
|
+
type: "function",
|
|
56
|
+
function: { name: "task", arguments: "{}" },
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
};
|
|
60
|
+
const otherRecord = { id: "other", role: "assistant", content: "Next step." };
|
|
61
|
+
const taskAndSubagentEvents = [
|
|
62
|
+
{ type: "TOOL_CALL_START", toolCallId: "task", toolCallName: "task" },
|
|
63
|
+
{ type: "TOOL_CALL_END", toolCallId: "task" },
|
|
64
|
+
{
|
|
65
|
+
type: "SUBAGENT_STARTED",
|
|
66
|
+
subagentRunId: "sub",
|
|
67
|
+
name: "worker",
|
|
68
|
+
parentToolCallId: "task",
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
type: "TEXT_MESSAGE_START",
|
|
72
|
+
messageId: "s1",
|
|
73
|
+
role: "assistant",
|
|
74
|
+
subagentRunId: "sub",
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
type: "TEXT_MESSAGE_CONTENT",
|
|
78
|
+
messageId: "s1",
|
|
79
|
+
delta: "working",
|
|
80
|
+
subagentRunId: "sub",
|
|
81
|
+
},
|
|
82
|
+
{ type: "TEXT_MESSAGE_END", messageId: "s1", subagentRunId: "sub" },
|
|
83
|
+
];
|
|
84
|
+
const subFinished = { type: "SUBAGENT_FINISHED", subagentRunId: "sub" };
|
|
85
|
+
const taskResult = {
|
|
86
|
+
type: "TOOL_CALL_RESULT",
|
|
87
|
+
messageId: "tool-task",
|
|
88
|
+
toolCallId: "task",
|
|
89
|
+
content: "done",
|
|
90
|
+
};
|
|
91
|
+
const finished = { type: "RUN_FINISHED", threadId: "thread", runId: "run" };
|
|
92
|
+
const snapshot = (wire: Wire, ...rest: object[]) => ({
|
|
93
|
+
type: "MESSAGES_SNAPSHOT",
|
|
94
|
+
messages: [...wire.messages, answerRecord, ...rest],
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
function statuses(core: AgUiThreadController) {
|
|
98
|
+
const answer = core.getMessages().find(({ id }) => id === "answer")!;
|
|
99
|
+
const toolCall = answer.content.find(
|
|
100
|
+
(part) => part.type === "tool-call" && part.toolCallId === "task",
|
|
101
|
+
);
|
|
102
|
+
const nested =
|
|
103
|
+
toolCall?.type === "tool-call"
|
|
104
|
+
? toolCall.messages?.find((message) => message.id === "sub")
|
|
105
|
+
: undefined;
|
|
106
|
+
return { answer: answer.status?.type, subagent: nested?.status?.type };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
describe("AgUiThreadController snapshot head moves", () => {
|
|
110
|
+
it("settles the moved-off answer when the snapshot has no tool call", async () => {
|
|
111
|
+
const core = createController((wire) => [
|
|
112
|
+
start,
|
|
113
|
+
...answerText,
|
|
114
|
+
{
|
|
115
|
+
type: "MESSAGES_SNAPSHOT",
|
|
116
|
+
messages: [
|
|
117
|
+
...wire.messages,
|
|
118
|
+
{ id: "answer", role: "assistant", content: "Let me check." },
|
|
119
|
+
otherRecord,
|
|
120
|
+
],
|
|
121
|
+
},
|
|
122
|
+
finished,
|
|
123
|
+
]);
|
|
124
|
+
await core.append(userMessage);
|
|
125
|
+
expect(statuses(core).answer).toBe("complete");
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("settles the moved-off answer and sub-agent after the tool result", async () => {
|
|
129
|
+
const core = createController((wire) => [
|
|
130
|
+
start,
|
|
131
|
+
...answerText,
|
|
132
|
+
...taskAndSubagentEvents,
|
|
133
|
+
snapshot(wire, otherRecord),
|
|
134
|
+
subFinished,
|
|
135
|
+
taskResult,
|
|
136
|
+
finished,
|
|
137
|
+
]);
|
|
138
|
+
await core.append(userMessage);
|
|
139
|
+
expect(core.isRunning()).toBe(false);
|
|
140
|
+
expect(statuses(core)).toEqual({
|
|
141
|
+
answer: "complete",
|
|
142
|
+
subagent: "complete",
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it("does not show a complete answer with a running sub-agent after a result snapshot", async () => {
|
|
147
|
+
const core = createController((wire) => [
|
|
148
|
+
start,
|
|
149
|
+
...answerText,
|
|
150
|
+
...taskAndSubagentEvents,
|
|
151
|
+
snapshot(wire, otherRecord),
|
|
152
|
+
subFinished,
|
|
153
|
+
taskResult,
|
|
154
|
+
snapshot(
|
|
155
|
+
wire,
|
|
156
|
+
{ id: "tool-task", role: "tool", toolCallId: "task", content: "done" },
|
|
157
|
+
otherRecord,
|
|
158
|
+
),
|
|
159
|
+
finished,
|
|
160
|
+
]);
|
|
161
|
+
await core.append(userMessage);
|
|
162
|
+
expect(statuses(core)).toEqual({
|
|
163
|
+
answer: "complete",
|
|
164
|
+
subagent: "complete",
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
});
|