deepagentsdk 0.12.0 → 0.14.0
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/dist/adapters/elements/index.cjs +478 -288
- package/dist/adapters/elements/index.cjs.map +1 -1
- package/dist/adapters/elements/index.d.cts +107 -172
- package/dist/adapters/elements/index.d.mts +107 -172
- package/dist/adapters/elements/index.mjs +471 -284
- package/dist/adapters/elements/index.mjs.map +1 -1
- package/dist/{types-4g9UvXal.d.mts → agent-D0bKkNI-.d.mts} +352 -3
- package/dist/{types-IulnvhFg.d.cts → agent-DwAj5emJ.d.cts} +352 -3
- package/dist/{chunk-CbDLau6x.cjs → chunk-C5azi7Hr.cjs} +33 -0
- package/dist/cli/index.cjs +12 -12
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.mjs +2 -2
- package/dist/cli/index.mjs.map +1 -1
- package/dist/{agent-Cuks-Idh.cjs → file-saver-BYPKakT4.cjs} +799 -205
- package/dist/file-saver-BYPKakT4.cjs.map +1 -0
- package/dist/{agent-CrH-He58.mjs → file-saver-Hj5so3dV.mjs} +793 -199
- package/dist/file-saver-Hj5so3dV.mjs.map +1 -0
- package/dist/index.cjs +83 -73
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -353
- package/dist/index.d.mts +5 -353
- package/dist/index.mjs +13 -3
- package/dist/index.mjs.map +1 -1
- package/dist/{load-B6CA5js_.mjs → load-BBYEnMwz.mjs} +1 -1
- package/dist/{load-B6CA5js_.mjs.map → load-BBYEnMwz.mjs.map} +1 -1
- package/dist/{load-94gjHorc.mjs → load-BDxe6Cet.mjs} +1 -1
- package/dist/{load-79a2H4m0.cjs → load-BrRAKlO6.cjs} +2 -2
- package/dist/{load-79a2H4m0.cjs.map → load-BrRAKlO6.cjs.map} +1 -1
- package/dist/load-DqllBbDc.cjs +4 -0
- package/package.json +1 -1
- package/dist/agent-CrH-He58.mjs.map +0 -1
- package/dist/agent-Cuks-Idh.cjs.map +0 -1
- package/dist/file-saver-BJCqMIb5.mjs +0 -655
- package/dist/file-saver-BJCqMIb5.mjs.map +0 -1
- package/dist/file-saver-C6O2LAvg.cjs +0 -679
- package/dist/file-saver-C6O2LAvg.cjs.map +0 -1
- package/dist/load-C2qVmZMp.cjs +0 -3
|
@@ -1,320 +1,507 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { useCallback, useMemo, useRef, useState } from "react";
|
|
1
|
+
import { convertToModelMessages, createUIMessageStream, createUIMessageStreamResponse } from "ai";
|
|
3
2
|
|
|
4
|
-
//#region src/adapters/elements/
|
|
3
|
+
//#region src/adapters/elements/createElementsRouteHandler.ts
|
|
5
4
|
/**
|
|
6
|
-
*
|
|
5
|
+
* Server-side route handler adapter for AI SDK Elements
|
|
7
6
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* @param uiStatus - Current UI status
|
|
11
|
-
* @returns Array of UIMessage objects for Elements Message component
|
|
7
|
+
* Creates a Next.js/Express-compatible route handler that runs DeepAgent
|
|
8
|
+
* and returns UI Message Stream compatible responses with full event visibility.
|
|
12
9
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
10
|
+
* This handler streams all DeepAgent event types (26+) including:
|
|
11
|
+
* - Text and tool events (standard protocol)
|
|
12
|
+
* - File system operations
|
|
13
|
+
* - Command execution
|
|
14
|
+
* - Web requests and searches
|
|
15
|
+
* - Subagent lifecycle
|
|
16
|
+
* - State changes (todos, checkpoints)
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* // app/api/chat/route.ts (Next.js App Router)
|
|
21
|
+
* import { createDeepAgent } from 'deepagentsdk';
|
|
22
|
+
* import { createElementsRouteHandler } from 'deepagentsdk/adapters/elements';
|
|
23
|
+
* import { anthropic } from '@ai-sdk/anthropic';
|
|
24
|
+
*
|
|
25
|
+
* const agent = createDeepAgent({
|
|
26
|
+
* model: anthropic('claude-sonnet-4-20250514'),
|
|
27
|
+
* });
|
|
28
|
+
*
|
|
29
|
+
* export const POST = createElementsRouteHandler({ agent });
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* @see https://ai-sdk.dev/docs/ai-sdk-ui/stream-protocol
|
|
18
33
|
*/
|
|
19
|
-
function convertEventsToUIMessages(events, streamingText, uiStatus) {
|
|
20
|
-
const messages = [];
|
|
21
|
-
let currentAssistantParts = [];
|
|
22
|
-
let messageIdCounter = 0;
|
|
23
|
-
const generateMessageId = () => {
|
|
24
|
-
return `msg-${Date.now()}-${++messageIdCounter}`;
|
|
25
|
-
};
|
|
26
|
-
for (const eventLog of events) {
|
|
27
|
-
const event = eventLog.event;
|
|
28
|
-
switch (event.type) {
|
|
29
|
-
case "user-message":
|
|
30
|
-
if (currentAssistantParts.length > 0) {
|
|
31
|
-
messages.push({
|
|
32
|
-
id: generateMessageId(),
|
|
33
|
-
role: "assistant",
|
|
34
|
-
parts: currentAssistantParts,
|
|
35
|
-
status: "ready"
|
|
36
|
-
});
|
|
37
|
-
currentAssistantParts = [];
|
|
38
|
-
}
|
|
39
|
-
messages.push({
|
|
40
|
-
id: eventLog.id,
|
|
41
|
-
role: "user",
|
|
42
|
-
parts: [{
|
|
43
|
-
type: "text",
|
|
44
|
-
text: event.content
|
|
45
|
-
}],
|
|
46
|
-
status: "ready"
|
|
47
|
-
});
|
|
48
|
-
break;
|
|
49
|
-
case "text-segment":
|
|
50
|
-
currentAssistantParts.push({
|
|
51
|
-
type: "text",
|
|
52
|
-
text: event.text
|
|
53
|
-
});
|
|
54
|
-
break;
|
|
55
|
-
case "tool-call":
|
|
56
|
-
currentAssistantParts.push({
|
|
57
|
-
type: "tool-call",
|
|
58
|
-
toolCallId: event.toolCallId,
|
|
59
|
-
toolName: event.toolName,
|
|
60
|
-
args: event.args
|
|
61
|
-
});
|
|
62
|
-
break;
|
|
63
|
-
case "tool-result":
|
|
64
|
-
currentAssistantParts.push({
|
|
65
|
-
type: "tool-result",
|
|
66
|
-
toolCallId: event.toolCallId,
|
|
67
|
-
toolName: event.toolName,
|
|
68
|
-
result: event.result,
|
|
69
|
-
isError: event.isError
|
|
70
|
-
});
|
|
71
|
-
break;
|
|
72
|
-
default: break;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
if (streamingText || currentAssistantParts.length > 0) {
|
|
76
|
-
if (streamingText) currentAssistantParts.push({
|
|
77
|
-
type: "text",
|
|
78
|
-
text: streamingText
|
|
79
|
-
});
|
|
80
|
-
let messageStatus = "ready";
|
|
81
|
-
if (uiStatus === "streaming") messageStatus = "streaming";
|
|
82
|
-
else if (uiStatus === "submitted") messageStatus = "submitted";
|
|
83
|
-
else if (uiStatus === "error") messageStatus = "error";
|
|
84
|
-
messages.push({
|
|
85
|
-
id: generateMessageId(),
|
|
86
|
-
role: "assistant",
|
|
87
|
-
parts: currentAssistantParts,
|
|
88
|
-
status: messageStatus
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
return messages;
|
|
92
|
-
}
|
|
93
34
|
/**
|
|
94
|
-
*
|
|
35
|
+
* Creates a route handler that processes chat requests using DeepAgent
|
|
36
|
+
* and streams all 26+ event types in UI Message Stream Protocol format.
|
|
37
|
+
*
|
|
38
|
+
* The returned handler:
|
|
39
|
+
* - Accepts POST requests with { messages: UIMessage[] } body
|
|
40
|
+
* - Runs DeepAgent with the conversation history
|
|
41
|
+
* - Streams responses in UI Message Stream Protocol format
|
|
42
|
+
* - Works with useChat hook from @ai-sdk/react
|
|
43
|
+
* - Provides full visibility into agent behavior (file ops, web requests, subagents, etc.)
|
|
95
44
|
*
|
|
96
|
-
* @param
|
|
97
|
-
* @returns
|
|
45
|
+
* @param options - Configuration options
|
|
46
|
+
* @returns A request handler function compatible with Next.js/Express
|
|
98
47
|
*/
|
|
99
|
-
function
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
48
|
+
function createElementsRouteHandler(options) {
|
|
49
|
+
const { agent, onRequest, initialState = {
|
|
50
|
+
todos: [],
|
|
51
|
+
files: {}
|
|
52
|
+
}, threadId, maxSteps, generateId } = options;
|
|
53
|
+
return async (req) => {
|
|
54
|
+
if (onRequest) try {
|
|
55
|
+
await onRequest(req);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
return new Response(JSON.stringify({ error: error instanceof Error ? error.message : "Request rejected" }), {
|
|
58
|
+
status: 401,
|
|
59
|
+
headers: { "Content-Type": "application/json" }
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
let requestBody;
|
|
63
|
+
try {
|
|
64
|
+
requestBody = await req.json();
|
|
65
|
+
} catch {
|
|
66
|
+
return new Response(JSON.stringify({ error: "Invalid JSON body" }), {
|
|
67
|
+
status: 400,
|
|
68
|
+
headers: { "Content-Type": "application/json" }
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
const { messages } = requestBody;
|
|
72
|
+
if (!messages || !Array.isArray(messages)) return new Response(JSON.stringify({ error: "messages array is required" }), {
|
|
73
|
+
status: 400,
|
|
74
|
+
headers: { "Content-Type": "application/json" }
|
|
75
|
+
});
|
|
76
|
+
const modelMessages = await convertToModelMessages(messages);
|
|
77
|
+
const genId = generateId || (() => crypto.randomUUID());
|
|
78
|
+
let currentTextId = null;
|
|
79
|
+
return createUIMessageStreamResponse({ stream: createUIMessageStream({
|
|
80
|
+
originalMessages: messages,
|
|
81
|
+
generateId: genId,
|
|
82
|
+
execute: async ({ writer }) => {
|
|
83
|
+
try {
|
|
84
|
+
for await (const event of agent.streamWithEvents({
|
|
85
|
+
messages: modelMessages,
|
|
86
|
+
state: initialState,
|
|
87
|
+
threadId,
|
|
88
|
+
maxSteps
|
|
89
|
+
})) {
|
|
90
|
+
const result = mapEventToProtocol(event, writer, genId, currentTextId);
|
|
91
|
+
if (typeof result === "string") currentTextId = result;
|
|
92
|
+
else if (result === null) currentTextId = null;
|
|
93
|
+
}
|
|
94
|
+
if (currentTextId) writer.write({
|
|
95
|
+
type: "text-end",
|
|
96
|
+
id: currentTextId
|
|
97
|
+
});
|
|
98
|
+
} catch (error) {
|
|
99
|
+
if (currentTextId) writer.write({
|
|
100
|
+
type: "text-end",
|
|
101
|
+
id: currentTextId
|
|
102
|
+
});
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
onError: (error) => {
|
|
107
|
+
return error instanceof Error ? error.message : "Unknown error";
|
|
108
|
+
}
|
|
109
|
+
}) });
|
|
110
|
+
};
|
|
117
111
|
}
|
|
118
|
-
|
|
119
|
-
//#endregion
|
|
120
|
-
//#region src/adapters/elements/statusAdapter.ts
|
|
121
112
|
/**
|
|
122
|
-
* Maps
|
|
113
|
+
* Maps a DeepAgent event to a UI Message Stream Protocol event.
|
|
114
|
+
*
|
|
115
|
+
* This function handles all 26+ DeepAgent event types, mapping:
|
|
116
|
+
* - Standard protocol events (text, tools, steps, errors)
|
|
117
|
+
* - Custom data events (file operations, web requests, subagents, execution)
|
|
123
118
|
*
|
|
124
|
-
* @param
|
|
125
|
-
* @
|
|
119
|
+
* @param event - The DeepAgent event to map
|
|
120
|
+
* @param writer - The UI message stream writer
|
|
121
|
+
* @param genId - ID generator function
|
|
122
|
+
* @param currentTextId - The current text part ID (for tracking streaming text)
|
|
123
|
+
* @returns The new currentTextId value (string | null)
|
|
126
124
|
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```typescript
|
|
127
|
+
* // Handles text streaming with proper ID tracking
|
|
128
|
+
* let textId: string | null = null;
|
|
129
|
+
* textId = mapEventToProtocol({ type: 'text', text: 'Hello' }, writer, genId, textId);
|
|
130
|
+
* // textId is now the ID of the active text part
|
|
131
|
+
* ```
|
|
132
132
|
*/
|
|
133
|
-
function
|
|
134
|
-
switch (
|
|
135
|
-
case "
|
|
133
|
+
function mapEventToProtocol(event, writer, genId, currentTextId) {
|
|
134
|
+
switch (event.type) {
|
|
135
|
+
case "step-start":
|
|
136
|
+
writer.write({ type: "start-step" });
|
|
137
|
+
return currentTextId;
|
|
138
|
+
case "step-finish":
|
|
139
|
+
writer.write({ type: "finish-step" });
|
|
140
|
+
return currentTextId;
|
|
141
|
+
case "text":
|
|
142
|
+
if (!currentTextId) {
|
|
143
|
+
const textId = genId();
|
|
144
|
+
writer.write({
|
|
145
|
+
type: "text-start",
|
|
146
|
+
id: textId
|
|
147
|
+
});
|
|
148
|
+
return textId;
|
|
149
|
+
}
|
|
150
|
+
writer.write({
|
|
151
|
+
type: "text-delta",
|
|
152
|
+
id: currentTextId,
|
|
153
|
+
delta: event.text
|
|
154
|
+
});
|
|
155
|
+
return currentTextId;
|
|
136
156
|
case "tool-call":
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
157
|
+
if (currentTextId) {
|
|
158
|
+
writer.write({
|
|
159
|
+
type: "text-end",
|
|
160
|
+
id: currentTextId
|
|
161
|
+
});
|
|
162
|
+
currentTextId = null;
|
|
163
|
+
}
|
|
164
|
+
writer.write({
|
|
165
|
+
type: "tool-input-available",
|
|
166
|
+
toolCallId: event.toolCallId,
|
|
167
|
+
toolName: event.toolName,
|
|
168
|
+
input: event.args
|
|
169
|
+
});
|
|
170
|
+
return null;
|
|
171
|
+
case "tool-result":
|
|
172
|
+
if (event.isError) writer.write({
|
|
173
|
+
type: "tool-output-error",
|
|
174
|
+
toolCallId: event.toolCallId,
|
|
175
|
+
errorText: String(event.result)
|
|
176
|
+
});
|
|
177
|
+
else writer.write({
|
|
178
|
+
type: "tool-output-available",
|
|
179
|
+
toolCallId: event.toolCallId,
|
|
180
|
+
output: event.result
|
|
181
|
+
});
|
|
182
|
+
return currentTextId;
|
|
183
|
+
case "todos-changed":
|
|
184
|
+
writer.write({
|
|
185
|
+
type: "data",
|
|
186
|
+
name: "todos-changed",
|
|
187
|
+
data: { todos: event.todos }
|
|
188
|
+
});
|
|
189
|
+
return currentTextId;
|
|
190
|
+
case "file-write-start":
|
|
191
|
+
writer.write({
|
|
192
|
+
type: "data",
|
|
193
|
+
name: "file-write-start",
|
|
194
|
+
data: {
|
|
195
|
+
path: event.path,
|
|
196
|
+
content: event.content
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
return currentTextId;
|
|
200
|
+
case "file-written":
|
|
201
|
+
writer.write({
|
|
202
|
+
type: "data",
|
|
203
|
+
name: "file-written",
|
|
204
|
+
data: {
|
|
205
|
+
path: event.path,
|
|
206
|
+
content: event.content
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
return currentTextId;
|
|
210
|
+
case "file-edited":
|
|
211
|
+
writer.write({
|
|
212
|
+
type: "data",
|
|
213
|
+
name: "file-edited",
|
|
214
|
+
data: {
|
|
215
|
+
path: event.path,
|
|
216
|
+
occurrences: event.occurrences
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
return currentTextId;
|
|
220
|
+
case "file-read":
|
|
221
|
+
writer.write({
|
|
222
|
+
type: "data",
|
|
223
|
+
name: "file-read",
|
|
224
|
+
data: {
|
|
225
|
+
path: event.path,
|
|
226
|
+
lines: event.lines
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
return currentTextId;
|
|
230
|
+
case "ls":
|
|
231
|
+
writer.write({
|
|
232
|
+
type: "data",
|
|
233
|
+
name: "ls",
|
|
234
|
+
data: {
|
|
235
|
+
path: event.path,
|
|
236
|
+
count: event.count
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
return currentTextId;
|
|
240
|
+
case "glob":
|
|
241
|
+
writer.write({
|
|
242
|
+
type: "data",
|
|
243
|
+
name: "glob",
|
|
244
|
+
data: {
|
|
245
|
+
pattern: event.pattern,
|
|
246
|
+
count: event.count
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
return currentTextId;
|
|
250
|
+
case "grep":
|
|
251
|
+
writer.write({
|
|
252
|
+
type: "data",
|
|
253
|
+
name: "grep",
|
|
254
|
+
data: {
|
|
255
|
+
pattern: event.pattern,
|
|
256
|
+
count: event.count
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
return currentTextId;
|
|
260
|
+
case "execute-start":
|
|
261
|
+
writer.write({
|
|
262
|
+
type: "data",
|
|
263
|
+
name: "execute-start",
|
|
264
|
+
data: {
|
|
265
|
+
command: event.command,
|
|
266
|
+
sandboxId: event.sandboxId
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
return currentTextId;
|
|
270
|
+
case "execute-finish":
|
|
271
|
+
writer.write({
|
|
272
|
+
type: "data",
|
|
273
|
+
name: "execute-finish",
|
|
274
|
+
data: {
|
|
275
|
+
command: event.command,
|
|
276
|
+
exitCode: event.exitCode,
|
|
277
|
+
truncated: event.truncated,
|
|
278
|
+
sandboxId: event.sandboxId
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
return currentTextId;
|
|
282
|
+
case "web-search-start":
|
|
283
|
+
writer.write({
|
|
284
|
+
type: "data",
|
|
285
|
+
name: "web-search-start",
|
|
286
|
+
data: { query: event.query }
|
|
287
|
+
});
|
|
288
|
+
return currentTextId;
|
|
289
|
+
case "web-search-finish":
|
|
290
|
+
writer.write({
|
|
291
|
+
type: "data",
|
|
292
|
+
name: "web-search-finish",
|
|
293
|
+
data: {
|
|
294
|
+
query: event.query,
|
|
295
|
+
resultCount: event.resultCount
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
return currentTextId;
|
|
299
|
+
case "http-request-start":
|
|
300
|
+
writer.write({
|
|
301
|
+
type: "data",
|
|
302
|
+
name: "http-request-start",
|
|
303
|
+
data: {
|
|
304
|
+
url: event.url,
|
|
305
|
+
method: event.method
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
return currentTextId;
|
|
309
|
+
case "http-request-finish":
|
|
310
|
+
writer.write({
|
|
311
|
+
type: "data",
|
|
312
|
+
name: "http-request-finish",
|
|
313
|
+
data: {
|
|
314
|
+
url: event.url,
|
|
315
|
+
statusCode: event.statusCode
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
return currentTextId;
|
|
319
|
+
case "fetch-url-start":
|
|
320
|
+
writer.write({
|
|
321
|
+
type: "data",
|
|
322
|
+
name: "fetch-url-start",
|
|
323
|
+
data: { url: event.url }
|
|
324
|
+
});
|
|
325
|
+
return currentTextId;
|
|
326
|
+
case "fetch-url-finish":
|
|
327
|
+
writer.write({
|
|
328
|
+
type: "data",
|
|
329
|
+
name: "fetch-url-finish",
|
|
330
|
+
data: {
|
|
331
|
+
url: event.url,
|
|
332
|
+
success: event.success
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
return currentTextId;
|
|
336
|
+
case "subagent-start":
|
|
337
|
+
writer.write({
|
|
338
|
+
type: "data",
|
|
339
|
+
name: "subagent-start",
|
|
340
|
+
data: {
|
|
341
|
+
name: event.name,
|
|
342
|
+
task: event.task
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
return currentTextId;
|
|
346
|
+
case "subagent-finish":
|
|
347
|
+
writer.write({
|
|
348
|
+
type: "data",
|
|
349
|
+
name: "subagent-finish",
|
|
350
|
+
data: {
|
|
351
|
+
name: event.name,
|
|
352
|
+
result: event.result
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
return currentTextId;
|
|
356
|
+
case "subagent-step":
|
|
357
|
+
writer.write({
|
|
358
|
+
type: "data",
|
|
359
|
+
name: "subagent-step",
|
|
360
|
+
data: {
|
|
361
|
+
stepIndex: event.stepIndex,
|
|
362
|
+
toolCalls: event.toolCalls
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
return currentTextId;
|
|
366
|
+
case "checkpoint-saved":
|
|
367
|
+
writer.write({
|
|
368
|
+
type: "data",
|
|
369
|
+
name: "checkpoint-saved",
|
|
370
|
+
data: {
|
|
371
|
+
threadId: event.threadId,
|
|
372
|
+
step: event.step
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
return currentTextId;
|
|
376
|
+
case "checkpoint-loaded":
|
|
377
|
+
writer.write({
|
|
378
|
+
type: "data",
|
|
379
|
+
name: "checkpoint-loaded",
|
|
380
|
+
data: {
|
|
381
|
+
threadId: event.threadId,
|
|
382
|
+
step: event.step,
|
|
383
|
+
messagesCount: event.messagesCount
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
return currentTextId;
|
|
387
|
+
case "error":
|
|
388
|
+
if (currentTextId) {
|
|
389
|
+
writer.write({
|
|
390
|
+
type: "text-end",
|
|
391
|
+
id: currentTextId
|
|
392
|
+
});
|
|
393
|
+
currentTextId = null;
|
|
394
|
+
}
|
|
395
|
+
writer.write({
|
|
396
|
+
type: "error",
|
|
397
|
+
errorText: event.error.message
|
|
398
|
+
});
|
|
399
|
+
return null;
|
|
141
400
|
case "done":
|
|
142
|
-
|
|
401
|
+
if (currentTextId) {
|
|
402
|
+
writer.write({
|
|
403
|
+
type: "text-end",
|
|
404
|
+
id: currentTextId
|
|
405
|
+
});
|
|
406
|
+
currentTextId = null;
|
|
407
|
+
}
|
|
408
|
+
writer.write({
|
|
409
|
+
type: "finish",
|
|
410
|
+
finishReason: "stop"
|
|
411
|
+
});
|
|
412
|
+
return null;
|
|
413
|
+
default: return currentTextId;
|
|
143
414
|
}
|
|
144
415
|
}
|
|
145
416
|
|
|
146
417
|
//#endregion
|
|
147
|
-
//#region src/adapters/elements/
|
|
418
|
+
//#region src/adapters/elements/messageConverters.ts
|
|
148
419
|
/**
|
|
149
|
-
*
|
|
420
|
+
* Message conversion utilities for AI SDK Elements adapter
|
|
150
421
|
*
|
|
151
|
-
* Provides
|
|
422
|
+
* Provides utilities for converting between UI message formats and model message formats.
|
|
423
|
+
* The primary conversion is handled by AI SDK's `convertToModelMessages`, but these
|
|
424
|
+
* utilities provide additional helpers for DeepAgent-specific needs.
|
|
152
425
|
*/
|
|
153
|
-
let eventCounter = 0;
|
|
154
|
-
function createEventId() {
|
|
155
|
-
return `event-${++eventCounter}`;
|
|
156
|
-
}
|
|
157
426
|
/**
|
|
158
|
-
*
|
|
427
|
+
* Re-export AI SDK's convertToModelMessages for convenience.
|
|
159
428
|
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
429
|
+
* This function converts UIMessage[] (from useChat) to ModelMessage[]
|
|
430
|
+
* (for agent consumption), handling:
|
|
431
|
+
* - Role mapping (user/assistant)
|
|
432
|
+
* - Tool call/result parts
|
|
433
|
+
* - Text content extraction
|
|
162
434
|
*
|
|
163
435
|
* @example
|
|
164
|
-
* ```
|
|
165
|
-
* import {
|
|
166
|
-
* import { Conversation, Message, PromptInput } from '@/components/ai-elements';
|
|
167
|
-
*
|
|
168
|
-
* function Chat() {
|
|
169
|
-
* const { uiMessages, sendMessage } = useElementsAdapter({
|
|
170
|
-
* model,
|
|
171
|
-
* backend
|
|
172
|
-
* });
|
|
436
|
+
* ```typescript
|
|
437
|
+
* import { convertUIMessagesToModelMessages } from 'deepagentsdk/adapters/elements';
|
|
173
438
|
*
|
|
174
|
-
*
|
|
175
|
-
* <Conversation>
|
|
176
|
-
* {uiMessages.map(msg => <Message key={msg.id} from={msg.role} />)}
|
|
177
|
-
* <PromptInput onSubmit={sendMessage} />
|
|
178
|
-
* </Conversation>
|
|
179
|
-
* );
|
|
180
|
-
* }
|
|
439
|
+
* const modelMessages = await convertUIMessagesToModelMessages(uiMessages);
|
|
181
440
|
* ```
|
|
182
441
|
*/
|
|
183
|
-
function
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
tools
|
|
200
|
-
}));
|
|
201
|
-
const addEvent = useCallback((event) => {
|
|
202
|
-
setEvents((prev) => [...prev, {
|
|
203
|
-
id: createEventId(),
|
|
204
|
-
type: event.type,
|
|
205
|
-
event,
|
|
206
|
-
timestamp: /* @__PURE__ */ new Date()
|
|
207
|
-
}]);
|
|
208
|
-
}, []);
|
|
209
|
-
const flushTextSegment = useCallback(() => {
|
|
210
|
-
if (accumulatedTextRef.current.trim()) {
|
|
211
|
-
addEvent({
|
|
212
|
-
type: "text-segment",
|
|
213
|
-
text: accumulatedTextRef.current
|
|
214
|
-
});
|
|
215
|
-
accumulatedTextRef.current = "";
|
|
216
|
-
setStreamingText("");
|
|
217
|
-
}
|
|
218
|
-
}, [addEvent]);
|
|
219
|
-
const sendMessage = async (message) => {
|
|
220
|
-
if (!message.text.trim()) return;
|
|
221
|
-
setStatus("thinking");
|
|
222
|
-
setStreamingText("");
|
|
223
|
-
accumulatedTextRef.current = "";
|
|
224
|
-
addEvent({
|
|
225
|
-
type: "user-message",
|
|
226
|
-
content: message.text
|
|
227
|
-
});
|
|
228
|
-
abortControllerRef.current = new AbortController();
|
|
229
|
-
try {
|
|
230
|
-
for await (const event of agentRef.current.streamWithEvents({
|
|
231
|
-
messages: [{
|
|
232
|
-
role: "user",
|
|
233
|
-
content: message.text
|
|
234
|
-
}],
|
|
235
|
-
state,
|
|
236
|
-
abortSignal: abortControllerRef.current.signal
|
|
237
|
-
})) switch (event.type) {
|
|
238
|
-
case "text":
|
|
239
|
-
setStatus("streaming");
|
|
240
|
-
accumulatedTextRef.current += event.text;
|
|
241
|
-
setStreamingText(accumulatedTextRef.current);
|
|
242
|
-
break;
|
|
243
|
-
case "step-start":
|
|
244
|
-
if (event.stepNumber > 1) addEvent(event);
|
|
245
|
-
break;
|
|
246
|
-
case "tool-call":
|
|
247
|
-
flushTextSegment();
|
|
248
|
-
setStatus("tool-call");
|
|
249
|
-
addEvent(event);
|
|
250
|
-
break;
|
|
251
|
-
case "tool-result":
|
|
252
|
-
addEvent(event);
|
|
253
|
-
break;
|
|
254
|
-
case "todos-changed":
|
|
255
|
-
flushTextSegment();
|
|
256
|
-
setStatus("tool-call");
|
|
257
|
-
setState((prev) => ({
|
|
258
|
-
...prev,
|
|
259
|
-
todos: event.todos
|
|
260
|
-
}));
|
|
261
|
-
addEvent(event);
|
|
262
|
-
break;
|
|
263
|
-
case "done":
|
|
264
|
-
flushTextSegment();
|
|
265
|
-
setStatus("done");
|
|
266
|
-
setState(event.state);
|
|
267
|
-
addEvent(event);
|
|
268
|
-
break;
|
|
269
|
-
case "error":
|
|
270
|
-
flushTextSegment();
|
|
271
|
-
setStatus("error");
|
|
272
|
-
addEvent(event);
|
|
273
|
-
break;
|
|
274
|
-
default:
|
|
275
|
-
addEvent(event);
|
|
276
|
-
break;
|
|
277
|
-
}
|
|
278
|
-
setStatus("idle");
|
|
279
|
-
} catch (err) {
|
|
280
|
-
if (err.name === "AbortError") {
|
|
281
|
-
flushTextSegment();
|
|
282
|
-
setStatus("idle");
|
|
283
|
-
} else {
|
|
284
|
-
flushTextSegment();
|
|
285
|
-
setStatus("error");
|
|
286
|
-
}
|
|
287
|
-
} finally {
|
|
288
|
-
abortControllerRef.current = null;
|
|
289
|
-
}
|
|
290
|
-
};
|
|
291
|
-
const abort = useCallback(() => {
|
|
292
|
-
if (abortControllerRef.current) {
|
|
293
|
-
abortControllerRef.current.abort();
|
|
294
|
-
setStatus("idle");
|
|
442
|
+
async function convertUIMessagesToModelMessages(messages) {
|
|
443
|
+
return await convertToModelMessages(messages);
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Extract the last user message text from a UIMessage array.
|
|
447
|
+
* Useful for extracting the prompt from a conversation.
|
|
448
|
+
*
|
|
449
|
+
* @param messages - Array of UI messages
|
|
450
|
+
* @returns The text content of the last user message, or undefined if none
|
|
451
|
+
*/
|
|
452
|
+
function extractLastUserMessage(messages) {
|
|
453
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
454
|
+
const msg = messages[i];
|
|
455
|
+
if (msg && msg.role === "user" && msg.parts) {
|
|
456
|
+
const textParts = msg.parts.filter((p) => p.type === "text");
|
|
457
|
+
if (textParts.length > 0) return textParts.map((p) => p.text).join("");
|
|
295
458
|
}
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Check if the messages contain any tool parts.
|
|
463
|
+
* This is a simplified helper that checks for any tool-related parts.
|
|
464
|
+
*
|
|
465
|
+
* @param messages - Array of UI messages
|
|
466
|
+
* @returns True if there are any tool-related parts in the messages
|
|
467
|
+
*/
|
|
468
|
+
function hasToolParts(messages) {
|
|
469
|
+
for (const msg of messages) {
|
|
470
|
+
if (!msg.parts) continue;
|
|
471
|
+
for (const part of msg.parts) if (part.type.startsWith("tool-") || part.type === "dynamic-tool") return true;
|
|
472
|
+
}
|
|
473
|
+
return false;
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Count the number of messages by role.
|
|
477
|
+
*
|
|
478
|
+
* @param messages - Array of UI messages
|
|
479
|
+
* @returns Object with counts by role
|
|
480
|
+
*/
|
|
481
|
+
function countMessagesByRole(messages) {
|
|
482
|
+
let user = 0;
|
|
483
|
+
let assistant = 0;
|
|
484
|
+
let system = 0;
|
|
485
|
+
for (const msg of messages) if (msg.role === "user") user++;
|
|
486
|
+
else if (msg.role === "assistant") assistant++;
|
|
487
|
+
else if (msg.role === "system") system++;
|
|
308
488
|
return {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
sendMessage,
|
|
313
|
-
abort,
|
|
314
|
-
clear
|
|
489
|
+
user,
|
|
490
|
+
assistant,
|
|
491
|
+
system
|
|
315
492
|
};
|
|
316
493
|
}
|
|
494
|
+
/**
|
|
495
|
+
* Extract all text content from a message.
|
|
496
|
+
*
|
|
497
|
+
* @param message - A UI message
|
|
498
|
+
* @returns Combined text from all text parts
|
|
499
|
+
*/
|
|
500
|
+
function extractTextFromMessage(message) {
|
|
501
|
+
if (!message.parts) return "";
|
|
502
|
+
return message.parts.filter((p) => p.type === "text").map((p) => p.text).join("");
|
|
503
|
+
}
|
|
317
504
|
|
|
318
505
|
//#endregion
|
|
319
|
-
export {
|
|
506
|
+
export { convertUIMessagesToModelMessages, countMessagesByRole, createElementsRouteHandler, extractLastUserMessage, extractTextFromMessage, hasToolParts, mapEventToProtocol };
|
|
320
507
|
//# sourceMappingURL=index.mjs.map
|