@agents24/chat-react 0.1.2 → 0.1.4
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 +12 -3
- package/dist/index.cjs +388 -146
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +124 -22
- package/dist/index.d.ts +124 -22
- package/dist/index.js +370 -137
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -13,7 +13,8 @@ var titleFromMessage = (text, files = []) => {
|
|
|
13
13
|
return base.replace(/\s+/g, " ").slice(0, 48);
|
|
14
14
|
};
|
|
15
15
|
var threadActivityDate = (thread) => String(thread.updated_at || thread.last_activity_at || thread.created_at || (/* @__PURE__ */ new Date()).toISOString());
|
|
16
|
-
var
|
|
16
|
+
var assistantTextFromResponseBlocks = (blocks) => (blocks || []).filter((block) => block.kind === "assistant_text" && typeof block.text === "string").map((block) => String(block.text)).join("\n\n").trim();
|
|
17
|
+
var assistantTextFromParts = (parts) => (parts || []).filter((part) => part.kind === "text").map((part) => part.text).join("\n\n").trim();
|
|
17
18
|
var textFromFinalOutput = (value) => {
|
|
18
19
|
if (typeof value === "string") return value;
|
|
19
20
|
if (!value || typeof value !== "object") return "";
|
|
@@ -58,95 +59,126 @@ var assistantTextFromEvents = (events) => {
|
|
|
58
59
|
if (typeof assistantText === "string" && assistantText.trim()) return assistantText;
|
|
59
60
|
return textFromFinalOutput(latestEventPayloadValue(events, "final_output"));
|
|
60
61
|
};
|
|
61
|
-
var
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
var asRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
63
|
+
var optionalString = (value) => typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
64
|
+
var toolStateFromStatus = (status) => {
|
|
65
|
+
const normalized = String(status || "").trim().toLowerCase();
|
|
66
|
+
if (["failed", "error"].includes(normalized)) return "output-error";
|
|
67
|
+
if (["cancelled", "canceled"].includes(normalized)) return "cancelled";
|
|
68
|
+
if (["complete", "completed", "done", "success"].includes(normalized)) return "output-available";
|
|
69
|
+
if (["running", "active", "pending", "streaming"].includes(normalized)) return "input-available";
|
|
70
|
+
return "input-available";
|
|
65
71
|
};
|
|
66
|
-
var
|
|
67
|
-
var
|
|
68
|
-
var
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
if (
|
|
90
|
-
|
|
91
|
-
return name ? humanize(name) : actionLabels[toolActionKey(tool)];
|
|
92
|
-
};
|
|
93
|
-
var toolDetail = (tool) => {
|
|
94
|
-
const summary = String(tool.summary || "").trim();
|
|
95
|
-
const detail = String(tool.detail || "").trim();
|
|
96
|
-
return summary || detail || void 0;
|
|
97
|
-
};
|
|
98
|
-
var summarizeToolGroup = (tools) => {
|
|
99
|
-
if (tools.length === 1) return tools[0].title;
|
|
100
|
-
const counts = /* @__PURE__ */ new Map();
|
|
101
|
-
tools.forEach((tool) => counts.set(tool.actionKey, (counts.get(tool.actionKey) || 0) + 1));
|
|
102
|
-
return Array.from(counts.entries()).map(([key, count]) => `${actionLabels[key]} ${count}`).join(", ");
|
|
103
|
-
};
|
|
104
|
-
var toolGroupStatus = (tools) => {
|
|
105
|
-
if (tools.some((tool) => tool.status === "error")) return "error";
|
|
106
|
-
if (tools.some((tool) => tool.status === "running")) return "running";
|
|
107
|
-
return "done";
|
|
72
|
+
var toolNameFromRecord = (tool) => String(tool.toolName || tool.tool_name || tool.name || tool.slug || tool.action || "tool").trim() || "tool";
|
|
73
|
+
var toolCallIdFromRecords = (block, tool) => optionalString(tool.toolCallId) || optionalString(tool.tool_call_id) || optionalString(block.toolCallId) || optionalString(block.tool_call_id) || optionalString(block.id) || null;
|
|
74
|
+
var presentationFromTool = (tool) => {
|
|
75
|
+
const presentation = asRecord(tool.presentation);
|
|
76
|
+
const outputView = asRecord(tool.outputView) || asRecord(tool.output_view);
|
|
77
|
+
const next = presentation ? { ...presentation } : {};
|
|
78
|
+
[
|
|
79
|
+
"title",
|
|
80
|
+
"activity",
|
|
81
|
+
"detail",
|
|
82
|
+
"category",
|
|
83
|
+
"groupKey",
|
|
84
|
+
"groupLabel",
|
|
85
|
+
"showOutput",
|
|
86
|
+
"outputView"
|
|
87
|
+
].forEach((key) => {
|
|
88
|
+
if (tool[key] !== void 0) {
|
|
89
|
+
next[key] = tool[key];
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
if (tool.group_key !== void 0) next.group_key = tool.group_key;
|
|
93
|
+
if (tool.group_label !== void 0) next.group_label = tool.group_label;
|
|
94
|
+
if (tool.show_output !== void 0) next.show_output = tool.show_output;
|
|
95
|
+
if (outputView && next.outputView === void 0) next.outputView = outputView;
|
|
96
|
+
return Object.keys(next).length > 0 ? next : null;
|
|
108
97
|
};
|
|
109
|
-
var
|
|
110
|
-
const tool = block.tool || {};
|
|
111
|
-
const
|
|
98
|
+
var createToolPart = (block, index) => {
|
|
99
|
+
const tool = asRecord(block.tool) || {};
|
|
100
|
+
const toolName = toolNameFromRecord(tool);
|
|
101
|
+
const errorText = optionalString(tool.errorText) || optionalString(tool.error) || optionalString(block.error) || null;
|
|
112
102
|
return {
|
|
113
103
|
id: String(block.id || `${block.kind || "tool"}-${index}`),
|
|
104
|
+
type: `tool-${toolName}`,
|
|
114
105
|
kind: "tool",
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
106
|
+
toolName,
|
|
107
|
+
toolCallId: toolCallIdFromRecords(block, tool),
|
|
108
|
+
state: toolStateFromStatus(block.status),
|
|
109
|
+
input: tool.input ?? block.input,
|
|
110
|
+
output: tool.output ?? block.output,
|
|
111
|
+
errorText,
|
|
112
|
+
presentation: presentationFromTool(tool),
|
|
113
|
+
raw: block
|
|
120
114
|
};
|
|
121
115
|
};
|
|
122
|
-
var
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
tools: pendingTools
|
|
133
|
-
});
|
|
134
|
-
pendingTools = [];
|
|
135
|
-
};
|
|
116
|
+
var createDataPart = (block, index, name = String(block.kind || "data")) => ({
|
|
117
|
+
id: String(block.id || `${name}-${index}`),
|
|
118
|
+
type: "data",
|
|
119
|
+
kind: "data",
|
|
120
|
+
name,
|
|
121
|
+
data: block,
|
|
122
|
+
raw: block
|
|
123
|
+
});
|
|
124
|
+
var partsFromResponseBlocks = (blocks, fallbackText) => {
|
|
125
|
+
const parts = [];
|
|
136
126
|
(blocks || []).forEach((block, index) => {
|
|
137
127
|
const id = String(block.id || `${block.kind || "block"}-${index}`);
|
|
138
128
|
if (block.kind === "assistant_text" && typeof block.text === "string") {
|
|
139
|
-
|
|
140
|
-
|
|
129
|
+
parts.push({ id, type: "text", kind: "text", text: String(block.text), raw: block });
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
if (block.kind === "tool_call") {
|
|
133
|
+
parts.push(createToolPart(block, index));
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
if (block.kind === "ui_blocks") {
|
|
137
|
+
parts.push({
|
|
138
|
+
id,
|
|
139
|
+
type: "ui-blocks",
|
|
140
|
+
kind: "ui-blocks",
|
|
141
|
+
state: toolStateFromStatus(block.status),
|
|
142
|
+
toolCallId: optionalString(block.toolCallId) || optionalString(block.tool_call_id) || null,
|
|
143
|
+
contractVersion: optionalString(block.contractVersion) || optionalString(block.contract_version) || null,
|
|
144
|
+
bundle: asRecord(block.bundle),
|
|
145
|
+
errorText: optionalString(block.error) || null,
|
|
146
|
+
raw: block
|
|
147
|
+
});
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
if (block.kind === "reasoning_note") {
|
|
151
|
+
parts.push({
|
|
152
|
+
id,
|
|
153
|
+
type: "reasoning",
|
|
154
|
+
kind: "reasoning",
|
|
155
|
+
label: optionalString(block.label) || null,
|
|
156
|
+
text: optionalString(block.text) || optionalString(block.summary) || null,
|
|
157
|
+
status: optionalString(block.status) || null,
|
|
158
|
+
raw: block
|
|
159
|
+
});
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
if (block.kind === "approval_request") {
|
|
163
|
+
parts.push({ id, type: "approval", kind: "approval", raw: block });
|
|
141
164
|
return;
|
|
142
165
|
}
|
|
143
|
-
if (block.kind === "
|
|
166
|
+
if (block.kind === "error") {
|
|
167
|
+
parts.push({
|
|
168
|
+
id,
|
|
169
|
+
type: "error",
|
|
170
|
+
kind: "error",
|
|
171
|
+
errorText: optionalString(block.error) || optionalString(block.message) || "Error",
|
|
172
|
+
raw: block
|
|
173
|
+
});
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
parts.push(createDataPart(block, index));
|
|
144
177
|
});
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
mapped.push({ id: "assistant-fallback-text", kind: "text", content: fallbackText });
|
|
178
|
+
if (!parts.some((part) => part.kind === "text") && fallbackText?.trim()) {
|
|
179
|
+
parts.push({ id: "assistant-fallback-text", type: "text", kind: "text", text: fallbackText });
|
|
148
180
|
}
|
|
149
|
-
return
|
|
181
|
+
return parts;
|
|
150
182
|
};
|
|
151
183
|
var mergeReasoningSteps = (steps, options) => {
|
|
152
184
|
if (!steps?.length) return [];
|
|
@@ -164,21 +196,20 @@ var mergeReasoningSteps = (steps, options) => {
|
|
|
164
196
|
});
|
|
165
197
|
return merged;
|
|
166
198
|
};
|
|
167
|
-
var
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const tool = block.tool || {};
|
|
199
|
+
var reasoningStepsFromParts = (parts) => (parts || []).map((block) => {
|
|
200
|
+
if (block.kind === "tool") {
|
|
201
|
+
const label = optionalString(block.presentation?.activity) || optionalString(block.presentation?.title) || block.toolName;
|
|
171
202
|
return {
|
|
172
|
-
label
|
|
173
|
-
status: block.
|
|
174
|
-
description:
|
|
203
|
+
label,
|
|
204
|
+
status: block.state === "input-available" || block.state === "input-streaming" ? "active" : "complete",
|
|
205
|
+
description: optionalString(block.presentation?.detail) || ""
|
|
175
206
|
};
|
|
176
207
|
}
|
|
177
|
-
if (kind === "
|
|
208
|
+
if (block.kind === "reasoning") {
|
|
178
209
|
return {
|
|
179
|
-
label:
|
|
210
|
+
label: block.label || "Reasoning",
|
|
180
211
|
status: block.status === "running" ? "active" : "complete",
|
|
181
|
-
description:
|
|
212
|
+
description: block.text || ""
|
|
182
213
|
};
|
|
183
214
|
}
|
|
184
215
|
return null;
|
|
@@ -197,19 +228,21 @@ var turnToMessages = (turn, activeRunId) => {
|
|
|
197
228
|
role: "user",
|
|
198
229
|
content: userContent,
|
|
199
230
|
createdAt,
|
|
231
|
+
parts: userContent ? [{ id: `${baseId}-user-text`, type: "text", kind: "text", text: userContent }] : [],
|
|
200
232
|
attachments
|
|
201
233
|
});
|
|
202
234
|
}
|
|
203
|
-
const assistantText = turn.assistant_output_text ||
|
|
235
|
+
const assistantText = turn.assistant_output_text || assistantTextFromResponseBlocks(responseBlocks) || assistantTextFromEvents(turn.run_events) || textFromFinalOutput(turn.final_output);
|
|
204
236
|
if (assistantText || responseBlocks.length > 0 || isRunning) {
|
|
237
|
+
const parts = partsFromResponseBlocks(responseBlocks, assistantText);
|
|
205
238
|
messages.push({
|
|
206
239
|
id: `${baseId}-assistant`,
|
|
207
240
|
role: "assistant",
|
|
208
241
|
runId: turn.run_id || null,
|
|
209
|
-
content: assistantText,
|
|
242
|
+
content: assistantText || assistantTextFromParts(parts),
|
|
210
243
|
createdAt: turn.completed_at ? new Date(turn.completed_at) : createdAt,
|
|
211
|
-
|
|
212
|
-
reasoningSteps: mergeReasoningSteps(
|
|
244
|
+
parts,
|
|
245
|
+
reasoningSteps: mergeReasoningSteps(reasoningStepsFromParts(parts), { finalize: !isRunning }),
|
|
213
246
|
isFinal: !isRunning
|
|
214
247
|
});
|
|
215
248
|
}
|
|
@@ -423,7 +456,7 @@ function useAgents24ChatController({
|
|
|
423
456
|
createdAt: /* @__PURE__ */ new Date(),
|
|
424
457
|
reasoningSteps: input.reasoning,
|
|
425
458
|
isFinal: false,
|
|
426
|
-
|
|
459
|
+
parts: input.parts || []
|
|
427
460
|
});
|
|
428
461
|
messagesRef.current = next2;
|
|
429
462
|
return next2;
|
|
@@ -435,7 +468,7 @@ function useAgents24ChatController({
|
|
|
435
468
|
content: input.content,
|
|
436
469
|
reasoningSteps: input.reasoning,
|
|
437
470
|
isFinal: false,
|
|
438
|
-
|
|
471
|
+
parts: input.parts ?? next[index].parts
|
|
439
472
|
};
|
|
440
473
|
messagesRef.current = next;
|
|
441
474
|
return next;
|
|
@@ -451,7 +484,7 @@ function useAgents24ChatController({
|
|
|
451
484
|
(message) => input.messageId && message.id === input.messageId || input.runId && message.role === "assistant" && message.runId === input.runId
|
|
452
485
|
);
|
|
453
486
|
const existing = existingIndex >= 0 ? input.baseMessages[existingIndex] : void 0;
|
|
454
|
-
const
|
|
487
|
+
const parts = input.parts || existing?.parts || partsFromResponseBlocks(void 0, content);
|
|
455
488
|
const assistant = {
|
|
456
489
|
id: existing?.id || input.messageId || createId(),
|
|
457
490
|
role: "assistant",
|
|
@@ -459,13 +492,7 @@ function useAgents24ChatController({
|
|
|
459
492
|
content,
|
|
460
493
|
createdAt: /* @__PURE__ */ new Date(),
|
|
461
494
|
isFinal: true,
|
|
462
|
-
|
|
463
|
-
if (block.kind === "tool") return { ...block, status: input.error ? "error" : "done" };
|
|
464
|
-
if (block.kind === "tool_group") {
|
|
465
|
-
return { ...block, status: input.error ? "error" : "done", tools: block.tools.map((tool) => ({ ...tool, status: input.error ? "error" : "done" })) };
|
|
466
|
-
}
|
|
467
|
-
return block;
|
|
468
|
-
}),
|
|
495
|
+
parts,
|
|
469
496
|
reasoningSteps: mergeReasoningSteps(input.reasoning, { finalize: true }),
|
|
470
497
|
thinkingDurationMs: input.thinkingDurationMs
|
|
471
498
|
};
|
|
@@ -500,7 +527,11 @@ function useAgents24ChatController({
|
|
|
500
527
|
setIsLoadingOlder(false);
|
|
501
528
|
isLoadingOlderRef.current = false;
|
|
502
529
|
try {
|
|
503
|
-
const detail = await transport.getThread({
|
|
530
|
+
const detail = await transport.getThread({
|
|
531
|
+
threadId,
|
|
532
|
+
limit: pageSize,
|
|
533
|
+
includeRunEvents: false
|
|
534
|
+
});
|
|
504
535
|
if (activeThreadIdRef.current !== threadId || seq !== requestSeqRef.current) return;
|
|
505
536
|
const nextMessages = threadDetailToMessages(detail);
|
|
506
537
|
const paging = threadPaging(detail);
|
|
@@ -532,7 +563,12 @@ function useAgents24ChatController({
|
|
|
532
563
|
isLoadingOlderRef.current = true;
|
|
533
564
|
setIsLoadingOlder(true);
|
|
534
565
|
try {
|
|
535
|
-
const detail = await transport.getThread({
|
|
566
|
+
const detail = await transport.getThread({
|
|
567
|
+
threadId,
|
|
568
|
+
limit: pageSize,
|
|
569
|
+
beforeTurnIndex,
|
|
570
|
+
includeRunEvents: false
|
|
571
|
+
});
|
|
536
572
|
if (activeThreadIdRef.current !== threadId) return;
|
|
537
573
|
const older = threadDetailToMessages(detail);
|
|
538
574
|
const paging = threadPaging(detail);
|
|
@@ -556,16 +592,17 @@ function useAgents24ChatController({
|
|
|
556
592
|
if (event.run_id) activeRunIdRef.current = event.run_id;
|
|
557
593
|
setContextStatus((current) => mergeContextWindow(current, payload.context_window));
|
|
558
594
|
if (responseBlocks) {
|
|
559
|
-
const blockText = String(payload.assistant_output_text || "") ||
|
|
595
|
+
const blockText = String(payload.assistant_output_text || "") || assistantTextFromResponseBlocks(responseBlocks) || streamingContentRef.current;
|
|
560
596
|
if (blockText) setStreamingText(blockText);
|
|
561
|
-
const
|
|
597
|
+
const parts = partsFromResponseBlocks(responseBlocks, blockText);
|
|
598
|
+
const reasoning = mergeReasoningSteps([...reasoningRef.current, ...reasoningStepsFromParts(parts)]);
|
|
562
599
|
setReasoningSteps(reasoning);
|
|
563
600
|
setLiveAssistantMessage({
|
|
564
601
|
messageId: assistantMessageId,
|
|
565
602
|
runId: event.run_id || activeRunIdRef.current,
|
|
566
603
|
content: blockText,
|
|
567
604
|
reasoning,
|
|
568
|
-
|
|
605
|
+
parts,
|
|
569
606
|
baseMessages
|
|
570
607
|
});
|
|
571
608
|
}
|
|
@@ -595,7 +632,7 @@ function useAgents24ChatController({
|
|
|
595
632
|
thinkingDurationMs: Date.now() - startedAt,
|
|
596
633
|
messageId: assistantMessageId,
|
|
597
634
|
runId: event.run_id || activeRunIdRef.current,
|
|
598
|
-
|
|
635
|
+
parts: responseBlocks ? partsFromResponseBlocks(responseBlocks, finalText) : void 0,
|
|
599
636
|
error: isFailed ? String(payload.message || payload.error || event.diagnostics?.[0]?.message || onStreamErrorMessage?.(event) || "The chat run failed.") : void 0
|
|
600
637
|
});
|
|
601
638
|
},
|
|
@@ -622,6 +659,7 @@ function useAgents24ChatController({
|
|
|
622
659
|
role: "user",
|
|
623
660
|
content: input.message.text,
|
|
624
661
|
createdAt: /* @__PURE__ */ new Date(),
|
|
662
|
+
parts: input.message.text ? [{ id: createId(), type: "text", kind: "text", text: input.message.text }] : [],
|
|
625
663
|
attachments: input.message.files
|
|
626
664
|
};
|
|
627
665
|
baseMessages = [...messagesRef.current, userMessage];
|
|
@@ -633,6 +671,7 @@ function useAgents24ChatController({
|
|
|
633
671
|
content: "",
|
|
634
672
|
createdAt: /* @__PURE__ */ new Date(),
|
|
635
673
|
isFinal: false,
|
|
674
|
+
parts: [],
|
|
636
675
|
reasoningSteps: []
|
|
637
676
|
};
|
|
638
677
|
const liveMessages = [...baseMessages, assistantMessage];
|
|
@@ -843,6 +882,7 @@ function useAgents24ChatController({
|
|
|
843
882
|
createdAt: /* @__PURE__ */ new Date(),
|
|
844
883
|
isFinal: Boolean(input.isFinal),
|
|
845
884
|
isVoice: input.role === "user",
|
|
885
|
+
parts: content ? [{ id: createId(), type: "text", kind: "text", text: content }] : [],
|
|
846
886
|
citations: input.citations,
|
|
847
887
|
reasoningSteps: input.reasoningSteps
|
|
848
888
|
};
|
|
@@ -906,6 +946,53 @@ function useAgents24ChatController({
|
|
|
906
946
|
]);
|
|
907
947
|
}
|
|
908
948
|
|
|
949
|
+
// src/renderers.tsx
|
|
950
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
951
|
+
var DefaultToolPart = ({ part }) => {
|
|
952
|
+
const label = typeof part.presentation?.activity === "string" ? part.presentation.activity : typeof part.presentation?.title === "string" ? part.presentation.title : part.toolName;
|
|
953
|
+
const detail = typeof part.presentation?.detail === "string" ? part.presentation.detail : part.errorText || part.state;
|
|
954
|
+
return /* @__PURE__ */ jsxs("div", { "data-agents24-tool-part": part.type, "data-state": part.state, children: [
|
|
955
|
+
/* @__PURE__ */ jsx("div", { children: label }),
|
|
956
|
+
detail ? /* @__PURE__ */ jsx("div", { children: detail }) : null
|
|
957
|
+
] });
|
|
958
|
+
};
|
|
959
|
+
var DefaultChatPart = ({
|
|
960
|
+
part,
|
|
961
|
+
message,
|
|
962
|
+
renderOptions
|
|
963
|
+
}) => {
|
|
964
|
+
if (renderOptions?.renderPart) {
|
|
965
|
+
return /* @__PURE__ */ jsx(Fragment, { children: renderOptions.renderPart(part, message) });
|
|
966
|
+
}
|
|
967
|
+
if (part.kind === "text") return /* @__PURE__ */ jsx(Fragment, { children: part.text });
|
|
968
|
+
if (part.kind === "tool") {
|
|
969
|
+
const ToolRenderer = renderOptions?.toolRenderers?.[part.type] || renderOptions?.fallbackToolRenderer || DefaultToolPart;
|
|
970
|
+
return /* @__PURE__ */ jsx(Fragment, { children: ToolRenderer({ part, message }) });
|
|
971
|
+
}
|
|
972
|
+
if (part.kind === "reasoning") {
|
|
973
|
+
return /* @__PURE__ */ jsx("div", { "data-agents24-reasoning-part": true, children: part.text || part.label });
|
|
974
|
+
}
|
|
975
|
+
if (part.kind === "ui-blocks") {
|
|
976
|
+
return /* @__PURE__ */ jsx("div", { "data-agents24-ui-blocks-part": true, "data-state": part.state });
|
|
977
|
+
}
|
|
978
|
+
if (part.kind === "approval") {
|
|
979
|
+
return /* @__PURE__ */ jsx("div", { "data-agents24-approval-part": true });
|
|
980
|
+
}
|
|
981
|
+
if (part.kind === "error") {
|
|
982
|
+
return /* @__PURE__ */ jsx("div", { "data-agents24-error-part": true, children: part.errorText });
|
|
983
|
+
}
|
|
984
|
+
return /* @__PURE__ */ jsx("div", { "data-agents24-data-part": part.name });
|
|
985
|
+
};
|
|
986
|
+
var renderChatPart = (part, message, renderOptions) => /* @__PURE__ */ jsx(
|
|
987
|
+
DefaultChatPart,
|
|
988
|
+
{
|
|
989
|
+
part,
|
|
990
|
+
message,
|
|
991
|
+
renderOptions
|
|
992
|
+
},
|
|
993
|
+
part.id
|
|
994
|
+
);
|
|
995
|
+
|
|
909
996
|
// src/sse.ts
|
|
910
997
|
var parseSseBlock = (block) => {
|
|
911
998
|
const data = block.split("\n").filter((line) => line.startsWith("data:")).map((line) => line.replace(/^data:\s?/, "")).join("\n").trim();
|
|
@@ -948,6 +1035,140 @@ var consumeSseResponse = async (response, onEvent) => {
|
|
|
948
1035
|
return { threadId, runId };
|
|
949
1036
|
};
|
|
950
1037
|
|
|
1038
|
+
// src/streaming-text.ts
|
|
1039
|
+
import { useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
1040
|
+
var DEFAULT_COMPLETED_TEXT_CACHE_SIZE = 200;
|
|
1041
|
+
var defaultCompletedTextCache = /* @__PURE__ */ new Map();
|
|
1042
|
+
var defaultStreamingTextCache = {
|
|
1043
|
+
get: (id) => defaultCompletedTextCache.get(id),
|
|
1044
|
+
set: (id, text) => {
|
|
1045
|
+
defaultCompletedTextCache.set(id, text);
|
|
1046
|
+
if (defaultCompletedTextCache.size > DEFAULT_COMPLETED_TEXT_CACHE_SIZE) {
|
|
1047
|
+
const firstKey = defaultCompletedTextCache.keys().next().value;
|
|
1048
|
+
if (firstKey) defaultCompletedTextCache.delete(firstKey);
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
};
|
|
1052
|
+
var getActiveStreamingTextPartId = (message, streamingMessageId) => {
|
|
1053
|
+
if (message.role !== "assistant" || streamingMessageId !== message.id) return null;
|
|
1054
|
+
return message.parts.slice().reverse().find((part) => part.kind === "text")?.id || null;
|
|
1055
|
+
};
|
|
1056
|
+
var isActiveStreamingTextPart = (message, part, streamingMessageId) => part.kind === "text" && part.id === getActiveStreamingTextPartId(message, streamingMessageId);
|
|
1057
|
+
function useStreamingText({
|
|
1058
|
+
id,
|
|
1059
|
+
isStreaming,
|
|
1060
|
+
text,
|
|
1061
|
+
cache = defaultStreamingTextCache,
|
|
1062
|
+
charsPerSecond = 72,
|
|
1063
|
+
catchupThreshold = 40,
|
|
1064
|
+
maxCatchupChars = 20
|
|
1065
|
+
}) {
|
|
1066
|
+
const cacheAdapter = cache === false ? null : cache;
|
|
1067
|
+
const [displayedText, setDisplayedText] = useState2(() => {
|
|
1068
|
+
const cachedText = cacheAdapter?.get(id);
|
|
1069
|
+
return isStreaming && cachedText !== text ? "" : text;
|
|
1070
|
+
});
|
|
1071
|
+
const targetRef = useRef2(text);
|
|
1072
|
+
const displayedRef = useRef2(displayedText);
|
|
1073
|
+
const rafRef = useRef2(null);
|
|
1074
|
+
const lastFrameAtRef = useRef2(null);
|
|
1075
|
+
const idRef = useRef2(id);
|
|
1076
|
+
const shouldAnimateRef = useRef2(isStreaming);
|
|
1077
|
+
useEffect2(() => {
|
|
1078
|
+
if (isStreaming || !text) return;
|
|
1079
|
+
cacheAdapter?.set(id, text);
|
|
1080
|
+
}, [cacheAdapter, id, isStreaming, text]);
|
|
1081
|
+
useEffect2(() => {
|
|
1082
|
+
targetRef.current = text;
|
|
1083
|
+
}, [text]);
|
|
1084
|
+
useEffect2(() => {
|
|
1085
|
+
if (idRef.current === id) return;
|
|
1086
|
+
idRef.current = id;
|
|
1087
|
+
const cachedText = cacheAdapter?.get(id);
|
|
1088
|
+
const initial = isStreaming && cachedText !== text ? "" : text;
|
|
1089
|
+
shouldAnimateRef.current = isStreaming && initial !== text;
|
|
1090
|
+
displayedRef.current = initial;
|
|
1091
|
+
setDisplayedText(initial);
|
|
1092
|
+
if (rafRef.current !== null) {
|
|
1093
|
+
cancelAnimationFrame(rafRef.current);
|
|
1094
|
+
rafRef.current = null;
|
|
1095
|
+
}
|
|
1096
|
+
lastFrameAtRef.current = null;
|
|
1097
|
+
}, [cacheAdapter, id, isStreaming, text]);
|
|
1098
|
+
useEffect2(() => {
|
|
1099
|
+
if (typeof window === "undefined") {
|
|
1100
|
+
displayedRef.current = text;
|
|
1101
|
+
setDisplayedText(text);
|
|
1102
|
+
return;
|
|
1103
|
+
}
|
|
1104
|
+
const reduceMotion = typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
1105
|
+
if (reduceMotion) {
|
|
1106
|
+
displayedRef.current = text;
|
|
1107
|
+
setDisplayedText(text);
|
|
1108
|
+
shouldAnimateRef.current = false;
|
|
1109
|
+
return;
|
|
1110
|
+
}
|
|
1111
|
+
const cachedText = cacheAdapter?.get(id);
|
|
1112
|
+
if (cachedText === text) {
|
|
1113
|
+
displayedRef.current = text;
|
|
1114
|
+
setDisplayedText(text);
|
|
1115
|
+
shouldAnimateRef.current = false;
|
|
1116
|
+
return;
|
|
1117
|
+
}
|
|
1118
|
+
if (isStreaming) {
|
|
1119
|
+
shouldAnimateRef.current = true;
|
|
1120
|
+
}
|
|
1121
|
+
if (!shouldAnimateRef.current) {
|
|
1122
|
+
displayedRef.current = text;
|
|
1123
|
+
setDisplayedText(text);
|
|
1124
|
+
return;
|
|
1125
|
+
}
|
|
1126
|
+
if (!text.startsWith(displayedRef.current)) {
|
|
1127
|
+
displayedRef.current = "";
|
|
1128
|
+
setDisplayedText("");
|
|
1129
|
+
}
|
|
1130
|
+
const tick = (timestamp) => {
|
|
1131
|
+
const previousTimestamp = lastFrameAtRef.current ?? timestamp;
|
|
1132
|
+
lastFrameAtRef.current = timestamp;
|
|
1133
|
+
const target = targetRef.current;
|
|
1134
|
+
const current = displayedRef.current;
|
|
1135
|
+
if (current.length >= target.length) {
|
|
1136
|
+
shouldAnimateRef.current = false;
|
|
1137
|
+
rafRef.current = null;
|
|
1138
|
+
return;
|
|
1139
|
+
}
|
|
1140
|
+
const elapsedMs = Math.max(8, timestamp - previousTimestamp);
|
|
1141
|
+
const charsFromTime = Math.max(1, Math.floor(elapsedMs / 1e3 * charsPerSecond));
|
|
1142
|
+
const gap = target.length - current.length;
|
|
1143
|
+
const catchupStep = gap > catchupThreshold ? Math.min(maxCatchupChars, Math.ceil(gap / 10)) : charsFromTime;
|
|
1144
|
+
const nextLength = Math.min(
|
|
1145
|
+
target.length,
|
|
1146
|
+
current.length + Math.max(charsFromTime, catchupStep)
|
|
1147
|
+
);
|
|
1148
|
+
const next = target.slice(0, nextLength);
|
|
1149
|
+
displayedRef.current = next;
|
|
1150
|
+
setDisplayedText(next);
|
|
1151
|
+
rafRef.current = window.requestAnimationFrame(tick);
|
|
1152
|
+
};
|
|
1153
|
+
if (rafRef.current === null && displayedRef.current.length < text.length) {
|
|
1154
|
+
rafRef.current = window.requestAnimationFrame(tick);
|
|
1155
|
+
}
|
|
1156
|
+
return () => {
|
|
1157
|
+
if (rafRef.current !== null) {
|
|
1158
|
+
cancelAnimationFrame(rafRef.current);
|
|
1159
|
+
rafRef.current = null;
|
|
1160
|
+
}
|
|
1161
|
+
lastFrameAtRef.current = null;
|
|
1162
|
+
};
|
|
1163
|
+
}, [cacheAdapter, catchupThreshold, charsPerSecond, id, isStreaming, maxCatchupChars, text]);
|
|
1164
|
+
return {
|
|
1165
|
+
displayedText,
|
|
1166
|
+
isAnimating: isStreaming,
|
|
1167
|
+
mode: isStreaming ? "streaming" : "static",
|
|
1168
|
+
parseIncompleteMarkdown: isStreaming
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1171
|
+
|
|
951
1172
|
// src/transport.ts
|
|
952
1173
|
var jsonHeaders = (headers) => ({
|
|
953
1174
|
...headers || {},
|
|
@@ -1031,13 +1252,13 @@ var createFetchChatTransport = ({
|
|
|
1031
1252
|
// src/viewport.tsx
|
|
1032
1253
|
import {
|
|
1033
1254
|
useCallback as useCallback2,
|
|
1034
|
-
useEffect as
|
|
1255
|
+
useEffect as useEffect3,
|
|
1035
1256
|
useLayoutEffect,
|
|
1036
1257
|
useMemo as useMemo2,
|
|
1037
|
-
useRef as
|
|
1038
|
-
useState as
|
|
1258
|
+
useRef as useRef3,
|
|
1259
|
+
useState as useState3
|
|
1039
1260
|
} from "react";
|
|
1040
|
-
import { jsxs } from "react/jsx-runtime";
|
|
1261
|
+
import { jsxs as jsxs2 } from "react/jsx-runtime";
|
|
1041
1262
|
var LATEST_EDGE_THRESHOLD_PX = 2;
|
|
1042
1263
|
var MIN_OLDER_PREFETCH_PX = 320;
|
|
1043
1264
|
var MAX_OLDER_PREFETCH_PX = 900;
|
|
@@ -1048,6 +1269,11 @@ var isAtTimelineLatestEdge = (element, isTopOrigin) => {
|
|
|
1048
1269
|
};
|
|
1049
1270
|
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));
|
|
1050
1271
|
var getLatestScrollTop = (element, isTopOrigin) => isTopOrigin ? Math.max(0, element.scrollHeight - element.clientHeight) : 0;
|
|
1272
|
+
var shouldUseTopOriginTimeline = ({
|
|
1273
|
+
hasOlder,
|
|
1274
|
+
itemCount,
|
|
1275
|
+
topOriginMaxItems = 4
|
|
1276
|
+
}) => !hasOlder && itemCount > 0 && itemCount <= topOriginMaxItems;
|
|
1051
1277
|
function useLatestThreadViewport({
|
|
1052
1278
|
itemCount,
|
|
1053
1279
|
hasOlder,
|
|
@@ -1057,18 +1283,16 @@ function useLatestThreadViewport({
|
|
|
1057
1283
|
shouldAutoFollow = true,
|
|
1058
1284
|
topOriginMaxItems = 4
|
|
1059
1285
|
}) {
|
|
1060
|
-
const scrollContainerRef =
|
|
1061
|
-
const olderPagePreserveRef =
|
|
1062
|
-
const olderPageRequestInFlightRef =
|
|
1063
|
-
const intrinsicResizePreserveRef =
|
|
1064
|
-
const autoFollowLatestRef =
|
|
1065
|
-
const programmaticScrollRef =
|
|
1066
|
-
const programmaticScrollTimeoutRef =
|
|
1067
|
-
const activeStreamKeyRef =
|
|
1068
|
-
const [isAtLatest, setIsAtLatest] =
|
|
1069
|
-
const
|
|
1070
|
-
const topOriginCandidate = !hasOlder && itemCount > 0 && itemCount <= topOriginMaxItems;
|
|
1071
|
-
const isTopOrigin = topOriginCandidate && !topOriginCandidateOverflows;
|
|
1286
|
+
const scrollContainerRef = useRef3(null);
|
|
1287
|
+
const olderPagePreserveRef = useRef3(null);
|
|
1288
|
+
const olderPageRequestInFlightRef = useRef3(false);
|
|
1289
|
+
const intrinsicResizePreserveRef = useRef3(null);
|
|
1290
|
+
const autoFollowLatestRef = useRef3(true);
|
|
1291
|
+
const programmaticScrollRef = useRef3(false);
|
|
1292
|
+
const programmaticScrollTimeoutRef = useRef3(null);
|
|
1293
|
+
const activeStreamKeyRef = useRef3(null);
|
|
1294
|
+
const [isAtLatest, setIsAtLatest] = useState3(true);
|
|
1295
|
+
const isTopOrigin = shouldUseTopOriginTimeline({ hasOlder, itemCount, topOriginMaxItems });
|
|
1072
1296
|
const markProgrammaticScroll = useCallback2(() => {
|
|
1073
1297
|
programmaticScrollRef.current = true;
|
|
1074
1298
|
if (programmaticScrollTimeoutRef.current) clearTimeout(programmaticScrollTimeoutRef.current);
|
|
@@ -1084,7 +1308,7 @@ function useLatestThreadViewport({
|
|
|
1084
1308
|
element.scrollTop = getLatestScrollTop(element, isTopOrigin);
|
|
1085
1309
|
setIsAtLatest(true);
|
|
1086
1310
|
}, [isTopOrigin, markProgrammaticScroll]);
|
|
1087
|
-
|
|
1311
|
+
useEffect3(() => {
|
|
1088
1312
|
return () => {
|
|
1089
1313
|
if (programmaticScrollTimeoutRef.current) clearTimeout(programmaticScrollTimeoutRef.current);
|
|
1090
1314
|
const preserve = intrinsicResizePreserveRef.current;
|
|
@@ -1095,11 +1319,6 @@ function useLatestThreadViewport({
|
|
|
1095
1319
|
const element = scrollContainerRef.current;
|
|
1096
1320
|
const preserve = olderPagePreserveRef.current;
|
|
1097
1321
|
if (!element) return;
|
|
1098
|
-
if (topOriginCandidate) {
|
|
1099
|
-
setTopOriginCandidateOverflows(isScrollable(element));
|
|
1100
|
-
} else if (topOriginCandidateOverflows) {
|
|
1101
|
-
setTopOriginCandidateOverflows(false);
|
|
1102
|
-
}
|
|
1103
1322
|
if (!preserve) {
|
|
1104
1323
|
setIsAtLatest(isAtTimelineLatestEdge(element, isTopOrigin));
|
|
1105
1324
|
return;
|
|
@@ -1110,7 +1329,7 @@ function useLatestThreadViewport({
|
|
|
1110
1329
|
olderPagePreserveRef.current = null;
|
|
1111
1330
|
olderPageRequestInFlightRef.current = false;
|
|
1112
1331
|
setIsAtLatest(isAtTimelineLatestEdge(element, isTopOrigin));
|
|
1113
|
-
}, [isTopOrigin, itemCount, markProgrammaticScroll
|
|
1332
|
+
}, [isTopOrigin, itemCount, markProgrammaticScroll]);
|
|
1114
1333
|
const handleScroll = useCallback2(
|
|
1115
1334
|
(event) => {
|
|
1116
1335
|
const element = event.currentTarget;
|
|
@@ -1164,25 +1383,30 @@ function useLatestThreadViewport({
|
|
|
1164
1383
|
};
|
|
1165
1384
|
intrinsicResizePreserveRef.current.frame = requestAnimationFrame(preserveFrame);
|
|
1166
1385
|
}, [isTopOrigin, markProgrammaticScroll]);
|
|
1167
|
-
|
|
1386
|
+
useEffect3(() => {
|
|
1168
1387
|
const key = activeStreamKey || null;
|
|
1169
1388
|
if (!key || activeStreamKeyRef.current === key) {
|
|
1170
1389
|
activeStreamKeyRef.current = key;
|
|
1171
1390
|
return;
|
|
1172
1391
|
}
|
|
1173
1392
|
autoFollowLatestRef.current = true;
|
|
1393
|
+
if (isTopOrigin) {
|
|
1394
|
+
activeStreamKeyRef.current = key;
|
|
1395
|
+
return;
|
|
1396
|
+
}
|
|
1174
1397
|
const frame = requestAnimationFrame(scrollToLatest);
|
|
1175
1398
|
activeStreamKeyRef.current = key;
|
|
1176
1399
|
return () => cancelAnimationFrame(frame);
|
|
1177
|
-
}, [activeStreamKey, scrollToLatest]);
|
|
1400
|
+
}, [activeStreamKey, isTopOrigin, scrollToLatest]);
|
|
1178
1401
|
useLayoutEffect(() => {
|
|
1402
|
+
if (isTopOrigin) return;
|
|
1179
1403
|
if (!activeStreamKey || !shouldAutoFollow || !autoFollowLatestRef.current) return;
|
|
1180
1404
|
if (isLoadingOlder || olderPageRequestInFlightRef.current) return;
|
|
1181
1405
|
const frame = requestAnimationFrame(() => {
|
|
1182
1406
|
if (autoFollowLatestRef.current && !isLoadingOlder && !olderPageRequestInFlightRef.current) scrollToLatest();
|
|
1183
1407
|
});
|
|
1184
1408
|
return () => cancelAnimationFrame(frame);
|
|
1185
|
-
}, [activeStreamKey, isLoadingOlder, itemCount, scrollToLatest, shouldAutoFollow]);
|
|
1409
|
+
}, [activeStreamKey, isLoadingOlder, isTopOrigin, itemCount, scrollToLatest, shouldAutoFollow]);
|
|
1186
1410
|
return {
|
|
1187
1411
|
scrollContainerRef,
|
|
1188
1412
|
isAtLatest,
|
|
@@ -1212,7 +1436,7 @@ function LatestThreadViewport({
|
|
|
1212
1436
|
activeStreamKey
|
|
1213
1437
|
});
|
|
1214
1438
|
const timelineItems = useMemo2(() => viewport.isTopOrigin ? items : [...items].reverse(), [items, viewport.isTopOrigin]);
|
|
1215
|
-
return /* @__PURE__ */
|
|
1439
|
+
return /* @__PURE__ */ jsxs2(
|
|
1216
1440
|
"div",
|
|
1217
1441
|
{
|
|
1218
1442
|
ref: viewport.scrollContainerRef,
|
|
@@ -1230,31 +1454,40 @@ function LatestThreadViewport({
|
|
|
1230
1454
|
}
|
|
1231
1455
|
export {
|
|
1232
1456
|
DEFAULT_THREAD_PAGE_SIZE,
|
|
1457
|
+
DefaultChatPart,
|
|
1458
|
+
DefaultToolPart,
|
|
1233
1459
|
LatestThreadViewport,
|
|
1234
1460
|
activeRunIdFromThread,
|
|
1235
1461
|
activeRunIdFromThreadDetail,
|
|
1236
|
-
|
|
1462
|
+
assistantTextFromParts,
|
|
1463
|
+
assistantTextFromResponseBlocks,
|
|
1237
1464
|
consumeSseResponse,
|
|
1238
1465
|
createChatId,
|
|
1239
1466
|
createFetchChatTransport,
|
|
1467
|
+
getActiveStreamingTextPartId,
|
|
1240
1468
|
getLatestScrollTop,
|
|
1241
1469
|
hasStaleUnfinishedAssistantCache,
|
|
1242
1470
|
hasUnfinishedAssistantMessage,
|
|
1471
|
+
isActiveStreamingTextPart,
|
|
1243
1472
|
isAtTimelineLatestEdge,
|
|
1244
1473
|
isRunningThreadStatus,
|
|
1245
1474
|
isScrollable,
|
|
1246
1475
|
latestContextWindowFromThread,
|
|
1247
1476
|
mergeReasoningSteps,
|
|
1248
1477
|
parseSseBlock,
|
|
1249
|
-
|
|
1250
|
-
|
|
1478
|
+
partsFromResponseBlocks,
|
|
1479
|
+
reasoningStepsFromParts,
|
|
1480
|
+
renderChatPart,
|
|
1251
1481
|
shouldPrefetchOlder,
|
|
1482
|
+
shouldUseTopOriginTimeline,
|
|
1252
1483
|
textFromFinalOutput,
|
|
1253
1484
|
threadActivityDate,
|
|
1254
1485
|
threadDetailToMessages,
|
|
1255
1486
|
threadPaging,
|
|
1256
1487
|
titleFromMessage,
|
|
1488
|
+
toolStateFromStatus,
|
|
1257
1489
|
useAgents24ChatController,
|
|
1258
|
-
useLatestThreadViewport
|
|
1490
|
+
useLatestThreadViewport,
|
|
1491
|
+
useStreamingText
|
|
1259
1492
|
};
|
|
1260
1493
|
//# sourceMappingURL=index.js.map
|