@agent-native/toolkit 0.201.1 → 0.201.2-nightly-20261006010750

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.
Files changed (68) hide show
  1. package/dist/app/agentkit/react/components.d.ts.map +1 -1
  2. package/dist/app/agentkit/react/components.js +292 -23
  3. package/dist/app/agentkit/react/components.js.map +1 -1
  4. package/dist/app/agentkit/react/context.d.ts +5 -0
  5. package/dist/app/agentkit/react/context.d.ts.map +1 -1
  6. package/dist/app/agentkit/react/context.js +5 -0
  7. package/dist/app/agentkit/react/context.js.map +1 -1
  8. package/dist/app/agentkit/react/styles.css +74 -2
  9. package/dist/app/chat/AgentKitAssistantChat.d.ts.map +1 -1
  10. package/dist/app/chat/AgentKitAssistantChat.js +5 -0
  11. package/dist/app/chat/AgentKitAssistantChat.js.map +1 -1
  12. package/dist/app/i18n/catalogs/ar-SA.d.ts.map +1 -1
  13. package/dist/app/i18n/catalogs/ar-SA.js +3 -0
  14. package/dist/app/i18n/catalogs/ar-SA.js.map +1 -1
  15. package/dist/app/i18n/catalogs/de-DE.d.ts.map +1 -1
  16. package/dist/app/i18n/catalogs/de-DE.js +3 -0
  17. package/dist/app/i18n/catalogs/de-DE.js.map +1 -1
  18. package/dist/app/i18n/catalogs/en-US.d.ts +3 -0
  19. package/dist/app/i18n/catalogs/en-US.d.ts.map +1 -1
  20. package/dist/app/i18n/catalogs/en-US.js +3 -0
  21. package/dist/app/i18n/catalogs/en-US.js.map +1 -1
  22. package/dist/app/i18n/catalogs/es-ES.d.ts.map +1 -1
  23. package/dist/app/i18n/catalogs/es-ES.js +3 -0
  24. package/dist/app/i18n/catalogs/es-ES.js.map +1 -1
  25. package/dist/app/i18n/catalogs/fr-FR.d.ts.map +1 -1
  26. package/dist/app/i18n/catalogs/fr-FR.js +3 -0
  27. package/dist/app/i18n/catalogs/fr-FR.js.map +1 -1
  28. package/dist/app/i18n/catalogs/hi-IN.d.ts.map +1 -1
  29. package/dist/app/i18n/catalogs/hi-IN.js +3 -0
  30. package/dist/app/i18n/catalogs/hi-IN.js.map +1 -1
  31. package/dist/app/i18n/catalogs/ja-JP.d.ts.map +1 -1
  32. package/dist/app/i18n/catalogs/ja-JP.js +3 -0
  33. package/dist/app/i18n/catalogs/ja-JP.js.map +1 -1
  34. package/dist/app/i18n/catalogs/ko-KR.d.ts.map +1 -1
  35. package/dist/app/i18n/catalogs/ko-KR.js +3 -0
  36. package/dist/app/i18n/catalogs/ko-KR.js.map +1 -1
  37. package/dist/app/i18n/catalogs/pt-BR.d.ts.map +1 -1
  38. package/dist/app/i18n/catalogs/pt-BR.js +3 -0
  39. package/dist/app/i18n/catalogs/pt-BR.js.map +1 -1
  40. package/dist/app/i18n/catalogs/zh-CN.d.ts.map +1 -1
  41. package/dist/app/i18n/catalogs/zh-CN.js +3 -0
  42. package/dist/app/i18n/catalogs/zh-CN.js.map +1 -1
  43. package/dist/app/i18n/catalogs/zh-TW.d.ts.map +1 -1
  44. package/dist/app/i18n/catalogs/zh-TW.js +3 -0
  45. package/dist/app/i18n/catalogs/zh-TW.js.map +1 -1
  46. package/dist/composer/AgentSuggestionBar.d.ts +1 -1
  47. package/dist/composer/AgentSuggestionBar.d.ts.map +1 -1
  48. package/dist/composer/AgentSuggestionBar.js +75 -6
  49. package/dist/composer/AgentSuggestionBar.js.map +1 -1
  50. package/package.json +4 -4
  51. package/src/app/agentkit/react/components.tsx +492 -60
  52. package/src/app/agentkit/react/context.tsx +10 -0
  53. package/src/app/agentkit/react/lifecycle.spec.tsx +487 -1
  54. package/src/app/agentkit/react/styles.css +74 -2
  55. package/src/app/chat/AgentKitAssistantChat.tsx +5 -0
  56. package/src/app/i18n/catalogs/ar-SA.ts +3 -0
  57. package/src/app/i18n/catalogs/de-DE.ts +3 -0
  58. package/src/app/i18n/catalogs/en-US.ts +3 -0
  59. package/src/app/i18n/catalogs/es-ES.ts +3 -0
  60. package/src/app/i18n/catalogs/fr-FR.ts +3 -0
  61. package/src/app/i18n/catalogs/hi-IN.ts +3 -0
  62. package/src/app/i18n/catalogs/ja-JP.ts +3 -0
  63. package/src/app/i18n/catalogs/ko-KR.ts +3 -0
  64. package/src/app/i18n/catalogs/pt-BR.ts +3 -0
  65. package/src/app/i18n/catalogs/zh-CN.ts +3 -0
  66. package/src/app/i18n/catalogs/zh-TW.ts +3 -0
  67. package/src/composer/AgentSuggestionBar.overflow.spec.tsx +277 -0
  68. package/src/composer/AgentSuggestionBar.tsx +113 -8
