@agent-native/agentkit 0.1.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/ARCHITECTURE.md +290 -0
- package/README.md +822 -0
- package/dist/adapters/http.d.ts +56 -0
- package/dist/adapters/http.d.ts.map +1 -0
- package/dist/adapters/http.js +950 -0
- package/dist/adapters/http.js.map +1 -0
- package/dist/adapters/index.d.ts +2 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +2 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/client/client.d.ts +240 -0
- package/dist/client/client.d.ts.map +1 -0
- package/dist/client/client.js +1605 -0
- package/dist/client/client.js.map +1 -0
- package/dist/client/index.d.ts +3 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +3 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/state.d.ts +72 -0
- package/dist/client/state.d.ts.map +1 -0
- package/dist/client/state.js +385 -0
- package/dist/client/state.js.map +1 -0
- package/dist/conformance/index.d.ts +41 -0
- package/dist/conformance/index.d.ts.map +1 -0
- package/dist/conformance/index.js +924 -0
- package/dist/conformance/index.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/protocol/agui-codec.d.ts +28 -0
- package/dist/protocol/agui-codec.d.ts.map +1 -0
- package/dist/protocol/agui-codec.js +250 -0
- package/dist/protocol/agui-codec.js.map +1 -0
- package/dist/protocol/agui.d.ts +144 -0
- package/dist/protocol/agui.d.ts.map +1 -0
- package/dist/protocol/agui.js +253 -0
- package/dist/protocol/agui.js.map +1 -0
- package/dist/protocol/compatibility.d.ts +35 -0
- package/dist/protocol/compatibility.d.ts.map +1 -0
- package/dist/protocol/compatibility.js +160 -0
- package/dist/protocol/compatibility.js.map +1 -0
- package/dist/protocol/errors.d.ts +24 -0
- package/dist/protocol/errors.d.ts.map +1 -0
- package/dist/protocol/errors.js +77 -0
- package/dist/protocol/errors.js.map +1 -0
- package/dist/protocol/index.d.ts +982 -0
- package/dist/protocol/index.d.ts.map +1 -0
- package/dist/protocol/index.js +56 -0
- package/dist/protocol/index.js.map +1 -0
- package/dist/protocol/validation.d.ts +94 -0
- package/dist/protocol/validation.d.ts.map +1 -0
- package/dist/protocol/validation.js +1871 -0
- package/dist/protocol/validation.js.map +1 -0
- package/dist/protocol/version.d.ts +7 -0
- package/dist/protocol/version.d.ts.map +1 -0
- package/dist/protocol/version.js +9 -0
- package/dist/protocol/version.js.map +1 -0
- package/dist/react/chat.d.ts +34 -0
- package/dist/react/chat.d.ts.map +1 -0
- package/dist/react/chat.js +23 -0
- package/dist/react/chat.js.map +1 -0
- package/dist/react/components.d.ts +96 -0
- package/dist/react/components.d.ts.map +1 -0
- package/dist/react/components.js +1300 -0
- package/dist/react/components.js.map +1 -0
- package/dist/react/context.d.ts +259 -0
- package/dist/react/context.d.ts.map +1 -0
- package/dist/react/context.js +359 -0
- package/dist/react/context.js.map +1 -0
- package/dist/react/headless.d.ts +3 -0
- package/dist/react/headless.d.ts.map +1 -0
- package/dist/react/headless.js +3 -0
- package/dist/react/headless.js.map +1 -0
- package/dist/react/index.d.ts +6 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +6 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/root.d.ts +58 -0
- package/dist/react/root.d.ts.map +1 -0
- package/dist/react/root.js +151 -0
- package/dist/react/root.js.map +1 -0
- package/dist/react/streaming-text.d.ts +19 -0
- package/dist/react/streaming-text.d.ts.map +1 -0
- package/dist/react/streaming-text.js +259 -0
- package/dist/react/streaming-text.js.map +1 -0
- package/dist/react/styles.css +1477 -0
- package/package.json +112 -0
|
@@ -0,0 +1,1300 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ActionButton, AgentSuggestionBar, IconButton, MessageQueueDrawer, PromptComposer, Surface, TextField, agentSuggestionPrompt, splitMarkdownBlocks, writeClipboardText, } from "@agent-native/toolkit/agentkit";
|
|
3
|
+
import { IconActivity, IconAlertCircle, IconArrowFork, IconBook2, IconBrain, IconChevronRight, IconCircleCheck, IconCode, IconCopy, IconFile, IconGitBranch, IconMessage, IconPlugConnected, IconPlayerPause, IconPlayerPlay, IconSearch, IconTerminal2, IconChecklist, IconThumbDown, IconThumbUp, IconTool, IconX, } from "@tabler/icons-react";
|
|
4
|
+
import { Component, memo, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, } from "react";
|
|
5
|
+
import ReactMarkdown from "react-markdown";
|
|
6
|
+
import remarkGfm from "remark-gfm";
|
|
7
|
+
import { inferAgentActivityKind, } from "../protocol/index.js";
|
|
8
|
+
import { useAgentCapability, useAgentConnection, useAgentKit, useAgentKitControl, useAgentKitMutation, useAgentThread, } from "./context.js";
|
|
9
|
+
import { AgentStreamingText } from "./streaming-text.js";
|
|
10
|
+
/** Isolates custom renderers so one extension cannot take down the chat. */
|
|
11
|
+
export class AgentKitErrorBoundary extends Component {
|
|
12
|
+
state = {
|
|
13
|
+
resetKey: this.props.resetKey,
|
|
14
|
+
};
|
|
15
|
+
static getDerivedStateFromError(error) {
|
|
16
|
+
return { error };
|
|
17
|
+
}
|
|
18
|
+
static getDerivedStateFromProps(props, state) {
|
|
19
|
+
return props.resetKey !== state.resetKey
|
|
20
|
+
? { error: undefined, resetKey: props.resetKey }
|
|
21
|
+
: null;
|
|
22
|
+
}
|
|
23
|
+
componentDidCatch(error, info) {
|
|
24
|
+
try {
|
|
25
|
+
this.props.onError?.(error, info);
|
|
26
|
+
}
|
|
27
|
+
catch (observerError) {
|
|
28
|
+
if (typeof globalThis.reportError === "function") {
|
|
29
|
+
globalThis.reportError(observerError);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
console.error("AgentKit render observer failed.", observerError);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
render() {
|
|
37
|
+
if (!this.state.error)
|
|
38
|
+
return this.props.children;
|
|
39
|
+
return typeof this.props.fallback === "function"
|
|
40
|
+
? this.props.fallback(this.state.error)
|
|
41
|
+
: this.props.fallback;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function AgentKitSurfaceBoundary({ surface, resetKey, children, }) {
|
|
45
|
+
const { labels, onRenderError, threadId } = useAgentKit();
|
|
46
|
+
return (_jsx(AgentKitErrorBoundary, { resetKey: resetKey, fallback: _jsxs("div", { className: "agentkit-error", "data-render-surface": surface, role: "alert", children: [_jsx(IconAlertCircle, { "aria-hidden": "true", className: "agentkit-icon" }), _jsx("span", { children: labels.renderError })] }), onError: (error, info) => onRenderError?.({
|
|
47
|
+
error,
|
|
48
|
+
surface,
|
|
49
|
+
threadId,
|
|
50
|
+
componentStack: info.componentStack ?? undefined,
|
|
51
|
+
}), children: children }));
|
|
52
|
+
}
|
|
53
|
+
function AgentKitRegionSlot({ slot: Slot, threadId, children, }) {
|
|
54
|
+
return Slot ? _jsx(Slot, { threadId: threadId, children: children }) : children;
|
|
55
|
+
}
|
|
56
|
+
const allowedAgentProtocols = new Set(["http:", "https:", "mailto:", "blob:"]);
|
|
57
|
+
const allowedAgentImageProtocols = new Set(["http:", "https:", "blob:"]);
|
|
58
|
+
/** Keeps an unfinished bold delimiter literal while a streamed message grows. */
|
|
59
|
+
function escapeIncompleteStrongMarkdown(text) {
|
|
60
|
+
const delimiterPositions = new Map();
|
|
61
|
+
let inFence = false;
|
|
62
|
+
let fenceMarker = "";
|
|
63
|
+
let inlineCodeTicks = 0;
|
|
64
|
+
let offset = 0;
|
|
65
|
+
for (const line of text.split("\n")) {
|
|
66
|
+
const trimmed = line.trimStart();
|
|
67
|
+
if (!inFence) {
|
|
68
|
+
const fenceMatch = /^(?:`{3,}|~{3,})/.exec(trimmed);
|
|
69
|
+
if (fenceMatch) {
|
|
70
|
+
inFence = true;
|
|
71
|
+
fenceMarker = fenceMatch[0].charAt(0).repeat(fenceMatch[0].length);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (!inFence) {
|
|
75
|
+
for (let index = 0; index < line.length; index += 1) {
|
|
76
|
+
if (line[index] === "\\") {
|
|
77
|
+
index += 1;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (line[index] === "`") {
|
|
81
|
+
let tickCount = 1;
|
|
82
|
+
while (line[index + tickCount] === "`")
|
|
83
|
+
tickCount += 1;
|
|
84
|
+
inlineCodeTicks = inlineCodeTicks === 0 ? tickCount : 0;
|
|
85
|
+
index += tickCount - 1;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (inlineCodeTicks !== 0)
|
|
89
|
+
continue;
|
|
90
|
+
const delimiter = line.slice(index, index + 2);
|
|
91
|
+
if (delimiter !== "**" && delimiter !== "__")
|
|
92
|
+
continue;
|
|
93
|
+
const positions = delimiterPositions.get(delimiter) ?? [];
|
|
94
|
+
positions.push(offset + index);
|
|
95
|
+
delimiterPositions.set(delimiter, positions);
|
|
96
|
+
index += 1;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
const closeMatch = /^(?:`{3,}|~{3,})\s*$/.exec(trimmed);
|
|
101
|
+
if (closeMatch &&
|
|
102
|
+
closeMatch[0].charAt(0) === fenceMarker.charAt(0) &&
|
|
103
|
+
closeMatch[0].trim().length >= fenceMarker.length) {
|
|
104
|
+
inFence = false;
|
|
105
|
+
fenceMarker = "";
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
offset += line.length + 1;
|
|
109
|
+
}
|
|
110
|
+
const unmatched = [...delimiterPositions.entries()].flatMap(([delimiter, positions]) => positions.length % 2 === 1
|
|
111
|
+
? [{ delimiter, position: positions.at(-1) }]
|
|
112
|
+
: []);
|
|
113
|
+
return unmatched
|
|
114
|
+
.sort((left, right) => right.position - left.position)
|
|
115
|
+
.reduce((value, { delimiter, position }) => `${value.slice(0, position)}\\${delimiter[0]}\\${delimiter[1]}${value.slice(position + 2)}`, text);
|
|
116
|
+
}
|
|
117
|
+
/** Rejects executable and embedded-data URLs before they reach a default anchor. */
|
|
118
|
+
export function safeAgentHref(href) {
|
|
119
|
+
if (!href)
|
|
120
|
+
return undefined;
|
|
121
|
+
try {
|
|
122
|
+
const parsed = new URL(href, "https://agentkit.invalid");
|
|
123
|
+
return allowedAgentProtocols.has(parsed.protocol) ? href : undefined;
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
if (error instanceof TypeError)
|
|
127
|
+
return undefined;
|
|
128
|
+
throw error;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const AgentMarkdownBlock = memo(function AgentMarkdownBlock({ text, }) {
|
|
132
|
+
const safeText = escapeIncompleteStrongMarkdown(text);
|
|
133
|
+
return (_jsx(ReactMarkdown, { skipHtml: true, remarkPlugins: [remarkGfm], components: {
|
|
134
|
+
a: ({ children, href }) => {
|
|
135
|
+
const safeHref = safeAgentHref(href);
|
|
136
|
+
return safeHref ? (_jsx("a", { href: safeHref, children: children })) : (_jsx("span", { children: children }));
|
|
137
|
+
},
|
|
138
|
+
}, children: safeText }));
|
|
139
|
+
});
|
|
140
|
+
function AgentMarkdown({ text }) {
|
|
141
|
+
const { completedBlocks, tail } = useMemo(() => splitMarkdownBlocks(text), [text]);
|
|
142
|
+
const blocks = useMemo(() => (tail ? [...completedBlocks, tail] : completedBlocks), [completedBlocks, tail]);
|
|
143
|
+
return (_jsx("div", { className: "agentkit-markdown", "data-format": "markdown", children: blocks.map((block, index) => (_jsx(AgentMarkdownBlock, { text: block }, index))) }));
|
|
144
|
+
}
|
|
145
|
+
/** Keeps participant avatars on image-capable, non-executable URL schemes. */
|
|
146
|
+
export function safeAgentImageSrc(src) {
|
|
147
|
+
if (!src)
|
|
148
|
+
return undefined;
|
|
149
|
+
try {
|
|
150
|
+
const parsed = new URL(src, "https://agentkit.invalid");
|
|
151
|
+
return allowedAgentImageProtocols.has(parsed.protocol) ? src : undefined;
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
if (error instanceof TypeError)
|
|
155
|
+
return undefined;
|
|
156
|
+
throw error;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function createInvocationId(widgetId, actionId) {
|
|
160
|
+
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
161
|
+
return `${widgetId}:${actionId}:${crypto.randomUUID()}`;
|
|
162
|
+
}
|
|
163
|
+
return `${widgetId}:${actionId}:${Date.now().toString(36)}`;
|
|
164
|
+
}
|
|
165
|
+
function activityIcon(kind) {
|
|
166
|
+
const props = { "aria-hidden": true, className: "agentkit-icon" };
|
|
167
|
+
switch (kind) {
|
|
168
|
+
case "status":
|
|
169
|
+
return _jsx(IconActivity, { ...props });
|
|
170
|
+
case "reasoning":
|
|
171
|
+
case "model":
|
|
172
|
+
return _jsx(IconBrain, { ...props });
|
|
173
|
+
case "search":
|
|
174
|
+
return _jsx(IconSearch, { ...props });
|
|
175
|
+
case "read":
|
|
176
|
+
return _jsx(IconBook2, { ...props });
|
|
177
|
+
case "write":
|
|
178
|
+
case "edit":
|
|
179
|
+
return _jsx(IconCode, { ...props });
|
|
180
|
+
case "command":
|
|
181
|
+
return _jsx(IconTerminal2, { ...props });
|
|
182
|
+
case "check":
|
|
183
|
+
return _jsx(IconCircleCheck, { ...props });
|
|
184
|
+
case "mcp":
|
|
185
|
+
case "connection":
|
|
186
|
+
return _jsx(IconPlugConnected, { ...props });
|
|
187
|
+
case "navigation":
|
|
188
|
+
return _jsx(IconGitBranch, { ...props });
|
|
189
|
+
case "delegation":
|
|
190
|
+
return _jsx(IconArrowFork, { ...props });
|
|
191
|
+
case "approval":
|
|
192
|
+
return _jsx(IconChecklist, { ...props });
|
|
193
|
+
default:
|
|
194
|
+
return _jsx(IconTool, { ...props });
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
function interactionIcon(kind) {
|
|
198
|
+
const props = { "aria-hidden": true, className: "agentkit-icon" };
|
|
199
|
+
switch (kind) {
|
|
200
|
+
case "started":
|
|
201
|
+
case "resumed":
|
|
202
|
+
return _jsx(IconPlayerPlay, { ...props });
|
|
203
|
+
case "messaged":
|
|
204
|
+
return _jsx(IconMessage, { ...props });
|
|
205
|
+
case "delegated":
|
|
206
|
+
return _jsx(IconArrowFork, { ...props });
|
|
207
|
+
case "paused":
|
|
208
|
+
return _jsx(IconPlayerPause, { ...props });
|
|
209
|
+
case "completed":
|
|
210
|
+
return _jsx(IconCircleCheck, { ...props });
|
|
211
|
+
case "failed":
|
|
212
|
+
return _jsx(IconAlertCircle, { ...props });
|
|
213
|
+
case "closed":
|
|
214
|
+
return _jsx(IconX, { ...props });
|
|
215
|
+
default:
|
|
216
|
+
return _jsx(IconActivity, { ...props });
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
export function AgentObjectReferenceView({ value: object, }) {
|
|
220
|
+
const { onOpenObject } = useAgentKit();
|
|
221
|
+
const content = (_jsxs(_Fragment, { children: [_jsx("span", { className: "agentkit-object-label", children: object.label }), typeof object.metadata?.added === "number" ? (_jsxs("span", { className: "agentkit-diff-added", children: ["+", object.metadata.added] })) : null, typeof object.metadata?.removed === "number" ? (_jsxs("span", { className: "agentkit-diff-removed", children: ["\u2212", object.metadata.removed] })) : null] }));
|
|
222
|
+
return onOpenObject ? (_jsx("button", { type: "button", className: "agentkit-object", onClick: () => onOpenObject(object), children: content })) : (_jsx("span", { className: "agentkit-object", children: content }));
|
|
223
|
+
}
|
|
224
|
+
export function AgentParticipantView({ value: agent, }) {
|
|
225
|
+
return (_jsx(AgentIdentityChip, { id: agent.id, name: agent.name, kind: agent.kind, status: agent.status }));
|
|
226
|
+
}
|
|
227
|
+
function AgentIdentityChip({ id, name, kind, status, }) {
|
|
228
|
+
return (_jsx("span", { className: "agentkit-agent", "data-agent-id": id, "data-agent-kind": kind, "data-status": status, children: _jsx("span", { className: "agentkit-agent-name", children: name }) }));
|
|
229
|
+
}
|
|
230
|
+
function defaultInteractionLabel(interaction, labels) {
|
|
231
|
+
if (interaction.label)
|
|
232
|
+
return interaction.label;
|
|
233
|
+
switch (interaction.kind) {
|
|
234
|
+
case "started":
|
|
235
|
+
return labels.agentStarted;
|
|
236
|
+
case "resumed":
|
|
237
|
+
return labels.agentResumed;
|
|
238
|
+
case "messaged":
|
|
239
|
+
return labels.agentMessaged;
|
|
240
|
+
case "delegated":
|
|
241
|
+
return labels.agentDelegated;
|
|
242
|
+
case "paused":
|
|
243
|
+
return labels.agentPaused;
|
|
244
|
+
case "completed":
|
|
245
|
+
return labels.agentCompleted;
|
|
246
|
+
case "failed":
|
|
247
|
+
return labels.agentFailed;
|
|
248
|
+
case "closed":
|
|
249
|
+
return labels.agentClosed;
|
|
250
|
+
default:
|
|
251
|
+
return interaction.kind;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
export function AgentInteractionItem({ value: interaction, threadId, }) {
|
|
255
|
+
const { slots, registry, labels } = useAgentKit();
|
|
256
|
+
const thread = useAgentThread(threadId);
|
|
257
|
+
const agent = thread.agents[interaction.agentId];
|
|
258
|
+
const target = interaction.targetAgentId
|
|
259
|
+
? thread.agents[interaction.targetAgentId]
|
|
260
|
+
: undefined;
|
|
261
|
+
const AgentRenderer = agent
|
|
262
|
+
? (registry.agents?.[agent.kind ?? ""] ??
|
|
263
|
+
slots.agent ??
|
|
264
|
+
AgentParticipantView)
|
|
265
|
+
: undefined;
|
|
266
|
+
const TargetRenderer = target
|
|
267
|
+
? (registry.agents?.[target.kind ?? ""] ??
|
|
268
|
+
slots.agent ??
|
|
269
|
+
AgentParticipantView)
|
|
270
|
+
: undefined;
|
|
271
|
+
const ObjectRenderer = slots.object ?? AgentObjectReferenceView;
|
|
272
|
+
const object = interaction.object ?? interaction.source;
|
|
273
|
+
return (_jsxs("div", { className: "agentkit-agent-interaction", "data-kind": interaction.kind, "data-scope": interaction.scope, children: [interactionIcon(interaction.kind), agent && AgentRenderer ? (_jsx(AgentRenderer, { value: agent, threadId: threadId })) : (_jsx(AgentIdentityChip, { id: interaction.agentId, name: interaction.agentId })), _jsx("span", { className: "agentkit-agent-interaction-label", children: defaultInteractionLabel(interaction, labels) }), target && TargetRenderer ? (_jsx(TargetRenderer, { value: target, threadId: threadId })) : interaction.targetAgentId ? (_jsx(AgentIdentityChip, { id: interaction.targetAgentId, name: interaction.targetAgentId })) : null, object ? (_jsx(ObjectRenderer, { value: object, threadId: threadId })) : interaction.detail ? (_jsx("span", { className: "agentkit-agent-interaction-detail", children: interaction.detail })) : null] }));
|
|
274
|
+
}
|
|
275
|
+
export function AgentActivityItem({ value: activity, threadId, }) {
|
|
276
|
+
const { slots, registry, labels } = useAgentKit();
|
|
277
|
+
const thread = useAgentThread();
|
|
278
|
+
const [open, setOpen] = useState(false);
|
|
279
|
+
const expandable = Boolean(activity.summary?.length);
|
|
280
|
+
const agent = activity.agentId ? thread.agents[activity.agentId] : undefined;
|
|
281
|
+
const AgentRenderer = agent
|
|
282
|
+
? (registry.agents?.[agent.kind ?? ""] ??
|
|
283
|
+
slots.agent ??
|
|
284
|
+
AgentParticipantView)
|
|
285
|
+
: undefined;
|
|
286
|
+
const ObjectRenderer = slots.object ?? AgentObjectReferenceView;
|
|
287
|
+
return (_jsxs("div", { className: "agentkit-activity-item", "data-activity-kind": activity.kind, "data-status": activity.status, children: [_jsxs("div", { className: "agentkit-activity-row", children: [activityIcon(activity.kind), agent && AgentRenderer ? (_jsx(AgentRenderer, { value: agent, threadId: threadId })) : activity.agentId ? (_jsx(AgentIdentityChip, { id: activity.agentId, name: activity.agentId })) : null, _jsx("span", { className: "agentkit-activity-label", children: activity.label }), activity.object ? (_jsx(ObjectRenderer, { value: activity.object, threadId: threadId })) : null, !activity.object && activity.source ? (_jsx(ObjectRenderer, { value: activity.source, threadId: threadId })) : !activity.object && activity.detail ? (_jsx("span", { className: "agentkit-activity-detail", children: activity.detail })) : null, expandable ? (_jsx("button", { type: "button", className: "agentkit-activity-disclosure", "aria-expanded": open, "aria-label": open ? labels.collapseActivity : labels.expandActivity, onClick: () => setOpen((current) => !current), children: _jsx(IconChevronRight, { "aria-hidden": "true", className: "agentkit-icon agentkit-disclosure-icon", "data-open": open ? "true" : "false" }) })) : null] }), open ? (_jsx("div", { className: "agentkit-activity-summary", children: activity.summary?.map((part, index) => (_jsx(AgentMessagePartView, { value: part, threadId: threadId }, `${activity.id}-summary-${index}`))) })) : null] }));
|
|
288
|
+
}
|
|
289
|
+
function objectReferenceIdentity(object) {
|
|
290
|
+
return object
|
|
291
|
+
? [object.kind, object.id, object.uri ?? ""].join("\u0000")
|
|
292
|
+
: "";
|
|
293
|
+
}
|
|
294
|
+
function activityClusterIdentity(activity) {
|
|
295
|
+
return [
|
|
296
|
+
activity.kind,
|
|
297
|
+
activity.label.trim(),
|
|
298
|
+
activity.status,
|
|
299
|
+
activity.agentId ?? "",
|
|
300
|
+
objectReferenceIdentity(activity.object),
|
|
301
|
+
objectReferenceIdentity(activity.source),
|
|
302
|
+
].join("\u0001");
|
|
303
|
+
}
|
|
304
|
+
function RepeatedActivityCluster({ activities, threadId, }) {
|
|
305
|
+
const { slots, registry } = useAgentKit();
|
|
306
|
+
const thread = useAgentThread();
|
|
307
|
+
const [open, setOpen] = useState(false);
|
|
308
|
+
const activity = activities[0];
|
|
309
|
+
if (!activity)
|
|
310
|
+
return null;
|
|
311
|
+
const agent = activity.agentId ? thread.agents[activity.agentId] : undefined;
|
|
312
|
+
const AgentRenderer = agent
|
|
313
|
+
? (registry.agents?.[agent.kind ?? ""] ??
|
|
314
|
+
slots.agent ??
|
|
315
|
+
AgentParticipantView)
|
|
316
|
+
: undefined;
|
|
317
|
+
const ObjectRenderer = slots.object ?? AgentObjectReferenceView;
|
|
318
|
+
return (_jsxs("details", { className: "agentkit-activity-cluster", "data-activity-kind": activity.kind, open: open, children: [_jsxs("summary", { className: "agentkit-activity-row", onClick: (event) => {
|
|
319
|
+
event.preventDefault();
|
|
320
|
+
setOpen((current) => !current);
|
|
321
|
+
}, children: [activityIcon(activity.kind), agent && AgentRenderer ? (_jsx(AgentRenderer, { value: agent, threadId: threadId })) : activity.agentId ? (_jsx(AgentIdentityChip, { id: activity.agentId, name: activity.agentId })) : null, _jsx("span", { className: "agentkit-activity-label", children: activity.label }), activity.object ? (_jsx(ObjectRenderer, { value: activity.object, threadId: threadId })) : null, !activity.object && activity.source ? (_jsx(ObjectRenderer, { value: activity.source, threadId: threadId })) : null, _jsxs("span", { className: "agentkit-activity-cluster-count", children: ["\u00D7", activities.length] }), _jsx(IconChevronRight, { "aria-hidden": "true", className: "agentkit-icon agentkit-disclosure-icon", "data-open": open ? "true" : "false" })] }), _jsx("div", { className: "agentkit-activity-cluster-items", children: activities.map((item) => (_jsx(AgentActivityItem, { value: item, threadId: threadId }, item.id))) })] }));
|
|
322
|
+
}
|
|
323
|
+
function toolToActivity(tool) {
|
|
324
|
+
return {
|
|
325
|
+
id: tool.id,
|
|
326
|
+
kind: inferAgentActivityKind(tool.name),
|
|
327
|
+
label: tool.name,
|
|
328
|
+
status: tool.status === "completed"
|
|
329
|
+
? "completed"
|
|
330
|
+
: tool.status === "running"
|
|
331
|
+
? "running"
|
|
332
|
+
: tool.status,
|
|
333
|
+
detail: typeof tool.output === "string"
|
|
334
|
+
? tool.output
|
|
335
|
+
: typeof tool.input === "string"
|
|
336
|
+
? tool.input
|
|
337
|
+
: undefined,
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
function sequenceInRange(sequence, { afterSequence, throughSequence }) {
|
|
341
|
+
return ((afterSequence === undefined || sequence > afterSequence) &&
|
|
342
|
+
(throughSequence === undefined || sequence <= throughSequence));
|
|
343
|
+
}
|
|
344
|
+
export function formatAgentKitDuration(ms, units = {}) {
|
|
345
|
+
const hour = units.hour ?? "h";
|
|
346
|
+
const minute = units.minute ?? "m";
|
|
347
|
+
const second = units.second ?? "s";
|
|
348
|
+
const totalSeconds = Math.max(0, Math.round(ms / 1_000));
|
|
349
|
+
if (totalSeconds < 60)
|
|
350
|
+
return `${Math.max(1, totalSeconds)}${second}`;
|
|
351
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
352
|
+
const seconds = totalSeconds % 60;
|
|
353
|
+
if (minutes < 60) {
|
|
354
|
+
return seconds === 0
|
|
355
|
+
? `${minutes}${minute}`
|
|
356
|
+
: `${minutes}${minute} ${seconds}${second}`;
|
|
357
|
+
}
|
|
358
|
+
const hours = Math.floor(minutes / 60);
|
|
359
|
+
const remainingMinutes = minutes % 60;
|
|
360
|
+
return remainingMinutes === 0
|
|
361
|
+
? `${hours}${hour}`
|
|
362
|
+
: `${hours}${hour} ${remainingMinutes}${minute}`;
|
|
363
|
+
}
|
|
364
|
+
function workEventIdentity(event) {
|
|
365
|
+
if (event.type === "activity.started" ||
|
|
366
|
+
event.type === "activity.updated" ||
|
|
367
|
+
event.type === "activity.completed") {
|
|
368
|
+
return `activity:${event.activity.id}`;
|
|
369
|
+
}
|
|
370
|
+
if (event.type === "tool.started" || event.type === "tool.updated") {
|
|
371
|
+
return `tool:${event.toolCall.id}`;
|
|
372
|
+
}
|
|
373
|
+
if (event.type === "tool.delta")
|
|
374
|
+
return `tool:${event.toolCallId}`;
|
|
375
|
+
if (event.type === "agent.interaction") {
|
|
376
|
+
return `interaction:${event.interaction.id}`;
|
|
377
|
+
}
|
|
378
|
+
if (event.type === "task.created" ||
|
|
379
|
+
event.type === "task.updated" ||
|
|
380
|
+
event.type === "task.completed") {
|
|
381
|
+
return `task:${event.task.id}`;
|
|
382
|
+
}
|
|
383
|
+
return undefined;
|
|
384
|
+
}
|
|
385
|
+
function firstWorkEvents(events) {
|
|
386
|
+
const seen = new Set();
|
|
387
|
+
return events.filter((event) => {
|
|
388
|
+
const identity = workEventIdentity(event);
|
|
389
|
+
if (!identity)
|
|
390
|
+
return false;
|
|
391
|
+
const scopedIdentity = `${event.runId}:${identity}`;
|
|
392
|
+
if (seen.has(scopedIdentity))
|
|
393
|
+
return false;
|
|
394
|
+
seen.add(scopedIdentity);
|
|
395
|
+
return true;
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
function messageEventHasVisibleAssistantOutput(event, assistantMessageIds) {
|
|
399
|
+
if (event.type === "message.delta") {
|
|
400
|
+
return (event.text.trim().length > 0 && assistantMessageIds.has(event.messageId));
|
|
401
|
+
}
|
|
402
|
+
if (event.type !== "message.created" && event.type !== "message.completed") {
|
|
403
|
+
return false;
|
|
404
|
+
}
|
|
405
|
+
return (event.message.role === "assistant" &&
|
|
406
|
+
event.message.parts.some((part) => {
|
|
407
|
+
if (part.type === "reasoning")
|
|
408
|
+
return false;
|
|
409
|
+
if (part.type === "text")
|
|
410
|
+
return part.text.trim().length > 0;
|
|
411
|
+
return true;
|
|
412
|
+
}));
|
|
413
|
+
}
|
|
414
|
+
export function AgentActivityGroup({ runId, afterSequence, throughSequence, excludeAgentActivities = false, }) {
|
|
415
|
+
const { threadId, slots, registry, labels } = useAgentKit();
|
|
416
|
+
const thread = useAgentThread();
|
|
417
|
+
const runEvents = runId
|
|
418
|
+
? thread.events.filter((event) => event.runId === runId)
|
|
419
|
+
: thread.events;
|
|
420
|
+
const activityMap = new Map();
|
|
421
|
+
const toolMap = new Map();
|
|
422
|
+
const firstSequence = new Map();
|
|
423
|
+
const itemOrder = [];
|
|
424
|
+
const seenItems = new Set();
|
|
425
|
+
const remember = (id, sequence) => {
|
|
426
|
+
if (seenItems.has(id))
|
|
427
|
+
return;
|
|
428
|
+
seenItems.add(id);
|
|
429
|
+
itemOrder.push(id);
|
|
430
|
+
firstSequence.set(id, sequence);
|
|
431
|
+
};
|
|
432
|
+
for (const event of runEvents) {
|
|
433
|
+
if (event.type === "activity.started" ||
|
|
434
|
+
event.type === "activity.updated" ||
|
|
435
|
+
event.type === "activity.completed") {
|
|
436
|
+
if (excludeAgentActivities && event.activity.agentId)
|
|
437
|
+
continue;
|
|
438
|
+
activityMap.set(event.activity.id, event.activity);
|
|
439
|
+
remember(event.activity.id, event.sequence);
|
|
440
|
+
}
|
|
441
|
+
if (event.type === "tool.started" || event.type === "tool.updated") {
|
|
442
|
+
toolMap.set(event.toolCall.id, event.toolCall);
|
|
443
|
+
remember(event.toolCall.id, event.sequence);
|
|
444
|
+
}
|
|
445
|
+
if (event.type === "tool.delta") {
|
|
446
|
+
const tool = thread.tools[event.toolCallId];
|
|
447
|
+
if (tool)
|
|
448
|
+
toolMap.set(tool.id, tool);
|
|
449
|
+
remember(event.toolCallId, event.sequence);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
const items = itemOrder.flatMap((id) => {
|
|
453
|
+
const sequence = firstSequence.get(id);
|
|
454
|
+
if (sequence === undefined ||
|
|
455
|
+
!sequenceInRange(sequence, { afterSequence, throughSequence })) {
|
|
456
|
+
return [];
|
|
457
|
+
}
|
|
458
|
+
const activity = activityMap.get(id);
|
|
459
|
+
if (activity)
|
|
460
|
+
return [activity];
|
|
461
|
+
const tool = toolMap.get(id);
|
|
462
|
+
return tool ? [toolToActivity(tool)] : [];
|
|
463
|
+
});
|
|
464
|
+
const running = items.some((item) => item.status === "running");
|
|
465
|
+
const run = runId ? thread.runs[runId] : undefined;
|
|
466
|
+
const segmentStartedEvent = firstWorkEvents(runEvents).find((event) => sequenceInRange(event.sequence, { afterSequence, throughSequence }));
|
|
467
|
+
const startedAt = afterSequence === undefined && run?.startedAt
|
|
468
|
+
? Date.parse(run.startedAt)
|
|
469
|
+
: segmentStartedEvent
|
|
470
|
+
? Date.parse(segmentStartedEvent.occurredAt)
|
|
471
|
+
: Number.NaN;
|
|
472
|
+
const responseStartedEvent = throughSequence === undefined
|
|
473
|
+
? undefined
|
|
474
|
+
: runEvents.find((event) => event.sequence === throughSequence);
|
|
475
|
+
const completedAt = responseStartedEvent
|
|
476
|
+
? Date.parse(responseStartedEvent.occurredAt)
|
|
477
|
+
: run?.completedAt
|
|
478
|
+
? Date.parse(run.completedAt)
|
|
479
|
+
: Number.NaN;
|
|
480
|
+
const durationMs = Number.isFinite(startedAt) && Number.isFinite(completedAt)
|
|
481
|
+
? Math.max(0, completedAt - startedAt)
|
|
482
|
+
: undefined;
|
|
483
|
+
const activelyWorking = throughSequence === undefined &&
|
|
484
|
+
run !== undefined &&
|
|
485
|
+
run.status === "running";
|
|
486
|
+
const visiblyRunning = throughSequence === undefined && running;
|
|
487
|
+
const [elapsedAt, setElapsedAt] = useState();
|
|
488
|
+
useEffect(() => {
|
|
489
|
+
if (!activelyWorking || !Number.isFinite(startedAt))
|
|
490
|
+
return;
|
|
491
|
+
const update = () => setElapsedAt(Date.now());
|
|
492
|
+
update();
|
|
493
|
+
const interval = globalThis.setInterval(update, 1_000);
|
|
494
|
+
return () => globalThis.clearInterval(interval);
|
|
495
|
+
}, [activelyWorking, startedAt]);
|
|
496
|
+
const activeDurationMs = activelyWorking && elapsedAt !== undefined && Number.isFinite(startedAt)
|
|
497
|
+
? Math.max(0, elapsedAt - startedAt)
|
|
498
|
+
: undefined;
|
|
499
|
+
const completedRunSummary = throughSequence !== undefined ||
|
|
500
|
+
(afterSequence === undefined &&
|
|
501
|
+
!running &&
|
|
502
|
+
run !== undefined &&
|
|
503
|
+
["completed", "failed", "cancelled"].includes(run.status));
|
|
504
|
+
const [open, setOpen] = useState(visiblyRunning);
|
|
505
|
+
const previousRunningRef = useRef(visiblyRunning);
|
|
506
|
+
useEffect(() => {
|
|
507
|
+
if (previousRunningRef.current === visiblyRunning)
|
|
508
|
+
return;
|
|
509
|
+
previousRunningRef.current = visiblyRunning;
|
|
510
|
+
setOpen(visiblyRunning);
|
|
511
|
+
}, [visiblyRunning]);
|
|
512
|
+
if (items.length === 0)
|
|
513
|
+
return null;
|
|
514
|
+
const displayGroups = [];
|
|
515
|
+
for (const activity of items) {
|
|
516
|
+
const sourceTool = toolMap.get(activity.id);
|
|
517
|
+
const hasCustomToolRenderer = Boolean(sourceTool &&
|
|
518
|
+
!activityMap.has(activity.id) &&
|
|
519
|
+
(registry.tools?.[sourceTool.name] ?? slots.tool));
|
|
520
|
+
const hasCustomActivityRenderer = Boolean(registry.activities?.[activity.kind] ?? slots.activity);
|
|
521
|
+
const previous = displayGroups.at(-1);
|
|
522
|
+
if (!hasCustomToolRenderer &&
|
|
523
|
+
!hasCustomActivityRenderer &&
|
|
524
|
+
previous &&
|
|
525
|
+
activityClusterIdentity(previous[0]) ===
|
|
526
|
+
activityClusterIdentity(activity)) {
|
|
527
|
+
previous.push(activity);
|
|
528
|
+
}
|
|
529
|
+
else {
|
|
530
|
+
displayGroups.push([activity]);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
const labelsSummary = Array.from(new Set(items.map((item) => item.label.trim()).filter(Boolean)));
|
|
534
|
+
const remaining = Math.max(0, labelsSummary.length - 2);
|
|
535
|
+
const summary = `${labelsSummary.slice(0, 2).join(", ")}${remaining ? ` +${remaining}` : ""}`;
|
|
536
|
+
const formatDuration = (ms) => formatAgentKitDuration(ms, {
|
|
537
|
+
hour: labels.durationHourShort,
|
|
538
|
+
minute: labels.durationMinuteShort,
|
|
539
|
+
second: labels.durationSecondShort,
|
|
540
|
+
});
|
|
541
|
+
const summaryLabel = activelyWorking
|
|
542
|
+
? activeDurationMs !== undefined && activeDurationMs >= 1_000
|
|
543
|
+
? labels.workingFor.replace("{{duration}}", formatDuration(activeDurationMs))
|
|
544
|
+
: labels.working
|
|
545
|
+
: completedRunSummary
|
|
546
|
+
? durationMs !== undefined && durationMs >= 1_000
|
|
547
|
+
? labels.workedFor.replace("{{duration}}", formatDuration(durationMs))
|
|
548
|
+
: labels.worked
|
|
549
|
+
: summary || labels.activities;
|
|
550
|
+
return (_jsxs("details", { className: "agentkit-activities", "data-running": visiblyRunning ? "true" : undefined, open: open, children: [_jsxs("summary", { className: "agentkit-activities-summary", onClick: (event) => {
|
|
551
|
+
event.preventDefault();
|
|
552
|
+
setOpen((current) => !current);
|
|
553
|
+
}, children: [_jsx(IconActivity, { "aria-hidden": "true", className: "agentkit-icon" }), _jsx("span", { className: "agentkit-activities-label", children: summaryLabel }), !completedRunSummary ? (_jsx("span", { className: "agentkit-activities-count", children: items.length })) : null, _jsx(IconChevronRight, { "aria-hidden": "true", className: "agentkit-icon agentkit-summary-chevron" })] }), _jsx("div", { className: "agentkit-activities-list", children: displayGroups.map((activities) => {
|
|
554
|
+
const activity = activities[0];
|
|
555
|
+
if (activities.length > 1) {
|
|
556
|
+
return (_jsx(RepeatedActivityCluster, { activities: activities, threadId: threadId }, `cluster:${activity.id}`));
|
|
557
|
+
}
|
|
558
|
+
const sourceTool = toolMap.get(activity.id);
|
|
559
|
+
const ToolRenderer = sourceTool
|
|
560
|
+
? (registry.tools?.[sourceTool.name] ?? slots.tool)
|
|
561
|
+
: undefined;
|
|
562
|
+
if (sourceTool && ToolRenderer && !activityMap.has(activity.id)) {
|
|
563
|
+
return (_jsx(ToolRenderer, { value: sourceTool, threadId: threadId }, sourceTool.id));
|
|
564
|
+
}
|
|
565
|
+
const Renderer = registry.activities?.[activity.kind] ??
|
|
566
|
+
slots.activity ??
|
|
567
|
+
AgentActivityItem;
|
|
568
|
+
return (_jsx(Renderer, { value: activity, threadId: threadId }, activity.id));
|
|
569
|
+
}) })] }));
|
|
570
|
+
}
|
|
571
|
+
export function AgentCollaborationFeed({ runId, afterSequence, throughSequence, }) {
|
|
572
|
+
const { threadId, slots, registry, labels } = useAgentKit();
|
|
573
|
+
const thread = useAgentThread();
|
|
574
|
+
const entries = new Map();
|
|
575
|
+
const firstSequence = new Map();
|
|
576
|
+
const order = [];
|
|
577
|
+
const remember = (key, sequence, entry) => {
|
|
578
|
+
if (!entries.has(key)) {
|
|
579
|
+
order.push(key);
|
|
580
|
+
firstSequence.set(key, sequence);
|
|
581
|
+
}
|
|
582
|
+
entries.set(key, entry);
|
|
583
|
+
};
|
|
584
|
+
for (const event of thread.events) {
|
|
585
|
+
if (runId && event.runId !== runId)
|
|
586
|
+
continue;
|
|
587
|
+
if (event.type === "agent.interaction") {
|
|
588
|
+
remember(`interaction:${event.interaction.id}`, event.sequence, {
|
|
589
|
+
type: "interaction",
|
|
590
|
+
value: event.interaction,
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
if ((event.type === "activity.started" ||
|
|
594
|
+
event.type === "activity.updated" ||
|
|
595
|
+
event.type === "activity.completed") &&
|
|
596
|
+
event.activity.agentId) {
|
|
597
|
+
remember(`activity:${event.activity.id}`, event.sequence, {
|
|
598
|
+
type: "activity",
|
|
599
|
+
value: event.activity,
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
const selectedOrder = order.filter((key) => {
|
|
604
|
+
const sequence = firstSequence.get(key);
|
|
605
|
+
return (sequence !== undefined &&
|
|
606
|
+
sequenceInRange(sequence, { afterSequence, throughSequence }));
|
|
607
|
+
});
|
|
608
|
+
if (selectedOrder.length === 0)
|
|
609
|
+
return null;
|
|
610
|
+
return (_jsx("section", { className: "agentkit-agent-feed", "aria-label": labels.agents, "data-agent-collaboration-feed": "true", children: selectedOrder.map((key) => {
|
|
611
|
+
const entry = entries.get(key);
|
|
612
|
+
if (!entry)
|
|
613
|
+
return null;
|
|
614
|
+
if (entry.type === "interaction") {
|
|
615
|
+
const Renderer = registry.agentInteractions?.[entry.value.kind] ??
|
|
616
|
+
slots.agentInteraction ??
|
|
617
|
+
AgentInteractionItem;
|
|
618
|
+
return _jsx(Renderer, { value: entry.value, threadId: threadId }, key);
|
|
619
|
+
}
|
|
620
|
+
const Renderer = registry.activities?.[entry.value.kind] ??
|
|
621
|
+
slots.activity ??
|
|
622
|
+
AgentActivityItem;
|
|
623
|
+
return _jsx(Renderer, { value: entry.value, threadId: threadId }, key);
|
|
624
|
+
}) }));
|
|
625
|
+
}
|
|
626
|
+
export function AgentTaskItem({ value: task, threadId, }) {
|
|
627
|
+
const { slots, registry } = useAgentKit();
|
|
628
|
+
const thread = useAgentThread();
|
|
629
|
+
const ObjectRenderer = slots.object ?? AgentObjectReferenceView;
|
|
630
|
+
const agent = task.assignedAgentId
|
|
631
|
+
? thread.agents[task.assignedAgentId]
|
|
632
|
+
: undefined;
|
|
633
|
+
const AgentRenderer = agent
|
|
634
|
+
? (registry.agents?.[agent.kind ?? ""] ??
|
|
635
|
+
slots.agent ??
|
|
636
|
+
AgentParticipantView)
|
|
637
|
+
: undefined;
|
|
638
|
+
const progress = task.progress
|
|
639
|
+
? `${task.progress.completed}/${task.progress.total}`
|
|
640
|
+
: undefined;
|
|
641
|
+
return (_jsxs("div", { className: "agentkit-task-row", "data-status": task.status, children: [_jsx(IconChecklist, { "aria-hidden": "true", className: "agentkit-icon" }), agent && AgentRenderer ? (_jsx(AgentRenderer, { value: agent, threadId: threadId })) : task.assignedAgentId ? (_jsx(AgentIdentityChip, { id: task.assignedAgentId, name: task.assignedAgentId })) : null, _jsx("span", { className: "agentkit-task-title", children: task.title }), task.object ? (_jsx(ObjectRenderer, { value: task.object, threadId: threadId })) : null, !task.object && task.source ? (_jsx(ObjectRenderer, { value: task.source, threadId: threadId })) : !task.object && task.detail ? (_jsx("span", { className: "agentkit-task-detail", children: task.detail })) : null, progress ? (_jsx("span", { className: "agentkit-task-progress", children: progress })) : null] }));
|
|
642
|
+
}
|
|
643
|
+
export function AgentTaskGroup({ runId, afterSequence, throughSequence, }) {
|
|
644
|
+
const { threadId, slots, registry, labels } = useAgentKit();
|
|
645
|
+
const thread = useAgentThread();
|
|
646
|
+
const ids = [];
|
|
647
|
+
const tasks = new Map();
|
|
648
|
+
const firstSequence = new Map();
|
|
649
|
+
for (const event of thread.events) {
|
|
650
|
+
if (runId && event.runId !== runId)
|
|
651
|
+
continue;
|
|
652
|
+
if (event.type !== "task.created" &&
|
|
653
|
+
event.type !== "task.updated" &&
|
|
654
|
+
event.type !== "task.completed") {
|
|
655
|
+
continue;
|
|
656
|
+
}
|
|
657
|
+
if (!tasks.has(event.task.id)) {
|
|
658
|
+
ids.push(event.task.id);
|
|
659
|
+
firstSequence.set(event.task.id, event.sequence);
|
|
660
|
+
}
|
|
661
|
+
tasks.set(event.task.id, event.task);
|
|
662
|
+
}
|
|
663
|
+
const selectedIds = ids.filter((id) => {
|
|
664
|
+
const sequence = firstSequence.get(id);
|
|
665
|
+
return (sequence !== undefined &&
|
|
666
|
+
sequenceInRange(sequence, { afterSequence, throughSequence }));
|
|
667
|
+
});
|
|
668
|
+
if (selectedIds.length === 0)
|
|
669
|
+
return null;
|
|
670
|
+
return (_jsxs("details", { className: "agentkit-tasks", children: [_jsxs("summary", { className: "agentkit-tasks-summary", children: [_jsx(IconChecklist, { "aria-hidden": "true", className: "agentkit-icon" }), _jsx("span", { children: labels.tasks }), _jsx("span", { className: "agentkit-tasks-count", children: selectedIds.length }), _jsx(IconChevronRight, { "aria-hidden": "true", className: "agentkit-icon agentkit-summary-chevron" })] }), _jsx("div", { className: "agentkit-tasks-list", children: selectedIds.map((id) => {
|
|
671
|
+
const task = tasks.get(id);
|
|
672
|
+
if (!task)
|
|
673
|
+
return null;
|
|
674
|
+
const Renderer = registry.tasks?.[task.kind ?? task.status] ??
|
|
675
|
+
slots.task ??
|
|
676
|
+
AgentTaskItem;
|
|
677
|
+
return _jsx(Renderer, { value: task, threadId: threadId }, id);
|
|
678
|
+
}) })] }));
|
|
679
|
+
}
|
|
680
|
+
export function AgentApprovalPrompt({ request, runId, }) {
|
|
681
|
+
const { labels, requestComposerFocus, threadId } = useAgentKit();
|
|
682
|
+
const control = useAgentKitControl();
|
|
683
|
+
const [selected, setSelected] = useState([]);
|
|
684
|
+
const [input, setInput] = useState("");
|
|
685
|
+
const [otherSelected, setOtherSelected] = useState(false);
|
|
686
|
+
const [other, setOther] = useState("");
|
|
687
|
+
const resolution = useAgentKitMutation((response) => control.resolveApproval(runId, request.id, response));
|
|
688
|
+
const options = request.options ?? [];
|
|
689
|
+
const choice = request.kind === "choice" || options.length > 0;
|
|
690
|
+
const allowOther = choice && request.allowOther !== false;
|
|
691
|
+
const simpleApproval = !choice && options.length === 0 && !request.input;
|
|
692
|
+
const toggle = (id) => {
|
|
693
|
+
if (!request.allowMultiple)
|
|
694
|
+
setOtherSelected(false);
|
|
695
|
+
setSelected((current) => request.allowMultiple
|
|
696
|
+
? current.includes(id)
|
|
697
|
+
? current.filter((item) => item !== id)
|
|
698
|
+
: [...current, id]
|
|
699
|
+
: [id]);
|
|
700
|
+
};
|
|
701
|
+
const toggleOther = () => {
|
|
702
|
+
setOtherSelected((current) => !current);
|
|
703
|
+
if (!request.allowMultiple)
|
|
704
|
+
setSelected([]);
|
|
705
|
+
};
|
|
706
|
+
const resolve = (response) => void resolution
|
|
707
|
+
.execute(response)
|
|
708
|
+
.catch(() => undefined)
|
|
709
|
+
.finally(() => requestComposerFocus(threadId));
|
|
710
|
+
return (_jsxs(Surface, { as: "section", className: "agentkit-approval", elevation: "low", padding: "none", "aria-labelledby": `${request.id}-title`, children: [_jsxs("div", { className: "agentkit-approval-copy", children: [_jsx("h3", { id: `${request.id}-title`, children: request.title }), request.description ? _jsx("p", { children: request.description }) : null] }), options.length || allowOther ? (_jsxs("div", { className: "agentkit-approval-options", children: [options.map((option) => (_jsxs("button", { type: "button", "aria-pressed": selected.includes(option.id), "data-kind": option.kind, disabled: resolution.pending, onClick: () => toggle(option.id), children: [_jsx("span", { children: option.label }), option.description ? _jsx("small", { children: option.description }) : null] }, option.id))), allowOther ? (_jsx("button", { type: "button", "aria-pressed": otherSelected, "data-kind": "other", disabled: resolution.pending, onClick: toggleOther, children: _jsx("span", { children: labels.approvalOther }) })) : null] })) : null, allowOther && otherSelected ? (_jsx(TextField, { autoFocus: true, className: "agentkit-approval-input", label: labels.approvalOther, disabled: resolution.pending, placeholder: labels.approvalOtherPlaceholder, value: other, onChange: setOther })) : null, request.input ? (_jsx(TextField, { className: "agentkit-approval-input", label: request.input.label, type: request.input.type === "url" ? "url" : "text", inputMode: request.input.type === "number" ? "decimal" : undefined, required: request.input.required, disabled: resolution.pending, placeholder: request.input.placeholder, value: input, onChange: setInput })) : null, _jsx("div", { className: "agentkit-approval-footer", children: simpleApproval ? (_jsxs(_Fragment, { children: [_jsx(ActionButton, { emphasis: "outline", size: "compact", disabled: resolution.pending, onPress: () => resolve({ decision: "deny", optionIds: ["deny"] }), children: labels.approvalDeny }), _jsx(ActionButton, { className: "agentkit-primary-button", intent: "primary", size: "compact", disabled: resolution.pending, pending: resolution.pending, onPress: () => resolve({ decision: "approve", optionIds: ["approve"] }), children: labels.approvalApprove })] })) : (_jsx(ActionButton, { className: "agentkit-primary-button", intent: "primary", size: "compact", disabled: (selected.length === 0 && !otherSelected && !request.input) ||
|
|
711
|
+
(otherSelected && other.trim().length === 0) ||
|
|
712
|
+
(request.input?.required && input.trim().length === 0) ||
|
|
713
|
+
resolution.pending, pending: resolution.pending, onPress: () => resolve({
|
|
714
|
+
decision: "approve",
|
|
715
|
+
optionIds: selected.length ? selected : undefined,
|
|
716
|
+
other: otherSelected ? other.trim() : undefined,
|
|
717
|
+
input: request.input
|
|
718
|
+
? { [request.input.id]: input }
|
|
719
|
+
: undefined,
|
|
720
|
+
}), children: labels.approvalSubmit })) }), resolution.error ? (_jsx("p", { className: "agentkit-command-error", role: "alert", children: resolution.error.message })) : null] }));
|
|
721
|
+
}
|
|
722
|
+
export function AgentConnectionRequestCard({ request, runId, }) {
|
|
723
|
+
const { labels, onConnectionRequest, requestComposerFocus, threadId } = useAgentKit();
|
|
724
|
+
const control = useAgentKitControl();
|
|
725
|
+
const resolution = useAgentKitMutation(async (decision) => {
|
|
726
|
+
const response = decision === "decline"
|
|
727
|
+
? { status: "declined" }
|
|
728
|
+
: await onConnectionRequest?.(request);
|
|
729
|
+
if (!response) {
|
|
730
|
+
throw new Error(labels.connectionFailed);
|
|
731
|
+
}
|
|
732
|
+
await control.resolveConnectionRequest(runId, request.id, response);
|
|
733
|
+
return response;
|
|
734
|
+
});
|
|
735
|
+
const resolve = (decision) => void resolution
|
|
736
|
+
.execute(decision)
|
|
737
|
+
.catch(() => undefined)
|
|
738
|
+
.finally(() => requestComposerFocus(threadId));
|
|
739
|
+
const terminal = request.status === "connected" ||
|
|
740
|
+
request.status === "declined" ||
|
|
741
|
+
request.status === "failed";
|
|
742
|
+
const title = request.status === "connected"
|
|
743
|
+
? labels.connectionConnected
|
|
744
|
+
: request.status === "failed"
|
|
745
|
+
? labels.connectionFailed
|
|
746
|
+
: request.reason === "admin_required"
|
|
747
|
+
? labels.connectionAdminRequired
|
|
748
|
+
: `${labels.connectionConnect} ${request.provider}`;
|
|
749
|
+
return (_jsxs(Surface, { as: "section", className: "agentkit-connection-request", elevation: "low", padding: "none", "data-status": request.status, "aria-labelledby": `${request.id}-title`, children: [_jsxs("div", { className: "agentkit-connection-request-copy", children: [_jsx(IconPlugConnected, { "aria-hidden": "true", className: "agentkit-icon" }), _jsxs("div", { children: [_jsx("h3", { id: `${request.id}-title`, children: title }), request.detail ? _jsx("p", { children: request.detail }) : null] })] }), !terminal && request.reason !== "admin_required" ? (_jsxs("div", { className: "agentkit-connection-request-actions", children: [_jsx(ActionButton, { emphasis: "outline", size: "compact", disabled: resolution.pending, onPress: () => resolve("decline"), children: labels.connectionNotNow }), _jsx(ActionButton, { className: "agentkit-primary-button", intent: "primary", size: "compact", disabled: resolution.pending || !onConnectionRequest, pending: resolution.pending, onPress: () => resolve("connect"), children: resolution.pending
|
|
750
|
+
? labels.connectionConnecting
|
|
751
|
+
: labels.connectionConnect })] })) : request.status === "failed" && onConnectionRequest ? (_jsx("div", { className: "agentkit-connection-request-actions", children: _jsx(ActionButton, { emphasis: "outline", size: "compact", disabled: resolution.pending, pending: resolution.pending, onPress: () => resolve("connect"), children: labels.connectionRetry }) })) : null, resolution.error ? (_jsxs("div", { className: "agentkit-command-error", role: "alert", children: [_jsx(IconAlertCircle, { "aria-hidden": "true", className: "agentkit-icon" }), _jsx("span", { children: resolution.error.message })] })) : null] }));
|
|
752
|
+
}
|
|
753
|
+
function AgentWidgetActionButton({ widget, action, threadId, }) {
|
|
754
|
+
const control = useAgentKitControl(threadId);
|
|
755
|
+
const invocation = useAgentKitMutation(() => control.invokeAction({
|
|
756
|
+
id: createInvocationId(widget.id, action.id),
|
|
757
|
+
action: action.action ?? "",
|
|
758
|
+
threadId,
|
|
759
|
+
widgetId: widget.id,
|
|
760
|
+
itemId: action.id,
|
|
761
|
+
payload: action.payload,
|
|
762
|
+
}), threadId);
|
|
763
|
+
return (_jsxs("div", { className: "agentkit-widget-action", children: [_jsx(ActionButton, { className: "agentkit-widget-action-button", intent: action.kind === "primary"
|
|
764
|
+
? "primary"
|
|
765
|
+
: action.kind === "danger"
|
|
766
|
+
? "danger"
|
|
767
|
+
: "neutral", emphasis: action.kind === "primary" ? "solid" : "outline", size: "compact", disabled: action.disabled || !action.action || invocation.pending, pending: invocation.pending, onPress: () => void invocation.execute().catch(() => undefined), children: action.label }), invocation.error ? (_jsx("span", { className: "agentkit-command-error", role: "alert", children: invocation.error.message })) : null] }));
|
|
768
|
+
}
|
|
769
|
+
export function AgentWidgetView({ value: widget, threadId, }) {
|
|
770
|
+
if (!widget.title &&
|
|
771
|
+
typeof widget.data !== "string" &&
|
|
772
|
+
!widget.actions?.length) {
|
|
773
|
+
return null;
|
|
774
|
+
}
|
|
775
|
+
const titleId = `${widget.id}-title`;
|
|
776
|
+
return (_jsx("section", { className: "agentkit-widget-shell", "data-widget-kind": widget.kind, "aria-labelledby": widget.title ? titleId : undefined, children: _jsxs(Surface, { className: "agentkit-widget", elevation: "low", padding: "none", children: [widget.title ? _jsx("h3", { id: titleId, children: widget.title }) : null, typeof widget.data === "string" ? _jsx("p", { children: widget.data }) : null, widget.actions?.length ? (_jsx("div", { className: "agentkit-widget-actions", children: widget.actions.map((action) => (_jsx(AgentWidgetActionButton, { widget: widget, action: action, threadId: threadId }, action.id))) })) : null] }) }));
|
|
777
|
+
}
|
|
778
|
+
export function AgentMessagePartView({ value: part, threadId, active = false, resetKey = `${threadId}:${part.type}`, }) {
|
|
779
|
+
const { labels, slots, registry } = useAgentKit();
|
|
780
|
+
const RegisteredRenderer = registry.messageParts?.[part.type];
|
|
781
|
+
if (RegisteredRenderer) {
|
|
782
|
+
return (_jsx(RegisteredRenderer, { value: part, threadId: threadId, active: active, resetKey: resetKey }));
|
|
783
|
+
}
|
|
784
|
+
switch (part.type) {
|
|
785
|
+
case "text": {
|
|
786
|
+
const Renderer = slots.text;
|
|
787
|
+
return Renderer ? (_jsx(Renderer, { value: part, threadId: threadId, active: active, resetKey: resetKey })) : part.format === "markdown" ? (_jsx(AgentStreamingText, { text: part.text, active: active, resetKey: resetKey, children: (visibleText) => _jsx(AgentMarkdown, { text: visibleText }) })) : (_jsx("p", { "data-format": "plain", children: _jsx(AgentStreamingText, { text: part.text, active: active, resetKey: resetKey }) }));
|
|
788
|
+
}
|
|
789
|
+
case "reasoning": {
|
|
790
|
+
const Renderer = slots.reasoning;
|
|
791
|
+
return Renderer ? (_jsx(Renderer, { value: part, threadId: threadId })) : part.visibility === "hidden" ? null : (_jsxs("details", { className: "agentkit-reasoning", "data-active": active ? "true" : undefined, children: [_jsxs("summary", { className: "agentkit-reasoning-summary", children: [activityIcon("reasoning"), _jsx("span", { className: "agentkit-reasoning-label", children: part.label ?? labels.reasoning }), _jsx(IconChevronRight, { "aria-hidden": "true", className: "agentkit-icon agentkit-reasoning-chevron" })] }), _jsx("div", { className: "agentkit-reasoning-content", children: _jsx("p", { children: _jsx(AgentStreamingText, { text: part.text, active: active, resetKey: resetKey }) }) })] }));
|
|
792
|
+
}
|
|
793
|
+
case "citation": {
|
|
794
|
+
const Renderer = slots.citation;
|
|
795
|
+
if (Renderer)
|
|
796
|
+
return _jsx(Renderer, { value: part, threadId: threadId });
|
|
797
|
+
const href = safeAgentHref(part.url);
|
|
798
|
+
return href ? _jsx("a", { href: href, children: part.title }) : _jsx("span", { children: part.title });
|
|
799
|
+
}
|
|
800
|
+
case "annotation": {
|
|
801
|
+
const Renderer = slots.annotation;
|
|
802
|
+
if (Renderer)
|
|
803
|
+
return _jsx(Renderer, { value: part, threadId: threadId });
|
|
804
|
+
const href = safeAgentHref(part.annotation.url);
|
|
805
|
+
return href ? (_jsx("a", { href: href, children: part.annotation.label })) : (_jsx("span", { children: part.annotation.label }));
|
|
806
|
+
}
|
|
807
|
+
case "file": {
|
|
808
|
+
const Renderer = slots.file;
|
|
809
|
+
if (Renderer)
|
|
810
|
+
return _jsx(Renderer, { value: part, threadId: threadId });
|
|
811
|
+
const href = safeAgentHref(part.url);
|
|
812
|
+
return href ? (_jsxs("a", { className: "agentkit-file", href: href, download: part.name, children: [_jsx(IconFile, { "aria-hidden": "true", className: "agentkit-icon" }), _jsx("span", { children: part.name })] })) : (_jsxs("span", { className: "agentkit-file", children: [_jsx(IconFile, { "aria-hidden": "true", className: "agentkit-icon" }), _jsx("span", { children: part.name })] }));
|
|
813
|
+
}
|
|
814
|
+
case "widget": {
|
|
815
|
+
const Renderer = registry.widgets?.[part.widget.kind] ?? slots.widget ?? AgentWidgetView;
|
|
816
|
+
return _jsx(Renderer, { value: part.widget, threadId: threadId });
|
|
817
|
+
}
|
|
818
|
+
case "data": {
|
|
819
|
+
const Renderer = slots.data;
|
|
820
|
+
return Renderer ? _jsx(Renderer, { value: part, threadId: threadId }) : null;
|
|
821
|
+
}
|
|
822
|
+
default:
|
|
823
|
+
return null;
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
export function AgentMessageActions({ value: message, threadId, }) {
|
|
827
|
+
const { labels, onThreadForked } = useAgentKit();
|
|
828
|
+
const feedbackCapability = useAgentCapability("feedback");
|
|
829
|
+
const forkingCapability = useAgentCapability("threadForking");
|
|
830
|
+
const control = useAgentKitControl(threadId);
|
|
831
|
+
const text = message.parts
|
|
832
|
+
.filter((part) => part.type === "text")
|
|
833
|
+
.map((part) => part.text)
|
|
834
|
+
.join("\n");
|
|
835
|
+
const [copied, setCopied] = useState(false);
|
|
836
|
+
const [feedback, setFeedback] = useState(null);
|
|
837
|
+
const copiedTimer = useRef(null);
|
|
838
|
+
useEffect(() => () => {
|
|
839
|
+
if (copiedTimer.current)
|
|
840
|
+
clearTimeout(copiedTimer.current);
|
|
841
|
+
}, [message.id]);
|
|
842
|
+
const copyAction = useAgentKitMutation(async () => {
|
|
843
|
+
if (!(await writeClipboardText(text))) {
|
|
844
|
+
throw new Error(labels.copyUnavailable);
|
|
845
|
+
}
|
|
846
|
+
setCopied(true);
|
|
847
|
+
if (copiedTimer.current)
|
|
848
|
+
clearTimeout(copiedTimer.current);
|
|
849
|
+
copiedTimer.current = setTimeout(() => setCopied(false), 1_400);
|
|
850
|
+
}, `${threadId}:${message.id}:copy`);
|
|
851
|
+
const feedbackAction = useAgentKitMutation((value) => control.submitFeedback(message.id, value), `${threadId}:${message.id}:feedback`);
|
|
852
|
+
const forkAction = useAgentKitMutation(async () => {
|
|
853
|
+
const thread = await control.fork(message.id);
|
|
854
|
+
onThreadForked?.(thread);
|
|
855
|
+
}, `${threadId}:${message.id}:fork`);
|
|
856
|
+
const updateFeedback = async (value) => {
|
|
857
|
+
const previous = feedback;
|
|
858
|
+
if (previous === value)
|
|
859
|
+
return;
|
|
860
|
+
setFeedback(value);
|
|
861
|
+
try {
|
|
862
|
+
await feedbackAction.execute(value);
|
|
863
|
+
}
|
|
864
|
+
catch {
|
|
865
|
+
setFeedback(previous);
|
|
866
|
+
}
|
|
867
|
+
};
|
|
868
|
+
const actionError = copyAction.error ?? feedbackAction.error ?? forkAction.error;
|
|
869
|
+
return (_jsxs("div", { className: "agentkit-message-actions", children: [_jsx(IconButton, { label: copied ? labels.copied : labels.copy, icon: copied ? (_jsx(IconCircleCheck, { "aria-hidden": "true" })) : (_jsx(IconCopy, { "aria-hidden": "true" })), size: "compact", pending: copyAction.pending, onPress: () => void copyAction.execute().catch(() => undefined) }), message.role === "assistant" && feedbackCapability.visible ? (_jsxs(_Fragment, { children: [_jsx(IconButton, { label: labels.positiveFeedback, icon: _jsx(IconThumbUp, { "aria-hidden": "true" }), size: "compact", "aria-pressed": feedback === "positive", pending: feedbackAction.pending && feedback === "positive", disabled: feedbackAction.pending || !feedbackCapability.enabled, title: feedbackCapability.reason, onPress: () => void updateFeedback("positive") }), _jsx(IconButton, { label: labels.negativeFeedback, icon: _jsx(IconThumbDown, { "aria-hidden": "true" }), size: "compact", "aria-pressed": feedback === "negative", pending: feedbackAction.pending && feedback === "negative", disabled: feedbackAction.pending || !feedbackCapability.enabled, title: feedbackCapability.reason, onPress: () => void updateFeedback("negative") })] })) : null, message.role === "assistant" &&
|
|
870
|
+
forkingCapability.visible &&
|
|
871
|
+
onThreadForked ? (_jsx(_Fragment, { children: _jsx(IconButton, { label: labels.fork, icon: _jsx(IconGitBranch, { "aria-hidden": "true" }), size: "compact", pending: forkAction.pending, disabled: !forkingCapability.enabled, title: forkingCapability.reason, onPress: () => void forkAction.execute().catch(() => undefined) }) })) : null, message.createdAt ? (_jsx("time", { dateTime: message.createdAt, children: new Date(message.createdAt).toLocaleTimeString([], {
|
|
872
|
+
hour: "numeric",
|
|
873
|
+
minute: "2-digit",
|
|
874
|
+
}) })) : null, actionError ? (_jsx("span", { className: "agentkit-command-error", role: "alert", children: actionError.message })) : null] }));
|
|
875
|
+
}
|
|
876
|
+
export function AgentMessageView({ value: message, threadId, }) {
|
|
877
|
+
const { labels, slots } = useAgentKit();
|
|
878
|
+
const thread = useAgentThread(threadId);
|
|
879
|
+
const Supplement = slots.messageSupplement;
|
|
880
|
+
const Actions = slots.messageActions ?? AgentMessageActions;
|
|
881
|
+
const embeddedWidgetIds = new Set(message.parts.flatMap((part) => part.type === "widget" ? [part.widget.id] : []));
|
|
882
|
+
const embeddedAnnotationIds = new Set(message.parts.flatMap((part) => part.type === "annotation" ? [part.annotation.id] : []));
|
|
883
|
+
const attachedWidgets = Object.values(thread.widgets).filter((widget) => thread.widgetMessageIds[widget.id] === message.id &&
|
|
884
|
+
!embeddedWidgetIds.has(widget.id));
|
|
885
|
+
const attachedAnnotations = Object.values(thread.annotations).filter((annotation) => thread.annotationMessageIds[annotation.id] === message.id &&
|
|
886
|
+
!embeddedAnnotationIds.has(annotation.id));
|
|
887
|
+
return (_jsxs("article", { className: "agentkit-message", "data-role": message.role, "data-message-id": message.id, "aria-label": message.role === "user" ? labels.you : labels.assistant, "aria-busy": message.status === "streaming", children: [_jsxs("div", { className: "agentkit-message-content", children: [message.parts.map((part, index) => (_jsx(AgentMessagePartView, { value: part, threadId: threadId, active: message.status === "streaming", resetKey: `${threadId}:${message.id}:${index}` }, `${message.id}-${index}`))), attachedWidgets.map((widget) => (_jsx(AgentMessagePartView, { value: { type: "widget", widget }, threadId: threadId }, widget.id))), attachedAnnotations.length ? (_jsx("div", { className: "agentkit-annotations", children: attachedAnnotations.map((annotation) => (_jsx(AgentMessagePartView, { value: { type: "annotation", annotation }, threadId: threadId }, annotation.id))) })) : null, Supplement ? _jsx(Supplement, { value: message, threadId: threadId }) : null] }), _jsx(Actions, { value: message, threadId: threadId })] }));
|
|
888
|
+
}
|
|
889
|
+
export function AgentRunFailure({ error, runId, threadId, }) {
|
|
890
|
+
const { labels } = useAgentKit();
|
|
891
|
+
return (_jsxs("div", { className: "agentkit-run-failure", "data-error-code": error.code, "data-run-id": runId, "data-thread-id": threadId, role: "alert", children: [_jsx(IconAlertCircle, { "aria-hidden": "true", className: "agentkit-icon" }), _jsxs("div", { className: "agentkit-run-failure-copy", children: [_jsx("strong", { children: labels.runFailed }), _jsx("span", { children: error.message })] })] }));
|
|
892
|
+
}
|
|
893
|
+
export function AgentConnectionErrorView({ error, threadId, recover, recovering, recoveryError, }) {
|
|
894
|
+
const { labels } = useAgentKit();
|
|
895
|
+
return (_jsxs("div", { className: "agentkit-error", "data-error-code": error.code, "data-thread-id": threadId, role: "alert", children: [_jsx("strong", { children: labels.error }), _jsx("span", { children: error.message }), error.retryable ? (_jsx("div", { className: "agentkit-error-actions", children: _jsx(ActionButton, { emphasis: "outline", size: "compact", pending: recovering, onPress: () => void recover().catch(() => undefined), children: labels.reconnect }) })) : null, recoveryError ? (_jsx("span", { className: "agentkit-command-error", children: recoveryError.message })) : null] }));
|
|
896
|
+
}
|
|
897
|
+
export function AgentKitComposer({ threadId: requestedThreadId, className, queueWhileRunning = true, showModelSelector = true, slashCommands, slashSkills, includeDefaultSlashCommands, includeDefaultSlashSkills, onSlashCommand, plusMenuMode, voiceEnabled = false, autoFocus = true, mode, defaultMode = "act", onModeChange, }) {
|
|
898
|
+
const { threadId: contextThreadId, labels, registerComposerFocus, slots, } = useAgentKit();
|
|
899
|
+
const threadId = requestedThreadId ?? contextThreadId;
|
|
900
|
+
const queueCapability = useAgentCapability("messageQueue");
|
|
901
|
+
const suggestionsCapability = useAgentCapability("suggestions");
|
|
902
|
+
const uploadsCapability = useAgentCapability("uploads");
|
|
903
|
+
const modelSelectionCapability = useAgentCapability("modelSelection");
|
|
904
|
+
const canQueue = queueCapability.enabled;
|
|
905
|
+
const canUpload = uploadsCapability.enabled;
|
|
906
|
+
// The host opts in through showModelSelector, so a capability the backend
|
|
907
|
+
// never reported keeps the selector instead of silently removing a control
|
|
908
|
+
// the host asked for. Only an explicit denial or outage takes it away.
|
|
909
|
+
const canSelectModel = modelSelectionCapability.state === "unknown" ||
|
|
910
|
+
modelSelectionCapability.enabled;
|
|
911
|
+
const control = useAgentKitControl(threadId);
|
|
912
|
+
const thread = useAgentThread(threadId);
|
|
913
|
+
const command = useAgentKitMutation((execute) => execute(), threadId);
|
|
914
|
+
const composerRef = useRef(null);
|
|
915
|
+
const [uncontrolledMode, setUncontrolledMode] = useState(defaultMode);
|
|
916
|
+
const executionMode = mode ?? uncontrolledMode;
|
|
917
|
+
const active = thread.activeRunIds.length > 0;
|
|
918
|
+
const focusComposer = useCallback(() => {
|
|
919
|
+
if (!autoFocus)
|
|
920
|
+
return;
|
|
921
|
+
composerRef.current?.focus();
|
|
922
|
+
if (typeof globalThis.requestAnimationFrame === "function") {
|
|
923
|
+
globalThis.requestAnimationFrame(() => composerRef.current?.focus());
|
|
924
|
+
}
|
|
925
|
+
}, [autoFocus]);
|
|
926
|
+
useEffect(() => registerComposerFocus(threadId, focusComposer), [focusComposer, registerComposerFocus, threadId]);
|
|
927
|
+
const submitText = (text) => active && queueWhileRunning && canQueue
|
|
928
|
+
? control.queue(text)
|
|
929
|
+
: control.send(text);
|
|
930
|
+
const steerQueued = !active
|
|
931
|
+
? (item) => void command
|
|
932
|
+
.execute(() => control.steerQueued(item.id))
|
|
933
|
+
.catch(() => undefined)
|
|
934
|
+
.finally(focusComposer)
|
|
935
|
+
: undefined;
|
|
936
|
+
const removeQueued = (item) => void command
|
|
937
|
+
.execute(() => control.removeQueued(item.id))
|
|
938
|
+
.catch(() => undefined)
|
|
939
|
+
.finally(focusComposer);
|
|
940
|
+
const selectSuggestion = (suggestion) => void command
|
|
941
|
+
.execute(() => submitText(agentSuggestionPrompt(suggestion)))
|
|
942
|
+
.catch(() => undefined)
|
|
943
|
+
.finally(focusComposer);
|
|
944
|
+
const Queue = slots.queue;
|
|
945
|
+
const Suggestions = slots.suggestions;
|
|
946
|
+
return (_jsxs("div", { className: `agentkit-composer-stack ${className ?? ""}`, children: [queueCapability.visible ? (Queue ? (_jsx(Queue, { items: thread.queuedMessages, threadId: threadId, active: active, pending: command.pending, onSteer: steerQueued, onRemove: removeQueued })) : (_jsx(MessageQueueDrawer, { variant: "recessed", items: thread.queuedMessages, disabled: command.pending, onSteer: steerQueued
|
|
947
|
+
? (item) => {
|
|
948
|
+
const message = thread.queuedMessages.find((candidate) => candidate.id === item.id);
|
|
949
|
+
if (message)
|
|
950
|
+
steerQueued(message);
|
|
951
|
+
}
|
|
952
|
+
: undefined, onRemove: (item) => {
|
|
953
|
+
const message = thread.queuedMessages.find((candidate) => candidate.id === item.id);
|
|
954
|
+
if (message)
|
|
955
|
+
removeQueued(message);
|
|
956
|
+
}, labels: {
|
|
957
|
+
region: labels.queue,
|
|
958
|
+
steer: labels.queueSteer,
|
|
959
|
+
steerHint: labels.queueSteerHint,
|
|
960
|
+
remove: labels.queueRemove,
|
|
961
|
+
moreActions: labels.queueMore,
|
|
962
|
+
} }))) : null, suggestionsCapability.visible && thread.suggestions.length ? (Suggestions ? (_jsx(Suggestions, { suggestions: thread.suggestions, threadId: threadId, pending: command.pending, onSelect: selectSuggestion })) : (_jsx(AgentSuggestionBar, { suggestions: thread.suggestions.map((suggestion) => ({
|
|
963
|
+
...suggestion,
|
|
964
|
+
disabled: command.pending,
|
|
965
|
+
})), ariaLabel: labels.suggestions, onSelect: selectSuggestion, className: "agentkit-suggestions" }))) : null, _jsx(PromptComposer, { rootClassName: "agentkit-composer", layoutVariant: "default", draftScope: `agentkit:${threadId}`, ariaLabel: labels.composerLabel, placeholder: labels.composerPlaceholder, autoFocus: autoFocus, composerRef: composerRef, submitting: command.pending, willQueue: active && queueWhileRunning && canQueue, showModelSelector: showModelSelector && canSelectModel, attachmentsEnabled: canUpload, slashCommands: slashCommands, slashSkills: slashSkills, includeDefaultSlashCommands: includeDefaultSlashCommands ?? false, includeDefaultSlashSkills: includeDefaultSlashSkills ?? false, onSlashCommand: onSlashCommand, plusMenuMode: plusMenuMode ?? (canUpload ? "upload-only" : "hidden"), voiceEnabled: voiceEnabled, execMode: executionMode === "plan" ? "plan" : "build", onExecModeChange: (nextMode) => {
|
|
966
|
+
const next = nextMode === "plan" ? "plan" : "act";
|
|
967
|
+
if (mode === undefined)
|
|
968
|
+
setUncontrolledMode(next);
|
|
969
|
+
onModeChange?.(next);
|
|
970
|
+
}, onSubmit: (text, files, references, options) => {
|
|
971
|
+
const submission = command.execute(async () => {
|
|
972
|
+
const attachments = files.length && canUpload
|
|
973
|
+
? await control.uploadFiles(files.map((file) => ({
|
|
974
|
+
name: file.name,
|
|
975
|
+
mediaType: file.type || "application/octet-stream",
|
|
976
|
+
size: file.size,
|
|
977
|
+
body: file,
|
|
978
|
+
})))
|
|
979
|
+
: [];
|
|
980
|
+
const effort = options.effort;
|
|
981
|
+
const runOptions = {
|
|
982
|
+
model: options.model,
|
|
983
|
+
mode: executionMode,
|
|
984
|
+
reasoningEffort: effort && !["auto", "max"].includes(effort)
|
|
985
|
+
? effort
|
|
986
|
+
: undefined,
|
|
987
|
+
};
|
|
988
|
+
const metadata = references.length ? { references } : undefined;
|
|
989
|
+
if (active && queueWhileRunning && canQueue) {
|
|
990
|
+
await control.queueMessage({ text, attachments, metadata });
|
|
991
|
+
}
|
|
992
|
+
else {
|
|
993
|
+
await control.sendMessage({
|
|
994
|
+
text,
|
|
995
|
+
attachments,
|
|
996
|
+
options: runOptions,
|
|
997
|
+
metadata,
|
|
998
|
+
});
|
|
999
|
+
}
|
|
1000
|
+
});
|
|
1001
|
+
focusComposer();
|
|
1002
|
+
void submission.catch(() => undefined).finally(focusComposer);
|
|
1003
|
+
} }), command.error ? (_jsxs("div", { className: "agentkit-composer-error", role: "alert", children: [_jsx(IconAlertCircle, { "aria-hidden": "true", className: "agentkit-icon" }), _jsx("span", { children: command.error.message })] })) : null] }));
|
|
1004
|
+
}
|
|
1005
|
+
const AGENTKIT_TRANSCRIPT_BOTTOM_THRESHOLD = 24;
|
|
1006
|
+
const AGENTKIT_TRANSCRIPT_SCROLLBAR_IDLE_MS = 900;
|
|
1007
|
+
const AGENTKIT_TRANSCRIPT_SCROLL_KEYS = new Set([
|
|
1008
|
+
"ArrowDown",
|
|
1009
|
+
"ArrowUp",
|
|
1010
|
+
"End",
|
|
1011
|
+
"Home",
|
|
1012
|
+
"PageDown",
|
|
1013
|
+
"PageUp",
|
|
1014
|
+
" ",
|
|
1015
|
+
]);
|
|
1016
|
+
export function isAgentKitTranscriptNearBottom(element, threshold = AGENTKIT_TRANSCRIPT_BOTTOM_THRESHOLD) {
|
|
1017
|
+
return (element.scrollHeight - element.clientHeight - element.scrollTop <= threshold);
|
|
1018
|
+
}
|
|
1019
|
+
export function AgentKitChat({ title, toolbar, composer = true, composerProps, emptyComposerPlacement = "center", autoScroll = true, className, }) {
|
|
1020
|
+
const { threadId, slots, labels } = useAgentKit();
|
|
1021
|
+
const connection = useAgentConnection();
|
|
1022
|
+
const control = useAgentKitControl(threadId);
|
|
1023
|
+
const recovery = useAgentKitMutation(() => control.load(), threadId);
|
|
1024
|
+
const thread = useAgentThread(threadId);
|
|
1025
|
+
const hasConversation = thread.messages.length > 0;
|
|
1026
|
+
const Message = slots.message ?? AgentMessageView;
|
|
1027
|
+
const EmptyState = slots.emptyState;
|
|
1028
|
+
const Composer = slots.composer ?? AgentKitComposer;
|
|
1029
|
+
const approvalEntries = Object.entries(thread.approvals);
|
|
1030
|
+
const connectionRequestEntries = Object.entries(thread.connectionRequests ?? {});
|
|
1031
|
+
const ErrorState = slots.connectionError ?? AgentConnectionErrorView;
|
|
1032
|
+
const RunFailure = slots.runFailure ?? AgentRunFailure;
|
|
1033
|
+
const Approval = slots.approval;
|
|
1034
|
+
const ConnectionRequest = slots.connectionRequest;
|
|
1035
|
+
const Header = slots.header;
|
|
1036
|
+
const Toolbar = slots.toolbar;
|
|
1037
|
+
const Transcript = slots.transcript;
|
|
1038
|
+
const Footer = slots.footer;
|
|
1039
|
+
const transcriptRef = useRef(null);
|
|
1040
|
+
const transcriptContentRef = useRef(null);
|
|
1041
|
+
const followsTranscriptRef = useRef(true);
|
|
1042
|
+
const transcriptThreadIdRef = useRef(threadId);
|
|
1043
|
+
const previousLastMessageIdRef = useRef(undefined);
|
|
1044
|
+
const transcriptFollowFrameRef = useRef(undefined);
|
|
1045
|
+
const transcriptScrollbarInteractionRef = useRef(false);
|
|
1046
|
+
const transcriptScrollbarTimeoutRef = useRef(undefined);
|
|
1047
|
+
const [transcriptScrollbarVisible, setTranscriptScrollbarVisible] = useState(false);
|
|
1048
|
+
const lastMessage = thread.messages.at(-1);
|
|
1049
|
+
const lastEventId = thread.events.at(-1)?.id;
|
|
1050
|
+
const connectionError = connection.status === "error" ? connection.error : undefined;
|
|
1051
|
+
const clearTranscriptScrollbarTimeout = useCallback(() => {
|
|
1052
|
+
if (transcriptScrollbarTimeoutRef.current === undefined)
|
|
1053
|
+
return;
|
|
1054
|
+
clearTimeout(transcriptScrollbarTimeoutRef.current);
|
|
1055
|
+
transcriptScrollbarTimeoutRef.current = undefined;
|
|
1056
|
+
}, []);
|
|
1057
|
+
const hideTranscriptScrollbar = useCallback(() => {
|
|
1058
|
+
clearTranscriptScrollbarTimeout();
|
|
1059
|
+
transcriptScrollbarInteractionRef.current = false;
|
|
1060
|
+
setTranscriptScrollbarVisible(false);
|
|
1061
|
+
}, [clearTranscriptScrollbarTimeout]);
|
|
1062
|
+
const scheduleTranscriptScrollbarHide = useCallback(() => {
|
|
1063
|
+
clearTranscriptScrollbarTimeout();
|
|
1064
|
+
transcriptScrollbarTimeoutRef.current = setTimeout(() => {
|
|
1065
|
+
transcriptScrollbarTimeoutRef.current = undefined;
|
|
1066
|
+
transcriptScrollbarInteractionRef.current = false;
|
|
1067
|
+
setTranscriptScrollbarVisible(false);
|
|
1068
|
+
}, AGENTKIT_TRANSCRIPT_SCROLLBAR_IDLE_MS);
|
|
1069
|
+
}, [clearTranscriptScrollbarTimeout]);
|
|
1070
|
+
const revealTranscriptScrollbar = useCallback(() => {
|
|
1071
|
+
const transcript = transcriptRef.current;
|
|
1072
|
+
if (!transcript || transcript.scrollHeight <= transcript.clientHeight)
|
|
1073
|
+
return;
|
|
1074
|
+
transcriptScrollbarInteractionRef.current = true;
|
|
1075
|
+
setTranscriptScrollbarVisible(true);
|
|
1076
|
+
scheduleTranscriptScrollbarHide();
|
|
1077
|
+
}, [scheduleTranscriptScrollbarHide]);
|
|
1078
|
+
const scrollTranscriptToBottom = useCallback(() => {
|
|
1079
|
+
const transcript = transcriptRef.current;
|
|
1080
|
+
if (!autoScroll || !transcript || !followsTranscriptRef.current)
|
|
1081
|
+
return;
|
|
1082
|
+
const nextScrollTop = Math.max(0, transcript.scrollHeight - transcript.clientHeight);
|
|
1083
|
+
if (Math.abs(transcript.scrollTop - nextScrollTop) <= 1)
|
|
1084
|
+
return;
|
|
1085
|
+
transcript.scrollTop = nextScrollTop;
|
|
1086
|
+
}, [autoScroll]);
|
|
1087
|
+
const cancelScheduledTranscriptFollow = useCallback(() => {
|
|
1088
|
+
if (transcriptFollowFrameRef.current === undefined)
|
|
1089
|
+
return;
|
|
1090
|
+
if (typeof globalThis.cancelAnimationFrame === "function") {
|
|
1091
|
+
globalThis.cancelAnimationFrame(transcriptFollowFrameRef.current);
|
|
1092
|
+
}
|
|
1093
|
+
transcriptFollowFrameRef.current = undefined;
|
|
1094
|
+
}, []);
|
|
1095
|
+
const scheduleTranscriptFollow = useCallback(() => {
|
|
1096
|
+
if (!autoScroll || transcriptFollowFrameRef.current !== undefined)
|
|
1097
|
+
return;
|
|
1098
|
+
if (typeof globalThis.requestAnimationFrame !== "function") {
|
|
1099
|
+
scrollTranscriptToBottom();
|
|
1100
|
+
return;
|
|
1101
|
+
}
|
|
1102
|
+
transcriptFollowFrameRef.current = globalThis.requestAnimationFrame(() => {
|
|
1103
|
+
transcriptFollowFrameRef.current = undefined;
|
|
1104
|
+
scrollTranscriptToBottom();
|
|
1105
|
+
});
|
|
1106
|
+
}, [autoScroll, scrollTranscriptToBottom]);
|
|
1107
|
+
useEffect(() => () => {
|
|
1108
|
+
clearTranscriptScrollbarTimeout();
|
|
1109
|
+
cancelScheduledTranscriptFollow();
|
|
1110
|
+
}, [cancelScheduledTranscriptFollow, clearTranscriptScrollbarTimeout]);
|
|
1111
|
+
useLayoutEffect(() => {
|
|
1112
|
+
if (transcriptThreadIdRef.current !== threadId) {
|
|
1113
|
+
transcriptThreadIdRef.current = threadId;
|
|
1114
|
+
previousLastMessageIdRef.current = undefined;
|
|
1115
|
+
followsTranscriptRef.current = true;
|
|
1116
|
+
hideTranscriptScrollbar();
|
|
1117
|
+
}
|
|
1118
|
+
const previousLastMessageId = previousLastMessageIdRef.current;
|
|
1119
|
+
previousLastMessageIdRef.current = lastMessage?.id;
|
|
1120
|
+
if (!autoScroll)
|
|
1121
|
+
return;
|
|
1122
|
+
if (lastMessage?.role === "user" &&
|
|
1123
|
+
lastMessage.id !== previousLastMessageId) {
|
|
1124
|
+
followsTranscriptRef.current = true;
|
|
1125
|
+
hideTranscriptScrollbar();
|
|
1126
|
+
}
|
|
1127
|
+
scrollTranscriptToBottom();
|
|
1128
|
+
}, [
|
|
1129
|
+
autoScroll,
|
|
1130
|
+
hideTranscriptScrollbar,
|
|
1131
|
+
lastEventId,
|
|
1132
|
+
lastMessage?.id,
|
|
1133
|
+
lastMessage?.role,
|
|
1134
|
+
scrollTranscriptToBottom,
|
|
1135
|
+
threadId,
|
|
1136
|
+
]);
|
|
1137
|
+
useLayoutEffect(() => {
|
|
1138
|
+
const transcript = transcriptRef.current;
|
|
1139
|
+
const content = transcriptContentRef.current;
|
|
1140
|
+
if (!autoScroll ||
|
|
1141
|
+
!transcript ||
|
|
1142
|
+
!content ||
|
|
1143
|
+
typeof ResizeObserver === "undefined") {
|
|
1144
|
+
return;
|
|
1145
|
+
}
|
|
1146
|
+
const observer = new ResizeObserver(scheduleTranscriptFollow);
|
|
1147
|
+
observer.observe(transcript);
|
|
1148
|
+
observer.observe(content);
|
|
1149
|
+
return () => {
|
|
1150
|
+
observer.disconnect();
|
|
1151
|
+
cancelScheduledTranscriptFollow();
|
|
1152
|
+
};
|
|
1153
|
+
}, [
|
|
1154
|
+
autoScroll,
|
|
1155
|
+
cancelScheduledTranscriptFollow,
|
|
1156
|
+
scheduleTranscriptFollow,
|
|
1157
|
+
threadId,
|
|
1158
|
+
]);
|
|
1159
|
+
const handleTranscriptScroll = useCallback(() => {
|
|
1160
|
+
const transcript = transcriptRef.current;
|
|
1161
|
+
if (!transcript)
|
|
1162
|
+
return;
|
|
1163
|
+
if (autoScroll && transcriptScrollbarInteractionRef.current) {
|
|
1164
|
+
followsTranscriptRef.current = isAgentKitTranscriptNearBottom(transcript);
|
|
1165
|
+
}
|
|
1166
|
+
if (transcriptScrollbarInteractionRef.current) {
|
|
1167
|
+
scheduleTranscriptScrollbarHide();
|
|
1168
|
+
}
|
|
1169
|
+
}, [autoScroll, scheduleTranscriptScrollbarHide]);
|
|
1170
|
+
const handleTranscriptPointerDown = useCallback((event) => {
|
|
1171
|
+
const bounds = event.currentTarget.getBoundingClientRect();
|
|
1172
|
+
const edgeDistance = Math.min(Math.abs(event.clientX - bounds.left), Math.abs(bounds.right - event.clientX));
|
|
1173
|
+
if (edgeDistance <= 12)
|
|
1174
|
+
revealTranscriptScrollbar();
|
|
1175
|
+
}, [revealTranscriptScrollbar]);
|
|
1176
|
+
const handleTranscriptKeyDown = useCallback((event) => {
|
|
1177
|
+
if (AGENTKIT_TRANSCRIPT_SCROLL_KEYS.has(event.key)) {
|
|
1178
|
+
revealTranscriptScrollbar();
|
|
1179
|
+
}
|
|
1180
|
+
}, [revealTranscriptScrollbar]);
|
|
1181
|
+
const messageRunIds = useMemo(() => {
|
|
1182
|
+
const result = new Map();
|
|
1183
|
+
for (const event of thread.events) {
|
|
1184
|
+
if (event.type === "message.created" ||
|
|
1185
|
+
event.type === "message.completed") {
|
|
1186
|
+
result.set(event.message.id, event.runId);
|
|
1187
|
+
}
|
|
1188
|
+
if (event.type === "message.delta" || event.type === "reasoning.delta") {
|
|
1189
|
+
result.set(event.messageId, event.runId);
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
return result;
|
|
1193
|
+
}, [thread.events]);
|
|
1194
|
+
const messageBoundarySequences = useMemo(() => {
|
|
1195
|
+
const result = new Map();
|
|
1196
|
+
const assistantMessageIds = new Set(thread.messages
|
|
1197
|
+
.filter((message) => message.role === "assistant")
|
|
1198
|
+
.map((message) => message.id));
|
|
1199
|
+
for (const event of thread.events) {
|
|
1200
|
+
if (!messageEventHasVisibleAssistantOutput(event, assistantMessageIds)) {
|
|
1201
|
+
continue;
|
|
1202
|
+
}
|
|
1203
|
+
const messageId = event.type === "message.created" || event.type === "message.completed"
|
|
1204
|
+
? event.message.id
|
|
1205
|
+
: event.type === "message.delta"
|
|
1206
|
+
? event.messageId
|
|
1207
|
+
: undefined;
|
|
1208
|
+
if (!messageId)
|
|
1209
|
+
continue;
|
|
1210
|
+
result.set(messageId, Math.min(result.get(messageId) ?? Infinity, event.sequence));
|
|
1211
|
+
}
|
|
1212
|
+
return result;
|
|
1213
|
+
}, [thread.events, thread.messages]);
|
|
1214
|
+
const lastAssistantMessagesByRun = useMemo(() => {
|
|
1215
|
+
const result = new Map();
|
|
1216
|
+
for (const message of thread.messages) {
|
|
1217
|
+
const runId = messageRunIds.get(message.id);
|
|
1218
|
+
const sequence = messageBoundarySequences.get(message.id);
|
|
1219
|
+
if (runId && message.role === "assistant" && sequence !== undefined) {
|
|
1220
|
+
result.set(runId, { id: message.id, sequence });
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
return result;
|
|
1224
|
+
}, [messageBoundarySequences, messageRunIds, thread.messages]);
|
|
1225
|
+
const failedRuns = useMemo(() => {
|
|
1226
|
+
const result = new Map();
|
|
1227
|
+
for (const run of Object.values(thread.runs)) {
|
|
1228
|
+
if (run.status === "failed" && run.error) {
|
|
1229
|
+
result.set(run.id, run.error);
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
return result;
|
|
1233
|
+
}, [thread.runs]);
|
|
1234
|
+
const runWorkStarts = useMemo(() => firstWorkEvents(thread.events), [thread.events]);
|
|
1235
|
+
const hasRunWork = (runId, afterSequence, throughSequence) => runWorkStarts.some((event) => event.runId === runId &&
|
|
1236
|
+
sequenceInRange(event.sequence, { afterSequence, throughSequence }));
|
|
1237
|
+
const pendingRunIds = Array.from(new Set(runWorkStarts
|
|
1238
|
+
.filter((event) => {
|
|
1239
|
+
const boundary = lastAssistantMessagesByRun.get(event.runId);
|
|
1240
|
+
return boundary === undefined || event.sequence > boundary.sequence;
|
|
1241
|
+
})
|
|
1242
|
+
.map((event) => event.runId)));
|
|
1243
|
+
const pendingRuns = new Set(pendingRunIds);
|
|
1244
|
+
const renderRunFailure = (runId) => {
|
|
1245
|
+
const error = failedRuns.get(runId);
|
|
1246
|
+
return error ? (_jsx(RunFailure, { error: error, runId: runId, threadId: threadId })) : null;
|
|
1247
|
+
};
|
|
1248
|
+
const renderRunWork = ({ runId, anchor, afterSequence, throughSequence, }) => (_jsxs(AgentKitSurfaceBoundary, { surface: "activity", resetKey: `${runId}:${anchor}:${thread.events.length}`, children: [_jsx(AgentCollaborationFeed, { runId: runId, afterSequence: afterSequence, throughSequence: throughSequence }), _jsx(AgentTaskGroup, { runId: runId, afterSequence: afterSequence, throughSequence: throughSequence }), _jsx(AgentActivityGroup, { runId: runId, afterSequence: afterSequence, throughSequence: throughSequence, excludeAgentActivities: true })] }, `run-work:${runId}:${anchor}`));
|
|
1249
|
+
const transcriptItems = [];
|
|
1250
|
+
const previousAssistantByRun = new Map();
|
|
1251
|
+
for (const message of thread.messages) {
|
|
1252
|
+
const runId = messageRunIds.get(message.id);
|
|
1253
|
+
const sequence = messageBoundarySequences.get(message.id);
|
|
1254
|
+
const isAssistantBoundary = message.role === "assistant" &&
|
|
1255
|
+
runId !== undefined &&
|
|
1256
|
+
sequence !== undefined;
|
|
1257
|
+
const previousAssistant = isAssistantBoundary && runId
|
|
1258
|
+
? previousAssistantByRun.get(runId)
|
|
1259
|
+
: undefined;
|
|
1260
|
+
if (isAssistantBoundary &&
|
|
1261
|
+
runId &&
|
|
1262
|
+
hasRunWork(runId, previousAssistant?.sequence, sequence)) {
|
|
1263
|
+
transcriptItems.push(renderRunWork({
|
|
1264
|
+
runId,
|
|
1265
|
+
anchor: previousAssistant?.id ?? "start",
|
|
1266
|
+
afterSequence: previousAssistant?.sequence,
|
|
1267
|
+
throughSequence: sequence,
|
|
1268
|
+
}));
|
|
1269
|
+
}
|
|
1270
|
+
transcriptItems.push(_jsx(AgentKitSurfaceBoundary, { surface: "message", resetKey: `${message.id}:${thread.events.length}`, children: _jsx(Message, { value: message, threadId: threadId }) }, `message:${message.id}`));
|
|
1271
|
+
if (isAssistantBoundary && runId) {
|
|
1272
|
+
previousAssistantByRun.set(runId, { id: message.id, sequence });
|
|
1273
|
+
}
|
|
1274
|
+
const concludesRun = isAssistantBoundary &&
|
|
1275
|
+
runId !== undefined &&
|
|
1276
|
+
lastAssistantMessagesByRun.get(runId)?.id === message.id;
|
|
1277
|
+
if (concludesRun && !pendingRuns.has(runId) && failedRuns.has(runId)) {
|
|
1278
|
+
transcriptItems.push(_jsx(AgentKitSurfaceBoundary, { surface: "activity", resetKey: `${runId}:${thread.events.length}`, children: renderRunFailure(runId) }, `run-failure:${runId}`));
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
for (const runId of pendingRunIds) {
|
|
1282
|
+
const boundary = lastAssistantMessagesByRun.get(runId);
|
|
1283
|
+
transcriptItems.push(renderRunWork({
|
|
1284
|
+
runId,
|
|
1285
|
+
anchor: boundary?.id ?? "start",
|
|
1286
|
+
afterSequence: boundary?.sequence,
|
|
1287
|
+
}));
|
|
1288
|
+
if (failedRuns.has(runId)) {
|
|
1289
|
+
transcriptItems.push(_jsx(AgentKitSurfaceBoundary, { surface: "activity", resetKey: `${runId}:${thread.events.length}`, children: renderRunFailure(runId) }, `run-failure:${runId}`));
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
for (const [runId] of failedRuns) {
|
|
1293
|
+
if (lastAssistantMessagesByRun.has(runId) || pendingRuns.has(runId)) {
|
|
1294
|
+
continue;
|
|
1295
|
+
}
|
|
1296
|
+
transcriptItems.push(_jsx(AgentKitSurfaceBoundary, { surface: "activity", resetKey: `${runId}:${thread.events.length}`, children: renderRunFailure(runId) }, `run-failure:${runId}`));
|
|
1297
|
+
}
|
|
1298
|
+
return (_jsxs("section", { "aria-label": typeof title === "string" ? title : labels.conversation, className: `agentkit-chat ${className ?? ""}`, "data-empty": !hasConversation, "data-empty-composer-placement": emptyComposerPlacement, children: [hasConversation && (title || toolbar) ? (_jsx(AgentKitSurfaceBoundary, { surface: "header", resetKey: threadId, children: _jsx(AgentKitRegionSlot, { slot: Header, threadId: threadId, children: _jsxs("header", { className: "agentkit-chat-header", children: [_jsx("div", { className: "agentkit-chat-title", children: title }), _jsx(AgentKitRegionSlot, { slot: Toolbar, threadId: threadId, children: _jsx("div", { className: "agentkit-chat-toolbar", children: toolbar }) })] }) }) })) : null, _jsx("div", { ref: transcriptRef, className: "agentkit-transcript", "aria-live": "off", "data-scrollbar-visible": transcriptScrollbarVisible, onKeyDown: handleTranscriptKeyDown, onPointerDown: handleTranscriptPointerDown, onScroll: handleTranscriptScroll, onTouchMove: revealTranscriptScrollbar, onWheel: revealTranscriptScrollbar, children: _jsx("div", { ref: transcriptContentRef, className: "agentkit-transcript-content", children: _jsxs(AgentKitRegionSlot, { slot: Transcript, threadId: threadId, children: [!hasConversation && EmptyState ? (_jsx(EmptyState, { threadId: threadId })) : null, transcriptItems, approvalEntries.map(([approvalId, request]) => (_jsx(AgentKitSurfaceBoundary, { surface: "approval", resetKey: `${approvalId}:${thread.events.length}`, children: Approval ? (_jsx(Approval, { value: request, threadId: threadId, runId: thread.approvalRunIds[approvalId] ?? "" })) : (_jsx(AgentApprovalPrompt, { request: request, runId: thread.approvalRunIds[approvalId] ?? "" })) }, approvalId))), connectionRequestEntries.map(([requestId, request]) => (_jsx(AgentKitSurfaceBoundary, { surface: "connection-request", resetKey: `${requestId}:${request.status}`, children: ConnectionRequest ? (_jsx(ConnectionRequest, { value: request, threadId: threadId, runId: thread.connectionRequestRunIds[requestId] ?? "" })) : (_jsx(AgentConnectionRequestCard, { request: request, runId: thread.connectionRequestRunIds[requestId] ?? "" })) }, requestId))), connectionError ? (_jsx(AgentKitSurfaceBoundary, { surface: "connection-error", resetKey: `${threadId}:${connectionError.code}`, children: _jsx(ErrorState, { error: connectionError, threadId: threadId, recover: recovery.execute, recovering: recovery.pending, recoveryError: recovery.error }) })) : null] }) }) }), composer ? (_jsx("footer", { className: "agentkit-chat-footer", children: _jsx(AgentKitSurfaceBoundary, { surface: "composer", resetKey: threadId, children: _jsx(AgentKitRegionSlot, { slot: Footer, threadId: threadId, children: slots.composer ? (_jsx(Composer, { threadId: threadId })) : (_jsx(AgentKitComposer, { ...composerProps, threadId: threadId })) }) }) })) : null] }));
|
|
1299
|
+
}
|
|
1300
|
+
//# sourceMappingURL=components.js.map
|