@agent-native/toolkit 0.213.1 → 0.216.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/agent-native.eject.json +9 -0
- package/dist/app/agentkit/react/chat.d.ts.map +1 -1
- package/dist/app/agentkit/react/chat.js +2 -2
- package/dist/app/agentkit/react/chat.js.map +1 -1
- package/dist/app/agentkit/react/components.d.ts +4 -1
- package/dist/app/agentkit/react/components.d.ts.map +1 -1
- package/dist/app/agentkit/react/components.js +73 -13
- package/dist/app/agentkit/react/components.js.map +1 -1
- package/dist/app/agentkit/react/context.d.ts +19 -1
- package/dist/app/agentkit/react/context.d.ts.map +1 -1
- package/dist/app/agentkit/react/context.js +7 -1
- package/dist/app/agentkit/react/context.js.map +1 -1
- package/dist/app/agentkit/react/index.d.ts +2 -0
- package/dist/app/agentkit/react/index.d.ts.map +1 -1
- package/dist/app/agentkit/react/index.js +2 -0
- package/dist/app/agentkit/react/index.js.map +1 -1
- package/dist/app/agentkit/react/message-content-order.d.ts +21 -0
- package/dist/app/agentkit/react/message-content-order.d.ts.map +1 -0
- package/dist/app/agentkit/react/message-content-order.js +173 -0
- package/dist/app/agentkit/react/message-content-order.js.map +1 -0
- package/dist/app/agentkit/react/root.d.ts +6 -1
- package/dist/app/agentkit/react/root.d.ts.map +1 -1
- package/dist/app/agentkit/react/root.js +2 -2
- package/dist/app/agentkit/react/root.js.map +1 -1
- package/dist/app/agentkit/react/styles.css +45 -8
- package/dist/app/agentkit/react/transcript-layout.d.ts +51 -0
- package/dist/app/agentkit/react/transcript-layout.d.ts.map +1 -0
- package/dist/app/agentkit/react/transcript-layout.js +34 -0
- package/dist/app/agentkit/react/transcript-layout.js.map +1 -0
- package/dist/app/chat/AgentKitAssistantChat.d.ts.map +1 -1
- package/dist/app/chat/AgentKitAssistantChat.js +9 -4
- package/dist/app/chat/AgentKitAssistantChat.js.map +1 -1
- package/dist/app/chat/AgentPanel.d.ts +16 -2
- package/dist/app/chat/AgentPanel.d.ts.map +1 -1
- package/dist/app/chat/AgentPanel.js +26 -5
- package/dist/app/chat/AgentPanel.js.map +1 -1
- package/dist/app/chat/chat/index.d.ts +2 -0
- package/dist/app/chat/chat/index.d.ts.map +1 -1
- package/dist/app/chat/chat/index.js.map +1 -1
- package/dist/app/chat/chat/surface-types.d.ts +15 -0
- package/dist/app/chat/chat/surface-types.d.ts.map +1 -1
- package/dist/app/chat/chat/surface-types.js.map +1 -1
- package/dist/app/chat/chat/tool-call-display.d.ts +7 -2
- package/dist/app/chat/chat/tool-call-display.d.ts.map +1 -1
- package/dist/app/chat/chat/tool-call-display.js +10 -9
- package/dist/app/chat/chat/tool-call-display.js.map +1 -1
- package/dist/app/chat/chat/widgets/DataChartRenderer.d.ts.map +1 -1
- package/dist/app/chat/chat/widgets/DataChartRenderer.js +300 -33
- package/dist/app/chat/chat/widgets/DataChartRenderer.js.map +1 -1
- package/dist/app/chat/chat/widgets/DataChartWidget.d.ts +3 -2
- package/dist/app/chat/chat/widgets/DataChartWidget.d.ts.map +1 -1
- package/dist/app/chat/chat/widgets/DataChartWidget.js +18 -9
- package/dist/app/chat/chat/widgets/DataChartWidget.js.map +1 -1
- package/dist/app/chat/chat/widgets/DataInsightsWidget.js +1 -1
- package/dist/app/chat/chat/widgets/DataInsightsWidget.js.map +1 -1
- package/dist/app/chat/chat/widgets/DataTableWidget.d.ts +3 -2
- package/dist/app/chat/chat/widgets/DataTableWidget.d.ts.map +1 -1
- package/dist/app/chat/chat/widgets/DataTableWidget.js +10 -66
- package/dist/app/chat/chat/widgets/DataTableWidget.js.map +1 -1
- package/dist/app/chat/chat/widgets/DataWidgetDisplayControls.d.ts +11 -0
- package/dist/app/chat/chat/widgets/DataWidgetDisplayControls.d.ts.map +1 -0
- package/dist/app/chat/chat/widgets/DataWidgetDisplayControls.js +133 -0
- package/dist/app/chat/chat/widgets/DataWidgetDisplayControls.js.map +1 -0
- package/dist/app/chat/chat/widgets/builtin-tool-renderers.js +2 -2
- package/dist/app/chat/chat/widgets/builtin-tool-renderers.js.map +1 -1
- package/dist/app/chat/mcp-apps/McpAppRenderer.d.ts.map +1 -1
- package/dist/app/chat/mcp-apps/McpAppRenderer.js +6 -5
- package/dist/app/chat/mcp-apps/McpAppRenderer.js.map +1 -1
- package/dist/app/chat/mcp-apps/mcp-app-theme.d.ts +2 -0
- package/dist/app/chat/mcp-apps/mcp-app-theme.d.ts.map +1 -0
- package/dist/app/chat/mcp-apps/mcp-app-theme.js +11 -0
- package/dist/app/chat/mcp-apps/mcp-app-theme.js.map +1 -0
- package/dist/app/i18n/catalogs/ar-SA.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ar-SA.js +9 -0
- package/dist/app/i18n/catalogs/ar-SA.js.map +1 -1
- package/dist/app/i18n/catalogs/de-DE.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/de-DE.js +9 -0
- package/dist/app/i18n/catalogs/de-DE.js.map +1 -1
- package/dist/app/i18n/catalogs/en-US.d.ts +9 -0
- package/dist/app/i18n/catalogs/en-US.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/en-US.js +9 -0
- package/dist/app/i18n/catalogs/en-US.js.map +1 -1
- package/dist/app/i18n/catalogs/es-ES.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/es-ES.js +9 -0
- package/dist/app/i18n/catalogs/es-ES.js.map +1 -1
- package/dist/app/i18n/catalogs/fr-FR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/fr-FR.js +9 -0
- package/dist/app/i18n/catalogs/fr-FR.js.map +1 -1
- package/dist/app/i18n/catalogs/hi-IN.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/hi-IN.js +9 -0
- package/dist/app/i18n/catalogs/hi-IN.js.map +1 -1
- package/dist/app/i18n/catalogs/ja-JP.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ja-JP.js +9 -0
- package/dist/app/i18n/catalogs/ja-JP.js.map +1 -1
- package/dist/app/i18n/catalogs/ko-KR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/ko-KR.js +9 -0
- package/dist/app/i18n/catalogs/ko-KR.js.map +1 -1
- package/dist/app/i18n/catalogs/pt-BR.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/pt-BR.js +9 -0
- package/dist/app/i18n/catalogs/pt-BR.js.map +1 -1
- package/dist/app/i18n/catalogs/zh-CN.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/zh-CN.js +9 -0
- package/dist/app/i18n/catalogs/zh-CN.js.map +1 -1
- package/dist/app/i18n/catalogs/zh-TW.d.ts.map +1 -1
- package/dist/app/i18n/catalogs/zh-TW.js +9 -0
- package/dist/app/i18n/catalogs/zh-TW.js.map +1 -1
- package/dist/app/providers/AppProviders.d.ts +2 -1
- package/dist/app/providers/AppProviders.d.ts.map +1 -1
- package/dist/app/providers/AppProviders.js +4 -3
- package/dist/app/providers/AppProviders.js.map +1 -1
- package/dist/app/providers/ThemeFamilySync.d.ts +2 -0
- package/dist/app/providers/ThemeFamilySync.d.ts.map +1 -0
- package/dist/app/providers/ThemeFamilySync.js +6 -0
- package/dist/app/providers/ThemeFamilySync.js.map +1 -0
- package/dist/app/settings/account/PreferencesSettings.d.ts.map +1 -1
- package/dist/app/settings/account/PreferencesSettings.js +2 -1
- package/dist/app/settings/account/PreferencesSettings.js.map +1 -1
- package/dist/app/settings/account/ThemeFamilySettings.d.ts +2 -0
- package/dist/app/settings/account/ThemeFamilySettings.d.ts.map +1 -0
- package/dist/app/settings/account/ThemeFamilySettings.js +31 -0
- package/dist/app/settings/account/ThemeFamilySettings.js.map +1 -0
- package/dist/app/settings/account/search-entries.d.ts.map +1 -1
- package/dist/app/settings/account/search-entries.js +6 -0
- package/dist/app/settings/account/search-entries.js.map +1 -1
- package/dist/app/shared/DefaultSpinner.d.ts.map +1 -1
- package/dist/app/shared/DefaultSpinner.js +4 -5
- package/dist/app/shared/DefaultSpinner.js.map +1 -1
- package/dist/app/shared/ErrorBoundary.d.ts +1 -0
- package/dist/app/shared/ErrorBoundary.d.ts.map +1 -1
- package/dist/app/shared/ErrorBoundary.js +27 -12
- package/dist/app/shared/ErrorBoundary.js.map +1 -1
- package/dist/app/shared/PoweredByBadge.d.ts.map +1 -1
- package/dist/app/shared/PoweredByBadge.js +8 -49
- package/dist/app/shared/PoweredByBadge.js.map +1 -1
- package/dist/app/styles/agent-conversation.css +0 -23
- package/dist/app/styles/agent-native.css +1 -1
- package/dist/app/styles/theme-families.css +66 -0
- package/dist/composer/ComposerContextBanner.d.ts +24 -0
- package/dist/composer/ComposerContextBanner.d.ts.map +1 -0
- package/dist/composer/ComposerContextBanner.js +9 -0
- package/dist/composer/ComposerContextBanner.js.map +1 -0
- package/dist/composer/ComposerModePicker.d.ts +26 -0
- package/dist/composer/ComposerModePicker.d.ts.map +1 -0
- package/dist/composer/ComposerModePicker.js +14 -0
- package/dist/composer/ComposerModePicker.js.map +1 -0
- package/dist/composer/index.d.ts +2 -0
- package/dist/composer/index.d.ts.map +1 -1
- package/dist/composer/index.js +2 -0
- package/dist/composer/index.js.map +1 -1
- package/dist/styles.css +1 -0
- package/package.json +3 -3
- package/src/app/agentkit/react/chat.tsx +2 -0
- package/src/app/agentkit/react/components.interaction.spec.tsx +107 -0
- package/src/app/agentkit/react/components.spec.tsx +40 -1
- package/src/app/agentkit/react/components.tsx +186 -31
- package/src/app/agentkit/react/context.tsx +29 -0
- package/src/app/agentkit/react/index.ts +2 -0
- package/src/app/agentkit/react/lifecycle.spec.tsx +289 -4
- package/src/app/agentkit/react/message-content-order.spec.ts +190 -0
- package/src/app/agentkit/react/message-content-order.ts +246 -0
- package/src/app/agentkit/react/root.tsx +11 -0
- package/src/app/agentkit/react/styles.css +45 -8
- package/src/app/agentkit/react/transcript-layout.spec.ts +72 -0
- package/src/app/agentkit/react/transcript-layout.ts +97 -0
- package/src/app/auth/AuthPage.attribution.spec.tsx +6 -0
- package/src/app/chat/AgentKitAssistantChat.spec.tsx +58 -0
- package/src/app/chat/AgentKitAssistantChat.tsx +15 -1
- package/src/app/chat/AgentPanel.header.spec.ts +72 -14
- package/src/app/chat/AgentPanel.page-header-share.spec.tsx +101 -0
- package/src/app/chat/AgentPanel.tsx +111 -55
- package/src/app/chat/chat/index.ts +2 -0
- package/src/app/chat/chat/surface-types.ts +18 -0
- package/src/app/chat/chat/tool-call-display.spec.tsx +83 -0
- package/src/app/chat/chat/tool-call-display.tsx +40 -8
- package/src/app/chat/chat/widgets/DataChartRenderer.spec.tsx +849 -0
- package/src/app/chat/chat/widgets/DataChartRenderer.tsx +567 -72
- package/src/app/chat/chat/widgets/DataChartWidget.spec.tsx +432 -0
- package/src/app/chat/chat/widgets/DataChartWidget.ssr.spec.tsx +25 -0
- package/src/app/chat/chat/widgets/DataChartWidget.tsx +58 -33
- package/src/app/chat/chat/widgets/DataInsightsWidget.tsx +2 -2
- package/src/app/chat/chat/widgets/DataTableWidget.spec.tsx +37 -3
- package/src/app/chat/chat/widgets/DataTableWidget.tsx +22 -86
- package/src/app/chat/chat/widgets/DataWidgetDisplayControls.tsx +321 -0
- package/src/app/chat/chat/widgets/builtin-tool-renderers.tsx +5 -5
- package/src/app/chat/mcp-apps/McpAppRenderer.tsx +10 -5
- package/src/app/chat/mcp-apps/mcp-app-theme.spec.ts +30 -0
- package/src/app/chat/mcp-apps/mcp-app-theme.ts +11 -0
- package/src/app/i18n/catalogs/ar-SA.ts +10 -0
- package/src/app/i18n/catalogs/de-DE.ts +11 -0
- package/src/app/i18n/catalogs/en-US.ts +11 -0
- package/src/app/i18n/catalogs/es-ES.ts +12 -0
- package/src/app/i18n/catalogs/fr-FR.ts +12 -0
- package/src/app/i18n/catalogs/hi-IN.ts +10 -0
- package/src/app/i18n/catalogs/ja-JP.ts +11 -0
- package/src/app/i18n/catalogs/ko-KR.ts +10 -0
- package/src/app/i18n/catalogs/pt-BR.ts +11 -0
- package/src/app/i18n/catalogs/zh-CN.ts +9 -0
- package/src/app/i18n/catalogs/zh-TW.ts +10 -0
- package/src/app/providers/AppProviders.spec.tsx +71 -0
- package/src/app/providers/AppProviders.tsx +10 -0
- package/src/app/providers/ThemeFamilySync.tsx +6 -0
- package/src/app/settings/account/PreferencesSettings.spec.tsx +13 -2
- package/src/app/settings/account/PreferencesSettings.tsx +8 -0
- package/src/app/settings/account/ThemeFamilySettings.tsx +61 -0
- package/src/app/settings/account/search-entries.ts +6 -0
- package/src/app/shared/DefaultSpinner.spec.tsx +14 -0
- package/src/app/shared/DefaultSpinner.tsx +4 -5
- package/src/app/shared/ErrorBoundary.spec.tsx +45 -2
- package/src/app/shared/ErrorBoundary.tsx +37 -12
- package/src/app/shared/PoweredByBadge.spec.tsx +16 -0
- package/src/app/shared/PoweredByBadge.tsx +8 -50
- package/src/app/styles/agent-conversation.css +0 -23
- package/src/app/styles/agent-native.css +1 -1
- package/src/app/styles/agent-native.spec.ts +18 -0
- package/src/app/styles/theme-families.css +66 -0
- package/src/app/styles/theme-families.spec.ts +29 -0
- package/src/composer/ComposerContextBanner.spec.tsx +100 -0
- package/src/composer/ComposerContextBanner.tsx +77 -0
- package/src/composer/ComposerModePicker.spec.tsx +101 -0
- package/src/composer/ComposerModePicker.tsx +98 -0
- package/src/composer/index.ts +9 -0
- package/src/styles.css +1 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AgentEvent,
|
|
3
|
+
AgentMessage,
|
|
4
|
+
AgentMessagePart,
|
|
5
|
+
AgentWidget,
|
|
6
|
+
} from "@agent-native/agentkit/protocol";
|
|
7
|
+
|
|
8
|
+
export type AgentMessageContentItem =
|
|
9
|
+
| { key: string; type: "part"; part: AgentMessagePart }
|
|
10
|
+
| { key: string; type: "widget"; widget: AgentWidget };
|
|
11
|
+
|
|
12
|
+
export interface AgentMessageContentOrderInput {
|
|
13
|
+
message: AgentMessage;
|
|
14
|
+
parts: AgentMessagePart[];
|
|
15
|
+
widgets: AgentWidget[];
|
|
16
|
+
events: AgentEvent[];
|
|
17
|
+
defaultOrder: AgentMessageContentItem[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type AgentMessageContentOrderResolver = (
|
|
21
|
+
input: AgentMessageContentOrderInput,
|
|
22
|
+
) => AgentMessageContentItem[];
|
|
23
|
+
|
|
24
|
+
type TextContentOrderItem = Extract<
|
|
25
|
+
AgentMessageContentItem,
|
|
26
|
+
{ type: "part" }
|
|
27
|
+
> & {
|
|
28
|
+
part: Extract<AgentMessagePart, { type: "text" }>;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
function isTextContentOrderItem(
|
|
32
|
+
item: AgentMessageContentItem | null | undefined,
|
|
33
|
+
): item is TextContentOrderItem {
|
|
34
|
+
return (
|
|
35
|
+
item?.type === "part" &&
|
|
36
|
+
typeof item.key === "string" &&
|
|
37
|
+
item.part?.type === "text" &&
|
|
38
|
+
typeof item.part.text === "string"
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function resolvedItemsPreserveContent(
|
|
43
|
+
defaultOrder: AgentMessageContentItem[],
|
|
44
|
+
resolvedOrder: AgentMessageContentItem[],
|
|
45
|
+
): AgentMessageContentItem[] | undefined {
|
|
46
|
+
if (!Array.isArray(resolvedOrder)) return undefined;
|
|
47
|
+
|
|
48
|
+
const defaultText = defaultOrder
|
|
49
|
+
.filter(isTextContentOrderItem)
|
|
50
|
+
.map((item) => item.part.text)
|
|
51
|
+
.join("");
|
|
52
|
+
const resolvedText = resolvedOrder
|
|
53
|
+
.filter(isTextContentOrderItem)
|
|
54
|
+
.map((item) => item.part.text)
|
|
55
|
+
.join("");
|
|
56
|
+
if (defaultText !== resolvedText) return undefined;
|
|
57
|
+
|
|
58
|
+
const expectedItems = new Map<string, AgentMessageContentItem[]>();
|
|
59
|
+
for (const item of defaultOrder) {
|
|
60
|
+
if (item.type === "part" && item.part.type === "text") continue;
|
|
61
|
+
const identity = `${item.type}:${item.key}`;
|
|
62
|
+
const matchingItems = expectedItems.get(identity) ?? [];
|
|
63
|
+
matchingItems.push(item);
|
|
64
|
+
expectedItems.set(identity, matchingItems);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const preservedItems: AgentMessageContentItem[] = [];
|
|
68
|
+
for (const item of resolvedOrder) {
|
|
69
|
+
if (!item || typeof item !== "object") return undefined;
|
|
70
|
+
if (item.type === "part" && item.part?.type === "text") {
|
|
71
|
+
if (typeof item.key !== "string" || typeof item.part.text !== "string") {
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
preservedItems.push(item);
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (
|
|
79
|
+
(item.type !== "part" && item.type !== "widget") ||
|
|
80
|
+
typeof item.key !== "string"
|
|
81
|
+
) {
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const identity = `${item.type}:${item.key}`;
|
|
86
|
+
const matchingItems = expectedItems.get(identity);
|
|
87
|
+
const original = matchingItems?.shift();
|
|
88
|
+
if (!original) return undefined;
|
|
89
|
+
preservedItems.push(original);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (
|
|
93
|
+
[...expectedItems.values()].some((matchingItems) => matchingItems.length)
|
|
94
|
+
) {
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
return preservedItems;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Uses the stream timeline only when it reconstructs the saved text exactly. */
|
|
101
|
+
export function orderMessageContent(
|
|
102
|
+
message: AgentMessage,
|
|
103
|
+
visibleParts: AgentMessagePart[],
|
|
104
|
+
attachedWidgets: AgentWidget[],
|
|
105
|
+
events: AgentEvent[],
|
|
106
|
+
resolveOrder?: AgentMessageContentOrderResolver,
|
|
107
|
+
): AgentMessageContentItem[] {
|
|
108
|
+
const fallback = [
|
|
109
|
+
...visibleParts.map((part, index) => ({
|
|
110
|
+
key: `${message.id}-${index}`,
|
|
111
|
+
type: "part" as const,
|
|
112
|
+
part,
|
|
113
|
+
})),
|
|
114
|
+
...attachedWidgets.map((widget) => ({
|
|
115
|
+
key: widget.id,
|
|
116
|
+
type: "widget" as const,
|
|
117
|
+
widget,
|
|
118
|
+
})),
|
|
119
|
+
];
|
|
120
|
+
const resolve = (defaultOrder: AgentMessageContentItem[]) => {
|
|
121
|
+
const resolvedOrder = resolveOrder?.({
|
|
122
|
+
message,
|
|
123
|
+
parts: visibleParts,
|
|
124
|
+
widgets: attachedWidgets,
|
|
125
|
+
events,
|
|
126
|
+
defaultOrder,
|
|
127
|
+
});
|
|
128
|
+
if (resolvedOrder == null) return defaultOrder;
|
|
129
|
+
return (
|
|
130
|
+
resolvedItemsPreserveContent(defaultOrder, resolvedOrder) ?? defaultOrder
|
|
131
|
+
);
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
if (
|
|
135
|
+
attachedWidgets.length === 0 ||
|
|
136
|
+
message.parts.length !== 1 ||
|
|
137
|
+
message.parts[0]?.type !== "text" ||
|
|
138
|
+
visibleParts.length !== 1 ||
|
|
139
|
+
visibleParts[0]?.type !== "text" ||
|
|
140
|
+
visibleParts[0].text !== message.parts[0].text
|
|
141
|
+
) {
|
|
142
|
+
return resolve(fallback);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const widgetIds = new Set(attachedWidgets.map((widget) => widget.id));
|
|
146
|
+
const widgetOffsets = new Map<string, number>();
|
|
147
|
+
const widgetEventOrder = new Map<string, number>();
|
|
148
|
+
let reconstructedText = "";
|
|
149
|
+
let textOffset = 0;
|
|
150
|
+
|
|
151
|
+
for (const [eventIndex, event] of events.entries()) {
|
|
152
|
+
if (event.type === "message.created" && event.message.id === message.id) {
|
|
153
|
+
const createdParts = event.message.parts;
|
|
154
|
+
if (
|
|
155
|
+
createdParts.length > 1 ||
|
|
156
|
+
createdParts.some((part) => part.type !== "text")
|
|
157
|
+
) {
|
|
158
|
+
return resolve(fallback);
|
|
159
|
+
}
|
|
160
|
+
reconstructedText =
|
|
161
|
+
createdParts[0]?.type === "text" ? createdParts[0].text : "";
|
|
162
|
+
textOffset = reconstructedText.length;
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (event.type === "message.delta" && event.messageId === message.id) {
|
|
167
|
+
reconstructedText += event.text;
|
|
168
|
+
textOffset += event.text.length;
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (
|
|
173
|
+
(event.type === "widget.created" || event.type === "widget.updated") &&
|
|
174
|
+
event.messageId === message.id &&
|
|
175
|
+
widgetIds.has(event.widget.id) &&
|
|
176
|
+
!widgetOffsets.has(event.widget.id)
|
|
177
|
+
) {
|
|
178
|
+
widgetOffsets.set(event.widget.id, textOffset);
|
|
179
|
+
widgetEventOrder.set(event.widget.id, eventIndex);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const fullText = message.parts[0].text;
|
|
184
|
+
if (
|
|
185
|
+
reconstructedText !== fullText ||
|
|
186
|
+
widgetOffsets.size !== attachedWidgets.length ||
|
|
187
|
+
[...widgetOffsets.values()].some((offset) => {
|
|
188
|
+
if (offset === 0 || offset === fullText.length) return false;
|
|
189
|
+
const preceding = fullText.charCodeAt(offset - 1);
|
|
190
|
+
const following = fullText.charCodeAt(offset);
|
|
191
|
+
return (
|
|
192
|
+
preceding >= 0xd800 &&
|
|
193
|
+
preceding <= 0xdbff &&
|
|
194
|
+
following >= 0xdc00 &&
|
|
195
|
+
following <= 0xdfff
|
|
196
|
+
);
|
|
197
|
+
})
|
|
198
|
+
) {
|
|
199
|
+
return resolve(fallback);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const widgetsAtOffset = new Map<number, AgentWidget[]>();
|
|
203
|
+
for (const widget of attachedWidgets) {
|
|
204
|
+
const offset = widgetOffsets.get(widget.id)!;
|
|
205
|
+
const widgets = widgetsAtOffset.get(offset) ?? [];
|
|
206
|
+
widgets.push(widget);
|
|
207
|
+
widgetsAtOffset.set(offset, widgets);
|
|
208
|
+
}
|
|
209
|
+
for (const widgets of widgetsAtOffset.values()) {
|
|
210
|
+
widgets.sort(
|
|
211
|
+
(first, second) =>
|
|
212
|
+
widgetEventOrder.get(first.id)! - widgetEventOrder.get(second.id)!,
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const insertions = [...widgetsAtOffset.entries()].sort(
|
|
217
|
+
([first], [second]) => first - second,
|
|
218
|
+
);
|
|
219
|
+
const part = visibleParts[0];
|
|
220
|
+
if (part.type !== "text") return resolve(fallback);
|
|
221
|
+
|
|
222
|
+
const ordered: AgentMessageContentItem[] = [];
|
|
223
|
+
let cursor = 0;
|
|
224
|
+
for (const [offset, widgets] of insertions) {
|
|
225
|
+
if (offset > cursor) {
|
|
226
|
+
ordered.push({
|
|
227
|
+
key: `${message.id}-text-${cursor}`,
|
|
228
|
+
type: "part",
|
|
229
|
+
part: { ...part, text: part.text.slice(cursor, offset) },
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
for (const widget of widgets) {
|
|
233
|
+
ordered.push({ key: widget.id, type: "widget", widget });
|
|
234
|
+
}
|
|
235
|
+
cursor = offset;
|
|
236
|
+
}
|
|
237
|
+
if (cursor < part.text.length) {
|
|
238
|
+
ordered.push({
|
|
239
|
+
key: `${message.id}-text-${cursor}`,
|
|
240
|
+
type: "part",
|
|
241
|
+
part: { ...part, text: part.text.slice(cursor) },
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return resolve(ordered);
|
|
246
|
+
}
|
|
@@ -30,6 +30,8 @@ import {
|
|
|
30
30
|
type AgentKitRunUsageLoader,
|
|
31
31
|
type AgentKitSlots,
|
|
32
32
|
} from "./context.js";
|
|
33
|
+
import type { AgentMessageContentOrderResolver } from "./message-content-order.js";
|
|
34
|
+
import type { AgentChatWorkedForRowLayout } from "./transcript-layout.js";
|
|
33
35
|
|
|
34
36
|
const mountedManagedClients = new WeakMap<AgentKitClient, number>();
|
|
35
37
|
|
|
@@ -84,6 +86,9 @@ export interface AgentKitRootBaseProps {
|
|
|
84
86
|
request: AgentConnectionRequest,
|
|
85
87
|
) => Promise<AgentConnectionResponse>;
|
|
86
88
|
onRenderError?: (failure: AgentKitRenderFailure) => void;
|
|
89
|
+
resolveMessageContentOrder?: AgentMessageContentOrderResolver;
|
|
90
|
+
workedForRowLayout?: AgentChatWorkedForRowLayout;
|
|
91
|
+
formatWorkedForDuration?: (durationMs: number) => string;
|
|
87
92
|
onClientEffect?: (effect: {
|
|
88
93
|
type: "client.effect" | "client.deeplink";
|
|
89
94
|
name: string;
|
|
@@ -113,6 +118,9 @@ export function AgentKitRoot({
|
|
|
113
118
|
loadRunUsage,
|
|
114
119
|
onConnectionRequest,
|
|
115
120
|
onRenderError,
|
|
121
|
+
resolveMessageContentOrder,
|
|
122
|
+
workedForRowLayout,
|
|
123
|
+
formatWorkedForDuration,
|
|
116
124
|
onClientEffect,
|
|
117
125
|
load = "auto",
|
|
118
126
|
onLoadError,
|
|
@@ -290,6 +298,9 @@ export function AgentKitRoot({
|
|
|
290
298
|
loadRunUsage={loadRunUsage}
|
|
291
299
|
onConnectionRequest={onConnectionRequest}
|
|
292
300
|
onRenderError={onRenderError}
|
|
301
|
+
resolveMessageContentOrder={resolveMessageContentOrder}
|
|
302
|
+
workedForRowLayout={workedForRowLayout}
|
|
303
|
+
formatWorkedForDuration={formatWorkedForDuration}
|
|
293
304
|
onClientEffect={onClientEffect}
|
|
294
305
|
>
|
|
295
306
|
{children}
|
|
@@ -669,11 +669,18 @@ body:has(> [data-agent-native-composer-popover="true"]) > .fixed.inset-0 {
|
|
|
669
669
|
}
|
|
670
670
|
|
|
671
671
|
.agentkit-transcript-content {
|
|
672
|
+
position: relative;
|
|
672
673
|
box-sizing: border-box;
|
|
673
|
-
inline-size: min(100%, 47rem);
|
|
674
|
+
inline-size: min(100%, var(--agentkit-transcript-lane-width, 47rem));
|
|
674
675
|
min-inline-size: 0;
|
|
675
676
|
margin-inline: auto;
|
|
677
|
+
inset-inline-start: clamp(
|
|
678
|
+
calc((100% - min(100%, var(--agentkit-transcript-lane-width, 47rem))) / -2),
|
|
679
|
+
var(--agentkit-transcript-lane-offset-inline, 0px),
|
|
680
|
+
calc((100% - min(100%, var(--agentkit-transcript-lane-width, 47rem))) / 2)
|
|
681
|
+
);
|
|
676
682
|
padding: 1.5rem 1rem;
|
|
683
|
+
padding-block-start: var(--agentkit-transcript-top-inset, 1.5rem);
|
|
677
684
|
}
|
|
678
685
|
|
|
679
686
|
.agentkit-scroll-to-bottom-control {
|
|
@@ -710,13 +717,21 @@ body:has(> [data-agent-native-composer-popover="true"]) > .fixed.inset-0 {
|
|
|
710
717
|
display: flex;
|
|
711
718
|
flex-direction: column;
|
|
712
719
|
align-items: flex-start;
|
|
713
|
-
margin-block: 0 1.25rem;
|
|
720
|
+
margin-block: 0 var(--agentkit-transcript-message-gap, 1.25rem);
|
|
714
721
|
font-size: 0.875rem;
|
|
715
|
-
|
|
722
|
+
font-family: var(
|
|
723
|
+
--agentkit-transcript-font-family,
|
|
724
|
+
var(--font-sans, inherit)
|
|
725
|
+
);
|
|
726
|
+
line-height: var(--agentkit-transcript-message-line-height, 1.52);
|
|
716
727
|
}
|
|
717
728
|
|
|
718
729
|
.agentkit-message[data-role="user"] {
|
|
719
730
|
align-items: flex-end;
|
|
731
|
+
line-height: var(
|
|
732
|
+
--agentkit-user-bubble-line-height,
|
|
733
|
+
var(--agentkit-transcript-message-line-height, 1.52)
|
|
734
|
+
);
|
|
720
735
|
}
|
|
721
736
|
|
|
722
737
|
.agentkit-message-content {
|
|
@@ -726,8 +741,11 @@ body:has(> [data-agent-native-composer-popover="true"]) > .fixed.inset-0 {
|
|
|
726
741
|
}
|
|
727
742
|
|
|
728
743
|
.agentkit-message[data-role="user"] .agentkit-message-content {
|
|
729
|
-
|
|
730
|
-
|
|
744
|
+
position: relative;
|
|
745
|
+
inset-inline-start: var(--agentkit-user-bubble-offset-inline, 0px);
|
|
746
|
+
max-inline-size: min(88%, var(--agentkit-user-bubble-max-width, 38rem));
|
|
747
|
+
padding: var(--agentkit-user-bubble-padding-block, 0.625rem)
|
|
748
|
+
var(--agentkit-user-bubble-padding-inline, 0.8125rem);
|
|
731
749
|
border-radius: var(--agentkit-radius-inner);
|
|
732
750
|
background: var(--agentkit-subtle);
|
|
733
751
|
}
|
|
@@ -845,6 +863,25 @@ body:has(> [data-agent-native-composer-popover="true"]) > .fixed.inset-0 {
|
|
|
845
863
|
background: var(--agentkit-canvas);
|
|
846
864
|
}
|
|
847
865
|
|
|
866
|
+
.agentkit-message-content [data-post-widget-text="true"] {
|
|
867
|
+
display: contents;
|
|
868
|
+
color: var(--agentkit-transcript-post-widget-text-color, inherit);
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
.agentkit-message-content [data-post-widget-text="true"] > p,
|
|
872
|
+
.agentkit-message-content [data-post-widget-text="true"] .agentkit-markdown p {
|
|
873
|
+
padding-block: var(
|
|
874
|
+
--agentkit-transcript-post-widget-paragraph-padding-block,
|
|
875
|
+
0px
|
|
876
|
+
);
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
.agentkit-message-content
|
|
880
|
+
> [data-post-widget-text="true"]:last-child
|
|
881
|
+
> :last-child {
|
|
882
|
+
margin-block-end: 0;
|
|
883
|
+
}
|
|
884
|
+
|
|
848
885
|
.agentkit-image-preview img {
|
|
849
886
|
max-inline-size: 92vw;
|
|
850
887
|
max-block-size: 90vh;
|
|
@@ -1216,7 +1253,7 @@ body:has(> [data-agent-native-composer-popover="true"]) > .fixed.inset-0 {
|
|
|
1216
1253
|
inline-size: fit-content;
|
|
1217
1254
|
max-inline-size: 100%;
|
|
1218
1255
|
align-items: center;
|
|
1219
|
-
gap:
|
|
1256
|
+
gap: 1rem;
|
|
1220
1257
|
}
|
|
1221
1258
|
|
|
1222
1259
|
.agentkit-activities {
|
|
@@ -1418,7 +1455,7 @@ body:has(> [data-agent-native-composer-popover="true"]) > .fixed.inset-0 {
|
|
|
1418
1455
|
}
|
|
1419
1456
|
|
|
1420
1457
|
.agentkit-activities-summary > .agentkit-summary-chevron {
|
|
1421
|
-
opacity:
|
|
1458
|
+
opacity: 1;
|
|
1422
1459
|
}
|
|
1423
1460
|
|
|
1424
1461
|
.agentkit-activities[data-expandable="true"]
|
|
@@ -2133,6 +2170,6 @@ button.agentkit-object {
|
|
|
2133
2170
|
}
|
|
2134
2171
|
|
|
2135
2172
|
.agentkit-message[data-role="user"] .agentkit-message-content {
|
|
2136
|
-
max-inline-size: 94
|
|
2173
|
+
max-inline-size: min(94%, var(--agentkit-user-bubble-max-width, 38rem));
|
|
2137
2174
|
}
|
|
2138
2175
|
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { AgentKitController } from "@agent-native/agentkit/client";
|
|
2
|
+
import { createElement } from "react";
|
|
3
|
+
import { renderToStaticMarkup } from "react-dom/server";
|
|
4
|
+
import { describe, expect, it } from "vitest";
|
|
5
|
+
|
|
6
|
+
import { useAgentKit } from "./context.js";
|
|
7
|
+
import { AgentKitRoot } from "./root.js";
|
|
8
|
+
import {
|
|
9
|
+
workedForRowChevronStyle,
|
|
10
|
+
workedForRowSummaryStyle,
|
|
11
|
+
} from "./transcript-layout.js";
|
|
12
|
+
|
|
13
|
+
function WorkedForLayoutProbe() {
|
|
14
|
+
const { workedForRowLayout, formatWorkedForDuration } = useAgentKit();
|
|
15
|
+
return createElement("span", {
|
|
16
|
+
"data-icon-gap": workedForRowLayout?.iconGap,
|
|
17
|
+
"data-duration": formatWorkedForDuration?.(16_000),
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe("worked-for row layout", () => {
|
|
22
|
+
it("applies shared dimensions to the summary and leading chevron", () => {
|
|
23
|
+
const layout = {
|
|
24
|
+
chevronSize: 12,
|
|
25
|
+
iconGap: 8,
|
|
26
|
+
fontSize: 13,
|
|
27
|
+
lineHeight: 16,
|
|
28
|
+
paddingBlock: 2,
|
|
29
|
+
paddingInline: 4,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
expect(workedForRowSummaryStyle(layout)).toEqual({
|
|
33
|
+
gap: "8px",
|
|
34
|
+
fontSize: "13px",
|
|
35
|
+
lineHeight: "16px",
|
|
36
|
+
paddingBlock: "2px",
|
|
37
|
+
paddingInline: "4px",
|
|
38
|
+
fontFamily: "inherit",
|
|
39
|
+
});
|
|
40
|
+
expect(workedForRowChevronStyle(layout)).toEqual({
|
|
41
|
+
width: "12px",
|
|
42
|
+
height: "12px",
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("rejects invalid CSS dimensions", () => {
|
|
47
|
+
expect(() => workedForRowSummaryStyle({ fontSize: 0 })).toThrow(
|
|
48
|
+
"workedForRowLayout.fontSize must be a valid CSS length",
|
|
49
|
+
);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("carries the layout from the AgentKit root into shared context", () => {
|
|
53
|
+
const layout = { iconGap: 8 };
|
|
54
|
+
const formatWorkedForDuration = (durationMs: number) =>
|
|
55
|
+
`${Math.round(durationMs / 1000)} seconds`;
|
|
56
|
+
const markup = renderToStaticMarkup(
|
|
57
|
+
createElement(
|
|
58
|
+
AgentKitRoot,
|
|
59
|
+
{
|
|
60
|
+
controller: {} as AgentKitController,
|
|
61
|
+
threadId: "thread",
|
|
62
|
+
workedForRowLayout: layout,
|
|
63
|
+
formatWorkedForDuration,
|
|
64
|
+
},
|
|
65
|
+
createElement(WorkedForLayoutProbe),
|
|
66
|
+
),
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
expect(markup).toContain('data-icon-gap="8"');
|
|
70
|
+
expect(markup).toContain('data-duration="16 seconds"');
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { CSSProperties } from "react";
|
|
2
|
+
|
|
3
|
+
export interface AgentChatTranscriptLayout {
|
|
4
|
+
/** Top padding above transcript messages, in CSS pixels. */
|
|
5
|
+
topInset?: number;
|
|
6
|
+
/** Maximum centered message lane width, in CSS pixels. */
|
|
7
|
+
messageLaneWidth?: number;
|
|
8
|
+
/** Signed inline offset for the centered message lane, in CSS pixels. */
|
|
9
|
+
messageLaneOffsetInline?: number;
|
|
10
|
+
/** Space after each message, in CSS pixels. */
|
|
11
|
+
messageGap?: number;
|
|
12
|
+
/** Assistant message line height, in CSS pixels. */
|
|
13
|
+
messageLineHeight?: number;
|
|
14
|
+
/** Font family for transcript messages. Omitted uses the shared semantic font. */
|
|
15
|
+
fontFamily?: string;
|
|
16
|
+
/** Optional appearance for assistant text displayed after a widget. */
|
|
17
|
+
postWidgetText?: {
|
|
18
|
+
tone?: "muted";
|
|
19
|
+
paragraphPaddingBlock?: number;
|
|
20
|
+
};
|
|
21
|
+
/** User bubble line height, in CSS pixels. */
|
|
22
|
+
userBubbleLineHeight?: number;
|
|
23
|
+
/** Maximum user bubble width, in CSS pixels. */
|
|
24
|
+
userBubbleMaxWidth?: number;
|
|
25
|
+
/** Signed inline offset for the user bubble, in CSS pixels. */
|
|
26
|
+
userBubbleOffsetInline?: number;
|
|
27
|
+
/** User bubble padding on the block and inline axes, in CSS pixels. */
|
|
28
|
+
userBubblePadding?: { block?: number; inline?: number };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Optional geometry for the completed-work disclosure row in chat. */
|
|
32
|
+
export interface AgentChatWorkedForRowLayout {
|
|
33
|
+
/** Chevron width and height, in CSS pixels. */
|
|
34
|
+
chevronSize?: number;
|
|
35
|
+
/** Space between the chevron and label, in CSS pixels. */
|
|
36
|
+
iconGap?: number;
|
|
37
|
+
/** Signed margin before the row, in CSS pixels. */
|
|
38
|
+
marginBlockStart?: number;
|
|
39
|
+
/** Label font size, in CSS pixels. */
|
|
40
|
+
fontSize?: number;
|
|
41
|
+
/** Label line height, in CSS pixels. */
|
|
42
|
+
lineHeight?: number;
|
|
43
|
+
/** Padding on the block axis, in CSS pixels. */
|
|
44
|
+
paddingBlock?: number;
|
|
45
|
+
/** Padding on the inline axis, in CSS pixels. */
|
|
46
|
+
paddingInline?: number;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function workedForRowLength(
|
|
50
|
+
value: number | undefined,
|
|
51
|
+
name: keyof AgentChatWorkedForRowLayout,
|
|
52
|
+
positive = false,
|
|
53
|
+
) {
|
|
54
|
+
if (value === undefined) return undefined;
|
|
55
|
+
if (!Number.isFinite(value) || value < 0 || (positive && value === 0)) {
|
|
56
|
+
throw new RangeError(
|
|
57
|
+
`workedForRowLayout.${name} must be a valid CSS length`,
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
return `${value}px`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function workedForRowOffset(
|
|
64
|
+
value: number | undefined,
|
|
65
|
+
name: keyof AgentChatWorkedForRowLayout,
|
|
66
|
+
) {
|
|
67
|
+
if (value === undefined) return undefined;
|
|
68
|
+
if (!Number.isFinite(value)) {
|
|
69
|
+
throw new RangeError(`workedForRowLayout.${name} must be finite`);
|
|
70
|
+
}
|
|
71
|
+
return `${value}px`;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function workedForRowSummaryStyle(
|
|
75
|
+
layout?: AgentChatWorkedForRowLayout,
|
|
76
|
+
): CSSProperties | undefined {
|
|
77
|
+
if (!layout) return undefined;
|
|
78
|
+
return {
|
|
79
|
+
gap: workedForRowLength(layout.iconGap, "iconGap"),
|
|
80
|
+
marginBlockStart: workedForRowOffset(
|
|
81
|
+
layout.marginBlockStart,
|
|
82
|
+
"marginBlockStart",
|
|
83
|
+
),
|
|
84
|
+
fontSize: workedForRowLength(layout.fontSize, "fontSize", true),
|
|
85
|
+
lineHeight: workedForRowLength(layout.lineHeight, "lineHeight", true),
|
|
86
|
+
paddingBlock: workedForRowLength(layout.paddingBlock, "paddingBlock"),
|
|
87
|
+
paddingInline: workedForRowLength(layout.paddingInline, "paddingInline"),
|
|
88
|
+
fontFamily: "inherit",
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function workedForRowChevronStyle(
|
|
93
|
+
layout?: AgentChatWorkedForRowLayout,
|
|
94
|
+
): CSSProperties | undefined {
|
|
95
|
+
const size = workedForRowLength(layout?.chevronSize, "chevronSize", true);
|
|
96
|
+
return size ? { width: size, height: size } : undefined;
|
|
97
|
+
}
|
|
@@ -129,6 +129,12 @@ async function recordBoth(
|
|
|
129
129
|
|
|
130
130
|
describe("AuthPage attribution", () => {
|
|
131
131
|
beforeEach(() => {
|
|
132
|
+
// Attribution storage depends on the visitor's time zone, so pin it.
|
|
133
|
+
const realOptions = new Intl.DateTimeFormat().resolvedOptions();
|
|
134
|
+
vi.spyOn(Intl.DateTimeFormat.prototype, "resolvedOptions").mockReturnValue({
|
|
135
|
+
...realOptions,
|
|
136
|
+
timeZone: "America/Los_Angeles",
|
|
137
|
+
});
|
|
132
138
|
vi.useFakeTimers({ toFake: ["Date"] });
|
|
133
139
|
vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
|
|
134
140
|
vi.stubGlobal(
|
|
@@ -1054,6 +1054,27 @@ describe("AgentKitAssistantChat host behavior", () => {
|
|
|
1054
1054
|
expect(chatMocks.composerProps.isReferenceTarget).toBe(true);
|
|
1055
1055
|
});
|
|
1056
1056
|
|
|
1057
|
+
it("passes the worked-for row layout into the shared AgentKit root", async () => {
|
|
1058
|
+
const layout = {
|
|
1059
|
+
chevronSize: 12,
|
|
1060
|
+
iconGap: 8,
|
|
1061
|
+
fontSize: 13,
|
|
1062
|
+
lineHeight: 16,
|
|
1063
|
+
paddingBlock: 2,
|
|
1064
|
+
paddingInline: 4,
|
|
1065
|
+
};
|
|
1066
|
+
const formatWorkedForDuration = (durationMs: number) =>
|
|
1067
|
+
`${Math.round(durationMs / 1000)} seconds`;
|
|
1068
|
+
await mount(
|
|
1069
|
+
baseProps({ workedForRowLayout: layout, formatWorkedForDuration }),
|
|
1070
|
+
);
|
|
1071
|
+
|
|
1072
|
+
expect(chatMocks.rootProps.workedForRowLayout).toEqual(layout);
|
|
1073
|
+
expect(chatMocks.rootProps.formatWorkedForDuration).toBe(
|
|
1074
|
+
formatWorkedForDuration,
|
|
1075
|
+
);
|
|
1076
|
+
});
|
|
1077
|
+
|
|
1057
1078
|
it("reports whether a composer can hold a prefill with its current context", async () => {
|
|
1058
1079
|
const ref = createRef<AssistantChatHandle>();
|
|
1059
1080
|
await mount(baseProps(), ref);
|
|
@@ -3271,6 +3292,24 @@ describe("AgentKitAssistantChat host behavior", () => {
|
|
|
3271
3292
|
).not.toBeNull();
|
|
3272
3293
|
});
|
|
3273
3294
|
|
|
3295
|
+
it("forwards transcript layout options to the shared chat component", async () => {
|
|
3296
|
+
const transcriptLayout = {
|
|
3297
|
+
topInset: 5,
|
|
3298
|
+
messageLaneWidth: 730,
|
|
3299
|
+
messageLaneOffsetInline: -33,
|
|
3300
|
+
messageGap: 12,
|
|
3301
|
+
messageLineHeight: 20,
|
|
3302
|
+
fontFamily: "IBM Plex Sans",
|
|
3303
|
+
userBubbleLineHeight: 18,
|
|
3304
|
+
userBubbleMaxWidth: 600,
|
|
3305
|
+
userBubbleOffsetInline: 10,
|
|
3306
|
+
userBubblePadding: { block: 8, inline: 13 },
|
|
3307
|
+
};
|
|
3308
|
+
await mount(baseProps({ transcriptLayout }));
|
|
3309
|
+
|
|
3310
|
+
expect(chatMocks.chatProps.transcriptLayout).toBe(transcriptLayout);
|
|
3311
|
+
});
|
|
3312
|
+
|
|
3274
3313
|
it("anchors the composer at the bottom while restoring a persisted thread", async () => {
|
|
3275
3314
|
await mount(
|
|
3276
3315
|
baseProps({
|
|
@@ -3348,6 +3387,25 @@ describe("AgentKitAssistantChat host behavior", () => {
|
|
|
3348
3387
|
expect(container.querySelector(".agentkit-home-intro")).toBeNull();
|
|
3349
3388
|
});
|
|
3350
3389
|
|
|
3390
|
+
it("renders the shared context banner slot alongside the existing composer slot", async () => {
|
|
3391
|
+
await mount(
|
|
3392
|
+
baseProps({
|
|
3393
|
+
composerSlot: <div data-testid="legacy-composer-slot">Notice</div>,
|
|
3394
|
+
composerContextBannerSlot: (
|
|
3395
|
+
<div data-testid="composer-context-banner-slot">Add context</div>
|
|
3396
|
+
),
|
|
3397
|
+
}),
|
|
3398
|
+
);
|
|
3399
|
+
|
|
3400
|
+
const composer = container.querySelector(".agentkit-host-composer")!;
|
|
3401
|
+
expect(
|
|
3402
|
+
composer.querySelector('[data-testid="legacy-composer-slot"]'),
|
|
3403
|
+
).not.toBeNull();
|
|
3404
|
+
expect(
|
|
3405
|
+
composer.querySelector('[data-testid="composer-context-banner-slot"]'),
|
|
3406
|
+
).not.toBeNull();
|
|
3407
|
+
});
|
|
3408
|
+
|
|
3351
3409
|
it("puts the beginning revert before messages inside the scrollable transcript", async () => {
|
|
3352
3410
|
chatMocks.thread.messages = [
|
|
3353
3411
|
{ id: "first-message", role: "user", parts: [] },
|