cortena-ui 1.5.0 → 1.7.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/CHANGELOG.md +183 -0
- package/README.md +122 -2
- package/dist/agent-chat/bridge.js +8 -4
- package/dist/agent-chat/bridge.js.map +1 -1
- package/dist/agent-chat/session.d.ts +22 -1
- package/dist/agent-chat/session.js +164 -8
- package/dist/agent-chat/session.js.map +1 -1
- package/dist/agent-chat/step-label.d.ts +99 -0
- package/dist/agent-chat/step-label.js +116 -0
- package/dist/agent-chat/step-label.js.map +1 -0
- package/dist/agent-chat/store.d.ts +90 -4
- package/dist/agent-chat/store.js +421 -28
- package/dist/agent-chat/store.js.map +1 -1
- package/dist/agent-chat/types.d.ts +101 -0
- package/dist/agent-chat/types.js.map +1 -1
- package/dist/agent-chat.d.ts +6 -5
- package/dist/agent-chat.js +5 -4
- package/dist/components/agent-chat-popup.d.ts +2 -2
- package/dist/components/agent-chat-popup.js.map +1 -1
- package/dist/components/agent-chat.d.ts +191 -15
- package/dist/components/agent-chat.js +300 -32
- package/dist/components/agent-chat.js.map +1 -1
- package/dist/components/badge.d.ts +1 -1
- package/dist/components/button.d.ts +1 -1
- package/dist/components/toast.d.ts +1 -1
- package/package.json +3 -2
- package/src/agent-chat/bridge.ts +17 -5
- package/src/agent-chat/session.ts +193 -6
- package/src/agent-chat/step-label.ts +177 -0
- package/src/agent-chat/store.ts +692 -24
- package/src/agent-chat/types.ts +106 -0
- package/src/components/agent-chat-popup.tsx +3 -3
- package/src/components/agent-chat.tsx +737 -147
- package/src/entries/agent-chat.ts +38 -2
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { A2UIAction } from "../a2ui/message.js";
|
|
3
3
|
import { A2UIChatBlock } from "../agent-chat/a2ui-block.js";
|
|
4
|
-
import { AgentApprovalRequest, AgentChatClient, AgentChatMessage, AgentSession } from "../agent-chat/types.js";
|
|
5
|
-
import { AgentToolEntry } from "../agent-chat/store.js";
|
|
4
|
+
import { AgentApprovalDecision, AgentApprovalRequest, AgentChatClient, AgentChatMessage, AgentChatStep, AgentSession } from "../agent-chat/types.js";
|
|
5
|
+
import { AgentToolEntry, UseAgentChatResult } from "../agent-chat/store.js";
|
|
6
6
|
import * as React from "react";
|
|
7
7
|
//#region src/components/agent-chat.d.ts
|
|
8
8
|
/**
|
|
@@ -26,6 +26,24 @@ export interface AgentThinkingProps {
|
|
|
26
26
|
streaming?: boolean;
|
|
27
27
|
}
|
|
28
28
|
declare function AgentThinking({ text, defaultOpen, streaming }: AgentThinkingProps): React.JSX.Element | null;
|
|
29
|
+
export interface AgentStepsProps {
|
|
30
|
+
steps: readonly AgentChatStep[];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* What the agent is doing, one plain sentence per tool call (SKILLS-9).
|
|
34
|
+
*
|
|
35
|
+
* This is the surface a person watches while they wait, and it is deliberately
|
|
36
|
+
* not the tool strip: the strip is the record — names, arguments, output, the
|
|
37
|
+
* MCP App seam — and reading it requires knowing what `broker_invoke` is. The
|
|
38
|
+
* strip stays at the foot for anyone who wants the detail.
|
|
39
|
+
*
|
|
40
|
+
* NOT a live region of its own. The strip is drawn inside the transcript, and
|
|
41
|
+
* the transcript is already `role="log" aria-live="polite"` — two nested live
|
|
42
|
+
* regions is one announcement per change from the inner one and another from
|
|
43
|
+
* the outer, which is how a screen reader ends up saying every step twice.
|
|
44
|
+
* `aria-label` stays: it names the group for anyone who navigates to it.
|
|
45
|
+
*/
|
|
46
|
+
declare function AgentSteps({ steps }: AgentStepsProps): React.JSX.Element | null;
|
|
29
47
|
export interface AgentA2UIBlocksProps {
|
|
30
48
|
blocks: readonly A2UIChatBlock[] | undefined;
|
|
31
49
|
/** Set on the streaming bubble: actions are disabled while the turn is live. */
|
|
@@ -59,6 +77,8 @@ export interface AgentStreamingBubbleProps {
|
|
|
59
77
|
text: string;
|
|
60
78
|
thinkingText: string;
|
|
61
79
|
a2ui: readonly A2UIChatBlock[];
|
|
80
|
+
/** The turn's tool calls in plain words, drawn under the agent's name. */
|
|
81
|
+
steps?: readonly AgentChatStep[];
|
|
62
82
|
}
|
|
63
83
|
/**
|
|
64
84
|
* The assistant bubble while a turn is live.
|
|
@@ -69,7 +89,7 @@ export interface AgentStreamingBubbleProps {
|
|
|
69
89
|
* (`**bo`) looks worse than its raw form — so the streaming view is plain text
|
|
70
90
|
* under `whitespace-pre-wrap` and `Markdown` takes over on `final`.
|
|
71
91
|
*/
|
|
72
|
-
declare function AgentStreamingBubble({ agentName, text, thinkingText, a2ui }: AgentStreamingBubbleProps): React.JSX.Element;
|
|
92
|
+
declare function AgentStreamingBubble({ agentName, text, thinkingText, a2ui, steps }: AgentStreamingBubbleProps): React.JSX.Element;
|
|
73
93
|
/** A `ui://` resource in a tool result is an MCP App: the extension's own screen. */
|
|
74
94
|
export declare function readMcpAppUri(output: unknown): string | null;
|
|
75
95
|
export interface AgentToolCardProps {
|
|
@@ -98,19 +118,118 @@ export interface AgentToolRenderContext {
|
|
|
98
118
|
/** The `ui://` resource this result carries, when it carries one. */
|
|
99
119
|
mcpAppUri: string | null;
|
|
100
120
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
121
|
+
/**
|
|
122
|
+
* What a host's own message bubble receives. `index` and `messages` are over
|
|
123
|
+
* the VISIBLE messages — the filter chain has already run — so
|
|
124
|
+
* `messages[index - 1]` is the turn before this one, which a feedback control
|
|
125
|
+
* or a transcript export wants.
|
|
126
|
+
*/
|
|
127
|
+
export interface AgentChatMessageSlotProps {
|
|
128
|
+
message: AgentChatMessage;
|
|
129
|
+
index: number;
|
|
130
|
+
messages: readonly AgentChatMessage[];
|
|
131
|
+
agentName: string;
|
|
132
|
+
sessionKey: string | null;
|
|
133
|
+
/** True while a run is live; every A2UI surface goes read-only. */
|
|
134
|
+
streaming: boolean;
|
|
135
|
+
onAction: (action: A2UIAction) => void;
|
|
136
|
+
}
|
|
137
|
+
export interface AgentChatStreamingSlotProps {
|
|
138
|
+
agentName: string;
|
|
139
|
+
text: string;
|
|
140
|
+
thinkingText: string;
|
|
141
|
+
a2ui: readonly A2UIChatBlock[];
|
|
142
|
+
/** The turn's tool calls in plain words; the default draws them under the name. */
|
|
143
|
+
steps: readonly AgentChatStep[];
|
|
144
|
+
}
|
|
145
|
+
export interface AgentChatEmptySlotProps {
|
|
105
146
|
agentName: string;
|
|
147
|
+
/** A history load is in flight for this session; a skeleton fits here. */
|
|
148
|
+
loadingHistory: boolean;
|
|
149
|
+
}
|
|
150
|
+
export interface AgentChatLoadOlderSlotProps {
|
|
151
|
+
hasMore: boolean;
|
|
152
|
+
loading: boolean;
|
|
153
|
+
onLoad: () => void;
|
|
154
|
+
}
|
|
155
|
+
export interface AgentChatToolsSlotProps {
|
|
156
|
+
entries: readonly AgentToolEntry[];
|
|
157
|
+
approvals: readonly AgentApprovalRequest[];
|
|
158
|
+
streaming: boolean;
|
|
106
159
|
/**
|
|
107
|
-
*
|
|
108
|
-
*
|
|
160
|
+
* The host's `renderToolCall`, as it was passed: `undefined` for a call the
|
|
161
|
+
* host declines, so the slot can draw its own line for those and still mount
|
|
162
|
+
* an MCP App through the one seam the component defines.
|
|
109
163
|
*/
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
164
|
+
renderToolCall: ((context: AgentToolRenderContext) => React.ReactNode | undefined) | undefined;
|
|
165
|
+
onResolveApproval: (id: string, decision: AgentApprovalDecision) => void;
|
|
166
|
+
}
|
|
167
|
+
export interface AgentChatComposerSlotProps {
|
|
168
|
+
agentName: string;
|
|
169
|
+
streaming: boolean;
|
|
170
|
+
send: UseAgentChatResult["send"];
|
|
171
|
+
abort: () => void;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Renders a host may substitute for the component's own, one region each.
|
|
175
|
+
*
|
|
176
|
+
* The surface — its state, the order of its regions, the scroller that stays
|
|
177
|
+
* pinned to the bottom, the sentinel that pages history, the steps and the
|
|
178
|
+
* tool-card seam — is shared; what each region LOOKS like need not be. This is
|
|
179
|
+
* how cortenaweb draws its own bubble (Shiki, KaTeX, feedback controls, a
|
|
180
|
+
* timestamp chip) and its own composer (attachments, agent and model
|
|
181
|
+
* selectors) on the shared surface instead of keeping a second chat
|
|
182
|
+
* (PLATFORM-64).
|
|
183
|
+
*
|
|
184
|
+
* A component given here replaces its region whole, wrapper included; nothing
|
|
185
|
+
* of the default is drawn around it.
|
|
186
|
+
*/
|
|
187
|
+
export interface AgentChatComponents {
|
|
188
|
+
Message: React.ComponentType<AgentChatMessageSlotProps>;
|
|
189
|
+
/**
|
|
190
|
+
* The live bubble. It is handed `steps` because the default draws the
|
|
191
|
+
* progress steps INSIDE the streaming bubble; a host's own bubble draws them
|
|
192
|
+
* itself, or not at all — nothing else draws them while a run is live.
|
|
193
|
+
*/
|
|
194
|
+
Streaming: React.ComponentType<AgentChatStreamingSlotProps>;
|
|
195
|
+
/**
|
|
196
|
+
* Replaces the whole transcript region while there is nothing to show. Not
|
|
197
|
+
* while there is an error: the transcript then mounts with the error banner
|
|
198
|
+
* in it, so a failure before the first message is not hidden behind the
|
|
199
|
+
* host's welcome screen.
|
|
200
|
+
*/
|
|
201
|
+
Empty: React.ComponentType<AgentChatEmptySlotProps>;
|
|
202
|
+
/** Drawn at the top of the transcript while there is, or may be, more. */
|
|
203
|
+
LoadOlder: React.ComponentType<AgentChatLoadOlderSlotProps>;
|
|
204
|
+
/** Replaces the tool strip and the approval cards at the foot. */
|
|
205
|
+
Tools: React.ComponentType<AgentChatToolsSlotProps>;
|
|
206
|
+
Composer: React.ComponentType<AgentChatComposerSlotProps>;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Class names for the wrappers a host cannot otherwise reach.
|
|
210
|
+
*
|
|
211
|
+
* `transcript` REPLACES the default spacing (`gap-5 px-4 py-4`) rather than
|
|
212
|
+
* merging with it: a reading column sets its own gutter through a class, and a
|
|
213
|
+
* utility left on the element would fight it. The structural classes — flex,
|
|
214
|
+
* min-width — stay in either case.
|
|
215
|
+
*/
|
|
216
|
+
export interface AgentChatClassNames {
|
|
217
|
+
header?: string;
|
|
218
|
+
scroll?: string;
|
|
219
|
+
transcript?: string;
|
|
220
|
+
/**
|
|
221
|
+
* The history sentinel at the top of the transcript. Out of the flow by
|
|
222
|
+
* default (`absolute inset-x-0 top-0 h-px`), so it adds no space; a host
|
|
223
|
+
* whose column already reserved a row for it passes an in-flow class.
|
|
224
|
+
*/
|
|
225
|
+
sentinel?: string;
|
|
226
|
+
tools?: string;
|
|
227
|
+
composer?: string;
|
|
228
|
+
}
|
|
229
|
+
/** What every `AgentChat` takes, however its state is owned. */
|
|
230
|
+
export interface AgentChatBaseProps extends Omit<React.ComponentProps<"div">, "children" | "onError"> {
|
|
231
|
+
/** The extension name, shown on each assistant turn. */
|
|
232
|
+
agentName: string;
|
|
114
233
|
/** Rendered between the tool strip and the composer — an attachment picker. */
|
|
115
234
|
attachmentsSlot?: React.ReactNode;
|
|
116
235
|
/**
|
|
@@ -121,8 +240,65 @@ export interface AgentChatProps extends Omit<React.ComponentProps<"div">, "child
|
|
|
121
240
|
renderToolCall?: (context: AgentToolRenderContext) => React.ReactNode | undefined;
|
|
122
241
|
/** Header content, e.g. the pop-up's own window controls. */
|
|
123
242
|
headerSlot?: React.ReactNode;
|
|
243
|
+
/** No header at all — for a host with its own session list and New button. */
|
|
244
|
+
hideHeader?: boolean;
|
|
245
|
+
/** The host's own renders for each region. See `AgentChatComponents`. */
|
|
246
|
+
components?: Partial<AgentChatComponents>;
|
|
247
|
+
/** Classes for the wrappers. See `AgentChatClassNames`. */
|
|
248
|
+
classNames?: AgentChatClassNames;
|
|
249
|
+
/**
|
|
250
|
+
* Page older history from the sentinel at the top of the transcript as the
|
|
251
|
+
* reader reaches it, not only from the `LoadOlder` button. Off by default —
|
|
252
|
+
* the pop-up pages on a click. When on, it is armed only once the scroller
|
|
253
|
+
* overflows: a transcript shorter than its viewport has its sentinel
|
|
254
|
+
* permanently in view, and paging on that pulled every page the server had
|
|
255
|
+
* into a chat with three messages in it.
|
|
256
|
+
*/
|
|
257
|
+
autoLoadOlder?: boolean;
|
|
124
258
|
}
|
|
125
|
-
|
|
259
|
+
/**
|
|
260
|
+
* The surface owning its own state: it calls `useAgentChat` on the client it is
|
|
261
|
+
* given. This is what `AgentChatPopup` mounts.
|
|
262
|
+
*/
|
|
263
|
+
export interface AgentChatOwnedProps extends AgentChatBaseProps {
|
|
264
|
+
/** The transport. `createAguiAgentChatClient` is the AG-UI implementation. */
|
|
265
|
+
client: AgentChatClient;
|
|
266
|
+
/**
|
|
267
|
+
* Names the `sessionStorage` slot this window's session key lives in. Scope
|
|
268
|
+
* it to the extension id; two chats with different scopes never share a key.
|
|
269
|
+
*/
|
|
270
|
+
storageScope: string;
|
|
271
|
+
/** Do not read or write `sessionStorage`; for a guide or a test. */
|
|
272
|
+
ephemeral?: boolean;
|
|
273
|
+
thinking?: "low" | "medium" | "high";
|
|
274
|
+
chat?: undefined;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* The surface drawing state the host owns.
|
|
278
|
+
*
|
|
279
|
+
* A host that needs the state OUTSIDE the surface — a sidebar that lists
|
|
280
|
+
* sessions, a shortcut that stops the run, a page that routes on the session
|
|
281
|
+
* key — holds it itself and passes a `UseAgentChatResult` here; the surface
|
|
282
|
+
* then draws that state instead of holding its own. The result may come from
|
|
283
|
+
* `useAgentChat`, or from a store of the host's own projected onto the same
|
|
284
|
+
* shape, which is how cortenaweb drives this surface from the zustand stores
|
|
285
|
+
* the rest of its shell reads (PLATFORM-64). No client, no storage: the host
|
|
286
|
+
* owns both.
|
|
287
|
+
*/
|
|
288
|
+
export interface AgentChatHostedProps extends AgentChatBaseProps {
|
|
289
|
+
chat: UseAgentChatResult;
|
|
290
|
+
client?: undefined;
|
|
291
|
+
storageScope?: undefined;
|
|
292
|
+
ephemeral?: undefined;
|
|
293
|
+
thinking?: undefined;
|
|
294
|
+
}
|
|
295
|
+
export type AgentChatProps = AgentChatOwnedProps | AgentChatHostedProps;
|
|
296
|
+
/**
|
|
297
|
+
* Two ways in, one surface. The hook is called in a component of its own so
|
|
298
|
+
* a host that hands over `chat` never calls it — and so a mount that switches
|
|
299
|
+
* from one mode to the other remounts rather than changing its hook order.
|
|
300
|
+
*/
|
|
301
|
+
declare function AgentChat(props: AgentChatProps): React.JSX.Element;
|
|
126
302
|
export interface AgentSessionDrawerProps {
|
|
127
303
|
sessions: readonly AgentSession[];
|
|
128
304
|
current: string | null;
|
|
@@ -139,5 +315,5 @@ export interface AgentSessionDrawerProps {
|
|
|
139
315
|
*/
|
|
140
316
|
declare function AgentSessionDrawer({ sessions, current, loading, onResume }: AgentSessionDrawerProps): React.JSX.Element;
|
|
141
317
|
//#endregion
|
|
142
|
-
export { AgentA2UIBlocks, AgentApprovalCard, AgentChat, AgentMessageBubble, AgentSessionDrawer, AgentStreamingBubble, AgentThinking, AgentToolCard };
|
|
318
|
+
export { AgentA2UIBlocks, AgentApprovalCard, AgentChat, AgentMessageBubble, AgentSessionDrawer, AgentSteps, AgentStreamingBubble, AgentThinking, AgentToolCard };
|
|
143
319
|
//# sourceMappingURL=agent-chat.d.ts.map
|