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.
@@ -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
- export interface AgentChatProps extends Omit<React.ComponentProps<"div">, "children" | "onError"> {
102
- /** The transport. `createAguiAgentChatClient` is the AG-UI implementation. */
103
- client: AgentChatClient;
104
- /** The extension name, shown on each assistant turn. */
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
- * Names the `sessionStorage` slot this window's session key lives in. Scope
108
- * it to the extension id; two chats with different scopes never share a key.
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
- storageScope: string;
111
- /** Do not read or write `sessionStorage`; for a guide or a test. */
112
- ephemeral?: boolean;
113
- thinking?: "low" | "medium" | "high";
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
- declare function AgentChat({ client, agentName, storageScope, ephemeral, thinking, attachmentsSlot, renderToolCall, headerSlot, className, ...props }: AgentChatProps): React.JSX.Element;
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