@dbx-tools/ui-mastra 0.9.132 → 0.9.138
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -6
- package/index.ts +3 -2
- package/package.json +6 -6
- package/src/react/_assistant-activity.ts +6 -3
- package/src/react/bubbles.tsx +8 -0
- package/src/react/chat-feedback.ts +68 -12
- package/src/react/chat-transcript.tsx +19 -2
- package/src/react/chat-view.tsx +2 -0
- package/src/react/feedback-controls.tsx +104 -0
- package/src/react/mastra-chat.tsx +12 -20
- package/src/react/thread-sidebar.tsx +4 -2
- package/src/react/types.ts +4 -1
- package/src/support/export.ts +1 -1
- package/src/support/genie-client.ts +14 -7
- package/src/support/index.ts +1 -1
- package/src/support/mastra-client.ts +8 -13
- package/src/support/request-context.ts +7 -14
- package/src/support/thread-sessions.ts +5 -5
package/README.md
CHANGED
|
@@ -221,7 +221,9 @@ supervisor agent:
|
|
|
221
221
|
|
|
222
222
|
The alias comes from the server plugin's `genieSpaces`. The client still uses
|
|
223
223
|
AI SDK `UIMessage` streams and the same `ChatView`. Genie conversations replace
|
|
224
|
-
Mastra threads and Genie messages
|
|
224
|
+
Mastra threads and Genie messages remain the visible history. When Mastra
|
|
225
|
+
memory is configured, the server injects resource-scoped semantic recall and
|
|
226
|
+
saves completed direct turns without replacing Genie's conversation ownership.
|
|
225
227
|
|
|
226
228
|
Turns and history require the Genie Agent API and never fall back to classic
|
|
227
229
|
Genie message polling. The sidebar filters the Genie conversation listing to
|
|
@@ -308,20 +310,24 @@ per-turn resolver. The driver snapshots it when a message is submitted and
|
|
|
308
310
|
keeps that snapshot with queued steers, regeneration, and approval continuation.
|
|
309
311
|
|
|
310
312
|
```tsx
|
|
313
|
+
import { RequestContext } from "@mastra/client-js";
|
|
314
|
+
|
|
311
315
|
type StoreContext = { storeId: string; route: string };
|
|
312
316
|
|
|
313
317
|
const chat = useMastraChat<StoreContext>({
|
|
314
|
-
requestContext: () =>
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
+
requestContext: () =>
|
|
319
|
+
new RequestContext<StoreContext>([
|
|
320
|
+
["storeId", selectedStore.id],
|
|
321
|
+
["route", location.pathname],
|
|
322
|
+
]),
|
|
318
323
|
});
|
|
319
324
|
```
|
|
320
325
|
|
|
321
326
|
On the server, declare the same contract with Mastra's native
|
|
322
327
|
`requestContextSchema` on `createAgent<StoreContext>()`. Application context
|
|
323
328
|
cannot override the authenticated memory resource, thread, user, scopes, model,
|
|
324
|
-
or trace fields stamped by AppKit-Mastra.
|
|
329
|
+
or trace fields stamped by AppKit-Mastra. Direct Genie chat forwards the same
|
|
330
|
+
native context as reference data for its one Agent Mode user message.
|
|
325
331
|
|
|
326
332
|
## Build a controlled chat surface
|
|
327
333
|
|
package/index.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Hand edits are overwritten on the next watch; this file is read-only.
|
|
4
4
|
|
|
5
5
|
export const PACKAGE_IDENTIFIER = "@dbx-tools/ui-mastra";
|
|
6
|
-
export const PACKAGE_VERSION = "0.9.
|
|
6
|
+
export const PACKAGE_VERSION = "0.9.138";
|
|
7
7
|
export * as reactBubbles from "./src/react/bubbles.tsx";
|
|
8
8
|
export * as reactChatApprovals from "./src/react/chat-approvals.ts";
|
|
9
9
|
export * as reactChatComposer from "./src/react/chat-composer.tsx";
|
|
@@ -44,6 +44,7 @@ export * as supportThreadTabs from "./src/support/thread-tabs.ts";
|
|
|
44
44
|
export * as supportToolEvents from "./src/support/tool-events.ts";
|
|
45
45
|
export { AssistantBubble, UserBubble } from "./src/react/bubbles.tsx";
|
|
46
46
|
export { ChatComposer } from "./src/react/chat-composer.tsx";
|
|
47
|
+
export type { GenieFeedbackTarget } from "./src/react/chat-feedback.ts";
|
|
47
48
|
export type { ThreadSessionReader, ThreadSessionUpdater, ThreadMessageWriter } from "./src/react/chat-sessions.ts";
|
|
48
49
|
export { ChatThreadLayout } from "./src/react/chat-thread-layout.tsx";
|
|
49
50
|
export { useChatTranscriptController, ChatTranscript } from "./src/react/chat-transcript.tsx";
|
|
@@ -77,7 +78,7 @@ export { GenieChatClient } from "./src/support/genie-client.ts";
|
|
|
77
78
|
export { MastraChatRequestError, MastraPluginClient, useMastraConfig, useMastraClient, useMastraMlflowExperiment, useMastraModels, useMastraDefaultModel, useMastraSuggestions, useMastraThreads, useChartFetch, useStatementFetch, useVisualizationFetch } from "./src/support/mastra-client.ts";
|
|
78
79
|
export type { MastraStreamResponse, MastraMemoryThread, ByIdFetchState } from "./src/support/mastra-client.ts";
|
|
79
80
|
export { defaultReasoningEffort, modelStorageKey, readStoredModel, storeSelectedModel } from "./src/support/model-selection.ts";
|
|
80
|
-
export type { MastraRequestContextInput, MastraRequestContextSource
|
|
81
|
+
export type { MastraRequestContextInput, MastraRequestContextSource } from "./src/support/request-context.ts";
|
|
81
82
|
export { DEFAULT_THREAD_SESSION_KEY } from "./src/support/thread-sessions.ts";
|
|
82
83
|
export type { SessionQueuedSteer, SessionRun, ThreadSession } from "./src/support/thread-sessions.ts";
|
|
83
84
|
export { THREAD_TAB_SEED_MAX } from "./src/support/thread-tabs.ts";
|
package/package.json
CHANGED
|
@@ -30,11 +30,11 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@databricks/appkit-ui": "0.81.0",
|
|
33
|
-
"@dbx-tools/shared-core": "^0.9.
|
|
34
|
-
"@dbx-tools/shared-genie": "^0.9.
|
|
35
|
-
"@dbx-tools/shared-mastra": "^0.9.
|
|
36
|
-
"@dbx-tools/shared-model": "^0.9.
|
|
37
|
-
"@dbx-tools/ui": "^0.9.
|
|
33
|
+
"@dbx-tools/shared-core": "^0.9.138",
|
|
34
|
+
"@dbx-tools/shared-genie": "^0.9.138",
|
|
35
|
+
"@dbx-tools/shared-mastra": "^0.9.138",
|
|
36
|
+
"@dbx-tools/shared-model": "^0.9.138",
|
|
37
|
+
"@dbx-tools/ui": "^0.9.138",
|
|
38
38
|
"@mastra/client-js": "1.50.0",
|
|
39
39
|
"@mastra/core": "1.71.0",
|
|
40
40
|
"@tanstack/react-table": "^8.21.3",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"publishConfig": {
|
|
52
52
|
"access": "public"
|
|
53
53
|
},
|
|
54
|
-
"version": "0.9.
|
|
54
|
+
"version": "0.9.138",
|
|
55
55
|
"dbxToolsConfig": {
|
|
56
56
|
"tags": [
|
|
57
57
|
"ui"
|
|
@@ -20,10 +20,13 @@ export const assistantActivityItems = (
|
|
|
20
20
|
if (renderedEventIds.has(event.id)) return;
|
|
21
21
|
renderedEventIds.add(event.id);
|
|
22
22
|
items.push({ type: "tool", key: `tool-${event.id}`, event });
|
|
23
|
-
|
|
24
|
-
if (progress.type !== "thinking")
|
|
23
|
+
const thoughts = (event.progress ?? []).flatMap((progress) => {
|
|
24
|
+
if (progress.type !== "thinking") return [];
|
|
25
25
|
const text = compactReasoningText(progress.text);
|
|
26
|
-
|
|
26
|
+
return text ? [text] : [];
|
|
27
|
+
});
|
|
28
|
+
if (thoughts.length > 0) {
|
|
29
|
+
items.push({ type: "thought", key: `thought-${event.id}`, text: thoughts.join("\n\n") });
|
|
27
30
|
}
|
|
28
31
|
};
|
|
29
32
|
|
package/src/react/bubbles.tsx
CHANGED
|
@@ -336,6 +336,10 @@ type AssistantBubbleProps = {
|
|
|
336
336
|
* when MLflow logging is enabled and the turn has a captured trace id.
|
|
337
337
|
*/
|
|
338
338
|
onFeedback?: (submission: FeedbackSubmission) => void | Promise<void>;
|
|
339
|
+
/** Feedback destination selected by the server. */
|
|
340
|
+
feedbackMode?: "mlflow" | "genie";
|
|
341
|
+
/** Original user request shown in Genie feedback. */
|
|
342
|
+
feedbackRequest?: string;
|
|
339
343
|
/** Last thumbs the user left on this message, for highlighting. */
|
|
340
344
|
feedbackValue?: FeedbackValue;
|
|
341
345
|
/** MLflow experiment link shown only to viewers with `CAN_MANAGE`. */
|
|
@@ -354,6 +358,8 @@ export const AssistantBubble = ({
|
|
|
354
358
|
externalApprovals,
|
|
355
359
|
onExport,
|
|
356
360
|
onFeedback,
|
|
361
|
+
feedbackMode,
|
|
362
|
+
feedbackRequest,
|
|
357
363
|
feedbackValue,
|
|
358
364
|
mlflowExperimentUrl,
|
|
359
365
|
}: AssistantBubbleProps) => {
|
|
@@ -493,6 +499,8 @@ export const AssistantBubble = ({
|
|
|
493
499
|
{hasText && onFeedback && (
|
|
494
500
|
<FeedbackControls
|
|
495
501
|
onSubmit={onFeedback}
|
|
502
|
+
{...(feedbackMode ? { mode: feedbackMode } : {})}
|
|
503
|
+
{...(feedbackRequest ? { request: feedbackRequest } : {})}
|
|
496
504
|
{...(feedbackValue ? { value: feedbackValue } : {})}
|
|
497
505
|
/>
|
|
498
506
|
)}
|
|
@@ -1,23 +1,58 @@
|
|
|
1
1
|
import { errorUtils, log } from "@dbx-tools/shared-core";
|
|
2
|
+
import { genieModel } from "@dbx-tools/shared-genie";
|
|
3
|
+
import type { FeedbackMode } from "@dbx-tools/shared-mastra/feedback";
|
|
2
4
|
import type { UIMessage } from "ai";
|
|
3
5
|
import { useCallback, useRef } from "react";
|
|
4
6
|
import type { ThreadSessionUpdater } from "./chat-sessions.ts";
|
|
5
7
|
import type { FeedbackSubmission, MessageFeedback } from "./types.ts";
|
|
6
8
|
import type { MastraPluginClient } from "../support/mastra-client.ts";
|
|
9
|
+
import { toolEventsFromParts } from "../support/tool-events.ts";
|
|
7
10
|
|
|
8
11
|
const logger = log.logger("ui-mastra/chat");
|
|
9
12
|
|
|
10
13
|
interface UseChatFeedbackOptions {
|
|
11
14
|
activeKey: string;
|
|
12
15
|
feedbackByMessage: Record<string, MessageFeedback>;
|
|
16
|
+
feedbackMode: FeedbackMode;
|
|
13
17
|
mastraClient: MastraPluginClient;
|
|
14
18
|
updateSession: ThreadSessionUpdater;
|
|
15
19
|
}
|
|
16
20
|
|
|
17
|
-
/**
|
|
21
|
+
/** Genie message target recovered from one completed ask_genie tool result. */
|
|
22
|
+
export interface GenieFeedbackTarget {
|
|
23
|
+
spaceId: string;
|
|
24
|
+
conversationId: string;
|
|
25
|
+
messageId: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Read the latest Genie target from an assistant message's tool results. */
|
|
29
|
+
export function genieFeedbackTarget(message: UIMessage): GenieFeedbackTarget | undefined {
|
|
30
|
+
for (const event of [...toolEventsFromParts(message.parts)].reverse()) {
|
|
31
|
+
if (!event.toolName.startsWith("ask_genie")) continue;
|
|
32
|
+
const output =
|
|
33
|
+
typeof event.output === "object" && event.output !== null && "message" in event.output
|
|
34
|
+
? event.output.message
|
|
35
|
+
: undefined;
|
|
36
|
+
const parsed = genieModel.GenieMessageSchema.safeParse(output);
|
|
37
|
+
if (!parsed.success) continue;
|
|
38
|
+
const genieMessage = parsed.data;
|
|
39
|
+
const messageId = genieMessage.message_id ?? genieMessage.id;
|
|
40
|
+
if (genieMessage.space_id && genieMessage.conversation_id && messageId) {
|
|
41
|
+
return {
|
|
42
|
+
spaceId: genieMessage.space_id,
|
|
43
|
+
conversationId: genieMessage.conversation_id,
|
|
44
|
+
messageId,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Submit feedback to the single destination selected by the server. */
|
|
18
52
|
export function useChatFeedback({
|
|
19
53
|
activeKey,
|
|
20
54
|
feedbackByMessage,
|
|
55
|
+
feedbackMode,
|
|
21
56
|
mastraClient,
|
|
22
57
|
updateSession,
|
|
23
58
|
}: UseChatFeedbackOptions) {
|
|
@@ -27,34 +62,55 @@ export function useChatFeedback({
|
|
|
27
62
|
return useCallback(
|
|
28
63
|
async (message: UIMessage, submission: FeedbackSubmission) => {
|
|
29
64
|
const traceId = feedbackByMessageRef.current[message.id]?.traceId;
|
|
30
|
-
|
|
65
|
+
const target = feedbackMode === "genie" ? genieFeedbackTarget(message) : undefined;
|
|
66
|
+
if (feedbackMode === "none") return;
|
|
67
|
+
|
|
31
68
|
if (submission.value) {
|
|
32
69
|
updateSession(activeKey, (session) => ({
|
|
33
70
|
...session,
|
|
34
71
|
feedbackByMessage: {
|
|
35
72
|
...session.feedbackByMessage,
|
|
36
|
-
[message.id]: {
|
|
73
|
+
[message.id]: {
|
|
74
|
+
...(traceId ? { traceId } : {}),
|
|
75
|
+
value: submission.value,
|
|
76
|
+
},
|
|
37
77
|
},
|
|
38
78
|
}));
|
|
39
79
|
}
|
|
40
80
|
try {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
81
|
+
let result;
|
|
82
|
+
if (feedbackMode === "genie") {
|
|
83
|
+
if (!target || !submission.value || !submission.request) return;
|
|
84
|
+
result = await mastraClient.feedback({
|
|
85
|
+
mode: "genie",
|
|
86
|
+
...target,
|
|
87
|
+
rating: submission.value === "up" ? "POSITIVE" : "NEGATIVE",
|
|
88
|
+
request: submission.request,
|
|
89
|
+
...(submission.comment ? { comment: submission.comment } : {}),
|
|
90
|
+
});
|
|
91
|
+
} else {
|
|
92
|
+
if (!traceId) return;
|
|
93
|
+
result = await mastraClient.feedback({
|
|
94
|
+
mode: "mlflow",
|
|
48
95
|
traceId,
|
|
96
|
+
...(submission.value !== undefined ? { value: submission.value === "up" } : {}),
|
|
97
|
+
...(submission.comment ? { comment: submission.comment } : {}),
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
if (!result.ok) {
|
|
101
|
+
logger.warn("feedback not recorded", {
|
|
102
|
+
feedbackMode,
|
|
103
|
+
...(traceId ? { traceId } : {}),
|
|
49
104
|
});
|
|
50
105
|
}
|
|
51
106
|
} catch (error) {
|
|
52
107
|
logger.error("feedback error", {
|
|
53
|
-
|
|
108
|
+
feedbackMode,
|
|
109
|
+
...(traceId ? { traceId } : {}),
|
|
54
110
|
error: errorUtils.toError(error),
|
|
55
111
|
});
|
|
56
112
|
}
|
|
57
113
|
},
|
|
58
|
-
[activeKey, mastraClient, updateSession],
|
|
114
|
+
[activeKey, feedbackMode, mastraClient, updateSession],
|
|
59
115
|
);
|
|
60
116
|
}
|
|
@@ -15,7 +15,9 @@ import { isToolUIPart } from "ai";
|
|
|
15
15
|
import { ArrowDownIcon, MessageSquareIcon, RefreshCwIcon, TriangleAlertIcon } from "lucide-react";
|
|
16
16
|
import React, { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
17
17
|
import { AssistantBubble, UserBubble } from "./bubbles.tsx";
|
|
18
|
+
import { genieFeedbackTarget } from "./chat-feedback.ts";
|
|
18
19
|
import type { ChatViewProps } from "./types.ts";
|
|
20
|
+
import { messageText } from "../support/export.ts";
|
|
19
21
|
|
|
20
22
|
const BOTTOM_THRESHOLD_PX = 24;
|
|
21
23
|
const TOP_LOAD_MORE_THRESHOLD_PX = 120;
|
|
@@ -156,6 +158,7 @@ type ChatTranscriptProps = {
|
|
|
156
158
|
pendingApprovalsByMessage: NonNullable<ChatViewProps["pendingApprovalsByMessage"]>;
|
|
157
159
|
onExportMessage: ChatViewProps["onExportMessage"];
|
|
158
160
|
feedbackByMessage: NonNullable<ChatViewProps["feedbackByMessage"]>;
|
|
161
|
+
feedbackMode: NonNullable<ChatViewProps["feedbackMode"]>;
|
|
159
162
|
onFeedback: ChatViewProps["onFeedback"];
|
|
160
163
|
mlflowExperimentUrl: ChatViewProps["mlflowExperimentUrl"];
|
|
161
164
|
};
|
|
@@ -176,6 +179,7 @@ export const ChatTranscript = ({
|
|
|
176
179
|
pendingApprovalsByMessage,
|
|
177
180
|
onExportMessage,
|
|
178
181
|
feedbackByMessage,
|
|
182
|
+
feedbackMode,
|
|
179
183
|
onFeedback,
|
|
180
184
|
mlflowExperimentUrl,
|
|
181
185
|
}: ChatTranscriptProps) => {
|
|
@@ -229,6 +233,17 @@ export const ChatTranscript = ({
|
|
|
229
233
|
const isLast = index === messages.length - 1;
|
|
230
234
|
if (message.role === "assistant") {
|
|
231
235
|
const messageFeedback = feedbackByMessage[message.id];
|
|
236
|
+
const genieTarget =
|
|
237
|
+
feedbackMode === "genie" ? genieFeedbackTarget(message) : undefined;
|
|
238
|
+
const canSubmitFeedback =
|
|
239
|
+
feedbackMode === "mlflow"
|
|
240
|
+
? Boolean(messageFeedback?.traceId)
|
|
241
|
+
: Boolean(genieTarget);
|
|
242
|
+
const requestMessage = [...messages.slice(0, index)]
|
|
243
|
+
.reverse()
|
|
244
|
+
.find((candidate) => candidate.role === "user");
|
|
245
|
+
const feedbackRequest = requestMessage ? messageText(requestMessage) : "";
|
|
246
|
+
const bubbleFeedbackMode = feedbackMode === "genie" ? "genie" : "mlflow";
|
|
232
247
|
return (
|
|
233
248
|
<AssistantBubble
|
|
234
249
|
key={message.id}
|
|
@@ -243,10 +258,12 @@ export const ChatTranscript = ({
|
|
|
243
258
|
{...(onExportMessage
|
|
244
259
|
? { onExport: (format) => onExportMessage(message, format) }
|
|
245
260
|
: {})}
|
|
246
|
-
{...(onFeedback &&
|
|
261
|
+
{...(onFeedback && canSubmitFeedback
|
|
247
262
|
? {
|
|
248
263
|
onFeedback: (submission) => onFeedback(message, submission),
|
|
249
|
-
|
|
264
|
+
feedbackMode: bubbleFeedbackMode,
|
|
265
|
+
...(feedbackRequest ? { feedbackRequest } : {}),
|
|
266
|
+
...(messageFeedback?.value
|
|
250
267
|
? { feedbackValue: messageFeedback.value }
|
|
251
268
|
: {}),
|
|
252
269
|
}
|
package/src/react/chat-view.tsx
CHANGED
|
@@ -64,6 +64,7 @@ export const ChatView = ({
|
|
|
64
64
|
onExportConversation,
|
|
65
65
|
onExportMessage,
|
|
66
66
|
feedbackByMessage = {},
|
|
67
|
+
feedbackMode = "none",
|
|
67
68
|
onFeedback,
|
|
68
69
|
mlflowExperimentUrl,
|
|
69
70
|
}: ChatViewProps) => {
|
|
@@ -113,6 +114,7 @@ export const ChatView = ({
|
|
|
113
114
|
pendingApprovalsByMessage={pendingApprovalsByMessage}
|
|
114
115
|
onExportMessage={onExportMessage}
|
|
115
116
|
feedbackByMessage={feedbackByMessage}
|
|
117
|
+
feedbackMode={feedbackMode}
|
|
116
118
|
onFeedback={onFeedback}
|
|
117
119
|
mlflowExperimentUrl={mlflowExperimentUrl}
|
|
118
120
|
/>
|
|
@@ -25,15 +25,22 @@ import type { FeedbackSubmission, FeedbackValue } from "./types.ts";
|
|
|
25
25
|
|
|
26
26
|
/** Render per-message rating and comment controls for an MLflow-backed trace. */
|
|
27
27
|
export const FeedbackControls = ({
|
|
28
|
+
mode = "mlflow",
|
|
29
|
+
request,
|
|
28
30
|
value,
|
|
29
31
|
onSubmit,
|
|
30
32
|
}: {
|
|
33
|
+
/** Server-selected feedback destination. */
|
|
34
|
+
mode?: "mlflow" | "genie";
|
|
35
|
+
/** Original user request shown in Genie feedback. */
|
|
36
|
+
request?: string;
|
|
31
37
|
/** Last thumbs the user chose, so the active button stays highlighted. */
|
|
32
38
|
value?: FeedbackValue;
|
|
33
39
|
onSubmit: (submission: FeedbackSubmission) => void | Promise<void>;
|
|
34
40
|
}) => {
|
|
35
41
|
const [open, setOpen] = useState(false);
|
|
36
42
|
const [comment, setComment] = useState("");
|
|
43
|
+
const [rating, setRating] = useState<FeedbackValue | undefined>(value);
|
|
37
44
|
const [sending, setSending] = useState(false);
|
|
38
45
|
|
|
39
46
|
const submitComment = async () => {
|
|
@@ -49,6 +56,103 @@ export const FeedbackControls = ({
|
|
|
49
56
|
}
|
|
50
57
|
};
|
|
51
58
|
|
|
59
|
+
const submitGenieFeedback = async () => {
|
|
60
|
+
if (!rating || !request?.trim() || sending) return;
|
|
61
|
+
setSending(true);
|
|
62
|
+
try {
|
|
63
|
+
await onSubmit({
|
|
64
|
+
value: rating,
|
|
65
|
+
request: request.trim(),
|
|
66
|
+
...(comment.trim() ? { comment: comment.trim() } : {}),
|
|
67
|
+
});
|
|
68
|
+
setOpen(false);
|
|
69
|
+
} finally {
|
|
70
|
+
setSending(false);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
if (mode === "genie") {
|
|
75
|
+
return (
|
|
76
|
+
<Dialog open={open} onOpenChange={setOpen}>
|
|
77
|
+
<Tooltip>
|
|
78
|
+
<TooltipTrigger asChild>
|
|
79
|
+
<DialogTrigger asChild>
|
|
80
|
+
<Button
|
|
81
|
+
type="button"
|
|
82
|
+
size="icon"
|
|
83
|
+
variant="ghost"
|
|
84
|
+
className="size-7"
|
|
85
|
+
aria-label="Give feedback"
|
|
86
|
+
>
|
|
87
|
+
<MessageSquareTextIcon className="size-3" />
|
|
88
|
+
</Button>
|
|
89
|
+
</DialogTrigger>
|
|
90
|
+
</TooltipTrigger>
|
|
91
|
+
<TooltipContent>Give feedback</TooltipContent>
|
|
92
|
+
</Tooltip>
|
|
93
|
+
<DialogContent className="sm:max-w-md">
|
|
94
|
+
<DialogHeader>
|
|
95
|
+
<DialogTitle>Feedback</DialogTitle>
|
|
96
|
+
<DialogDescription>Send feedback directly to this Genie response.</DialogDescription>
|
|
97
|
+
</DialogHeader>
|
|
98
|
+
<div className="space-y-4">
|
|
99
|
+
<fieldset className="space-y-2">
|
|
100
|
+
<legend className="text-sm font-medium">Rating</legend>
|
|
101
|
+
<div className="flex gap-2">
|
|
102
|
+
<Button
|
|
103
|
+
type="button"
|
|
104
|
+
variant={rating === "up" ? "default" : "outline"}
|
|
105
|
+
aria-pressed={rating === "up"}
|
|
106
|
+
onClick={() => setRating("up")}
|
|
107
|
+
>
|
|
108
|
+
<ThumbsUpIcon className="size-4" />
|
|
109
|
+
Good
|
|
110
|
+
</Button>
|
|
111
|
+
<Button
|
|
112
|
+
type="button"
|
|
113
|
+
variant={rating === "down" ? "destructive" : "outline"}
|
|
114
|
+
aria-pressed={rating === "down"}
|
|
115
|
+
onClick={() => setRating("down")}
|
|
116
|
+
>
|
|
117
|
+
<ThumbsDownIcon className="size-4" />
|
|
118
|
+
Bad
|
|
119
|
+
</Button>
|
|
120
|
+
</div>
|
|
121
|
+
</fieldset>
|
|
122
|
+
<div className="space-y-1.5">
|
|
123
|
+
<p className="text-sm font-medium">Request</p>
|
|
124
|
+
<p className="rounded-md border bg-muted/40 px-3 py-2 text-sm text-foreground">
|
|
125
|
+
{request}
|
|
126
|
+
</p>
|
|
127
|
+
</div>
|
|
128
|
+
<label className="block space-y-1.5 text-sm font-medium">
|
|
129
|
+
<span>Comment</span>
|
|
130
|
+
<Textarea
|
|
131
|
+
value={comment}
|
|
132
|
+
maxLength={5_000}
|
|
133
|
+
onChange={(event) => setComment(event.target.value)}
|
|
134
|
+
placeholder="Optional details"
|
|
135
|
+
rows={4}
|
|
136
|
+
/>
|
|
137
|
+
</label>
|
|
138
|
+
</div>
|
|
139
|
+
<DialogFooter>
|
|
140
|
+
<Button type="button" variant="ghost" onClick={() => setOpen(false)}>
|
|
141
|
+
Cancel
|
|
142
|
+
</Button>
|
|
143
|
+
<Button
|
|
144
|
+
type="button"
|
|
145
|
+
disabled={!rating || !request?.trim() || sending}
|
|
146
|
+
onClick={() => void submitGenieFeedback()}
|
|
147
|
+
>
|
|
148
|
+
{sending ? "Sending..." : "Send feedback"}
|
|
149
|
+
</Button>
|
|
150
|
+
</DialogFooter>
|
|
151
|
+
</DialogContent>
|
|
152
|
+
</Dialog>
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
52
156
|
return (
|
|
53
157
|
<>
|
|
54
158
|
<Tooltip>
|
|
@@ -3,6 +3,7 @@ import { isStaleMastraResumeError } from "@dbx-tools/shared-mastra/resume";
|
|
|
3
3
|
import type { ReasoningEffort } from "@dbx-tools/shared-model";
|
|
4
4
|
import { getAuthStatus } from "@dbx-tools/ui/auth/react";
|
|
5
5
|
import { useBrand } from "@dbx-tools/ui/branding/react";
|
|
6
|
+
import type { RequestContext } from "@mastra/client-js";
|
|
6
7
|
import type { FileUIPart, UIMessage } from "ai";
|
|
7
8
|
import { type ReactNode, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
8
9
|
import { toChronologicalUiMessages } from "./_history-messages.ts";
|
|
@@ -42,7 +43,6 @@ import {
|
|
|
42
43
|
} from "../support/model-selection.ts";
|
|
43
44
|
import {
|
|
44
45
|
snapshotRequestContext,
|
|
45
|
-
type MastraRequestContextSnapshot,
|
|
46
46
|
type MastraRequestContextSource,
|
|
47
47
|
} from "../support/request-context.ts";
|
|
48
48
|
import { threadStorageKey } from "../support/thread-persistence.ts";
|
|
@@ -238,14 +238,9 @@ export interface UseMastraChatOptions<
|
|
|
238
238
|
*/
|
|
239
239
|
enableClear?: boolean;
|
|
240
240
|
/**
|
|
241
|
-
* Surface per-message feedback controls
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
* Defaults to auto: controls render when the server reports MLflow
|
|
245
|
-
* feedback is available. Pass `false` to hide them or `true` to request
|
|
246
|
-
* them explicitly. Regardless of this flag, controls only render when the
|
|
247
|
-
* server reports MLflow logging is enabled (`clientConfig.feedbackEnabled`)
|
|
248
|
-
* and the turn produced a trace id.
|
|
241
|
+
* Surface per-message feedback controls for the destination selected by the
|
|
242
|
+
* server. Genie Agent Mode posts Rating and Comment to Genie; traced agent
|
|
243
|
+
* mode posts thumbs/comment assessments to MLflow.
|
|
249
244
|
*/
|
|
250
245
|
enableFeedback?: boolean;
|
|
251
246
|
/**
|
|
@@ -329,8 +324,9 @@ export const useMastraChat = <TValues extends Record<string, unknown> = Record<s
|
|
|
329
324
|
// Feedback defaults to automatic server capability detection. An explicit
|
|
330
325
|
// false hides it; true keeps it requested but cannot bypass the server gate.
|
|
331
326
|
const enableFeedback = options.enableFeedback !== false;
|
|
332
|
-
const
|
|
333
|
-
const
|
|
327
|
+
const feedbackMode = enableFeedback ? mastraClient.feedbackMode : "none";
|
|
328
|
+
const feedbackAvailable = feedbackMode !== "none";
|
|
329
|
+
const { url: mlflowExperimentUrl } = useMastraMlflowExperiment(feedbackMode === "mlflow");
|
|
334
330
|
const [resourceScope, setResourceScope] = useState<string | null>(null);
|
|
335
331
|
useEffect(() => {
|
|
336
332
|
let cancelled = false;
|
|
@@ -577,6 +573,7 @@ export const useMastraChat = <TValues extends Record<string, unknown> = Record<s
|
|
|
577
573
|
const submitFeedback = useChatFeedback({
|
|
578
574
|
activeKey,
|
|
579
575
|
feedbackByMessage: activeSession.feedbackByMessage,
|
|
576
|
+
feedbackMode,
|
|
580
577
|
mastraClient,
|
|
581
578
|
updateSession,
|
|
582
579
|
});
|
|
@@ -755,11 +752,7 @@ export const useMastraChat = <TValues extends Record<string, unknown> = Record<s
|
|
|
755
752
|
);
|
|
756
753
|
|
|
757
754
|
const runStream = useCallback(
|
|
758
|
-
(
|
|
759
|
-
threadId: string,
|
|
760
|
-
messages: UIMessage | UIMessage[],
|
|
761
|
-
requestContext?: MastraRequestContextSnapshot,
|
|
762
|
-
) => {
|
|
755
|
+
(threadId: string, messages: UIMessage | UIMessage[], requestContext?: RequestContext) => {
|
|
763
756
|
const turnMessages = Array.isArray(messages) ? messages : [messages];
|
|
764
757
|
const userMessage = lastUserMessage(turnMessages);
|
|
765
758
|
if (!userMessage) throw new Error("A Mastra chat turn requires a user message");
|
|
@@ -1493,12 +1486,11 @@ export const useMastraChat = <TValues extends Record<string, unknown> = Record<s
|
|
|
1493
1486
|
onExportMessage: exportMessage,
|
|
1494
1487
|
}
|
|
1495
1488
|
: {}),
|
|
1496
|
-
// Feedback:
|
|
1497
|
-
//
|
|
1498
|
-
// is enabled AND the server can log to MLflow. `feedbackByMessage`
|
|
1499
|
-
// still gates per-message on a captured trace id.
|
|
1489
|
+
// Feedback: expose one server-selected destination. MLflow messages still
|
|
1490
|
+
// require trace state; Genie messages derive their target from ask_genie.
|
|
1500
1491
|
...(feedbackAvailable
|
|
1501
1492
|
? {
|
|
1493
|
+
feedbackMode,
|
|
1502
1494
|
feedbackByMessage: activeSession.feedbackByMessage,
|
|
1503
1495
|
onFeedback: submitFeedback,
|
|
1504
1496
|
...(mlflowExperimentUrl ? { mlflowExperimentUrl } : {}),
|
|
@@ -152,7 +152,9 @@ export const ThreadSidebar = ({
|
|
|
152
152
|
New chat
|
|
153
153
|
</Button>
|
|
154
154
|
)}
|
|
155
|
-
{headerActions
|
|
155
|
+
{headerActions ? (
|
|
156
|
+
<div className={cn("shrink-0", !onNew && "ml-auto")}>{headerActions}</div>
|
|
157
|
+
) : null}
|
|
156
158
|
{onHide && (
|
|
157
159
|
<Tooltip>
|
|
158
160
|
<TooltipTrigger asChild>
|
|
@@ -162,7 +164,7 @@ export const ThreadSidebar = ({
|
|
|
162
164
|
size="icon"
|
|
163
165
|
onClick={onHide}
|
|
164
166
|
aria-label="Hide conversations"
|
|
165
|
-
className={cn("size-8 shrink-0", !onNew && "ml-auto")}
|
|
167
|
+
className={cn("size-8 shrink-0", !onNew && !headerActions && "ml-auto")}
|
|
166
168
|
>
|
|
167
169
|
<HideIcon className="size-4" />
|
|
168
170
|
</Button>
|
package/src/react/types.ts
CHANGED
|
@@ -70,6 +70,7 @@ export type FeedbackValue = "up" | "down";
|
|
|
70
70
|
*/
|
|
71
71
|
export type FeedbackSubmission = {
|
|
72
72
|
value?: FeedbackValue;
|
|
73
|
+
request?: string;
|
|
73
74
|
comment?: string;
|
|
74
75
|
};
|
|
75
76
|
|
|
@@ -81,7 +82,7 @@ export type FeedbackSubmission = {
|
|
|
81
82
|
* active thumb stays highlighted.
|
|
82
83
|
*/
|
|
83
84
|
export type MessageFeedback = {
|
|
84
|
-
traceId
|
|
85
|
+
traceId?: string;
|
|
85
86
|
value?: FeedbackValue;
|
|
86
87
|
};
|
|
87
88
|
|
|
@@ -364,6 +365,8 @@ export type ChatViewProps = {
|
|
|
364
365
|
* response header when MLflow logging is enabled.
|
|
365
366
|
*/
|
|
366
367
|
feedbackByMessage?: Record<string, MessageFeedback>;
|
|
368
|
+
/** Resolved feedback destination selected by the server. */
|
|
369
|
+
feedbackMode?: "none" | "mlflow" | "genie";
|
|
367
370
|
/**
|
|
368
371
|
* Submit thumbs / comment feedback for an assistant message. When
|
|
369
372
|
* provided (and the message has a {@link feedbackByMessage} entry),
|
package/src/support/export.ts
CHANGED
|
@@ -217,7 +217,7 @@ function splitSegments(text: string): Segment[] {
|
|
|
217
217
|
}
|
|
218
218
|
|
|
219
219
|
/** Concatenate a message's `text` parts (matches the on-screen bubbles). */
|
|
220
|
-
function messageText(message: UIMessage): string {
|
|
220
|
+
export function messageText(message: UIMessage): string {
|
|
221
221
|
return message.parts
|
|
222
222
|
.filter((p): p is { type: "text"; text: string } => p.type === "text")
|
|
223
223
|
.map((p) => p.text)
|
|
@@ -3,17 +3,19 @@ import type {
|
|
|
3
3
|
ListAgentSuspendedRunsResponse,
|
|
4
4
|
ListMemoryThreadMessagesResponse,
|
|
5
5
|
ListMemoryThreadsResponse,
|
|
6
|
+
RequestContext,
|
|
6
7
|
} from "@mastra/client-js";
|
|
7
8
|
import { validateUIMessages, type UIMessage, type UIMessageChunk } from "ai";
|
|
8
9
|
import { MastraPluginClient, type MastraStreamResponse } from "./mastra-client.ts";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* {@link MastraPluginClient} that talks to one Genie space directly through
|
|
12
|
-
* the Mastra plugin's `/genie/:alias` routes instead of an agent
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
13
|
+
* the Mastra plugin's `/genie/:alias` routes instead of an outer agent. Genie
|
|
14
|
+
* owns conversation state while the server may add Mastra request context and
|
|
15
|
+
* resource-scoped memory. Its conversations are the threads (the conversation
|
|
16
|
+
* id is the thread id), its messages are the history, and each turn streams
|
|
17
|
+
* the same AI SDK chunks as an agent's `ask_genie` call, so the Mastra chat
|
|
18
|
+
* renders it unchanged.
|
|
17
19
|
*
|
|
18
20
|
* A brand-new thread has no Genie conversation until its first turn; the
|
|
19
21
|
* stream announces the conversation id, which {@link MastraStreamResponse.threadId}
|
|
@@ -23,7 +25,7 @@ export class GenieChatClient extends MastraPluginClient {
|
|
|
23
25
|
/** Genie space alias every route is scoped to. */
|
|
24
26
|
readonly alias: string;
|
|
25
27
|
override readonly backgroundTurns = false;
|
|
26
|
-
override readonly
|
|
28
|
+
override readonly feedbackMode = "none";
|
|
27
29
|
override readonly threadRename = false;
|
|
28
30
|
override readonly attachments = false;
|
|
29
31
|
/** Thread ids known to be Genie conversations (listed, loaded, or announced). */
|
|
@@ -54,6 +56,7 @@ export class GenieChatClient extends MastraPluginClient {
|
|
|
54
56
|
messages: UIMessage[];
|
|
55
57
|
runId: string;
|
|
56
58
|
threadId?: string;
|
|
59
|
+
requestContext?: RequestContext;
|
|
57
60
|
signal?: AbortSignal;
|
|
58
61
|
}): Promise<MastraStreamResponse> {
|
|
59
62
|
const userMessage = [...params.messages].reverse().find((message) => message.role === "user");
|
|
@@ -67,7 +70,11 @@ export class GenieChatClient extends MastraPluginClient {
|
|
|
67
70
|
path: this.#url(routes.MASTRA_ROUTES.chat),
|
|
68
71
|
chatId: params.threadId ?? params.runId,
|
|
69
72
|
messages: userMessage ? [userMessage] : [],
|
|
70
|
-
body: {
|
|
73
|
+
body: {
|
|
74
|
+
question,
|
|
75
|
+
...(conversationId ? { conversationId } : {}),
|
|
76
|
+
...(params.requestContext ? { requestContext: params.requestContext } : {}),
|
|
77
|
+
},
|
|
71
78
|
routing: {},
|
|
72
79
|
signal: params.signal,
|
|
73
80
|
});
|
package/src/support/index.ts
CHANGED
|
@@ -26,7 +26,7 @@ export { GenieChatClient } from "./genie-client.ts";
|
|
|
26
26
|
export { MastraChatRequestError, MastraPluginClient, useMastraConfig, useMastraClient, useMastraMlflowExperiment, useMastraModels, useMastraDefaultModel, useMastraSuggestions, useMastraThreads, useChartFetch, useStatementFetch, useVisualizationFetch } from "./mastra-client.ts";
|
|
27
27
|
export type { MastraStreamResponse, MastraMemoryThread, ByIdFetchState } from "./mastra-client.ts";
|
|
28
28
|
export { defaultReasoningEffort, modelStorageKey, readStoredModel, storeSelectedModel } from "./model-selection.ts";
|
|
29
|
-
export type { MastraRequestContextInput, MastraRequestContextSource
|
|
29
|
+
export type { MastraRequestContextInput, MastraRequestContextSource } from "./request-context.ts";
|
|
30
30
|
export { DEFAULT_THREAD_SESSION_KEY } from "./thread-sessions.ts";
|
|
31
31
|
export type { SessionQueuedSteer, SessionRun, ThreadSession } from "./thread-sessions.ts";
|
|
32
32
|
export { THREAD_TAB_SEED_MAX } from "./thread-tabs.ts";
|
|
@@ -20,10 +20,10 @@ import {
|
|
|
20
20
|
type ListAgentSuspendedRunsResponse,
|
|
21
21
|
type ListMemoryThreadMessagesResponse,
|
|
22
22
|
type ListMemoryThreadsResponse,
|
|
23
|
+
type RequestContext,
|
|
23
24
|
} from "@mastra/client-js";
|
|
24
25
|
import { DefaultChatTransport, type UIMessage, type UIMessageChunk } from "ai";
|
|
25
26
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
26
|
-
import type { MastraRequestContextSnapshot } from "./request-context.ts";
|
|
27
27
|
|
|
28
28
|
type NativeAgentClient = ReturnType<MastraClient["getAgent"]>;
|
|
29
29
|
|
|
@@ -79,13 +79,8 @@ export class MastraPluginClient extends MastraClient {
|
|
|
79
79
|
readonly defaultAgent: string;
|
|
80
80
|
/** Registered agent ids, surfaced for pickers. */
|
|
81
81
|
readonly agents: readonly string[];
|
|
82
|
-
/**
|
|
83
|
-
|
|
84
|
-
* chat UI hides thumbs / comment controls and {@link feedback} would
|
|
85
|
-
* be rejected server-side, so callers gate on this before offering
|
|
86
|
-
* feedback affordances.
|
|
87
|
-
*/
|
|
88
|
-
readonly feedbackEnabled: boolean;
|
|
82
|
+
/** Resolved feedback destination published by the server. */
|
|
83
|
+
readonly feedbackMode: feedback.FeedbackMode;
|
|
89
84
|
/**
|
|
90
85
|
* Whether the agents run their Databricks calls as the app service principal
|
|
91
86
|
* rather than on-behalf-of the signed-in user. When `true` the chat works for
|
|
@@ -111,7 +106,7 @@ export class MastraPluginClient extends MastraClient {
|
|
|
111
106
|
this.basePath = config.basePath;
|
|
112
107
|
this.defaultAgent = config.defaultAgent;
|
|
113
108
|
this.agents = config.agents;
|
|
114
|
-
this.
|
|
109
|
+
this.feedbackMode = config.feedbackMode ?? "none";
|
|
115
110
|
this.chatAlwaysAvailable = config.chatAlwaysAvailable ?? false;
|
|
116
111
|
this.backgroundTurns = config.backgroundTurns ?? false;
|
|
117
112
|
}
|
|
@@ -227,7 +222,7 @@ export class MastraPluginClient extends MastraClient {
|
|
|
227
222
|
threadId?: string;
|
|
228
223
|
model?: string;
|
|
229
224
|
reasoningEffort?: ReasoningEffort;
|
|
230
|
-
requestContext?:
|
|
225
|
+
requestContext?: RequestContext;
|
|
231
226
|
signal?: AbortSignal;
|
|
232
227
|
}): Promise<MastraStreamResponse> {
|
|
233
228
|
return this.uiStream({
|
|
@@ -295,7 +290,7 @@ export class MastraPluginClient extends MastraClient {
|
|
|
295
290
|
runId: string;
|
|
296
291
|
toolCallId: string;
|
|
297
292
|
threadId?: string;
|
|
298
|
-
requestContext?:
|
|
293
|
+
requestContext?: RequestContext;
|
|
299
294
|
signal?: AbortSignal;
|
|
300
295
|
},
|
|
301
296
|
): Promise<MastraStreamResponse> {
|
|
@@ -312,7 +307,7 @@ export class MastraPluginClient extends MastraClient {
|
|
|
312
307
|
toolCallId: string;
|
|
313
308
|
threadId?: string;
|
|
314
309
|
reason?: string;
|
|
315
|
-
requestContext?:
|
|
310
|
+
requestContext?: RequestContext;
|
|
316
311
|
signal?: AbortSignal;
|
|
317
312
|
},
|
|
318
313
|
): Promise<MastraStreamResponse> {
|
|
@@ -327,7 +322,7 @@ export class MastraPluginClient extends MastraClient {
|
|
|
327
322
|
toolCallId: string;
|
|
328
323
|
threadId?: string;
|
|
329
324
|
reason?: string;
|
|
330
|
-
requestContext?:
|
|
325
|
+
requestContext?: RequestContext;
|
|
331
326
|
signal?: AbortSignal;
|
|
332
327
|
},
|
|
333
328
|
): Promise<MastraStreamResponse> {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { RequestContext } from "@mastra/client-js";
|
|
1
|
+
import { RequestContext } from "@mastra/client-js";
|
|
3
2
|
|
|
4
3
|
/** Typed plain values or Mastra's native typed request-context container. */
|
|
5
4
|
export type MastraRequestContextInput<TValues extends Record<string, unknown>> =
|
|
@@ -9,22 +8,16 @@ export type MastraRequestContextInput<TValues extends Record<string, unknown>> =
|
|
|
9
8
|
export type MastraRequestContextSource<TValues extends Record<string, unknown>> =
|
|
10
9
|
MastraRequestContextInput<TValues> | (() => MastraRequestContextInput<TValues> | undefined);
|
|
11
10
|
|
|
12
|
-
/** JSON-safe immutable snapshot retained for one run and its continuation. */
|
|
13
|
-
export type MastraRequestContextSnapshot = Record<string, SerializableValue>;
|
|
14
|
-
|
|
15
11
|
/**
|
|
16
|
-
* Materialize
|
|
17
|
-
*
|
|
12
|
+
* Materialize one run's application context through Mastra's native container
|
|
13
|
+
* and serialization policy.
|
|
18
14
|
*/
|
|
19
15
|
export function snapshotRequestContext<TValues extends Record<string, unknown>>(
|
|
20
16
|
source: MastraRequestContextSource<TValues> | undefined,
|
|
21
|
-
):
|
|
17
|
+
): RequestContext | undefined {
|
|
22
18
|
const input = typeof source === "function" ? source() : source;
|
|
23
19
|
if (input === undefined) return undefined;
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
throw new TypeError("Mastra request context must be a JSON-serializable record");
|
|
28
|
-
}
|
|
29
|
-
return structuredClone(candidate) as MastraRequestContextSnapshot;
|
|
20
|
+
const context =
|
|
21
|
+
input instanceof RequestContext ? input : new RequestContext<unknown>(Object.entries(input));
|
|
22
|
+
return new RequestContext<unknown>(Object.entries(structuredClone(context.toJSON())));
|
|
30
23
|
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
+
import type { RequestContext } from "@mastra/client-js";
|
|
1
2
|
import type { UIMessage } from "ai";
|
|
2
|
-
import type { MastraRequestContextSnapshot } from "./request-context.ts";
|
|
3
3
|
import type { ChatStatus, MessageFeedback, PendingApproval, QueuedSteer } from "../react/types.ts";
|
|
4
4
|
|
|
5
5
|
export type { QueuedSteer } from "../react/types.ts";
|
|
6
6
|
|
|
7
7
|
/** A queued steer plus the application context captured when it was submitted. */
|
|
8
8
|
export type SessionQueuedSteer = QueuedSteer & {
|
|
9
|
-
requestContext?:
|
|
9
|
+
requestContext?: RequestContext;
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
/** UI target and immutable application context captured for one Mastra run. */
|
|
13
13
|
export type SessionRun = {
|
|
14
14
|
assistantId: string;
|
|
15
|
-
requestContext?:
|
|
15
|
+
requestContext?: RequestContext;
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
/** Session-scoped transcript + stream state for one conversation thread. */
|
|
@@ -32,9 +32,9 @@ export type ThreadSession = {
|
|
|
32
32
|
hasMoreHistory: boolean;
|
|
33
33
|
historyPage: number;
|
|
34
34
|
/** Context snapshot for the active run and approval continuation. */
|
|
35
|
-
runRequestContext?:
|
|
35
|
+
runRequestContext?: RequestContext;
|
|
36
36
|
/** Context snapshot reused when regenerating the last turn. */
|
|
37
|
-
lastRequestContext?:
|
|
37
|
+
lastRequestContext?: RequestContext;
|
|
38
38
|
/** Steers submitted mid-turn, waiting to run (oldest first). */
|
|
39
39
|
queuedSteers: SessionQueuedSteer[];
|
|
40
40
|
};
|