@agents24/chat-react 0.1.1 → 0.1.3
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 +7 -3
- package/dist/index.cjs +227 -125
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +100 -22
- package/dist/index.d.ts +100 -22
- package/dist/index.js +218 -122
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Agents24 Chat React
|
|
2
2
|
|
|
3
|
-
Last Updated: 2026-06-
|
|
3
|
+
Last Updated: 2026-06-10
|
|
4
4
|
|
|
5
5
|
Headless React primitives for Agents24 chat surfaces.
|
|
6
6
|
|
|
7
|
-
The package owns thread hydration, older-page pagination, stream/reattach state, active run cancellation, normalized message
|
|
7
|
+
The package owns thread hydration, older-page pagination, stream/reattach state, active run cancellation, normalized message parts, and latest-thread viewport behavior. Hosts provide transport routes, cache storage, product rendering, source handling, and styling.
|
|
8
8
|
|
|
9
9
|
## Public API
|
|
10
10
|
|
|
@@ -13,6 +13,10 @@ The package owns thread hydration, older-page pagination, stream/reattach state,
|
|
|
13
13
|
- `LatestThreadViewport`
|
|
14
14
|
- `createFetchChatTransport(options)`
|
|
15
15
|
- `consumeSseResponse(response, onEvent)`
|
|
16
|
-
- normalized chat message,
|
|
16
|
+
- normalized chat message, part, transport, and storage types
|
|
17
|
+
- `partsFromResponseBlocks(blocks, fallbackText)`
|
|
18
|
+
- `renderChatPart(part, message, renderOptions)`
|
|
19
|
+
|
|
20
|
+
`ChatMessage.parts` is the only render model. Backend `response_blocks` are normalized into ordered parts such as `text`, `tool-get_meteo`, `ui-blocks`, `reasoning`, `approval`, `error`, and `data`. Tool UI is client-owned through `renderPart`, `toolRenderers`, and `fallbackToolRenderer`; the package does not infer English tool labels or group tool rows.
|
|
17
21
|
|
|
18
22
|
Network access is always injected by the host. This browser package never requires platform API keys.
|
package/dist/index.cjs
CHANGED
|
@@ -21,10 +21,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
DEFAULT_THREAD_PAGE_SIZE: () => DEFAULT_THREAD_PAGE_SIZE,
|
|
24
|
+
DefaultChatPart: () => DefaultChatPart,
|
|
25
|
+
DefaultToolPart: () => DefaultToolPart,
|
|
24
26
|
LatestThreadViewport: () => LatestThreadViewport,
|
|
25
27
|
activeRunIdFromThread: () => activeRunIdFromThread,
|
|
26
28
|
activeRunIdFromThreadDetail: () => activeRunIdFromThreadDetail,
|
|
27
|
-
|
|
29
|
+
assistantTextFromParts: () => assistantTextFromParts,
|
|
30
|
+
assistantTextFromResponseBlocks: () => assistantTextFromResponseBlocks,
|
|
28
31
|
consumeSseResponse: () => consumeSseResponse,
|
|
29
32
|
createChatId: () => createChatId,
|
|
30
33
|
createFetchChatTransport: () => createFetchChatTransport,
|
|
@@ -37,14 +40,17 @@ __export(index_exports, {
|
|
|
37
40
|
latestContextWindowFromThread: () => latestContextWindowFromThread,
|
|
38
41
|
mergeReasoningSteps: () => mergeReasoningSteps,
|
|
39
42
|
parseSseBlock: () => parseSseBlock,
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
partsFromResponseBlocks: () => partsFromResponseBlocks,
|
|
44
|
+
reasoningStepsFromParts: () => reasoningStepsFromParts,
|
|
45
|
+
renderChatPart: () => renderChatPart,
|
|
42
46
|
shouldPrefetchOlder: () => shouldPrefetchOlder,
|
|
47
|
+
shouldUseTopOriginTimeline: () => shouldUseTopOriginTimeline,
|
|
43
48
|
textFromFinalOutput: () => textFromFinalOutput,
|
|
44
49
|
threadActivityDate: () => threadActivityDate,
|
|
45
50
|
threadDetailToMessages: () => threadDetailToMessages,
|
|
46
51
|
threadPaging: () => threadPaging,
|
|
47
52
|
titleFromMessage: () => titleFromMessage,
|
|
53
|
+
toolStateFromStatus: () => toolStateFromStatus,
|
|
48
54
|
useAgents24ChatController: () => useAgents24ChatController,
|
|
49
55
|
useLatestThreadViewport: () => useLatestThreadViewport
|
|
50
56
|
});
|
|
@@ -65,7 +71,8 @@ var titleFromMessage = (text, files = []) => {
|
|
|
65
71
|
return base.replace(/\s+/g, " ").slice(0, 48);
|
|
66
72
|
};
|
|
67
73
|
var threadActivityDate = (thread) => String(thread.updated_at || thread.last_activity_at || thread.created_at || (/* @__PURE__ */ new Date()).toISOString());
|
|
68
|
-
var
|
|
74
|
+
var assistantTextFromResponseBlocks = (blocks) => (blocks || []).filter((block) => block.kind === "assistant_text" && typeof block.text === "string").map((block) => String(block.text)).join("\n\n").trim();
|
|
75
|
+
var assistantTextFromParts = (parts) => (parts || []).filter((part) => part.kind === "text").map((part) => part.text).join("\n\n").trim();
|
|
69
76
|
var textFromFinalOutput = (value) => {
|
|
70
77
|
if (typeof value === "string") return value;
|
|
71
78
|
if (!value || typeof value !== "object") return "";
|
|
@@ -110,95 +117,126 @@ var assistantTextFromEvents = (events) => {
|
|
|
110
117
|
if (typeof assistantText === "string" && assistantText.trim()) return assistantText;
|
|
111
118
|
return textFromFinalOutput(latestEventPayloadValue(events, "final_output"));
|
|
112
119
|
};
|
|
113
|
-
var
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
120
|
+
var asRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
121
|
+
var optionalString = (value) => typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
122
|
+
var toolStateFromStatus = (status) => {
|
|
123
|
+
const normalized = String(status || "").trim().toLowerCase();
|
|
124
|
+
if (["failed", "error"].includes(normalized)) return "output-error";
|
|
125
|
+
if (["cancelled", "canceled"].includes(normalized)) return "cancelled";
|
|
126
|
+
if (["complete", "completed", "done", "success"].includes(normalized)) return "output-available";
|
|
127
|
+
if (["running", "active", "pending", "streaming"].includes(normalized)) return "input-available";
|
|
128
|
+
return "input-available";
|
|
117
129
|
};
|
|
118
|
-
var
|
|
119
|
-
var
|
|
120
|
-
var
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
if (
|
|
142
|
-
|
|
143
|
-
return name ? humanize(name) : actionLabels[toolActionKey(tool)];
|
|
144
|
-
};
|
|
145
|
-
var toolDetail = (tool) => {
|
|
146
|
-
const summary = String(tool.summary || "").trim();
|
|
147
|
-
const detail = String(tool.detail || "").trim();
|
|
148
|
-
return summary || detail || void 0;
|
|
149
|
-
};
|
|
150
|
-
var summarizeToolGroup = (tools) => {
|
|
151
|
-
if (tools.length === 1) return tools[0].title;
|
|
152
|
-
const counts = /* @__PURE__ */ new Map();
|
|
153
|
-
tools.forEach((tool) => counts.set(tool.actionKey, (counts.get(tool.actionKey) || 0) + 1));
|
|
154
|
-
return Array.from(counts.entries()).map(([key, count]) => `${actionLabels[key]} ${count}`).join(", ");
|
|
155
|
-
};
|
|
156
|
-
var toolGroupStatus = (tools) => {
|
|
157
|
-
if (tools.some((tool) => tool.status === "error")) return "error";
|
|
158
|
-
if (tools.some((tool) => tool.status === "running")) return "running";
|
|
159
|
-
return "done";
|
|
130
|
+
var toolNameFromRecord = (tool) => String(tool.toolName || tool.tool_name || tool.name || tool.slug || tool.action || "tool").trim() || "tool";
|
|
131
|
+
var toolCallIdFromRecords = (block, tool) => optionalString(tool.toolCallId) || optionalString(tool.tool_call_id) || optionalString(block.toolCallId) || optionalString(block.tool_call_id) || optionalString(block.id) || null;
|
|
132
|
+
var presentationFromTool = (tool) => {
|
|
133
|
+
const presentation = asRecord(tool.presentation);
|
|
134
|
+
const outputView = asRecord(tool.outputView) || asRecord(tool.output_view);
|
|
135
|
+
const next = presentation ? { ...presentation } : {};
|
|
136
|
+
[
|
|
137
|
+
"title",
|
|
138
|
+
"activity",
|
|
139
|
+
"detail",
|
|
140
|
+
"category",
|
|
141
|
+
"groupKey",
|
|
142
|
+
"groupLabel",
|
|
143
|
+
"showOutput",
|
|
144
|
+
"outputView"
|
|
145
|
+
].forEach((key) => {
|
|
146
|
+
if (tool[key] !== void 0) {
|
|
147
|
+
next[key] = tool[key];
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
if (tool.group_key !== void 0) next.group_key = tool.group_key;
|
|
151
|
+
if (tool.group_label !== void 0) next.group_label = tool.group_label;
|
|
152
|
+
if (tool.show_output !== void 0) next.show_output = tool.show_output;
|
|
153
|
+
if (outputView && next.outputView === void 0) next.outputView = outputView;
|
|
154
|
+
return Object.keys(next).length > 0 ? next : null;
|
|
160
155
|
};
|
|
161
|
-
var
|
|
162
|
-
const tool = block.tool || {};
|
|
163
|
-
const
|
|
156
|
+
var createToolPart = (block, index) => {
|
|
157
|
+
const tool = asRecord(block.tool) || {};
|
|
158
|
+
const toolName = toolNameFromRecord(tool);
|
|
159
|
+
const errorText = optionalString(tool.errorText) || optionalString(tool.error) || optionalString(block.error) || null;
|
|
164
160
|
return {
|
|
165
161
|
id: String(block.id || `${block.kind || "tool"}-${index}`),
|
|
162
|
+
type: `tool-${toolName}`,
|
|
166
163
|
kind: "tool",
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
164
|
+
toolName,
|
|
165
|
+
toolCallId: toolCallIdFromRecords(block, tool),
|
|
166
|
+
state: toolStateFromStatus(block.status),
|
|
167
|
+
input: tool.input ?? block.input,
|
|
168
|
+
output: tool.output ?? block.output,
|
|
169
|
+
errorText,
|
|
170
|
+
presentation: presentationFromTool(tool),
|
|
171
|
+
raw: block
|
|
172
172
|
};
|
|
173
173
|
};
|
|
174
|
-
var
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
tools: pendingTools
|
|
185
|
-
});
|
|
186
|
-
pendingTools = [];
|
|
187
|
-
};
|
|
174
|
+
var createDataPart = (block, index, name = String(block.kind || "data")) => ({
|
|
175
|
+
id: String(block.id || `${name}-${index}`),
|
|
176
|
+
type: "data",
|
|
177
|
+
kind: "data",
|
|
178
|
+
name,
|
|
179
|
+
data: block,
|
|
180
|
+
raw: block
|
|
181
|
+
});
|
|
182
|
+
var partsFromResponseBlocks = (blocks, fallbackText) => {
|
|
183
|
+
const parts = [];
|
|
188
184
|
(blocks || []).forEach((block, index) => {
|
|
189
185
|
const id = String(block.id || `${block.kind || "block"}-${index}`);
|
|
190
186
|
if (block.kind === "assistant_text" && typeof block.text === "string") {
|
|
191
|
-
|
|
192
|
-
|
|
187
|
+
parts.push({ id, type: "text", kind: "text", text: String(block.text), raw: block });
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
if (block.kind === "tool_call") {
|
|
191
|
+
parts.push(createToolPart(block, index));
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
if (block.kind === "ui_blocks") {
|
|
195
|
+
parts.push({
|
|
196
|
+
id,
|
|
197
|
+
type: "ui-blocks",
|
|
198
|
+
kind: "ui-blocks",
|
|
199
|
+
state: toolStateFromStatus(block.status),
|
|
200
|
+
toolCallId: optionalString(block.toolCallId) || optionalString(block.tool_call_id) || null,
|
|
201
|
+
contractVersion: optionalString(block.contractVersion) || optionalString(block.contract_version) || null,
|
|
202
|
+
bundle: asRecord(block.bundle),
|
|
203
|
+
errorText: optionalString(block.error) || null,
|
|
204
|
+
raw: block
|
|
205
|
+
});
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
if (block.kind === "reasoning_note") {
|
|
209
|
+
parts.push({
|
|
210
|
+
id,
|
|
211
|
+
type: "reasoning",
|
|
212
|
+
kind: "reasoning",
|
|
213
|
+
label: optionalString(block.label) || null,
|
|
214
|
+
text: optionalString(block.text) || optionalString(block.summary) || null,
|
|
215
|
+
status: optionalString(block.status) || null,
|
|
216
|
+
raw: block
|
|
217
|
+
});
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
if (block.kind === "approval_request") {
|
|
221
|
+
parts.push({ id, type: "approval", kind: "approval", raw: block });
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
if (block.kind === "error") {
|
|
225
|
+
parts.push({
|
|
226
|
+
id,
|
|
227
|
+
type: "error",
|
|
228
|
+
kind: "error",
|
|
229
|
+
errorText: optionalString(block.error) || optionalString(block.message) || "Error",
|
|
230
|
+
raw: block
|
|
231
|
+
});
|
|
193
232
|
return;
|
|
194
233
|
}
|
|
195
|
-
|
|
234
|
+
parts.push(createDataPart(block, index));
|
|
196
235
|
});
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
mapped.push({ id: "assistant-fallback-text", kind: "text", content: fallbackText });
|
|
236
|
+
if (!parts.some((part) => part.kind === "text") && fallbackText?.trim()) {
|
|
237
|
+
parts.push({ id: "assistant-fallback-text", type: "text", kind: "text", text: fallbackText });
|
|
200
238
|
}
|
|
201
|
-
return
|
|
239
|
+
return parts;
|
|
202
240
|
};
|
|
203
241
|
var mergeReasoningSteps = (steps, options) => {
|
|
204
242
|
if (!steps?.length) return [];
|
|
@@ -216,21 +254,20 @@ var mergeReasoningSteps = (steps, options) => {
|
|
|
216
254
|
});
|
|
217
255
|
return merged;
|
|
218
256
|
};
|
|
219
|
-
var
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
const tool = block.tool || {};
|
|
257
|
+
var reasoningStepsFromParts = (parts) => (parts || []).map((block) => {
|
|
258
|
+
if (block.kind === "tool") {
|
|
259
|
+
const label = optionalString(block.presentation?.activity) || optionalString(block.presentation?.title) || block.toolName;
|
|
223
260
|
return {
|
|
224
|
-
label
|
|
225
|
-
status: block.
|
|
226
|
-
description:
|
|
261
|
+
label,
|
|
262
|
+
status: block.state === "input-available" || block.state === "input-streaming" ? "active" : "complete",
|
|
263
|
+
description: optionalString(block.presentation?.detail) || ""
|
|
227
264
|
};
|
|
228
265
|
}
|
|
229
|
-
if (kind === "
|
|
266
|
+
if (block.kind === "reasoning") {
|
|
230
267
|
return {
|
|
231
|
-
label:
|
|
268
|
+
label: block.label || "Reasoning",
|
|
232
269
|
status: block.status === "running" ? "active" : "complete",
|
|
233
|
-
description:
|
|
270
|
+
description: block.text || ""
|
|
234
271
|
};
|
|
235
272
|
}
|
|
236
273
|
return null;
|
|
@@ -249,19 +286,21 @@ var turnToMessages = (turn, activeRunId) => {
|
|
|
249
286
|
role: "user",
|
|
250
287
|
content: userContent,
|
|
251
288
|
createdAt,
|
|
289
|
+
parts: userContent ? [{ id: `${baseId}-user-text`, type: "text", kind: "text", text: userContent }] : [],
|
|
252
290
|
attachments
|
|
253
291
|
});
|
|
254
292
|
}
|
|
255
|
-
const assistantText = turn.assistant_output_text ||
|
|
293
|
+
const assistantText = turn.assistant_output_text || assistantTextFromResponseBlocks(responseBlocks) || assistantTextFromEvents(turn.run_events) || textFromFinalOutput(turn.final_output);
|
|
256
294
|
if (assistantText || responseBlocks.length > 0 || isRunning) {
|
|
295
|
+
const parts = partsFromResponseBlocks(responseBlocks, assistantText);
|
|
257
296
|
messages.push({
|
|
258
297
|
id: `${baseId}-assistant`,
|
|
259
298
|
role: "assistant",
|
|
260
299
|
runId: turn.run_id || null,
|
|
261
|
-
content: assistantText,
|
|
300
|
+
content: assistantText || assistantTextFromParts(parts),
|
|
262
301
|
createdAt: turn.completed_at ? new Date(turn.completed_at) : createdAt,
|
|
263
|
-
|
|
264
|
-
reasoningSteps: mergeReasoningSteps(
|
|
302
|
+
parts,
|
|
303
|
+
reasoningSteps: mergeReasoningSteps(reasoningStepsFromParts(parts), { finalize: !isRunning }),
|
|
265
304
|
isFinal: !isRunning
|
|
266
305
|
});
|
|
267
306
|
}
|
|
@@ -475,7 +514,7 @@ function useAgents24ChatController({
|
|
|
475
514
|
createdAt: /* @__PURE__ */ new Date(),
|
|
476
515
|
reasoningSteps: input.reasoning,
|
|
477
516
|
isFinal: false,
|
|
478
|
-
|
|
517
|
+
parts: input.parts || []
|
|
479
518
|
});
|
|
480
519
|
messagesRef.current = next2;
|
|
481
520
|
return next2;
|
|
@@ -487,7 +526,7 @@ function useAgents24ChatController({
|
|
|
487
526
|
content: input.content,
|
|
488
527
|
reasoningSteps: input.reasoning,
|
|
489
528
|
isFinal: false,
|
|
490
|
-
|
|
529
|
+
parts: input.parts ?? next[index].parts
|
|
491
530
|
};
|
|
492
531
|
messagesRef.current = next;
|
|
493
532
|
return next;
|
|
@@ -503,7 +542,7 @@ function useAgents24ChatController({
|
|
|
503
542
|
(message) => input.messageId && message.id === input.messageId || input.runId && message.role === "assistant" && message.runId === input.runId
|
|
504
543
|
);
|
|
505
544
|
const existing = existingIndex >= 0 ? input.baseMessages[existingIndex] : void 0;
|
|
506
|
-
const
|
|
545
|
+
const parts = input.parts || existing?.parts || partsFromResponseBlocks(void 0, content);
|
|
507
546
|
const assistant = {
|
|
508
547
|
id: existing?.id || input.messageId || createId(),
|
|
509
548
|
role: "assistant",
|
|
@@ -511,13 +550,7 @@ function useAgents24ChatController({
|
|
|
511
550
|
content,
|
|
512
551
|
createdAt: /* @__PURE__ */ new Date(),
|
|
513
552
|
isFinal: true,
|
|
514
|
-
|
|
515
|
-
if (block.kind === "tool") return { ...block, status: input.error ? "error" : "done" };
|
|
516
|
-
if (block.kind === "tool_group") {
|
|
517
|
-
return { ...block, status: input.error ? "error" : "done", tools: block.tools.map((tool) => ({ ...tool, status: input.error ? "error" : "done" })) };
|
|
518
|
-
}
|
|
519
|
-
return block;
|
|
520
|
-
}),
|
|
553
|
+
parts,
|
|
521
554
|
reasoningSteps: mergeReasoningSteps(input.reasoning, { finalize: true }),
|
|
522
555
|
thinkingDurationMs: input.thinkingDurationMs
|
|
523
556
|
};
|
|
@@ -552,7 +585,11 @@ function useAgents24ChatController({
|
|
|
552
585
|
setIsLoadingOlder(false);
|
|
553
586
|
isLoadingOlderRef.current = false;
|
|
554
587
|
try {
|
|
555
|
-
const detail = await transport.getThread({
|
|
588
|
+
const detail = await transport.getThread({
|
|
589
|
+
threadId,
|
|
590
|
+
limit: pageSize,
|
|
591
|
+
includeRunEvents: false
|
|
592
|
+
});
|
|
556
593
|
if (activeThreadIdRef.current !== threadId || seq !== requestSeqRef.current) return;
|
|
557
594
|
const nextMessages = threadDetailToMessages(detail);
|
|
558
595
|
const paging = threadPaging(detail);
|
|
@@ -584,7 +621,12 @@ function useAgents24ChatController({
|
|
|
584
621
|
isLoadingOlderRef.current = true;
|
|
585
622
|
setIsLoadingOlder(true);
|
|
586
623
|
try {
|
|
587
|
-
const detail = await transport.getThread({
|
|
624
|
+
const detail = await transport.getThread({
|
|
625
|
+
threadId,
|
|
626
|
+
limit: pageSize,
|
|
627
|
+
beforeTurnIndex,
|
|
628
|
+
includeRunEvents: false
|
|
629
|
+
});
|
|
588
630
|
if (activeThreadIdRef.current !== threadId) return;
|
|
589
631
|
const older = threadDetailToMessages(detail);
|
|
590
632
|
const paging = threadPaging(detail);
|
|
@@ -608,16 +650,17 @@ function useAgents24ChatController({
|
|
|
608
650
|
if (event.run_id) activeRunIdRef.current = event.run_id;
|
|
609
651
|
setContextStatus((current) => mergeContextWindow(current, payload.context_window));
|
|
610
652
|
if (responseBlocks) {
|
|
611
|
-
const blockText = String(payload.assistant_output_text || "") ||
|
|
653
|
+
const blockText = String(payload.assistant_output_text || "") || assistantTextFromResponseBlocks(responseBlocks) || streamingContentRef.current;
|
|
612
654
|
if (blockText) setStreamingText(blockText);
|
|
613
|
-
const
|
|
655
|
+
const parts = partsFromResponseBlocks(responseBlocks, blockText);
|
|
656
|
+
const reasoning = mergeReasoningSteps([...reasoningRef.current, ...reasoningStepsFromParts(parts)]);
|
|
614
657
|
setReasoningSteps(reasoning);
|
|
615
658
|
setLiveAssistantMessage({
|
|
616
659
|
messageId: assistantMessageId,
|
|
617
660
|
runId: event.run_id || activeRunIdRef.current,
|
|
618
661
|
content: blockText,
|
|
619
662
|
reasoning,
|
|
620
|
-
|
|
663
|
+
parts,
|
|
621
664
|
baseMessages
|
|
622
665
|
});
|
|
623
666
|
}
|
|
@@ -647,7 +690,7 @@ function useAgents24ChatController({
|
|
|
647
690
|
thinkingDurationMs: Date.now() - startedAt,
|
|
648
691
|
messageId: assistantMessageId,
|
|
649
692
|
runId: event.run_id || activeRunIdRef.current,
|
|
650
|
-
|
|
693
|
+
parts: responseBlocks ? partsFromResponseBlocks(responseBlocks, finalText) : void 0,
|
|
651
694
|
error: isFailed ? String(payload.message || payload.error || event.diagnostics?.[0]?.message || onStreamErrorMessage?.(event) || "The chat run failed.") : void 0
|
|
652
695
|
});
|
|
653
696
|
},
|
|
@@ -674,6 +717,7 @@ function useAgents24ChatController({
|
|
|
674
717
|
role: "user",
|
|
675
718
|
content: input.message.text,
|
|
676
719
|
createdAt: /* @__PURE__ */ new Date(),
|
|
720
|
+
parts: input.message.text ? [{ id: createId(), type: "text", kind: "text", text: input.message.text }] : [],
|
|
677
721
|
attachments: input.message.files
|
|
678
722
|
};
|
|
679
723
|
baseMessages = [...messagesRef.current, userMessage];
|
|
@@ -685,6 +729,7 @@ function useAgents24ChatController({
|
|
|
685
729
|
content: "",
|
|
686
730
|
createdAt: /* @__PURE__ */ new Date(),
|
|
687
731
|
isFinal: false,
|
|
732
|
+
parts: [],
|
|
688
733
|
reasoningSteps: []
|
|
689
734
|
};
|
|
690
735
|
const liveMessages = [...baseMessages, assistantMessage];
|
|
@@ -895,6 +940,7 @@ function useAgents24ChatController({
|
|
|
895
940
|
createdAt: /* @__PURE__ */ new Date(),
|
|
896
941
|
isFinal: Boolean(input.isFinal),
|
|
897
942
|
isVoice: input.role === "user",
|
|
943
|
+
parts: content ? [{ id: createId(), type: "text", kind: "text", text: content }] : [],
|
|
898
944
|
citations: input.citations,
|
|
899
945
|
reasoningSteps: input.reasoningSteps
|
|
900
946
|
};
|
|
@@ -958,6 +1004,53 @@ function useAgents24ChatController({
|
|
|
958
1004
|
]);
|
|
959
1005
|
}
|
|
960
1006
|
|
|
1007
|
+
// src/renderers.tsx
|
|
1008
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
1009
|
+
var DefaultToolPart = ({ part }) => {
|
|
1010
|
+
const label = typeof part.presentation?.activity === "string" ? part.presentation.activity : typeof part.presentation?.title === "string" ? part.presentation.title : part.toolName;
|
|
1011
|
+
const detail = typeof part.presentation?.detail === "string" ? part.presentation.detail : part.errorText || part.state;
|
|
1012
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { "data-agents24-tool-part": part.type, "data-state": part.state, children: [
|
|
1013
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: label }),
|
|
1014
|
+
detail ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: detail }) : null
|
|
1015
|
+
] });
|
|
1016
|
+
};
|
|
1017
|
+
var DefaultChatPart = ({
|
|
1018
|
+
part,
|
|
1019
|
+
message,
|
|
1020
|
+
renderOptions
|
|
1021
|
+
}) => {
|
|
1022
|
+
if (renderOptions?.renderPart) {
|
|
1023
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: renderOptions.renderPart(part, message) });
|
|
1024
|
+
}
|
|
1025
|
+
if (part.kind === "text") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: part.text });
|
|
1026
|
+
if (part.kind === "tool") {
|
|
1027
|
+
const ToolRenderer = renderOptions?.toolRenderers?.[part.type] || renderOptions?.fallbackToolRenderer || DefaultToolPart;
|
|
1028
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: ToolRenderer({ part, message }) });
|
|
1029
|
+
}
|
|
1030
|
+
if (part.kind === "reasoning") {
|
|
1031
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { "data-agents24-reasoning-part": true, children: part.text || part.label });
|
|
1032
|
+
}
|
|
1033
|
+
if (part.kind === "ui-blocks") {
|
|
1034
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { "data-agents24-ui-blocks-part": true, "data-state": part.state });
|
|
1035
|
+
}
|
|
1036
|
+
if (part.kind === "approval") {
|
|
1037
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { "data-agents24-approval-part": true });
|
|
1038
|
+
}
|
|
1039
|
+
if (part.kind === "error") {
|
|
1040
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { "data-agents24-error-part": true, children: part.errorText });
|
|
1041
|
+
}
|
|
1042
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { "data-agents24-data-part": part.name });
|
|
1043
|
+
};
|
|
1044
|
+
var renderChatPart = (part, message, renderOptions) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1045
|
+
DefaultChatPart,
|
|
1046
|
+
{
|
|
1047
|
+
part,
|
|
1048
|
+
message,
|
|
1049
|
+
renderOptions
|
|
1050
|
+
},
|
|
1051
|
+
part.id
|
|
1052
|
+
);
|
|
1053
|
+
|
|
961
1054
|
// src/sse.ts
|
|
962
1055
|
var parseSseBlock = (block) => {
|
|
963
1056
|
const data = block.split("\n").filter((line) => line.startsWith("data:")).map((line) => line.replace(/^data:\s?/, "")).join("\n").trim();
|
|
@@ -1082,7 +1175,7 @@ var createFetchChatTransport = ({
|
|
|
1082
1175
|
|
|
1083
1176
|
// src/viewport.tsx
|
|
1084
1177
|
var import_react2 = require("react");
|
|
1085
|
-
var
|
|
1178
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
1086
1179
|
var LATEST_EDGE_THRESHOLD_PX = 2;
|
|
1087
1180
|
var MIN_OLDER_PREFETCH_PX = 320;
|
|
1088
1181
|
var MAX_OLDER_PREFETCH_PX = 900;
|
|
@@ -1093,6 +1186,11 @@ var isAtTimelineLatestEdge = (element, isTopOrigin) => {
|
|
|
1093
1186
|
};
|
|
1094
1187
|
var shouldPrefetchOlder = (element) => Math.abs(element.scrollTop) + element.clientHeight >= element.scrollHeight - Math.min(MAX_OLDER_PREFETCH_PX, Math.max(MIN_OLDER_PREFETCH_PX, element.clientHeight * 0.75));
|
|
1095
1188
|
var getLatestScrollTop = (element, isTopOrigin) => isTopOrigin ? Math.max(0, element.scrollHeight - element.clientHeight) : 0;
|
|
1189
|
+
var shouldUseTopOriginTimeline = ({
|
|
1190
|
+
hasOlder,
|
|
1191
|
+
itemCount,
|
|
1192
|
+
topOriginMaxItems = 4
|
|
1193
|
+
}) => !hasOlder && itemCount > 0 && itemCount <= topOriginMaxItems;
|
|
1096
1194
|
function useLatestThreadViewport({
|
|
1097
1195
|
itemCount,
|
|
1098
1196
|
hasOlder,
|
|
@@ -1111,9 +1209,7 @@ function useLatestThreadViewport({
|
|
|
1111
1209
|
const programmaticScrollTimeoutRef = (0, import_react2.useRef)(null);
|
|
1112
1210
|
const activeStreamKeyRef = (0, import_react2.useRef)(null);
|
|
1113
1211
|
const [isAtLatest, setIsAtLatest] = (0, import_react2.useState)(true);
|
|
1114
|
-
const
|
|
1115
|
-
const topOriginCandidate = !hasOlder && itemCount > 0 && itemCount <= topOriginMaxItems;
|
|
1116
|
-
const isTopOrigin = topOriginCandidate && !topOriginCandidateOverflows;
|
|
1212
|
+
const isTopOrigin = shouldUseTopOriginTimeline({ hasOlder, itemCount, topOriginMaxItems });
|
|
1117
1213
|
const markProgrammaticScroll = (0, import_react2.useCallback)(() => {
|
|
1118
1214
|
programmaticScrollRef.current = true;
|
|
1119
1215
|
if (programmaticScrollTimeoutRef.current) clearTimeout(programmaticScrollTimeoutRef.current);
|
|
@@ -1140,11 +1236,6 @@ function useLatestThreadViewport({
|
|
|
1140
1236
|
const element = scrollContainerRef.current;
|
|
1141
1237
|
const preserve = olderPagePreserveRef.current;
|
|
1142
1238
|
if (!element) return;
|
|
1143
|
-
if (topOriginCandidate) {
|
|
1144
|
-
setTopOriginCandidateOverflows(isScrollable(element));
|
|
1145
|
-
} else if (topOriginCandidateOverflows) {
|
|
1146
|
-
setTopOriginCandidateOverflows(false);
|
|
1147
|
-
}
|
|
1148
1239
|
if (!preserve) {
|
|
1149
1240
|
setIsAtLatest(isAtTimelineLatestEdge(element, isTopOrigin));
|
|
1150
1241
|
return;
|
|
@@ -1155,7 +1246,7 @@ function useLatestThreadViewport({
|
|
|
1155
1246
|
olderPagePreserveRef.current = null;
|
|
1156
1247
|
olderPageRequestInFlightRef.current = false;
|
|
1157
1248
|
setIsAtLatest(isAtTimelineLatestEdge(element, isTopOrigin));
|
|
1158
|
-
}, [isTopOrigin, itemCount, markProgrammaticScroll
|
|
1249
|
+
}, [isTopOrigin, itemCount, markProgrammaticScroll]);
|
|
1159
1250
|
const handleScroll = (0, import_react2.useCallback)(
|
|
1160
1251
|
(event) => {
|
|
1161
1252
|
const element = event.currentTarget;
|
|
@@ -1216,18 +1307,23 @@ function useLatestThreadViewport({
|
|
|
1216
1307
|
return;
|
|
1217
1308
|
}
|
|
1218
1309
|
autoFollowLatestRef.current = true;
|
|
1310
|
+
if (isTopOrigin) {
|
|
1311
|
+
activeStreamKeyRef.current = key;
|
|
1312
|
+
return;
|
|
1313
|
+
}
|
|
1219
1314
|
const frame = requestAnimationFrame(scrollToLatest);
|
|
1220
1315
|
activeStreamKeyRef.current = key;
|
|
1221
1316
|
return () => cancelAnimationFrame(frame);
|
|
1222
|
-
}, [activeStreamKey, scrollToLatest]);
|
|
1317
|
+
}, [activeStreamKey, isTopOrigin, scrollToLatest]);
|
|
1223
1318
|
(0, import_react2.useLayoutEffect)(() => {
|
|
1319
|
+
if (isTopOrigin) return;
|
|
1224
1320
|
if (!activeStreamKey || !shouldAutoFollow || !autoFollowLatestRef.current) return;
|
|
1225
1321
|
if (isLoadingOlder || olderPageRequestInFlightRef.current) return;
|
|
1226
1322
|
const frame = requestAnimationFrame(() => {
|
|
1227
1323
|
if (autoFollowLatestRef.current && !isLoadingOlder && !olderPageRequestInFlightRef.current) scrollToLatest();
|
|
1228
1324
|
});
|
|
1229
1325
|
return () => cancelAnimationFrame(frame);
|
|
1230
|
-
}, [activeStreamKey, isLoadingOlder, itemCount, scrollToLatest, shouldAutoFollow]);
|
|
1326
|
+
}, [activeStreamKey, isLoadingOlder, isTopOrigin, itemCount, scrollToLatest, shouldAutoFollow]);
|
|
1231
1327
|
return {
|
|
1232
1328
|
scrollContainerRef,
|
|
1233
1329
|
isAtLatest,
|
|
@@ -1257,7 +1353,7 @@ function LatestThreadViewport({
|
|
|
1257
1353
|
activeStreamKey
|
|
1258
1354
|
});
|
|
1259
1355
|
const timelineItems = (0, import_react2.useMemo)(() => viewport.isTopOrigin ? items : [...items].reverse(), [items, viewport.isTopOrigin]);
|
|
1260
|
-
return /* @__PURE__ */ (0,
|
|
1356
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1261
1357
|
"div",
|
|
1262
1358
|
{
|
|
1263
1359
|
ref: viewport.scrollContainerRef,
|
|
@@ -1276,10 +1372,13 @@ function LatestThreadViewport({
|
|
|
1276
1372
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1277
1373
|
0 && (module.exports = {
|
|
1278
1374
|
DEFAULT_THREAD_PAGE_SIZE,
|
|
1375
|
+
DefaultChatPart,
|
|
1376
|
+
DefaultToolPart,
|
|
1279
1377
|
LatestThreadViewport,
|
|
1280
1378
|
activeRunIdFromThread,
|
|
1281
1379
|
activeRunIdFromThreadDetail,
|
|
1282
|
-
|
|
1380
|
+
assistantTextFromParts,
|
|
1381
|
+
assistantTextFromResponseBlocks,
|
|
1283
1382
|
consumeSseResponse,
|
|
1284
1383
|
createChatId,
|
|
1285
1384
|
createFetchChatTransport,
|
|
@@ -1292,14 +1391,17 @@ function LatestThreadViewport({
|
|
|
1292
1391
|
latestContextWindowFromThread,
|
|
1293
1392
|
mergeReasoningSteps,
|
|
1294
1393
|
parseSseBlock,
|
|
1295
|
-
|
|
1296
|
-
|
|
1394
|
+
partsFromResponseBlocks,
|
|
1395
|
+
reasoningStepsFromParts,
|
|
1396
|
+
renderChatPart,
|
|
1297
1397
|
shouldPrefetchOlder,
|
|
1398
|
+
shouldUseTopOriginTimeline,
|
|
1298
1399
|
textFromFinalOutput,
|
|
1299
1400
|
threadActivityDate,
|
|
1300
1401
|
threadDetailToMessages,
|
|
1301
1402
|
threadPaging,
|
|
1302
1403
|
titleFromMessage,
|
|
1404
|
+
toolStateFromStatus,
|
|
1303
1405
|
useAgents24ChatController,
|
|
1304
1406
|
useLatestThreadViewport
|
|
1305
1407
|
});
|