@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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/toolkit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.219.0",
|
|
4
4
|
"description": "Reusable app-building UI and helpers for Agent-Native apps.",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -685,7 +685,7 @@
|
|
|
685
685
|
"y-protocols": "^1.0.7",
|
|
686
686
|
"yjs": "^13.6.33",
|
|
687
687
|
"zod": "^4.3.6",
|
|
688
|
-
"@agent-native/agentkit": "^0.
|
|
688
|
+
"@agent-native/agentkit": "^0.219.0"
|
|
689
689
|
},
|
|
690
690
|
"devDependencies": {
|
|
691
691
|
"@excalidraw/excalidraw": "0.18.1",
|
|
@@ -709,7 +709,7 @@
|
|
|
709
709
|
"typescript-7": "npm:typescript@^7.0.2",
|
|
710
710
|
"vite": "8.1.0",
|
|
711
711
|
"vitest": "^4.1.5",
|
|
712
|
-
"@agent-native/core": "^0.
|
|
712
|
+
"@agent-native/core": "^0.219.0"
|
|
713
713
|
},
|
|
714
714
|
"peerDependencies": {
|
|
715
715
|
"@agent-native/core": ">=0.205.1",
|
|
@@ -503,17 +503,19 @@ describe("AgentKitChat", () => {
|
|
|
503
503
|
expect(styles).toMatch(
|
|
504
504
|
/@media \(max-width: 40rem\)[\s\S]*\[data-agent-composer-slot="area"\][\s\S]*padding-inline: 0;/,
|
|
505
505
|
);
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
);
|
|
506
|
+
const modelButtonRule = styles.match(
|
|
507
|
+
/\.agentkit-composer \[data-agent-composer-slot="model-button"\] \{([^}]*)\}/,
|
|
508
|
+
)?.[1];
|
|
509
|
+
expect(modelButtonRule).toContain("max-inline-size: 11rem;");
|
|
510
|
+
expect(modelButtonRule).toContain("flex: 0 1 auto;");
|
|
509
511
|
expect(styles).toMatch(
|
|
510
512
|
/\[data-agent-composer-slot="mode-button"\] \{[\s\S]*min-inline-size: 3\.5rem;/,
|
|
511
513
|
);
|
|
512
514
|
expect(styles).toMatch(
|
|
513
|
-
/@
|
|
515
|
+
/@container \(max-width: 24rem\)[\s\S]*\[data-agent-composer-slot="model-button"\][\s\S]*max-inline-size: 7\.5rem;/,
|
|
514
516
|
);
|
|
515
517
|
expect(styles).toMatch(
|
|
516
|
-
/@
|
|
518
|
+
/@container \(max-width: 24rem\)[\s\S]*\.agent-composer-model-effort[\s\S]*display: none;/,
|
|
517
519
|
);
|
|
518
520
|
const composerPopoverRule = styles.match(
|
|
519
521
|
/\[data-agent-native-composer-popover="true"\] \{([^}]*)\}/,
|
|
@@ -104,6 +104,7 @@
|
|
|
104
104
|
var(--agent-kit-composer-surface, var(--agentkit-surface))
|
|
105
105
|
);
|
|
106
106
|
box-shadow: var(--agentkit-elevation);
|
|
107
|
+
container-type: inline-size;
|
|
107
108
|
}
|
|
108
109
|
|
|
109
110
|
.agentkit-composer[data-agent-composer-slot="root"]:focus-within {
|
|
@@ -161,9 +162,11 @@
|
|
|
161
162
|
flex: 1;
|
|
162
163
|
}
|
|
163
164
|
|
|
165
|
+
/* Only the model picker shrinks, so narrow composers never push out send. */
|
|
164
166
|
.agentkit-composer [data-agent-composer-slot="model-button"] {
|
|
165
|
-
flex:
|
|
167
|
+
flex: 0 1 auto;
|
|
166
168
|
max-inline-size: 11rem;
|
|
169
|
+
overflow: hidden;
|
|
167
170
|
}
|
|
168
171
|
|
|
169
172
|
.agentkit-composer [data-agent-composer-slot="mode-button"] {
|
|
@@ -2169,9 +2172,16 @@ button.agentkit-object {
|
|
|
2169
2172
|
padding-inline: 0;
|
|
2170
2173
|
}
|
|
2171
2174
|
|
|
2175
|
+
.agentkit-message[data-role="user"] .agentkit-message-content {
|
|
2176
|
+
max-inline-size: min(94%, var(--agentkit-user-bubble-max-width, 38rem));
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2179
|
+
|
|
2180
|
+
/* Composer width, not viewport: desktop side panels are as narrow as phones. */
|
|
2181
|
+
@container (max-width: 24rem) {
|
|
2172
2182
|
.agentkit-composer [data-agent-composer-slot="toolbar"] {
|
|
2173
2183
|
gap: 0.125rem;
|
|
2174
|
-
padding-inline: 0.
|
|
2184
|
+
padding-inline: 0.375rem;
|
|
2175
2185
|
}
|
|
2176
2186
|
|
|
2177
2187
|
.agentkit-composer [data-agent-composer-slot="model-button"] {
|
|
@@ -2180,14 +2190,11 @@ button.agentkit-object {
|
|
|
2180
2190
|
}
|
|
2181
2191
|
|
|
2182
2192
|
.agentkit-composer [data-agent-composer-slot="mode-button"] {
|
|
2193
|
+
min-inline-size: 0;
|
|
2183
2194
|
padding-inline: 0.375rem;
|
|
2184
2195
|
}
|
|
2185
2196
|
|
|
2186
2197
|
.agentkit-composer .agent-composer-model-effort {
|
|
2187
2198
|
display: none;
|
|
2188
2199
|
}
|
|
2189
|
-
|
|
2190
|
-
.agentkit-message[data-role="user"] .agentkit-message-content {
|
|
2191
|
-
max-inline-size: min(94%, var(--agentkit-user-bubble-max-width, 38rem));
|
|
2192
|
-
}
|
|
2193
2200
|
}
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
} from "@agent-native/agentkit/protocol";
|
|
11
11
|
import type {
|
|
12
12
|
AgentInteraction,
|
|
13
|
+
AgentToolCall,
|
|
13
14
|
FilePart,
|
|
14
15
|
AgentMessage,
|
|
15
16
|
AgentTransport,
|
|
@@ -24,6 +25,10 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
24
25
|
import { AgentSuggestionBar } from "../../composer/AgentSuggestionBar.js";
|
|
25
26
|
import { AgentInteractionItem } from "../agentkit/react/components.js";
|
|
26
27
|
import { AgentKitProvider } from "../agentkit/react/context.js";
|
|
28
|
+
import {
|
|
29
|
+
clearToolRenderersForTests,
|
|
30
|
+
registerToolRenderer,
|
|
31
|
+
} from "./chat/tool-render-registry.js";
|
|
27
32
|
|
|
28
33
|
function largePngBytes(
|
|
29
34
|
width = 2560,
|
|
@@ -106,6 +111,7 @@ const chatMocks = vi.hoisted(() => ({
|
|
|
106
111
|
runtimeOptions: null as any,
|
|
107
112
|
inBuilder: false,
|
|
108
113
|
useRealRoot: false,
|
|
114
|
+
renderRealToolCalls: false,
|
|
109
115
|
realComposerController: null as AgentKitClient | null,
|
|
110
116
|
useRealChat: false,
|
|
111
117
|
routeControllerPersistenceThroughTransport: false,
|
|
@@ -675,29 +681,33 @@ vi.mock("@agent-native/core/client/agent-chat", async (importOriginal) => {
|
|
|
675
681
|
};
|
|
676
682
|
});
|
|
677
683
|
|
|
678
|
-
vi.mock("./chat/run-recovery.js", async (importOriginal) =>
|
|
679
|
-
|
|
680
|
-
await importOriginal<typeof import("./chat/run-recovery.js")>()
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
}
|
|
684
|
+
vi.mock("./chat/run-recovery.js", async (importOriginal) => {
|
|
685
|
+
const actual =
|
|
686
|
+
await importOriginal<typeof import("./chat/run-recovery.js")>();
|
|
687
|
+
return {
|
|
688
|
+
...actual,
|
|
689
|
+
RunErrorRecoveryCard: (props: unknown) => {
|
|
690
|
+
chatMocks.failureProps = props;
|
|
691
|
+
chatMocks.failurePropsHistory.push(props);
|
|
692
|
+
return React.createElement("div", {
|
|
693
|
+
"data-testid": "run-error-recovery-card",
|
|
694
|
+
});
|
|
695
|
+
},
|
|
696
|
+
BuilderSetupCard: (props: unknown) => {
|
|
697
|
+
chatMocks.setupCardProps = props;
|
|
698
|
+
chatMocks.setupCardPropsHistory.push(props);
|
|
699
|
+
return React.createElement("div", {
|
|
700
|
+
"data-testid": "builder-setup-card",
|
|
701
|
+
});
|
|
702
|
+
},
|
|
703
|
+
LoopLimitContinueCard: (props: unknown) => {
|
|
704
|
+
chatMocks.loopLimitProps = props;
|
|
705
|
+
return null;
|
|
706
|
+
},
|
|
707
|
+
PlanModeCallout: () => null,
|
|
708
|
+
getRequestModeMetadata: () => undefined,
|
|
709
|
+
};
|
|
710
|
+
});
|
|
701
711
|
|
|
702
712
|
vi.mock("./FileStorageSetupPopover.js", async () => {
|
|
703
713
|
const React = await import("react");
|
|
@@ -771,12 +781,17 @@ vi.mock("@agent-native/core/client/use-session", () => ({
|
|
|
771
781
|
useSession: () => ({ session: chatMocks.session, status: "authenticated" }),
|
|
772
782
|
}));
|
|
773
783
|
|
|
774
|
-
vi.mock("./chat/tool-call-display.js", async () => {
|
|
784
|
+
vi.mock("./chat/tool-call-display.js", async (importOriginal) => {
|
|
775
785
|
const React = await import("react");
|
|
786
|
+
const actual =
|
|
787
|
+
await importOriginal<typeof import("./chat/tool-call-display.js")>();
|
|
776
788
|
return {
|
|
777
|
-
ChatRunningContext:
|
|
778
|
-
SuppressInlineOpenAppContext:
|
|
779
|
-
ToolCallDisplay: () =>
|
|
789
|
+
ChatRunningContext: actual.ChatRunningContext,
|
|
790
|
+
SuppressInlineOpenAppContext: actual.SuppressInlineOpenAppContext,
|
|
791
|
+
ToolCallDisplay: (props: any) =>
|
|
792
|
+
chatMocks.renderRealToolCalls
|
|
793
|
+
? React.createElement(actual.ToolCallDisplay, props)
|
|
794
|
+
: null,
|
|
780
795
|
AgentApprovalCard: (props: any) => {
|
|
781
796
|
chatMocks.approvalCardProps = props;
|
|
782
797
|
return React.createElement(
|
|
@@ -1000,6 +1015,7 @@ beforeEach(() => {
|
|
|
1000
1015
|
chatMocks.transportOptions = null;
|
|
1001
1016
|
chatMocks.inBuilder = false;
|
|
1002
1017
|
chatMocks.useRealRoot = false;
|
|
1018
|
+
chatMocks.renderRealToolCalls = false;
|
|
1003
1019
|
chatMocks.realComposerController = null;
|
|
1004
1020
|
chatMocks.useRealChat = false;
|
|
1005
1021
|
chatMocks.routeControllerPersistenceThroughTransport = false;
|
|
@@ -1035,6 +1051,7 @@ afterEach(async () => {
|
|
|
1035
1051
|
await unmount();
|
|
1036
1052
|
chatMocks.realComposerController?.dispose();
|
|
1037
1053
|
window.sessionStorage.clear();
|
|
1054
|
+
clearToolRenderersForTests();
|
|
1038
1055
|
});
|
|
1039
1056
|
|
|
1040
1057
|
describe("AgentKitAssistantChat host behavior", () => {
|
|
@@ -1331,6 +1348,161 @@ describe("AgentKitAssistantChat host behavior", () => {
|
|
|
1331
1348
|
expect(chatMocks.rootProps.slots.widget).toBe(AgentKitActionWidget);
|
|
1332
1349
|
});
|
|
1333
1350
|
|
|
1351
|
+
it("shows failed tools through the shared fallback without an app renderer", async () => {
|
|
1352
|
+
const at = "2026-09-28T00:00:00.000Z";
|
|
1353
|
+
const failedTool: AgentToolCall = {
|
|
1354
|
+
id: "query-1",
|
|
1355
|
+
name: "query-analytics",
|
|
1356
|
+
input: {},
|
|
1357
|
+
output: "Query execution failed.",
|
|
1358
|
+
error: { code: "query_failed", message: "Query execution failed." },
|
|
1359
|
+
status: "failed",
|
|
1360
|
+
runId: "run-1",
|
|
1361
|
+
messageId: "assistant-1",
|
|
1362
|
+
metadata: { chatUI: { renderer: "analytics.query-result.v1" } },
|
|
1363
|
+
};
|
|
1364
|
+
chatMocks.useRealChat = true;
|
|
1365
|
+
chatMocks.useRealRoot = true;
|
|
1366
|
+
chatMocks.renderRealToolCalls = true;
|
|
1367
|
+
chatMocks.thread.messages = [
|
|
1368
|
+
{
|
|
1369
|
+
id: "assistant-1",
|
|
1370
|
+
role: "assistant",
|
|
1371
|
+
status: "complete",
|
|
1372
|
+
parts: [{ type: "text", text: "The query could not be completed." }],
|
|
1373
|
+
},
|
|
1374
|
+
];
|
|
1375
|
+
chatMocks.thread.tools = { [failedTool.id]: failedTool };
|
|
1376
|
+
chatMocks.thread.runs = {
|
|
1377
|
+
"run-1": { id: "run-1", status: "failed", lastSequence: 3 },
|
|
1378
|
+
};
|
|
1379
|
+
chatMocks.thread.events = [
|
|
1380
|
+
{
|
|
1381
|
+
id: "tool-started",
|
|
1382
|
+
threadId: chatMocks.threadId,
|
|
1383
|
+
runId: "run-1",
|
|
1384
|
+
sequence: 1,
|
|
1385
|
+
occurredAt: at,
|
|
1386
|
+
type: "tool.started",
|
|
1387
|
+
toolCall: { ...failedTool, status: "running" },
|
|
1388
|
+
},
|
|
1389
|
+
{
|
|
1390
|
+
id: "tool-failed",
|
|
1391
|
+
threadId: chatMocks.threadId,
|
|
1392
|
+
runId: "run-1",
|
|
1393
|
+
sequence: 2,
|
|
1394
|
+
occurredAt: at,
|
|
1395
|
+
type: "tool.updated",
|
|
1396
|
+
toolCall: failedTool,
|
|
1397
|
+
},
|
|
1398
|
+
{
|
|
1399
|
+
id: "run-failed",
|
|
1400
|
+
threadId: chatMocks.threadId,
|
|
1401
|
+
runId: "run-1",
|
|
1402
|
+
sequence: 3,
|
|
1403
|
+
occurredAt: at,
|
|
1404
|
+
type: "run.failed",
|
|
1405
|
+
error: { code: "query_failed", message: "Query execution failed." },
|
|
1406
|
+
},
|
|
1407
|
+
];
|
|
1408
|
+
|
|
1409
|
+
await useRealComposer();
|
|
1410
|
+
await mount(baseProps({ isNewThread: false }));
|
|
1411
|
+
|
|
1412
|
+
const toolRow = container.querySelector<HTMLButtonElement>(
|
|
1413
|
+
"button[aria-expanded]",
|
|
1414
|
+
);
|
|
1415
|
+
expect(toolRow?.textContent).toContain("query analytics");
|
|
1416
|
+
expect(toolRow?.getAttribute("aria-expanded")).toBe("false");
|
|
1417
|
+
expect(container.textContent).not.toContain("Query execution failed.");
|
|
1418
|
+
|
|
1419
|
+
await act(async () => {
|
|
1420
|
+
toolRow?.click();
|
|
1421
|
+
});
|
|
1422
|
+
|
|
1423
|
+
expect(toolRow?.getAttribute("aria-expanded")).toBe("true");
|
|
1424
|
+
expect(container.textContent).toContain("Query execution failed.");
|
|
1425
|
+
});
|
|
1426
|
+
|
|
1427
|
+
it.each(["completed", "cancelled"] as const)(
|
|
1428
|
+
"passes %s status to custom renderers in the regular transcript",
|
|
1429
|
+
async (status) => {
|
|
1430
|
+
const at = "2026-09-28T00:00:00.000Z";
|
|
1431
|
+
const tool: AgentToolCall = {
|
|
1432
|
+
id: "status-tool-1",
|
|
1433
|
+
name: "example-status-tool",
|
|
1434
|
+
input: {},
|
|
1435
|
+
output: "Finished.",
|
|
1436
|
+
status,
|
|
1437
|
+
runId: "status-run-1",
|
|
1438
|
+
messageId: "status-assistant-1",
|
|
1439
|
+
};
|
|
1440
|
+
registerToolRenderer({
|
|
1441
|
+
id: "example-status-renderer",
|
|
1442
|
+
match: "example-status-tool",
|
|
1443
|
+
Component: ({ context }) => (
|
|
1444
|
+
<div data-testid="custom-tool-status" data-status={context.status} />
|
|
1445
|
+
),
|
|
1446
|
+
});
|
|
1447
|
+
chatMocks.useRealChat = true;
|
|
1448
|
+
chatMocks.useRealRoot = true;
|
|
1449
|
+
chatMocks.renderRealToolCalls = true;
|
|
1450
|
+
chatMocks.thread.messages = [
|
|
1451
|
+
{
|
|
1452
|
+
id: "status-assistant-1",
|
|
1453
|
+
role: "assistant",
|
|
1454
|
+
status: "complete",
|
|
1455
|
+
parts: [{ type: "text", text: "The tool finished." }],
|
|
1456
|
+
},
|
|
1457
|
+
];
|
|
1458
|
+
chatMocks.thread.tools = { [tool.id]: tool };
|
|
1459
|
+
chatMocks.thread.runs = {
|
|
1460
|
+
"status-run-1": {
|
|
1461
|
+
id: "status-run-1",
|
|
1462
|
+
status,
|
|
1463
|
+
lastSequence: 3,
|
|
1464
|
+
},
|
|
1465
|
+
};
|
|
1466
|
+
chatMocks.thread.events = [
|
|
1467
|
+
{
|
|
1468
|
+
id: "status-tool-started",
|
|
1469
|
+
threadId: chatMocks.threadId,
|
|
1470
|
+
runId: "status-run-1",
|
|
1471
|
+
sequence: 1,
|
|
1472
|
+
occurredAt: at,
|
|
1473
|
+
type: "tool.started",
|
|
1474
|
+
toolCall: { ...tool, status: "running" },
|
|
1475
|
+
},
|
|
1476
|
+
{
|
|
1477
|
+
id: "status-tool-updated",
|
|
1478
|
+
threadId: chatMocks.threadId,
|
|
1479
|
+
runId: "status-run-1",
|
|
1480
|
+
sequence: 2,
|
|
1481
|
+
occurredAt: at,
|
|
1482
|
+
type: "tool.updated",
|
|
1483
|
+
toolCall: tool,
|
|
1484
|
+
},
|
|
1485
|
+
{
|
|
1486
|
+
id: "status-run-ended",
|
|
1487
|
+
threadId: chatMocks.threadId,
|
|
1488
|
+
runId: "status-run-1",
|
|
1489
|
+
sequence: 3,
|
|
1490
|
+
occurredAt: at,
|
|
1491
|
+
type: status === "completed" ? "run.completed" : "run.cancelled",
|
|
1492
|
+
},
|
|
1493
|
+
];
|
|
1494
|
+
|
|
1495
|
+
await useRealComposer();
|
|
1496
|
+
await mount(baseProps({ isNewThread: false }));
|
|
1497
|
+
|
|
1498
|
+
expect(
|
|
1499
|
+
container
|
|
1500
|
+
.querySelector('[data-testid="custom-tool-status"]')
|
|
1501
|
+
?.getAttribute("data-status"),
|
|
1502
|
+
).toBe(status);
|
|
1503
|
+
},
|
|
1504
|
+
);
|
|
1505
|
+
|
|
1334
1506
|
it("checks readiness on the configured chat API server", async () => {
|
|
1335
1507
|
await mount(
|
|
1336
1508
|
baseProps({
|
|
@@ -1863,12 +2035,14 @@ describe("AgentKitAssistantChat host behavior", () => {
|
|
|
1863
2035
|
createdAt: at,
|
|
1864
2036
|
updatedAt: at,
|
|
1865
2037
|
messages: chatMocks.thread.messages,
|
|
2038
|
+
events: chatMocks.thread.events,
|
|
1866
2039
|
runs: Object.values(chatMocks.thread.runs).map((run) => ({
|
|
1867
2040
|
...run,
|
|
1868
2041
|
threadId,
|
|
1869
2042
|
startedAt: at,
|
|
1870
2043
|
completedAt: at,
|
|
1871
2044
|
})),
|
|
2045
|
+
toolCalls: Object.values(chatMocks.thread.tools),
|
|
1872
2046
|
suggestions: chatMocks.thread.suggestions,
|
|
1873
2047
|
}),
|
|
1874
2048
|
startRun,
|
|
@@ -6467,6 +6467,7 @@ function AgentKitTool({ value, active }: AgentKitRenderProps<AgentToolCall>) {
|
|
|
6467
6467
|
args={input}
|
|
6468
6468
|
argsText={JSON.stringify(input)}
|
|
6469
6469
|
result={output}
|
|
6470
|
+
status={value.status}
|
|
6470
6471
|
isError={value.status === "failed"}
|
|
6471
6472
|
isRunning={value.status === "running"}
|
|
6472
6473
|
structuredMeta={metadata}
|
|
@@ -1965,7 +1965,7 @@ function AgentPanelInner({
|
|
|
1965
1965
|
return (
|
|
1966
1966
|
<div
|
|
1967
1967
|
key={tab.id}
|
|
1968
|
-
className="agent-tab-group relative flex
|
|
1968
|
+
className="agent-tab-group relative flex min-w-[56px] max-w-[150px] shrink items-center"
|
|
1969
1969
|
>
|
|
1970
1970
|
<div
|
|
1971
1971
|
role="tab"
|
|
@@ -1981,7 +1981,7 @@ function AgentPanelInner({
|
|
|
1981
1981
|
switchMode("chat");
|
|
1982
1982
|
})}
|
|
1983
1983
|
className={cn(
|
|
1984
|
-
"agent-tab relative flex
|
|
1984
|
+
"agent-tab relative flex w-full min-w-0 items-center gap-1 rounded-md px-2.5 py-1.5 text-[11px] font-medium cursor-pointer",
|
|
1985
1985
|
isActive
|
|
1986
1986
|
? "bg-accent text-foreground"
|
|
1987
1987
|
: "text-muted-foreground hover:bg-accent hover:text-foreground",
|
|
@@ -2104,7 +2104,7 @@ function AgentPanelInner({
|
|
|
2104
2104
|
return (
|
|
2105
2105
|
<div
|
|
2106
2106
|
key={tab.id}
|
|
2107
|
-
className="agent-tab-group relative shrink
|
|
2107
|
+
className="agent-tab-group relative min-w-[56px] max-w-[150px] shrink"
|
|
2108
2108
|
>
|
|
2109
2109
|
<div
|
|
2110
2110
|
role="button"
|
|
@@ -2115,7 +2115,7 @@ function AgentPanelInner({
|
|
|
2115
2115
|
setActiveTabId(tab.id),
|
|
2116
2116
|
)}
|
|
2117
2117
|
className={cn(
|
|
2118
|
-
"agent-tab relative flex
|
|
2118
|
+
"agent-tab relative flex w-full min-w-0 items-center gap-1 rounded-md px-2.5 py-1.5 text-[11px] font-medium cursor-pointer",
|
|
2119
2119
|
isActive
|
|
2120
2120
|
? "bg-accent text-foreground"
|
|
2121
2121
|
: "text-muted-foreground hover:bg-accent hover:text-foreground",
|
|
@@ -2208,7 +2208,7 @@ function AgentPanelInner({
|
|
|
2208
2208
|
return (
|
|
2209
2209
|
<div
|
|
2210
2210
|
key={tab.id}
|
|
2211
|
-
className="agent-tab-group relative shrink
|
|
2211
|
+
className="agent-tab-group relative min-w-[56px] max-w-[150px] shrink"
|
|
2212
2212
|
>
|
|
2213
2213
|
<div
|
|
2214
2214
|
role="button"
|
|
@@ -2219,7 +2219,7 @@ function AgentPanelInner({
|
|
|
2219
2219
|
setActiveTabId(tab.id),
|
|
2220
2220
|
)}
|
|
2221
2221
|
className={cn(
|
|
2222
|
-
"agent-tab relative flex
|
|
2222
|
+
"agent-tab relative flex w-full min-w-0 items-center gap-1 rounded-md px-2.5 py-1.5 text-[11px] font-medium cursor-pointer",
|
|
2223
2223
|
isActive
|
|
2224
2224
|
? "bg-accent text-foreground"
|
|
2225
2225
|
: "text-muted-foreground hover:bg-accent hover:text-foreground",
|
|
@@ -2338,7 +2338,7 @@ function AgentPanelInner({
|
|
|
2338
2338
|
{childTabs.map((tab) => (
|
|
2339
2339
|
<div
|
|
2340
2340
|
key={tab.id}
|
|
2341
|
-
className="agent-tab-group relative shrink
|
|
2341
|
+
className="agent-tab-group relative min-w-[48px] max-w-[140px] shrink"
|
|
2342
2342
|
>
|
|
2343
2343
|
<div
|
|
2344
2344
|
role="button"
|
|
@@ -2353,7 +2353,7 @@ function AgentPanelInner({
|
|
|
2353
2353
|
setActiveTabId(tab.id),
|
|
2354
2354
|
)}
|
|
2355
2355
|
className={cn(
|
|
2356
|
-
"agent-tab relative flex
|
|
2356
|
+
"agent-tab relative flex w-full min-w-0 items-center gap-1 rounded-md px-2 py-1 text-[10px] font-medium cursor-pointer",
|
|
2357
2357
|
tab.id === activeTabId
|
|
2358
2358
|
? "bg-accent text-foreground"
|
|
2359
2359
|
: "text-muted-foreground hover:bg-accent hover:text-foreground",
|
|
@@ -3680,7 +3680,7 @@ export function MultiTabAssistantChat({
|
|
|
3680
3680
|
key={tab.id}
|
|
3681
3681
|
ref={isActive ? activeTabRefCb : undefined}
|
|
3682
3682
|
className={cn(
|
|
3683
|
-
"agent-tab agent-tab-group relative flex items-center rounded-md text-[11px] font-medium shrink
|
|
3683
|
+
"agent-tab agent-tab-group relative flex items-center rounded-md text-[11px] font-medium shrink min-w-[56px] max-w-[130px]",
|
|
3684
3684
|
isActive
|
|
3685
3685
|
? "bg-accent text-foreground ring-1 ring-inset ring-border/60 shadow-sm"
|
|
3686
3686
|
: "text-muted-foreground hover:text-foreground hover:bg-accent/50",
|
|
@@ -3782,7 +3782,7 @@ export function MultiTabAssistantChat({
|
|
|
3782
3782
|
: undefined
|
|
3783
3783
|
}
|
|
3784
3784
|
className={cn(
|
|
3785
|
-
"agent-tab agent-tab-group relative flex shrink
|
|
3785
|
+
"agent-tab agent-tab-group relative flex shrink items-center rounded-md text-[10px] font-medium min-w-[48px] max-w-[130px]",
|
|
3786
3786
|
tab.id === activeThreadId
|
|
3787
3787
|
? "bg-accent text-foreground"
|
|
3788
3788
|
: "text-muted-foreground hover:bg-accent hover:text-foreground",
|
|
@@ -32,6 +32,68 @@ import { AgentKitActionWidget } from "./action-widget.js";
|
|
|
32
32
|
const catalog = createToolkitI18nCatalog({ messages: {} });
|
|
33
33
|
|
|
34
34
|
describe("AgentKitActionWidget", () => {
|
|
35
|
+
it.each(["running", "completed", "failed", "cancelled"] as const)(
|
|
36
|
+
"exposes the %s tool status to renderers while retaining isRunning",
|
|
37
|
+
async (status) => {
|
|
38
|
+
const toolCall: AgentToolCall = {
|
|
39
|
+
id: "tool-1",
|
|
40
|
+
name: "preview-inbox",
|
|
41
|
+
input: {},
|
|
42
|
+
output: { ok: true },
|
|
43
|
+
status,
|
|
44
|
+
};
|
|
45
|
+
const widget: AgentWidget = {
|
|
46
|
+
id: "tool-1:chat-ui",
|
|
47
|
+
kind: "mail.inbox-preview",
|
|
48
|
+
data: { toolCallId: toolCall.id, toolName: toolCall.name },
|
|
49
|
+
};
|
|
50
|
+
const client = new AgentKitClient({
|
|
51
|
+
transport: {
|
|
52
|
+
async startRun() {
|
|
53
|
+
return { runId: "run-1" };
|
|
54
|
+
},
|
|
55
|
+
async *subscribeToRun() {},
|
|
56
|
+
async cancelRun() {},
|
|
57
|
+
async getThreadSnapshot() {
|
|
58
|
+
return {
|
|
59
|
+
id: "thread-1",
|
|
60
|
+
createdAt: "2026-09-26T00:00:00.000Z",
|
|
61
|
+
updatedAt: "2026-09-26T00:00:00.000Z",
|
|
62
|
+
messages: [],
|
|
63
|
+
toolCalls: [toolCall],
|
|
64
|
+
};
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
await client.loadThread("thread-1");
|
|
69
|
+
const unregister = registerActionChatRenderer({
|
|
70
|
+
id: `test.agentkit-action-widget-status-${status}`,
|
|
71
|
+
renderer: widget.kind,
|
|
72
|
+
Component: ({ context }: ToolRendererProps) => (
|
|
73
|
+
<output
|
|
74
|
+
data-status={context.status}
|
|
75
|
+
data-running={String(context.isRunning)}
|
|
76
|
+
/>
|
|
77
|
+
),
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
const html = renderToStaticMarkup(
|
|
82
|
+
<AgentKitProvider controller={client} threadId="thread-1">
|
|
83
|
+
<AgentKitActionWidget value={widget} threadId="thread-1" />
|
|
84
|
+
</AgentKitProvider>,
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
expect(html).toContain(`data-status="${status}"`);
|
|
88
|
+
expect(html).toContain(
|
|
89
|
+
`data-running="${String(status === "running")}"`,
|
|
90
|
+
);
|
|
91
|
+
} finally {
|
|
92
|
+
unregister();
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
);
|
|
96
|
+
|
|
35
97
|
it("resolves the renderer with stored action args and structured result", async () => {
|
|
36
98
|
const toolCall: AgentToolCall = {
|
|
37
99
|
id: "tool-1",
|
|
@@ -79,7 +79,10 @@ import {
|
|
|
79
79
|
IntegrationToolBadge,
|
|
80
80
|
resolveToolIntegration,
|
|
81
81
|
} from "./tool-integration.js";
|
|
82
|
-
import {
|
|
82
|
+
import {
|
|
83
|
+
resolveToolRenderer,
|
|
84
|
+
type ToolRendererContext,
|
|
85
|
+
} from "./tool-render-registry.js";
|
|
83
86
|
import {
|
|
84
87
|
isBuiltinDataWidgetActionRenderer,
|
|
85
88
|
isBuiltinWorkspaceFileResult,
|
|
@@ -636,6 +639,7 @@ export function ToolCallDisplay({
|
|
|
636
639
|
argsText,
|
|
637
640
|
args,
|
|
638
641
|
result,
|
|
642
|
+
status,
|
|
639
643
|
mcpApp,
|
|
640
644
|
chatUI,
|
|
641
645
|
isRunning,
|
|
@@ -656,6 +660,7 @@ export function ToolCallDisplay({
|
|
|
656
660
|
argsText?: string;
|
|
657
661
|
args: Record<string, unknown>;
|
|
658
662
|
result?: string;
|
|
663
|
+
status?: ToolRendererContext["status"];
|
|
659
664
|
mcpApp?: AgentMcpAppPayload;
|
|
660
665
|
chatUI?: ActionChatUIConfig;
|
|
661
666
|
isRunning: boolean;
|
|
@@ -750,6 +755,7 @@ export function ToolCallDisplay({
|
|
|
750
755
|
argsText={argsText}
|
|
751
756
|
args={args}
|
|
752
757
|
result={result}
|
|
758
|
+
status={status}
|
|
753
759
|
mcpApp={mcpApp}
|
|
754
760
|
chatUI={chatUI}
|
|
755
761
|
isRunning={effectiveIsRunning}
|
|
@@ -775,6 +781,7 @@ function ToolCallDisplayGeneric({
|
|
|
775
781
|
argsText,
|
|
776
782
|
args,
|
|
777
783
|
result,
|
|
784
|
+
status,
|
|
778
785
|
mcpApp,
|
|
779
786
|
chatUI,
|
|
780
787
|
isRunning,
|
|
@@ -794,6 +801,7 @@ function ToolCallDisplayGeneric({
|
|
|
794
801
|
argsText?: string;
|
|
795
802
|
args: Record<string, unknown>;
|
|
796
803
|
result?: string;
|
|
804
|
+
status?: ToolRendererContext["status"];
|
|
797
805
|
mcpApp?: AgentMcpAppPayload;
|
|
798
806
|
chatUI?: ActionChatUIConfig;
|
|
799
807
|
isRunning: boolean;
|
|
@@ -923,6 +931,7 @@ function ToolCallDisplayGeneric({
|
|
|
923
931
|
args,
|
|
924
932
|
resultText: result,
|
|
925
933
|
resultJson: parsedResult,
|
|
934
|
+
status,
|
|
926
935
|
isRunning,
|
|
927
936
|
isActiveTail,
|
|
928
937
|
dataChartLayout,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AgentToolCall } from "@agent-native/agentkit/protocol";
|
|
1
2
|
import type { ActionChatUIConfig } from "@agent-native/core/action-ui";
|
|
2
3
|
import type { ComponentType } from "react";
|
|
3
4
|
|
|
@@ -14,6 +15,7 @@ export interface ToolRendererContext {
|
|
|
14
15
|
toolName?: string;
|
|
15
16
|
}>;
|
|
16
17
|
widgetId?: string;
|
|
18
|
+
status?: AgentToolCall["status"];
|
|
17
19
|
isRunning: boolean;
|
|
18
20
|
isActiveTail?: boolean;
|
|
19
21
|
chatUI?: ActionChatUIConfig;
|