@alexkroman1/aai-ui 6.11.0 → 7.0.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/README.md +104 -3
- package/dist/_run-controls.d.ts +33 -0
- package/dist/{chat-view-ByQFf94G.js → chat-view-BKsFfFZJ.js} +57 -11
- package/dist/client-config-B4nznRvH.js +134 -0
- package/dist/client-config.d.ts +45 -2
- package/dist/client-dir.d.ts +3 -1
- package/dist/client-dir.js +3 -1
- package/dist/components/auto-scroll.d.ts +24 -13
- package/dist/components/button.d.ts +8 -4
- package/dist/components/button.js +4 -4
- package/dist/components/chat-view.d.ts +4 -3
- package/dist/components/chat-view.js +1 -1
- package/dist/components/console-shell.d.ts +71 -10
- package/dist/components/controls.d.ts +15 -4
- package/dist/components/controls.js +48 -2
- package/dist/components/form-fields.d.ts +142 -0
- package/dist/components/form-types.d.ts +6 -0
- package/dist/components/form.d.ts +38 -80
- package/dist/components/markdown.d.ts +31 -5
- package/dist/components/message-list.d.ts +21 -4
- package/dist/components/message-list.js +1 -1
- package/dist/components/sidebar-layout.d.ts +11 -0
- package/dist/components/sidebar-layout.js +2 -0
- package/dist/components/start-screen.d.ts +8 -0
- package/dist/components/start-screen.js +2 -0
- package/dist/components/tool-call-block.js +1 -1
- package/dist/components/tool-call-row.d.ts +24 -0
- package/dist/components/upload-progress.d.ts +17 -7
- package/dist/components/workflow-fields.d.ts +10 -22
- package/dist/components/workflow-progress.d.ts +29 -10
- package/dist/context.d.ts +36 -0
- package/dist/context.js +105 -14
- package/dist/default-client/assets/index-S5fkKi6B.css +2 -0
- package/dist/default-client/assets/index-fEkrcZgo.js +293 -0
- package/dist/default-client/index.html +2 -2
- package/dist/define-client.d.ts +67 -62
- package/dist/define-client.js +56 -22
- package/dist/hooks.d.ts +88 -3
- package/dist/index.d.ts +12 -11
- package/dist/index.js +501 -167
- package/dist/internal.d.ts +40 -0
- package/dist/internal.js +6 -0
- package/dist/{message-list-CpPV7dGx.js → message-list-DHddO4QC.js} +217 -72
- package/dist/{session-core-CAfYmUbg.js → session-core-C2JtLArh.js} +267 -165
- package/dist/session-core-audio-setup.d.ts +3 -0
- package/dist/session-core-messages.d.ts +3 -0
- package/dist/session-core-state.d.ts +146 -0
- package/dist/session-core-types.d.ts +77 -32
- package/dist/session-core.d.ts +3 -2
- package/dist/session-core.js +1 -1
- package/dist/{tool-call-block-D6pTEPrT.js → tool-call-block-DoF-cSIZ.js} +27 -19
- package/dist/tool-config-context-DzAofqi_.js +19 -0
- package/dist/types.d.ts +31 -5
- package/dist/types.js +5 -4
- package/dist/{controls-CjG91QJ4.js → url-chips-DpM7Oocj.js} +3 -46
- package/dist/use-conversation.d.ts +122 -0
- package/dist/use-download-url.d.ts +83 -0
- package/dist/use-workflow-form.d.ts +59 -3
- package/dist/use-workflow-run.d.ts +35 -0
- package/dist/use-workflow-stream.d.ts +36 -62
- package/dist/workflow-client.d.ts +36 -11
- package/dist/workflow-status-labels.d.ts +35 -0
- package/package.json +10 -5
- package/styles.css +14 -0
- package/dist/default-client/assets/index-DTLrhtTF.css +0 -2
- package/dist/default-client/assets/index-DXODx_9r.js +0 -293
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@alexkroman1/aai-ui/internal` — the plumbing `client()` and the default
|
|
3
|
+
* client install for themselves, NOT part of the public client API and not
|
|
4
|
+
* covered by semver. A `client.tsx` should never import from here; everything
|
|
5
|
+
* an author writes a page or a custom chrome against lives on the root export
|
|
6
|
+
* and the documented subpaths.
|
|
7
|
+
*
|
|
8
|
+
* These names used to ride on the root barrel, tagged `@internal` and nothing
|
|
9
|
+
* else, which meant they were in a client author's autocomplete beside
|
|
10
|
+
* `client()`, `<Form>`, `useAgentState` and `useWorkflowRun` — eight symbols an
|
|
11
|
+
* author is invited to reach for and no capability contract covers. Keeping
|
|
12
|
+
* them on their own subpath keeps the root importable surface the same shape as
|
|
13
|
+
* the promise: what is on it is contracted.
|
|
14
|
+
*
|
|
15
|
+
* A release tag cannot do this from the barrel. API Extractor reads `@internal`
|
|
16
|
+
* at the DECLARATION site, so a tag written on a re-export clause member is
|
|
17
|
+
* silently ignored and the name stays `@public` in the report — and the
|
|
18
|
+
* contract exemption in `contracts/internal-surface.json` is per SUBPATH, so a
|
|
19
|
+
* tag on the root barrel buys an entry on that ratchet rather than removing
|
|
20
|
+
* one. A subpath is the mechanism, the same one `@alexkroman1/aai` and
|
|
21
|
+
* `@alexkroman1/aai-runtime` already use, and `NON_AUTHORING_SUBPATHS` in
|
|
22
|
+
* `scripts/_api-contracts-tree.mjs` carries the matching entry so a name
|
|
23
|
+
* arriving here joins no capability contract.
|
|
24
|
+
*
|
|
25
|
+
* The corollary is the rule for adding to this file, and it runs the other way
|
|
26
|
+
* too: a name that WANTS to be public gets its `@internal` tag removed and
|
|
27
|
+
* joins a capability contract — it does not stay on the barrel wearing a tag.
|
|
28
|
+
* That is what happened to `fetchClientConfig`, which the SDK's own `@public`
|
|
29
|
+
* prose told a workflow-app author to call while the export excluded it.
|
|
30
|
+
*
|
|
31
|
+
* Named re-exports rather than `export *`: the wildcard form needs a
|
|
32
|
+
* `noReExportAll` suppression, and the escape-hatch ratchet only moves down.
|
|
33
|
+
*
|
|
34
|
+
* @module internal
|
|
35
|
+
*/
|
|
36
|
+
export { buildAgentUrl, loadClientConfig } from "./client-config.ts";
|
|
37
|
+
export { ToolConfigContext } from "./components/tool-config-context.ts";
|
|
38
|
+
export { ApiUrlChip, SessionUrlChips, UiUrlChip } from "./components/url-chips.tsx";
|
|
39
|
+
export { SessionProvider, ThemeProvider } from "./context.ts";
|
|
40
|
+
export { VOICE_CAPTURE_CONSTRAINTS } from "./types.ts";
|
package/dist/internal.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { r as loadClientConfig, t as buildAgentUrl } from "./client-config-B4nznRvH.js";
|
|
2
|
+
import { SessionProvider, ThemeProvider } from "./context.js";
|
|
3
|
+
import { n as SessionUrlChips, r as UiUrlChip, t as ApiUrlChip } from "./url-chips-DpM7Oocj.js";
|
|
4
|
+
import { t as ToolConfigContext } from "./tool-config-context-DzAofqi_.js";
|
|
5
|
+
import { VOICE_CAPTURE_CONSTRAINTS } from "./types.js";
|
|
6
|
+
export { ApiUrlChip, SessionProvider, SessionUrlChips, ThemeProvider, ToolConfigContext, UiUrlChip, VOICE_CAPTURE_CONSTRAINTS, buildAgentUrl, loadClientConfig };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useSessionSelector, useTheme } from "./context.js";
|
|
2
2
|
import { i as primaryTint, r as inkTint } from "./_colors-CcAi2FOU.js";
|
|
3
|
-
import { t as ToolCallBlock } from "./tool-call-block-
|
|
3
|
+
import { t as ToolCallBlock } from "./tool-call-block-DoF-cSIZ.js";
|
|
4
4
|
import clsx from "clsx";
|
|
5
5
|
import { StickToBottom } from "use-stick-to-bottom";
|
|
6
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -46,19 +46,7 @@ import remarkGfm from "remark-gfm";
|
|
|
46
46
|
* }
|
|
47
47
|
* ```
|
|
48
48
|
*
|
|
49
|
-
* @param
|
|
50
|
-
* @param className - Classes for the outer container. It must be given a
|
|
51
|
-
* bounded height (`flex-1 min-h-0`, `h-full`, a fixed height) — an unbounded
|
|
52
|
-
* one grows with its content and never scrolls, so nothing pins.
|
|
53
|
-
* @param contentClassName - Classes for the inner content element, where
|
|
54
|
-
* padding and the children's own layout belong.
|
|
55
|
-
* @param scrollClassName - Classes for the scrolling element itself. Defaults
|
|
56
|
-
* to hiding the scrollbar; pass `"overflow-y-auto"` to show a native one.
|
|
57
|
-
* @param style - Inline styles for the outer container.
|
|
58
|
-
* @param initial - Scroll behavior on mount. Defaults to `"instant"` (start at
|
|
59
|
-
* the latest content without animating a scroll the reader did not ask for).
|
|
60
|
-
* @param resize - Scroll behavior when pinned content grows. Defaults to
|
|
61
|
-
* `"smooth"`.
|
|
49
|
+
* @param props - Scroll container props.
|
|
62
50
|
*
|
|
63
51
|
* @public
|
|
64
52
|
*/
|
|
@@ -77,6 +65,196 @@ function AutoScroll({ children, className, contentClassName, scrollClassName = "
|
|
|
77
65
|
});
|
|
78
66
|
}
|
|
79
67
|
//#endregion
|
|
68
|
+
//#region use-user-transcript.ts
|
|
69
|
+
/**
|
|
70
|
+
* `useUserTranscript` — what the caller is saying RIGHT NOW, read correctly.
|
|
71
|
+
*
|
|
72
|
+
* `SessionSnapshot.userTranscript` is `string | null`, and the two falsy values
|
|
73
|
+
* mean different things:
|
|
74
|
+
*
|
|
75
|
+
* - `null` — nobody is speaking. There is no partial turn.
|
|
76
|
+
* - `""` — speech HAS been detected and no words have come back yet. A live
|
|
77
|
+
* session sits here for a few hundred milliseconds at the start of every turn.
|
|
78
|
+
*
|
|
79
|
+
* Read as one falsy check, those collapse and the indicator never appears at the
|
|
80
|
+
* start of a turn — which is the moment it is for. So every custom chrome writes
|
|
81
|
+
* `transcript !== null && (transcript === "" ? "…" : transcript)`, three
|
|
82
|
+
* templates did exactly that, and each one re-derived a protocol distinction
|
|
83
|
+
* from the type rather than from anything that told them.
|
|
84
|
+
*
|
|
85
|
+
* This is the same distinction as two named booleans, so a component can say
|
|
86
|
+
* what it means: render on `speaking`, show `text`, and use the SDK's own
|
|
87
|
+
* placeholder when there is nothing to show yet.
|
|
88
|
+
*/
|
|
89
|
+
/**
|
|
90
|
+
* Placeholder for "listening, no words yet" — the `""` case above.
|
|
91
|
+
*
|
|
92
|
+
* A one-character ellipsis rather than three dots, because it is read by a
|
|
93
|
+
* screen reader as an ellipsis and it does not reflow the row when the first
|
|
94
|
+
* real word replaces it.
|
|
95
|
+
*
|
|
96
|
+
* @public
|
|
97
|
+
*/
|
|
98
|
+
const TRANSCRIBING_PLACEHOLDER = "…";
|
|
99
|
+
/**
|
|
100
|
+
* Subscribe to the caller's in-progress turn.
|
|
101
|
+
*
|
|
102
|
+
* Narrowly subscribed — a component using this re-renders at STT-partial rate,
|
|
103
|
+
* which is exactly what it is for and exactly what a whole-page `useSession()`
|
|
104
|
+
* should not do.
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```tsx
|
|
108
|
+
* import { useUserTranscript } from "@alexkroman1/aai-ui";
|
|
109
|
+
*
|
|
110
|
+
* function LiveTranscript() {
|
|
111
|
+
* const { speaking, text } = useUserTranscript();
|
|
112
|
+
* if (!speaking) return null;
|
|
113
|
+
* return <div className="italic opacity-60">{text}</div>;
|
|
114
|
+
* }
|
|
115
|
+
* ```
|
|
116
|
+
*
|
|
117
|
+
* @public
|
|
118
|
+
*/
|
|
119
|
+
function useUserTranscript() {
|
|
120
|
+
const partial = useSessionSelector((snapshot) => snapshot.userTranscript);
|
|
121
|
+
return {
|
|
122
|
+
speaking: partial !== null,
|
|
123
|
+
text: displayText(partial),
|
|
124
|
+
partial
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
/** The three cases, spelled out: silent, detected-but-wordless, and words. */
|
|
128
|
+
function displayText(partial) {
|
|
129
|
+
if (partial === null) return "";
|
|
130
|
+
return partial === "" ? "…" : partial;
|
|
131
|
+
}
|
|
132
|
+
//#endregion
|
|
133
|
+
//#region use-conversation.ts
|
|
134
|
+
/**
|
|
135
|
+
* `useConversation` — the exchange, already assembled, with nothing rendered.
|
|
136
|
+
*
|
|
137
|
+
* `<MessageList>` owns four decisions that are not obvious and are not
|
|
138
|
+
* derivable from the snapshot by eye: the message/tool-call INTERLEAVE, the
|
|
139
|
+
* streaming agent utterance, the live user transcript with its `null`-vs-`""`
|
|
140
|
+
* protocol distinction, and the thinking indicator's suppression rule. Its only
|
|
141
|
+
* prop is `className`, so the moment a client wants its own bubble markup it
|
|
142
|
+
* drops all four at once — and the three hand-rolled chromes in the template
|
|
143
|
+
* tree each shipped a strictly worse conversation for exactly that reason. One
|
|
144
|
+
* of them runs fifteen tools and its operator sees none of them, because the
|
|
145
|
+
* tool calls live in a second array nothing in that page ever reads.
|
|
146
|
+
*
|
|
147
|
+
* This is the headless half. `<MessageList>` is now a thin consumer of it —
|
|
148
|
+
* which is the only way to know the hook is complete, since a hook that the
|
|
149
|
+
* package's own list cannot be built from is a hook a custom chrome will find a
|
|
150
|
+
* hole in.
|
|
151
|
+
*
|
|
152
|
+
* ## It subscribes NARROWLY, and that is half the value
|
|
153
|
+
*
|
|
154
|
+
* The three custom chromes also call whole-page `useSession()`, which re-renders
|
|
155
|
+
* on *every* snapshot change — so a dispatch board re-renders at STT-partial
|
|
156
|
+
* rate. `<ChatView>` deliberately avoids that with per-field
|
|
157
|
+
* {@link useSessionSelector} calls, and so does this: a component that reads the
|
|
158
|
+
* conversation gets the conversation's own update rate, not the session's.
|
|
159
|
+
*/
|
|
160
|
+
/**
|
|
161
|
+
* Interleave messages and tool calls, ordered by insertion time.
|
|
162
|
+
*
|
|
163
|
+
* Each tool call belongs immediately after its anchor message
|
|
164
|
+
* (`afterMessageId`); tool calls whose anchor slid out of the retained window —
|
|
165
|
+
* or that were inserted before any message existed — come first, since there is
|
|
166
|
+
* nothing left for them to follow.
|
|
167
|
+
*/
|
|
168
|
+
function interleave(messages, toolCalls) {
|
|
169
|
+
const items = [];
|
|
170
|
+
let tci = 0;
|
|
171
|
+
const pushToolCallsThrough = (maxAfterId) => {
|
|
172
|
+
let tc = toolCalls[tci];
|
|
173
|
+
while (tc && tc.afterMessageId <= maxAfterId) {
|
|
174
|
+
items.push({
|
|
175
|
+
kind: "tool",
|
|
176
|
+
toolCall: tc
|
|
177
|
+
});
|
|
178
|
+
tci++;
|
|
179
|
+
tc = toolCalls[tci];
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
const firstMessage = messages[0];
|
|
183
|
+
if (firstMessage) pushToolCallsThrough(firstMessage.id - 1);
|
|
184
|
+
for (const message of messages) {
|
|
185
|
+
items.push({
|
|
186
|
+
kind: "message",
|
|
187
|
+
message
|
|
188
|
+
});
|
|
189
|
+
pushToolCallsThrough(message.id);
|
|
190
|
+
}
|
|
191
|
+
pushToolCallsThrough(Number.POSITIVE_INFINITY);
|
|
192
|
+
return items;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Whether the thinking indicator should show — see
|
|
196
|
+
* {@link UseConversationResult.thinking} for the rule and the argument.
|
|
197
|
+
*/
|
|
198
|
+
function isThinking(state, messages, toolCalls) {
|
|
199
|
+
if (state !== "thinking") return false;
|
|
200
|
+
const last = toolCalls.at(-1);
|
|
201
|
+
if (last?.status === "pending") return false;
|
|
202
|
+
const lastMessage = messages.at(-1);
|
|
203
|
+
return !lastMessage || lastMessage.role === "user" || Boolean(last);
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Subscribe to the conversation: the interleaved exchange, the streaming
|
|
207
|
+
* utterance, the live transcript and the thinking rule — with no markup.
|
|
208
|
+
*
|
|
209
|
+
* Must be used inside the provider `client()` installs.
|
|
210
|
+
*
|
|
211
|
+
* @example A custom bubble, keeping every rule `<MessageList>` knows
|
|
212
|
+
* ```tsx
|
|
213
|
+
* import { useConversation } from "@alexkroman1/aai-ui";
|
|
214
|
+
*
|
|
215
|
+
* function Transcript() {
|
|
216
|
+
* const { items, streaming, transcript, thinking } = useConversation();
|
|
217
|
+
* return (
|
|
218
|
+
* <div>
|
|
219
|
+
* {items.map((item) =>
|
|
220
|
+
* item.kind === "message" ? (
|
|
221
|
+
* <p key={item.message.id} data-role={item.message.role}>
|
|
222
|
+
* {item.message.content}
|
|
223
|
+
* </p>
|
|
224
|
+
* ) : (
|
|
225
|
+
* <code key={item.toolCall.callId}>{item.toolCall.name}</code>
|
|
226
|
+
* ),
|
|
227
|
+
* )}
|
|
228
|
+
* {streaming !== null && <p data-role="assistant">{streaming}</p>}
|
|
229
|
+
* {transcript.speaking && <p data-role="user">{transcript.text}</p>}
|
|
230
|
+
* {thinking && <p>…</p>}
|
|
231
|
+
* </div>
|
|
232
|
+
* );
|
|
233
|
+
* }
|
|
234
|
+
* ```
|
|
235
|
+
*
|
|
236
|
+
* @returns See {@link UseConversationResult}.
|
|
237
|
+
*
|
|
238
|
+
* @public
|
|
239
|
+
*/
|
|
240
|
+
function useConversation() {
|
|
241
|
+
const state = useSessionSelector((s) => s.state);
|
|
242
|
+
const messages = useSessionSelector((s) => s.messages);
|
|
243
|
+
const toolCalls = useSessionSelector((s) => s.toolCalls);
|
|
244
|
+
const streaming = useSessionSelector((s) => s.agentTranscript);
|
|
245
|
+
const transcript = useUserTranscript();
|
|
246
|
+
return {
|
|
247
|
+
items: useMemo(() => interleave(messages, toolCalls), [messages, toolCalls]),
|
|
248
|
+
streaming,
|
|
249
|
+
transcript,
|
|
250
|
+
thinking: useMemo(() => isThinking(state, messages, toolCalls), [
|
|
251
|
+
state,
|
|
252
|
+
messages,
|
|
253
|
+
toolCalls
|
|
254
|
+
])
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
//#endregion
|
|
80
258
|
//#region components/markdown.tsx
|
|
81
259
|
/** @jsxImportSource react */
|
|
82
260
|
const BARE_ORDERED_MARKER = /^(\s*)(\d{1,9})([.)])\s*$/;
|
|
@@ -137,6 +315,18 @@ const SCALE_CLASSES = {
|
|
|
137
315
|
* Memoized alongside `MessageBubble`: message content is referentially
|
|
138
316
|
* stable across snapshots, so only the streaming row re-parses.
|
|
139
317
|
*
|
|
318
|
+
* @example
|
|
319
|
+
* ```tsx
|
|
320
|
+
* import { Markdown, useSessionSelector } from "@alexkroman1/aai-ui";
|
|
321
|
+
*
|
|
322
|
+
* // The agent's reply as it streams, rendered rather than shown as literal
|
|
323
|
+
* // asterisks and backticks.
|
|
324
|
+
* function LiveReply() {
|
|
325
|
+
* const text = useSessionSelector((snapshot) => snapshot.agentTranscript);
|
|
326
|
+
* return text === null ? null : <Markdown text={text} variant="compact" />;
|
|
327
|
+
* }
|
|
328
|
+
* ```
|
|
329
|
+
*
|
|
140
330
|
* @public
|
|
141
331
|
*/
|
|
142
332
|
const Markdown = memo(function Markdown({ text, variant = "default" }) {
|
|
@@ -339,32 +529,6 @@ const MessageBubble = memo(function MessageBubble({ message, theme }) {
|
|
|
339
529
|
});
|
|
340
530
|
});
|
|
341
531
|
/**
|
|
342
|
-
* Interleave messages and tool calls into render items, ordered by insertion
|
|
343
|
-
* time. Each tool call renders immediately after its anchor message
|
|
344
|
-
* (`afterMessageId`); tool calls whose anchor slid out of the retained window
|
|
345
|
-
* (or that were inserted before any message existed) render first.
|
|
346
|
-
*/
|
|
347
|
-
function interleave(messages, toolCalls, renderMessage, renderToolCall) {
|
|
348
|
-
const items = [];
|
|
349
|
-
let tci = 0;
|
|
350
|
-
const pushToolCallsThrough = (maxAfterId) => {
|
|
351
|
-
let tc = toolCalls[tci];
|
|
352
|
-
while (tc && tc.afterMessageId <= maxAfterId) {
|
|
353
|
-
items.push(renderToolCall(tc));
|
|
354
|
-
tci++;
|
|
355
|
-
tc = toolCalls[tci];
|
|
356
|
-
}
|
|
357
|
-
};
|
|
358
|
-
const firstMessage = messages[0];
|
|
359
|
-
if (firstMessage) pushToolCallsThrough(firstMessage.id - 1);
|
|
360
|
-
for (const msg of messages) {
|
|
361
|
-
items.push(renderMessage(msg));
|
|
362
|
-
pushToolCallsThrough(msg.id);
|
|
363
|
-
}
|
|
364
|
-
pushToolCallsThrough(Number.POSITIVE_INFINITY);
|
|
365
|
-
return items;
|
|
366
|
-
}
|
|
367
|
-
/**
|
|
368
532
|
* Scrollable list of all chat messages, tool-call blocks, live transcript,
|
|
369
533
|
* streaming agent utterance, and a thinking indicator.
|
|
370
534
|
*
|
|
@@ -382,58 +546,39 @@ function interleave(messages, toolCalls, renderMessage, renderToolCall) {
|
|
|
382
546
|
* }
|
|
383
547
|
* ```
|
|
384
548
|
*
|
|
385
|
-
* @param
|
|
549
|
+
* @param props - Container props.
|
|
386
550
|
*
|
|
387
551
|
* @public
|
|
388
552
|
*/
|
|
389
553
|
const MessageList = memo(function MessageList({ className }) {
|
|
390
|
-
const
|
|
391
|
-
const messages = useSessionSelector((s) => s.messages);
|
|
392
|
-
const toolCalls = useSessionSelector((s) => s.toolCalls);
|
|
393
|
-
const userTranscript = useSessionSelector((s) => s.userTranscript);
|
|
394
|
-
const agentTranscript = useSessionSelector((s) => s.agentTranscript);
|
|
554
|
+
const { items, streaming, transcript, thinking } = useConversation();
|
|
395
555
|
const theme = useTheme();
|
|
396
|
-
const
|
|
397
|
-
if (state !== "thinking") return false;
|
|
398
|
-
const last = toolCalls.at(-1);
|
|
399
|
-
if (last?.status === "pending") return false;
|
|
400
|
-
const lastMsg = messages.at(-1);
|
|
401
|
-
return !lastMsg || lastMsg.role === "user" || Boolean(last);
|
|
402
|
-
}, [
|
|
403
|
-
state,
|
|
404
|
-
toolCalls,
|
|
405
|
-
messages
|
|
406
|
-
]);
|
|
407
|
-
const streamingMessage = useMemo(() => agentTranscript ? {
|
|
556
|
+
const streamingMessage = useMemo(() => streaming ? {
|
|
408
557
|
role: "assistant",
|
|
409
|
-
content:
|
|
410
|
-
} : null, [
|
|
411
|
-
const
|
|
412
|
-
message:
|
|
413
|
-
theme
|
|
414
|
-
}, msg.id), (tc) => /* @__PURE__ */ jsx(ToolCallBlock, { toolCall: tc }, tc.callId)), [
|
|
415
|
-
messages,
|
|
416
|
-
toolCalls,
|
|
558
|
+
content: streaming
|
|
559
|
+
} : null, [streaming]);
|
|
560
|
+
const rows = useMemo(() => items.map((item) => item.kind === "message" ? /* @__PURE__ */ jsx(MessageBubble, {
|
|
561
|
+
message: item.message,
|
|
417
562
|
theme
|
|
418
|
-
]);
|
|
563
|
+
}, item.message.id) : /* @__PURE__ */ jsx(ToolCallBlock, { toolCall: item.toolCall }, item.toolCall.callId)), [items, theme]);
|
|
419
564
|
return /* @__PURE__ */ jsxs(AutoScroll, {
|
|
420
565
|
className,
|
|
421
566
|
style: { background: theme.surface },
|
|
422
567
|
contentClassName: "flex flex-col gap-4 p-7",
|
|
423
568
|
children: [
|
|
424
|
-
|
|
569
|
+
rows,
|
|
425
570
|
streamingMessage && /* @__PURE__ */ jsx(MessageBubble, {
|
|
426
571
|
message: streamingMessage,
|
|
427
572
|
theme
|
|
428
573
|
}),
|
|
429
|
-
|
|
574
|
+
transcript.speaking && /* @__PURE__ */ jsx(UserBubble, {
|
|
430
575
|
theme,
|
|
431
576
|
color: inkTint(theme.text, theme.surface, 65),
|
|
432
|
-
children:
|
|
577
|
+
children: transcript.partial ? transcript.partial : /* @__PURE__ */ jsx(ThinkingDots, {})
|
|
433
578
|
}),
|
|
434
|
-
|
|
579
|
+
thinking && /* @__PURE__ */ jsx(ThinkingDots, {})
|
|
435
580
|
]
|
|
436
581
|
});
|
|
437
582
|
});
|
|
438
583
|
//#endregion
|
|
439
|
-
export { Markdown as n, AutoScroll as r, MessageList as t };
|
|
584
|
+
export { useUserTranscript as a, TRANSCRIBING_PLACEHOLDER as i, Markdown as n, AutoScroll as o, useConversation as r, MessageList as t };
|