@@ -213,6 +213,11 @@ export interface AgentKitLabels {
213
213
  durationSecondShort: string;
214
214
  agents: string;
215
215
  tasks: string;
216
+ toolInput?: string;
217
+ toolResult?: string;
218
+ activityValueIdentifierHidden?: string;
219
+ activityValueOmitted?: string;
220
+ activityValueCircular?: string;
216
221
  composerLabel: string;
217
222
  composerPlaceholder: string;
218
223
  queue: string;
@@ -309,6 +314,11 @@ export const defaultAgentKitLabels: AgentKitLabels = {
309
314
  durationSecondShort: "s",
310
315
  agents: "Agent collaboration",
311
316
  tasks: "Agent tasks",
317
+ toolInput: "Input",
318
+ toolResult: "Result",
319
+ activityValueIdentifierHidden: "[Identifier hidden]",
320
+ activityValueOmitted: "[Content omitted]",
321
+ activityValueCircular: "[Circular reference]",
312
322
  composerLabel: "Message agent",
313
323
  composerPlaceholder: "Ask the agent to explore, build, or explain…",
314
324
  queue: "Queued messages",
@@ -9,7 +9,10 @@ import {
9
9
  } from "@agent-native/agentkit/client";
10
10
  import { createAgentKitHttpHandler } from "@agent-native/agentkit/http";
11
11
  import type {
12
+ AgentActivity,
12
13
  AgentEvent,
14
+ AgentObjectReference,
15
+ AgentTask,
13
16
  AgentToolCall,
14
17
  AgentTransport,
15
18
  } from "@agent-native/agentkit/protocol";
@@ -32,6 +35,7 @@ import {
32
35
  AgentConnectionRequestCard,
33
36
  AgentKitChat,
34
37
  AgentMessageActions,
38
+ AgentTaskGroup,
35
39
  formatAgentKitDuration,
36
40
  } from "./components.js";
37
41
  import {
@@ -2249,7 +2253,7 @@ describe("AgentChat lifecycle", () => {
2249
2253
  ).find(
2250
2254
  (row) =>
2251
2255
  row.querySelector(".agentkit-activity-label")?.textContent ===
2252
- "update-slide",
2256
+ "Update Slide",
2253
2257
  );
2254
2258
  expect(failedToolRow?.textContent).not.toContain(
2255
2259
  "slide_content_edit_failed",
@@ -2699,6 +2703,155 @@ describe("AgentChat lifecycle", () => {
2699
2703
  await tree.unmount();
2700
2704
  });
2701
2705
 
2706
+ it("preserves distinct agent sources and hides UUID-only labels", async () => {
2707
+ const threadId = "thread-agent-sources";
2708
+ const runId = "run-agent-sources";
2709
+ const internalId = "550e8400-e29b-41d4-a716-446655440000";
2710
+ const source: AgentObjectReference = {
2711
+ id: "source-agent",
2712
+ kind: "agent",
2713
+ label: "Source Agent",
2714
+ };
2715
+ const activities: AgentActivity[] = [
2716
+ ...["activity-1", "activity-2"].map((id) => ({
2717
+ id,
2718
+ kind: "read",
2719
+ label: "Read files",
2720
+ status: "completed" as const,
2721
+ agentId: "actor-agent",
2722
+ runId,
2723
+ source,
2724
+ })),
2725
+ {
2726
+ id: "activity-uuid-label",
2727
+ kind: internalId,
2728
+ label: internalId,
2729
+ status: "completed",
2730
+ runId,
2731
+ object: { id: internalId, kind: internalId, label: internalId },
2732
+ },
2733
+ ];
2734
+ const interaction = {
2735
+ id: "interaction-source",
2736
+ kind: internalId,
2737
+ agentId: "actor-agent",
2738
+ targetAgentId: "target-agent",
2739
+ source,
2740
+ } as const;
2741
+ const task: AgentTask = {
2742
+ id: "task-source",
2743
+ title: "Review report",
2744
+ status: "completed",
2745
+ assignedAgentId: "actor-agent",
2746
+ runId,
2747
+ source,
2748
+ };
2749
+ const events: AgentEvent[] = [
2750
+ ...activities.map(
2751
+ (activity, index): AgentEvent => ({
2752
+ id: `event-${activity.id}`,
2753
+ threadId,
2754
+ runId,
2755
+ sequence: index + 1,
2756
+ occurredAt: `2026-10-01T00:00:0${index + 1}.000Z`,
2757
+ type: "activity.completed",
2758
+ activity,
2759
+ }),
2760
+ ),
2761
+ {
2762
+ id: "event-interaction-source",
2763
+ threadId,
2764
+ runId,
2765
+ sequence: 4,
2766
+ occurredAt: "2026-10-01T00:00:04.000Z",
2767
+ type: "agent.interaction",
2768
+ interaction,
2769
+ },
2770
+ {
2771
+ id: "event-task-source",
2772
+ threadId,
2773
+ runId,
2774
+ sequence: 5,
2775
+ occurredAt: "2026-10-01T00:00:05.000Z",
2776
+ type: "task.created",
2777
+ task,
2778
+ },
2779
+ ];
2780
+ const thread = {
2781
+ ...createAgentThreadState(threadId),
2782
+ events,
2783
+ activities: Object.fromEntries(
2784
+ activities.map((activity) => [activity.id, activity]),
2785
+ ),
2786
+ tasks: { [task.id]: task },
2787
+ runs: {
2788
+ [runId]: {
2789
+ id: runId,
2790
+ status: "completed" as const,
2791
+ lastSequence: 5,
2792
+ startedAt: "2026-10-01T00:00:00.000Z",
2793
+ completedAt: "2026-10-01T00:00:06.000Z",
2794
+ },
2795
+ },
2796
+ };
2797
+ const { controller } = observableController({
2798
+ connection: "connected",
2799
+ capabilities: {},
2800
+ capabilitiesStatus: "ready",
2801
+ threads: { [threadId]: thread },
2802
+ revision: 0,
2803
+ });
2804
+ const tree = mount();
2805
+
2806
+ await tree.render(
2807
+ <AgentKitProvider controller={controller} threadId={threadId}>
2808
+ <AgentActivityGroup runId={runId} />
2809
+ <AgentCollaborationFeed runId={runId} />
2810
+ <AgentTaskGroup runId={runId} />
2811
+ </AgentKitProvider>,
2812
+ );
2813
+
2814
+ const cluster = tree.container.querySelector(".agentkit-activity-cluster");
2815
+ expect(
2816
+ cluster?.querySelector("summary .agentkit-agent-name")?.textContent,
2817
+ ).toBe("Assistant");
2818
+ expect(
2819
+ cluster?.querySelector("summary .agentkit-object-label")?.textContent,
2820
+ ).toBe("Source Agent");
2821
+ expect(
2822
+ cluster?.querySelector(
2823
+ ".agentkit-activity-cluster-items .agentkit-object-label",
2824
+ )?.textContent,
2825
+ ).toBe("Source Agent");
2826
+
2827
+ const interactionRow = tree.container.querySelector(
2828
+ ".agentkit-agent-interaction",
2829
+ );
2830
+ expect(
2831
+ interactionRow?.querySelector(".agentkit-agent-interaction-label")
2832
+ ?.textContent,
2833
+ ).toBe("Working");
2834
+ expect(
2835
+ interactionRow?.querySelector(".agentkit-object-label")?.textContent,
2836
+ ).toBe("Source Agent");
2837
+
2838
+ expect(
2839
+ tree.container.querySelector(".agentkit-task-row .agentkit-object-label")
2840
+ ?.textContent,
2841
+ ).toBe("Source Agent");
2842
+ const uuidActivity = Array.from(
2843
+ tree.container.querySelectorAll<HTMLElement>(".agentkit-activity-item"),
2844
+ ).find((item) => item.dataset.activityKind === internalId);
2845
+ expect(
2846
+ uuidActivity?.querySelector(".agentkit-activity-label")?.textContent,
2847
+ ).toBe("Working");
2848
+ expect(
2849
+ uuidActivity?.querySelector(".agentkit-object-label")?.textContent,
2850
+ ).toBe("Assistant");
2851
+ expect(tree.container.textContent).not.toContain(internalId);
2852
+ await tree.unmount();
2853
+ });
2854
+
2702
2855
  it("keeps generic tool results in collapsed history but preserves rich surfaces", async () => {
2703
2856
  const threadId = "thread-collapsed-tool-results";
2704
2857
  const runId = "run-collapsed-tool-results";
@@ -2855,6 +3008,339 @@ describe("AgentChat lifecycle", () => {
2855
3008
  ).toBe("The file could not be saved.");
2856
3009
  });
2857
3010
 
3011
+ it("sanitizes and bounds expanded tool details for keyboard access", async () => {
3012
+ const threadId = "thread-bounded-tool-details";
3013
+ const runId = "run-bounded-tool-details";
3014
+ const internalId = "550e8400-e29b-41d4-a716-446655440000";
3015
+ const sparseOutput = new Array(100_000);
3016
+ sparseOutput[99_999] = "beyond preview";
3017
+ const tool: AgentToolCall = {
3018
+ id: "tool-read-file",
3019
+ name: "read-file",
3020
+ status: "completed",
3021
+ input: {
3022
+ documentId: internalId,
3023
+ resource: `document_${internalId}_revision`,
3024
+ empty: "",
3025
+ whitespace: " ",
3026
+ },
3027
+ output: {
3028
+ documentId: internalId,
3029
+ resource: `document_${internalId}_revision`,
3030
+ entries: sparseOutput,
3031
+ },
3032
+ };
3033
+ const thread = reduceAgentEvent(createAgentThreadState(threadId), {
3034
+ id: "event-read-file",
3035
+ threadId,
3036
+ runId,
3037
+ sequence: 1,
3038
+ occurredAt: "2026-10-01T00:00:00.000Z",
3039
+ type: "tool.updated",
3040
+ toolCall: tool,
3041
+ });
3042
+ const { controller } = observableController({
3043
+ connection: "connected",
3044
+ capabilities: {},
3045
+ capabilitiesStatus: "ready",
3046
+ threads: { [threadId]: thread },
3047
+ revision: 0,
3048
+ });
3049
+ const tree = mount();
3050
+ await tree.render(
3051
+ <AgentKitProvider controller={controller} threadId={threadId}>
3052
+ <AgentActivityGroup runId={runId} />
3053
+ </AgentKitProvider>,
3054
+ );
3055
+
3056
+ const work = tree.container.querySelector<HTMLDetailsElement>(
3057
+ ".agentkit-activities",
3058
+ );
3059
+ await act(async () => work?.querySelector("summary")?.click());
3060
+ const row = Array.from(
3061
+ work?.querySelectorAll<HTMLElement>(".agentkit-activity-item") ?? [],
3062
+ ).find(
3063
+ (item) =>
3064
+ item.querySelector(".agentkit-activity-label")?.textContent ===
3065
+ "Read File",
3066
+ );
3067
+ expect(row?.textContent).not.toContain(internalId);
3068
+ await act(async () => row?.querySelector("button")?.click());
3069
+
3070
+ const details = Array.from(
3071
+ row?.querySelectorAll<HTMLPreElement>(
3072
+ ".agentkit-activity-summary-value",
3073
+ ) ?? [],
3074
+ );
3075
+ expect(details.map((detail) => detail.getAttribute("aria-label"))).toEqual([
3076
+ "Input",
3077
+ "Result",
3078
+ ]);
3079
+ expect(
3080
+ details.every((detail) => detail.getAttribute("role") === "region"),
3081
+ ).toBe(true);
3082
+ expect(details.every((detail) => detail.tabIndex === 0)).toBe(true);
3083
+ expect(details[0]?.textContent).toContain("[Identifier hidden]");
3084
+ expect(details[1]?.textContent).toContain("[Identifier hidden]");
3085
+ expect(details[0]?.textContent).toContain(
3086
+ '"resource": "document__revision"',
3087
+ );
3088
+ expect(details[0]?.textContent).toContain('"empty": ""');
3089
+ expect(details[0]?.textContent).toContain('"whitespace": " "');
3090
+ expect(details[1]?.textContent).toContain("[Content omitted]");
3091
+ expect(details[1]?.textContent).not.toContain(internalId);
3092
+ expect(details[1]?.textContent).not.toContain("beyond preview");
3093
+ await tree.unmount();
3094
+ });
3095
+
3096
+ it("keeps the omission marker visible when formatted tool output expands", async () => {
3097
+ const threadId = "thread-expanded-tool-output";
3098
+ const runId = "run-expanded-tool-output";
3099
+ const output = Object.fromEntries(
3100
+ Array.from({ length: 79 }, (_, index) => [
3101
+ `field-${index}-${"x".repeat(20)}`,
3102
+ "",
3103
+ ]),
3104
+ );
3105
+ const tool: AgentToolCall = {
3106
+ id: "tool-large-output",
3107
+ name: "read-records",
3108
+ input: { query: "all records" },
3109
+ output,
3110
+ status: "completed",
3111
+ };
3112
+ const thread = {
3113
+ ...createAgentThreadState(threadId),
3114
+ tools: { [tool.id]: tool },
3115
+ events: [
3116
+ {
3117
+ id: "event-large-output",
3118
+ threadId,
3119
+ runId,
3120
+ sequence: 1,
3121
+ occurredAt: "2026-10-01T00:00:01.000Z",
3122
+ type: "tool.started" as const,
3123
+ toolCall: { ...tool, status: "running" as const },
3124
+ },
3125
+ ],
3126
+ runs: {
3127
+ [runId]: {
3128
+ id: runId,
3129
+ status: "completed" as const,
3130
+ lastSequence: 1,
3131
+ startedAt: "2026-10-01T00:00:00.000Z",
3132
+ completedAt: "2026-10-01T00:00:02.000Z",
3133
+ },
3134
+ },
3135
+ };
3136
+ const { controller } = observableController({
3137
+ connection: "connected",
3138
+ capabilities: {},
3139
+ capabilitiesStatus: "ready",
3140
+ threads: { [threadId]: thread },
3141
+ revision: 0,
3142
+ });
3143
+ const tree = mount();
3144
+ await tree.render(
3145
+ <AgentKitProvider controller={controller} threadId={threadId}>
3146
+ <AgentActivityGroup runId={runId} />
3147
+ </AgentKitProvider>,
3148
+ );
3149
+
3150
+ const work = tree.container.querySelector<HTMLDetailsElement>(
3151
+ ".agentkit-activities",
3152
+ );
3153
+ await act(async () => work?.querySelector("summary")?.click());
3154
+ const row = tree.container.querySelector<HTMLElement>(
3155
+ ".agentkit-activity-item",
3156
+ );
3157
+ await act(async () => row?.querySelector("button")?.click());
3158
+ const result = row?.querySelector<HTMLPreElement>('[aria-label="Result"]');
3159
+ expect(result?.textContent?.length).toBeLessThanOrEqual(2_000);
3160
+ expect(result?.textContent).toContain("[Content omitted]");
3161
+ expect(result?.textContent).toMatch(/…\n\[Content omitted\]$/);
3162
+ await tree.unmount();
3163
+ });
3164
+
3165
+ it("keeps distinct agent sources visible and sanitizes fallback labels", async () => {
3166
+ const threadId = "thread-agent-source-labels";
3167
+ const runId = "run-agent-source-labels";
3168
+ const internalId = "550e8400-e29b-41d4-a716-446655440000";
3169
+ const source = {
3170
+ id: "external-agent",
3171
+ kind: "agent",
3172
+ label: "Different source agent",
3173
+ };
3174
+ const repeatedActivity = (id: string): AgentActivity => ({
3175
+ id,
3176
+ kind: "read",
3177
+ label: "Reading a file",
3178
+ status: "completed",
3179
+ agentId: "displayed-agent",
3180
+ source,
3181
+ });
3182
+ const sourceEvents: AgentEvent[] = ["source-a", "source-b"].map(
3183
+ (id, index) => ({
3184
+ id: `event-${id}`,
3185
+ threadId,
3186
+ runId,
3187
+ sequence: index + 1,
3188
+ occurredAt: `2026-10-01T00:00:0${index + 1}.000Z`,
3189
+ type: "activity.completed",
3190
+ activity: repeatedActivity(id),
3191
+ }),
3192
+ );
3193
+ const privateLabelActivity: AgentActivity = {
3194
+ id: "activity-private-label",
3195
+ kind: internalId,
3196
+ label: internalId,
3197
+ status: "running",
3198
+ agentId: "displayed-agent",
3199
+ object: { id: "private-object", kind: internalId, label: internalId },
3200
+ };
3201
+ const events: AgentEvent[] = [
3202
+ ...sourceEvents,
3203
+ {
3204
+ id: "event-private-label",
3205
+ threadId,
3206
+ runId,
3207
+ sequence: 3,
3208
+ occurredAt: "2026-10-01T00:00:03.000Z",
3209
+ type: "activity.started",
3210
+ activity: privateLabelActivity,
3211
+ },
3212
+ ];
3213
+ const thread = {
3214
+ ...createAgentThreadState(threadId),
3215
+ events,
3216
+ activities: {
3217
+ [privateLabelActivity.id]: privateLabelActivity,
3218
+ },
3219
+ runs: {
3220
+ [runId]: {
3221
+ id: runId,
3222
+ status: "running" as const,
3223
+ lastSequence: 3,
3224
+ startedAt: "2026-10-01T00:00:00.000Z",
3225
+ },
3226
+ },
3227
+ activeRunIds: [runId],
3228
+ };
3229
+ const { controller } = observableController({
3230
+ connection: "connected",
3231
+ capabilities: {},
3232
+ capabilitiesStatus: "ready",
3233
+ threads: { [threadId]: thread },
3234
+ revision: 0,
3235
+ });
3236
+ const tree = mount();
3237
+ await tree.render(
3238
+ <AgentKitProvider controller={controller} threadId={threadId}>
3239
+ <AgentActivityGroup runId={runId} />
3240
+ </AgentKitProvider>,
3241
+ );
3242
+
3243
+ const work = tree.container.querySelector<HTMLDetailsElement>(
3244
+ ".agentkit-activities",
3245
+ );
3246
+ expect(
3247
+ work?.querySelectorAll(
3248
+ ".agentkit-activity-cluster summary .agentkit-object-label",
3249
+ ),
3250
+ ).toHaveLength(1);
3251
+ expect(
3252
+ work?.querySelector(
3253
+ ".agentkit-activity-cluster summary .agentkit-object-label",
3254
+ )?.textContent,
3255
+ ).toBe("Different source agent");
3256
+ const privateRow = Array.from(
3257
+ work?.querySelectorAll<HTMLElement>(".agentkit-activity-item") ?? [],
3258
+ ).find((row) => row.dataset.activityKind === internalId);
3259
+ expect(
3260
+ privateRow?.querySelector(".agentkit-activity-label")?.textContent,
3261
+ ).toBe("Working");
3262
+ expect(
3263
+ privateRow?.querySelector(".agentkit-object-label")?.textContent,
3264
+ ).toBe("Assistant");
3265
+ expect(work?.textContent).not.toContain(internalId);
3266
+ await tree.unmount();
3267
+ });
3268
+
3269
+ it("keeps the omission marker after pretty-print expansion exceeds its budget", async () => {
3270
+ const threadId = "thread-formatted-tool-budget";
3271
+ const runId = "run-formatted-tool-budget";
3272
+ const formattedOutput = Object.fromEntries(
3273
+ Array.from({ length: 38 }, (_, index) => [
3274
+ `property_${String(index).padStart(2, "0")}_long_name_for_serialization`,
3275
+ "0123456789",
3276
+ ]),
3277
+ );
3278
+ const tool: AgentToolCall = {
3279
+ id: "tool-formatted-output",
3280
+ name: "read-file",
3281
+ input: { path: "guide.md" },
3282
+ output: formattedOutput,
3283
+ status: "completed",
3284
+ };
3285
+ const thread = {
3286
+ ...createAgentThreadState(threadId),
3287
+ tools: { [tool.id]: tool },
3288
+ events: [
3289
+ {
3290
+ id: "event-formatted-output",
3291
+ threadId,
3292
+ runId,
3293
+ sequence: 1,
3294
+ occurredAt: "2026-10-01T00:00:00.000Z",
3295
+ type: "tool.updated" as const,
3296
+ toolCall: tool,
3297
+ },
3298
+ ],
3299
+ runs: {
3300
+ [runId]: {
3301
+ id: runId,
3302
+ status: "completed" as const,
3303
+ lastSequence: 1,
3304
+ startedAt: "2026-10-01T00:00:00.000Z",
3305
+ completedAt: "2026-10-01T00:00:01.000Z",
3306
+ },
3307
+ },
3308
+ };
3309
+ const { controller } = observableController({
3310
+ connection: "connected",
3311
+ capabilities: {},
3312
+ capabilitiesStatus: "ready",
3313
+ threads: { [threadId]: thread },
3314
+ revision: 0,
3315
+ });
3316
+ const tree = mount();
3317
+ await tree.render(
3318
+ <AgentKitProvider controller={controller} threadId={threadId}>
3319
+ <AgentActivityGroup runId={runId} />
3320
+ </AgentKitProvider>,
3321
+ );
3322
+
3323
+ const work = tree.container.querySelector<HTMLDetailsElement>(
3324
+ ".agentkit-activities",
3325
+ );
3326
+ await act(async () => work?.querySelector("summary")?.click());
3327
+ const row = Array.from(
3328
+ tree.container.querySelectorAll<HTMLElement>(".agentkit-activity-item"),
3329
+ ).find(
3330
+ (item) =>
3331
+ item.querySelector(".agentkit-activity-label")?.textContent ===
3332
+ "Read File",
3333
+ );
3334
+ await act(async () => row?.querySelector("button")?.click());
3335
+ const result = row?.querySelectorAll<HTMLPreElement>(
3336
+ ".agentkit-activity-summary-value",
3337
+ )[1]?.textContent;
3338
+ expect(result).toBeDefined();
3339
+ expect(result!.length).toBeLessThanOrEqual(2_000);
3340
+ expect(result).toMatch(/\[Content omitted\]$/);
3341
+ await tree.unmount();
3342
+ });
3343
+
2858
3344
  it("resets disclosure state when switching threads with reused run ids", async () => {
2859
3345
  const threads = Object.fromEntries(
2860
3346
  ["thread-a", "thread-b"].map((threadId) => [
@@ -373,11 +373,10 @@
373
373
  }
374
374
 
375
375
  .agentkit-suggestions [data-agent-suggestion-scroller="true"] {
376
- display: flex;
377
376
  inline-size: 100%;
378
- gap: 0.375rem;
379
377
  overflow-x: auto;
380
378
  overscroll-behavior-inline: contain;
379
+ scroll-padding-inline: 1.5rem;
381
380
  scrollbar-width: none;
382
381
  }
383
382
 
@@ -386,6 +385,46 @@
386
385
  display: none;
387
386
  }
388
387
 
388
+ .agentkit-suggestions [data-agent-suggestion-track="true"] {
389
+ display: flex;
390
+ flex-wrap: wrap;
391
+ inline-size: var(--agent-suggestion-track-width);
392
+ min-inline-size: 100%;
393
+ gap: 0.375rem;
394
+ }
395
+
396
+ [data-agent-suggestion-scroller="true"]:is(
397
+ [data-overflow-start],
398
+ [data-overflow-end]
399
+ ) {
400
+ -webkit-mask-image: linear-gradient(
401
+ var(--agent-suggestion-fade-direction, to right),
402
+ transparent 0,
403
+ black var(--agent-suggestion-fade-start, 0px),
404
+ black calc(100% - var(--agent-suggestion-fade-end, 0px)),
405
+ transparent 100%
406
+ );
407
+ mask-image: linear-gradient(
408
+ var(--agent-suggestion-fade-direction, to right),
409
+ transparent 0,
410
+ black var(--agent-suggestion-fade-start, 0px),
411
+ black calc(100% - var(--agent-suggestion-fade-end, 0px)),
412
+ transparent 100%
413
+ );
414
+ }
415
+
416
+ [data-agent-suggestion-scroller="true"]:dir(rtl) {
417
+ --agent-suggestion-fade-direction: to left;
418
+ }
419
+
420
+ [data-agent-suggestion-scroller="true"][data-overflow-start] {
421
+ --agent-suggestion-fade-start: 1.5rem;
422
+ }
423
+
424
+ [data-agent-suggestion-scroller="true"][data-overflow-end] {
425
+ --agent-suggestion-fade-end: 1.5rem;
426
+ }
427
+
389
428
  .agentkit-suggestions button {
390
429
  flex: none;
391
430
  padding: 0.375rem 0.625rem;
@@ -1478,6 +1517,39 @@ button.agentkit-object {
1478
1517
  color: var(--agentkit-text);
1479
1518
  }
1480
1519
 
1520
+ .agentkit-activity-summary-section {
1521
+ display: grid;
1522
+ gap: 0.25rem;
1523
+ margin-block-start: 0.5rem;
1524
+ }
1525
+
1526
+ .agentkit-activity-summary-label {
1527
+ color: var(--agentkit-text-muted);
1528
+ font-size: 0.6875rem;
1529
+ font-weight: 500;
1530
+ }
1531
+
1532
+ .agentkit-activity-summary-value {
1533
+ max-block-size: 12rem;
1534
+ overflow: auto;
1535
+ border: 1px solid var(--agentkit-border);
1536
+ border-radius: var(--radius-md, var(--radius));
1537
+ padding: 0.5rem 0.625rem;
1538
+ background: var(--agentkit-subtle);
1539
+ color: var(--agentkit-text);
1540
+ font: inherit;
1541
+ font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
1542
+ font-size: 0.75rem;
1543
+ line-height: 1.5;
1544
+ white-space: pre-wrap;
1545
+ overflow-wrap: anywhere;
1546
+ }
1547
+
1548
+ .agentkit-activity-summary-value:focus-visible {
1549
+ outline: 2px solid var(--agentkit-focus);
1550
+ outline-offset: 2px;
1551
+ }
1552
+
1481
1553
  .agentkit-approval,
1482
1554
  .agentkit-connection-request,
1483
1555
  .agentkit-widget {
@@ -728,6 +728,11 @@ export const AgentKitAssistantChat = forwardRef<
728
728
  },
729
729
  agents: t("agentChat.activity.agents"),
730
730
  tasks: t("agentChat.activity.tasks"),
731
+ toolInput: t("agentChat.tool.input"),
732
+ toolResult: t("agentChat.tool.result"),
733
+ activityValueIdentifierHidden: t("agentChat.tool.identifierHidden"),
734
+ activityValueOmitted: t("agentChat.tool.contentOmitted"),
735
+ activityValueCircular: t("agentChat.tool.circularReference"),
731
736
  working: t("agentChat.status.working"),
732
737
  workingFor: t("agentChat.status.workingFor", {
733
738
  duration: "{{duration}}",
@@ -1300,6 +1300,9 @@ const messages: ToolkitAgentChatTranslation = {
1300
1300
  "tool.failedWithoutDetails": "لا تتوفر تفاصيل للخطأ.",
1301
1301
  "tool.input": "الإدخال",
1302
1302
  "tool.inputWithLabel": "الإدخال - {{label}}",
1303
+ "tool.identifierHidden": "[تم إخفاء المعرّف]",
1304
+ "tool.contentOmitted": "[تم حذف المحتوى]",
1305
+ "tool.circularReference": "[مرجع دائري]",
1303
1306
  "tool.interrupted":
1304
1307
  "توقفت العملية قبل اكتمال التقرير — ربما اكتملت أو لم تكتمل. تحقّق قبل إعادة المحاولة.",
1305
1308
  "tool.longRunning":
@@ -920,6 +920,9 @@ const messages: ToolkitAgentChatTranslation = {
920
920
  "tool.failedWithoutDetails": "Keine Fehlerdetails verfügbar.",
921
921
  "tool.input": "Eingabe",
922
922
  "tool.inputWithLabel": "Eingabe – {{label}}",
923
+ "tool.identifierHidden": "[Kennung ausgeblendet]",
924
+ "tool.contentOmitted": "[Inhalt ausgelassen]",
925
+ "tool.circularReference": "[Zirkuläre Referenz]",
923
926
  "tool.interrupted":
924
927
  "Die Ausgabe wurde vorzeitig unterbrochen. Der Vorgang kann abgeschlossen worden sein oder nicht. Prüfe dies vor einem erneuten Versuch.",
925
928
  "tool.longRunning":
@@ -1291,6 +1291,9 @@ const messages = {
1291
1291
  "tool.failedWithoutDetails": "No error details are available.",
1292
1292
  "tool.input": "Input",
1293
1293
  "tool.inputWithLabel": "Input - {{label}}",
1294
+ "tool.identifierHidden": "[Identifier hidden]",
1295
+ "tool.contentOmitted": "[Content omitted]",
1296
+ "tool.circularReference": "[Circular reference]",
1294
1297
  "tool.interrupted":
1295
1298
  "Interrupted before this finished reporting — it may or may not have completed. Check before retrying.",
1296
1299
  "tool.longRunning": "Still working. Large updates can take a minute or two.",
@@ -915,6 +915,9 @@ const messages: ToolkitAgentChatTranslation = {
915
915
  "tool.failedWithoutDetails": "No hay detalles de error disponibles.",
916
916
  "tool.input": "Entrada",
917
917
  "tool.inputWithLabel": "Entrada - {{label}}",
918
+ "tool.identifierHidden": "[Identificador oculto]",
919
+ "tool.contentOmitted": "[Contenido omitido]",
920
+ "tool.circularReference": "[Referencia circular]",
918
921
  "tool.interrupted":
919
922
  "Se interrumpió antes de informar de la finalización; puede que haya terminado o no. Compruébalo antes de reintentarlo.",
920
923
  "tool.longRunning":