@agent-native/toolkit 0.218.0 → 0.219.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/dist/app/agentkit/react/styles.css +13 -6
- package/dist/app/chat/AgentKitAssistantChat.d.ts.map +1 -1
- package/dist/app/chat/AgentKitAssistantChat.js +1 -1
- package/dist/app/chat/AgentKitAssistantChat.js.map +1 -1
- package/dist/app/chat/AgentPanel.js +6 -6
- package/dist/app/chat/AgentPanel.js.map +1 -1
- package/dist/app/chat/MultiTabAssistantChat.js +2 -2
- package/dist/app/chat/MultiTabAssistantChat.js.map +1 -1
- package/dist/app/chat/agentkit-chat/action-widget.d.ts.map +1 -1
- package/dist/app/chat/agentkit-chat/action-widget.js +1 -0
- package/dist/app/chat/agentkit-chat/action-widget.js.map +1 -1
- package/dist/app/chat/chat/tool-call-display.d.ts +3 -1
- package/dist/app/chat/chat/tool-call-display.d.ts.map +1 -1
- package/dist/app/chat/chat/tool-call-display.js +5 -4
- package/dist/app/chat/chat/tool-call-display.js.map +1 -1
- package/dist/app/chat/chat/tool-render-registry.d.ts +2 -0
- package/dist/app/chat/chat/tool-render-registry.d.ts.map +1 -1
- package/dist/app/chat/chat/tool-render-registry.js.map +1 -1
- package/dist/app/chat/conversation/AgentConversation.d.ts.map +1 -1
- package/dist/app/chat/conversation/AgentConversation.js +6 -1
- package/dist/app/chat/conversation/AgentConversation.js.map +1 -1
- package/dist/app/shared/CommandMenu.d.ts +2 -0
- package/dist/app/shared/CommandMenu.d.ts.map +1 -1
- package/dist/app/shared/CommandMenu.js +11 -6
- package/dist/app/shared/CommandMenu.js.map +1 -1
- package/dist/composer/TiptapComposer.js +1 -1
- package/dist/composer/TiptapComposer.js.map +1 -1
- package/package.json +3 -3
- package/src/app/agentkit/react/components.spec.tsx +7 -5
- package/src/app/agentkit/react/styles.css +13 -6
- package/src/app/chat/AgentKitAssistantChat.spec.tsx +201 -27
- package/src/app/chat/AgentKitAssistantChat.tsx +1 -0
- package/src/app/chat/AgentPanel.tsx +8 -8
- package/src/app/chat/MultiTabAssistantChat.tsx +2 -2
- package/src/app/chat/agentkit-chat/action-widget.spec.tsx +62 -0
- package/src/app/chat/agentkit-chat/action-widget.tsx +1 -0
- package/src/app/chat/chat/tool-call-display.tsx +10 -1
- package/src/app/chat/chat/tool-render-registry.tsx +2 -0
- package/src/app/chat/conversation/AgentConversation.spec.tsx +51 -1
- package/src/app/chat/conversation/AgentConversation.tsx +11 -2
- package/src/app/shared/CommandMenu.spec.tsx +175 -6
- package/src/app/shared/CommandMenu.tsx +24 -7
- package/src/composer/TiptapComposer.tsx +1 -1
|
@@ -116,7 +116,9 @@ describe("AgentConversationMessageView", () => {
|
|
|
116
116
|
id: "example-renderer",
|
|
117
117
|
match: "example-tool",
|
|
118
118
|
Component: ({ context }) => (
|
|
119
|
-
<div data-testid="example-renderer">
|
|
119
|
+
<div data-testid="example-renderer">
|
|
120
|
+
Custom renderer: {context.resultText}
|
|
121
|
+
</div>
|
|
120
122
|
),
|
|
121
123
|
});
|
|
122
124
|
act(() =>
|
|
@@ -144,11 +146,59 @@ describe("AgentConversationMessageView", () => {
|
|
|
144
146
|
expect(container.querySelector('[data-testid="example-renderer"]')).toBe(
|
|
145
147
|
null,
|
|
146
148
|
);
|
|
149
|
+
expect(container.textContent).not.toContain("Custom renderer:");
|
|
150
|
+
expect(container.querySelector("pre span")?.textContent).toBe(
|
|
151
|
+
"Example Document failed.",
|
|
152
|
+
);
|
|
147
153
|
expect(
|
|
148
154
|
container.querySelector("pre span")?.hasAttribute("data-an-mask"),
|
|
149
155
|
).toBe(true);
|
|
150
156
|
});
|
|
151
157
|
|
|
158
|
+
it.each([
|
|
159
|
+
["running", "running"],
|
|
160
|
+
["activity", "running"],
|
|
161
|
+
["completed", "completed"],
|
|
162
|
+
] as const)(
|
|
163
|
+
"passes %s status to conversation custom renderers as %s",
|
|
164
|
+
(state, status) => {
|
|
165
|
+
registerToolRenderer({
|
|
166
|
+
id: "example-status-renderer",
|
|
167
|
+
match: "example-status-tool",
|
|
168
|
+
Component: ({ context }) => (
|
|
169
|
+
<div data-testid="example-tool-status" data-status={context.status} />
|
|
170
|
+
),
|
|
171
|
+
});
|
|
172
|
+
act(() =>
|
|
173
|
+
root.render(
|
|
174
|
+
<AgentConversationMessageView
|
|
175
|
+
message={{
|
|
176
|
+
id: "message-status",
|
|
177
|
+
role: "assistant",
|
|
178
|
+
parts: [
|
|
179
|
+
{
|
|
180
|
+
id: "tool-status",
|
|
181
|
+
type: "tool",
|
|
182
|
+
tool: {
|
|
183
|
+
id: "tool-status",
|
|
184
|
+
name: "example-status-tool",
|
|
185
|
+
state,
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
],
|
|
189
|
+
}}
|
|
190
|
+
/>,
|
|
191
|
+
),
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
expect(
|
|
195
|
+
container
|
|
196
|
+
.querySelector('[data-testid="example-tool-status"]')
|
|
197
|
+
?.getAttribute("data-status"),
|
|
198
|
+
).toBe(status);
|
|
199
|
+
},
|
|
200
|
+
);
|
|
201
|
+
|
|
152
202
|
it.each(["errored", "completed"] as const)(
|
|
153
203
|
"blocks only an errored tool's MCP App from replays (%s)",
|
|
154
204
|
(state) => {
|
|
@@ -17,7 +17,10 @@ import ReactMarkdown, { defaultUrlTransform } from "react-markdown";
|
|
|
17
17
|
import remarkGfm from "remark-gfm";
|
|
18
18
|
|
|
19
19
|
import { ActionChatUiSurface } from "../chat/action-chat-ui-surface.js";
|
|
20
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
resolveToolRenderer,
|
|
22
|
+
type ToolRendererContext,
|
|
23
|
+
} from "../chat/tool-render-registry.js";
|
|
21
24
|
import {
|
|
22
25
|
isBuiltinConnectRequiredResult,
|
|
23
26
|
resolveBuiltinActionChatRenderer,
|
|
@@ -407,11 +410,17 @@ function parseJsonObject(value: string | undefined): Record<string, unknown> {
|
|
|
407
410
|
function ConversationToolCall({ tool }: { tool: AgentConversationToolCall }) {
|
|
408
411
|
const t = useT();
|
|
409
412
|
const resultJson = parseJsonText(tool.result);
|
|
410
|
-
const nativeToolContext = {
|
|
413
|
+
const nativeToolContext: ToolRendererContext = {
|
|
411
414
|
toolName: tool.name,
|
|
412
415
|
args: tool.args ?? parseJsonObject(tool.input),
|
|
413
416
|
resultText: tool.result,
|
|
414
417
|
resultJson: tool.resultJson ?? resultJson,
|
|
418
|
+
status:
|
|
419
|
+
tool.state === "errored"
|
|
420
|
+
? undefined
|
|
421
|
+
: tool.state === "activity"
|
|
422
|
+
? "running"
|
|
423
|
+
: tool.state,
|
|
415
424
|
isRunning: tool.state === "running" || tool.state === "activity",
|
|
416
425
|
chatUI: tool.chatUI,
|
|
417
426
|
};
|
|
@@ -9,13 +9,19 @@ const agentEngineStatusMock = vi.hoisted(() => ({
|
|
|
9
9
|
state: "missing" as "unknown" | "configured" | "missing" | "unavailable",
|
|
10
10
|
}));
|
|
11
11
|
|
|
12
|
-
vi.mock(
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
vi.mock(
|
|
13
|
+
"@agent-native/core/client/use-agent-engine-configured",
|
|
14
|
+
async (importOriginal) => ({
|
|
15
|
+
...(await importOriginal<
|
|
16
|
+
typeof import("@agent-native/core/client/use-agent-engine-configured")
|
|
17
|
+
>()),
|
|
18
|
+
useAgentEngineConfigured: () => ({
|
|
19
|
+
canChat: agentEngineStatusMock.state === "configured",
|
|
20
|
+
missing: agentEngineStatusMock.state === "missing",
|
|
21
|
+
state: agentEngineStatusMock.state,
|
|
22
|
+
}),
|
|
17
23
|
}),
|
|
18
|
-
|
|
24
|
+
);
|
|
19
25
|
|
|
20
26
|
vi.mock("../chat/chat/run-recovery.js", async () => {
|
|
21
27
|
const { createElement } = await import("react");
|
|
@@ -44,6 +50,7 @@ import {
|
|
|
44
50
|
openAgentSettings,
|
|
45
51
|
useCommandMenuNestedDialog,
|
|
46
52
|
useCommandMenuShortcut,
|
|
53
|
+
type AppCommandContext,
|
|
47
54
|
type AppCommandGroup,
|
|
48
55
|
type CommandMenuItemMatchContext,
|
|
49
56
|
type CommandMenuItemMatcher,
|
|
@@ -1836,6 +1843,168 @@ describe("CommandMenu", () => {
|
|
|
1836
1843
|
).toContain("Selected preview");
|
|
1837
1844
|
});
|
|
1838
1845
|
|
|
1846
|
+
it("renders opt-in app command previews in only the selected row", () => {
|
|
1847
|
+
renderAppCommands({
|
|
1848
|
+
groups: [
|
|
1849
|
+
{
|
|
1850
|
+
id: "results",
|
|
1851
|
+
order: 1,
|
|
1852
|
+
commands: [
|
|
1853
|
+
{
|
|
1854
|
+
id: "record",
|
|
1855
|
+
order: 1,
|
|
1856
|
+
label: "Meeting notes",
|
|
1857
|
+
inlinePreview: <span>First row preview</span>,
|
|
1858
|
+
onSelect() {},
|
|
1859
|
+
},
|
|
1860
|
+
{
|
|
1861
|
+
id: "meeting-agenda",
|
|
1862
|
+
order: 2,
|
|
1863
|
+
label: "Meeting agenda",
|
|
1864
|
+
inlinePreview: <span>Second row preview</span>,
|
|
1865
|
+
onSelect() {},
|
|
1866
|
+
},
|
|
1867
|
+
],
|
|
1868
|
+
},
|
|
1869
|
+
],
|
|
1870
|
+
});
|
|
1871
|
+
|
|
1872
|
+
const firstRow = document.querySelector(
|
|
1873
|
+
'[cmdk-item][data-value="app-command:results:record"]',
|
|
1874
|
+
);
|
|
1875
|
+
const secondRow = document.querySelector(
|
|
1876
|
+
'[cmdk-item][data-value="app-command:results:meeting-agenda"]',
|
|
1877
|
+
);
|
|
1878
|
+
expect(
|
|
1879
|
+
firstRow?.querySelector(
|
|
1880
|
+
'[data-testid="command-menu-app-command-preview"]',
|
|
1881
|
+
)?.textContent,
|
|
1882
|
+
).toBe("First row preview");
|
|
1883
|
+
expect(
|
|
1884
|
+
secondRow?.querySelector(
|
|
1885
|
+
'[data-testid="command-menu-app-command-preview"]',
|
|
1886
|
+
),
|
|
1887
|
+
).toBeNull();
|
|
1888
|
+
|
|
1889
|
+
const input = document.querySelector<HTMLInputElement>("[cmdk-input]");
|
|
1890
|
+
expect(input).toBeTruthy();
|
|
1891
|
+
act(() =>
|
|
1892
|
+
input!.dispatchEvent(
|
|
1893
|
+
new KeyboardEvent("keydown", { key: "ArrowDown", bubbles: true }),
|
|
1894
|
+
),
|
|
1895
|
+
);
|
|
1896
|
+
|
|
1897
|
+
expect(
|
|
1898
|
+
firstRow?.querySelector(
|
|
1899
|
+
'[data-testid="command-menu-app-command-preview"]',
|
|
1900
|
+
),
|
|
1901
|
+
).toBeNull();
|
|
1902
|
+
expect(
|
|
1903
|
+
secondRow?.querySelector(
|
|
1904
|
+
'[data-testid="command-menu-app-command-preview"]',
|
|
1905
|
+
)?.textContent,
|
|
1906
|
+
).toBe("Second row preview");
|
|
1907
|
+
});
|
|
1908
|
+
|
|
1909
|
+
it("keeps the selected app preview when search retains the highlighted row", () => {
|
|
1910
|
+
renderAppCommands({
|
|
1911
|
+
groups: [
|
|
1912
|
+
{
|
|
1913
|
+
id: "results",
|
|
1914
|
+
order: 1,
|
|
1915
|
+
commands: [
|
|
1916
|
+
{
|
|
1917
|
+
id: "meeting-notes",
|
|
1918
|
+
order: 1,
|
|
1919
|
+
label: "Meeting notes",
|
|
1920
|
+
inlinePreview: <span>Meeting preview</span>,
|
|
1921
|
+
onSelect() {},
|
|
1922
|
+
},
|
|
1923
|
+
{
|
|
1924
|
+
id: "other-task",
|
|
1925
|
+
order: 2,
|
|
1926
|
+
label: "Other task",
|
|
1927
|
+
inlinePreview: <span>Other preview</span>,
|
|
1928
|
+
onSelect() {},
|
|
1929
|
+
},
|
|
1930
|
+
],
|
|
1931
|
+
},
|
|
1932
|
+
],
|
|
1933
|
+
});
|
|
1934
|
+
|
|
1935
|
+
const selectedPreview = () =>
|
|
1936
|
+
document.querySelector(
|
|
1937
|
+
'[cmdk-item][data-value="app-command:results:meeting-notes"] [data-testid="command-menu-app-command-preview"]',
|
|
1938
|
+
)?.textContent;
|
|
1939
|
+
|
|
1940
|
+
expect(selectedPreview()).toBe("Meeting preview");
|
|
1941
|
+
search("Meeting");
|
|
1942
|
+
expect(selectedPreview()).toBe("Meeting preview");
|
|
1943
|
+
});
|
|
1944
|
+
|
|
1945
|
+
it("passes app context and search to an app command row preview", () => {
|
|
1946
|
+
const renderPreview = vi.fn(
|
|
1947
|
+
({
|
|
1948
|
+
search: currentSearch,
|
|
1949
|
+
appContext,
|
|
1950
|
+
}: AppCommandContext<{ workspace: string }>) => (
|
|
1951
|
+
<span>{`${currentSearch}|${appContext?.workspace}`}</span>
|
|
1952
|
+
),
|
|
1953
|
+
);
|
|
1954
|
+
renderAppCommands({
|
|
1955
|
+
initialSelection: "none",
|
|
1956
|
+
context: { workspace: "alpha" },
|
|
1957
|
+
groups: [
|
|
1958
|
+
{
|
|
1959
|
+
id: "results",
|
|
1960
|
+
order: 1,
|
|
1961
|
+
commands: [
|
|
1962
|
+
{
|
|
1963
|
+
id: "workspace",
|
|
1964
|
+
order: 1,
|
|
1965
|
+
label: "Open workspace",
|
|
1966
|
+
inlinePreview: renderPreview,
|
|
1967
|
+
onSelect() {},
|
|
1968
|
+
},
|
|
1969
|
+
],
|
|
1970
|
+
},
|
|
1971
|
+
],
|
|
1972
|
+
});
|
|
1973
|
+
|
|
1974
|
+
const input = document.querySelector<HTMLInputElement>("[cmdk-input]");
|
|
1975
|
+
expect(input).toBeTruthy();
|
|
1976
|
+
const moveDown = () =>
|
|
1977
|
+
act(() =>
|
|
1978
|
+
input!.dispatchEvent(
|
|
1979
|
+
new KeyboardEvent("keydown", { key: "ArrowDown", bubbles: true }),
|
|
1980
|
+
),
|
|
1981
|
+
);
|
|
1982
|
+
moveDown();
|
|
1983
|
+
|
|
1984
|
+
expect(renderPreview).toHaveBeenCalledWith(
|
|
1985
|
+
expect.objectContaining({
|
|
1986
|
+
search: "",
|
|
1987
|
+
appContext: { workspace: "alpha" },
|
|
1988
|
+
}),
|
|
1989
|
+
);
|
|
1990
|
+
expect(
|
|
1991
|
+
document.querySelector('[data-testid="command-menu-app-command-preview"]')
|
|
1992
|
+
?.textContent,
|
|
1993
|
+
).toBe("|alpha");
|
|
1994
|
+
|
|
1995
|
+
search("workspace");
|
|
1996
|
+
moveDown();
|
|
1997
|
+
expect(
|
|
1998
|
+
document.querySelector(
|
|
1999
|
+
'[cmdk-item][data-value="app-command:results:workspace"]',
|
|
2000
|
+
),
|
|
2001
|
+
).toBeTruthy();
|
|
2002
|
+
expect(
|
|
2003
|
+
document.querySelector('[data-testid="command-menu-app-command-preview"]')
|
|
2004
|
+
?.textContent,
|
|
2005
|
+
).toBe("workspace|alpha");
|
|
2006
|
+
});
|
|
2007
|
+
|
|
1839
2008
|
it("hides the app preview when a non-app result is selected", () => {
|
|
1840
2009
|
renderAppCommands({
|
|
1841
2010
|
groups: [
|
|
@@ -304,6 +304,10 @@ interface AppCommandBase<TAppContext> {
|
|
|
304
304
|
preview?:
|
|
305
305
|
| ReactNode
|
|
306
306
|
| ((context: AppCommandContext<TAppContext>) => ReactNode);
|
|
307
|
+
/** Content rendered at the end of this command's selected row. */
|
|
308
|
+
inlinePreview?:
|
|
309
|
+
| ReactNode
|
|
310
|
+
| ((context: AppCommandContext<TAppContext>) => ReactNode);
|
|
307
311
|
visibleWhen?: (context: AppCommandContext<TAppContext>) => boolean;
|
|
308
312
|
enabledWhen?: (context: AppCommandContext<TAppContext>) => boolean;
|
|
309
313
|
deferSelect?: boolean;
|
|
@@ -877,9 +881,10 @@ export function CommandMenu<TAppContext = unknown>({
|
|
|
877
881
|
firstEnabledAppCommand?.value ??
|
|
878
882
|
NO_COMMAND_SELECTION)
|
|
879
883
|
: undefined;
|
|
884
|
+
const selectedAppCommandValue = commandMenuValue ?? selectedCommandValue;
|
|
880
885
|
const previewAppCommand =
|
|
881
886
|
appCommandEntries.find(
|
|
882
|
-
(entry) => entry.value ===
|
|
887
|
+
(entry) => entry.value === selectedAppCommandValue,
|
|
883
888
|
) ?? selectedAppCommand;
|
|
884
889
|
const appPreview = previewAppCommand?.command.preview;
|
|
885
890
|
const renderedAppPreview =
|
|
@@ -973,6 +978,12 @@ export function CommandMenu<TAppContext = unknown>({
|
|
|
973
978
|
{commands.map((command) => {
|
|
974
979
|
const value = `app-command:${group.id}:${command.id}`;
|
|
975
980
|
const enabled = command.enabledWhen?.(appCommandContext) ?? true;
|
|
981
|
+
const inlinePreview =
|
|
982
|
+
value === selectedAppCommandValue
|
|
983
|
+
? typeof command.inlinePreview === "function"
|
|
984
|
+
? command.inlinePreview(appCommandContext)
|
|
985
|
+
: command.inlinePreview
|
|
986
|
+
: null;
|
|
976
987
|
return (
|
|
977
988
|
<CommandItemPrimitive
|
|
978
989
|
key={command.id}
|
|
@@ -1003,6 +1014,14 @@ export function CommandMenu<TAppContext = unknown>({
|
|
|
1003
1014
|
{command.shortcutHint}
|
|
1004
1015
|
</CommandShortcutPrimitive>
|
|
1005
1016
|
) : null}
|
|
1017
|
+
{inlinePreview != null ? (
|
|
1018
|
+
<div
|
|
1019
|
+
data-testid="command-menu-app-command-preview"
|
|
1020
|
+
className="ms-auto min-w-0"
|
|
1021
|
+
>
|
|
1022
|
+
{inlinePreview}
|
|
1023
|
+
</div>
|
|
1024
|
+
) : null}
|
|
1006
1025
|
</CommandItemPrimitive>
|
|
1007
1026
|
);
|
|
1008
1027
|
})}
|
|
@@ -1299,12 +1318,10 @@ export function CommandMenu<TAppContext = unknown>({
|
|
|
1299
1318
|
onValueChange={(value) => {
|
|
1300
1319
|
updateSearch(value);
|
|
1301
1320
|
selectionEnabledRef.current = false;
|
|
1302
|
-
if (initialSelection === "none")
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
: "",
|
|
1307
|
-
);
|
|
1321
|
+
if (initialSelection === "none") {
|
|
1322
|
+
setSelectionEnabled(false);
|
|
1323
|
+
setSelectedCommandValue(nextEmptySelectionValue());
|
|
1324
|
+
}
|
|
1308
1325
|
}}
|
|
1309
1326
|
onKeyDown={(event) => {
|
|
1310
1327
|
if (
|
|
@@ -2207,7 +2207,7 @@ function ModelSelector({
|
|
|
2207
2207
|
? `. Agent: ${selectedAgentLabel}`
|
|
2208
2208
|
: ""
|
|
2209
2209
|
}`}
|
|
2210
|
-
className="agent-composer-model-button flex min-w-0 max-w-none shrink
|
|
2210
|
+
className="agent-composer-model-button flex min-w-0 max-w-none shrink items-center gap-1 overflow-hidden rounded-md px-2 py-1 text-[12px] font-medium text-muted-foreground hover:bg-accent/50 hover:text-foreground"
|
|
2211
2211
|
>
|
|
2212
2212
|
<span className="min-w-0 truncate">
|
|
2213
2213
|
{selectedAgentOption?.icon ? (
|