@agent-native/toolkit 0.14.2 → 0.15.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.
Files changed (79) hide show
  1. package/dist/composer/ComposerPlusMenu.d.ts.map +1 -1
  2. package/dist/composer/ComposerPlusMenu.js +131 -35
  3. package/dist/composer/ComposerPlusMenu.js.map +1 -1
  4. package/dist/composer/MentionPopover.d.ts.map +1 -1
  5. package/dist/composer/MentionPopover.js +40 -5
  6. package/dist/composer/MentionPopover.js.map +1 -1
  7. package/dist/composer/PastedTextChip.d.ts.map +1 -1
  8. package/dist/composer/PastedTextChip.js +26 -2
  9. package/dist/composer/PastedTextChip.js.map +1 -1
  10. package/dist/composer/PastedTextChip.spec.d.ts +2 -0
  11. package/dist/composer/PastedTextChip.spec.d.ts.map +1 -0
  12. package/dist/composer/PastedTextChip.spec.js +42 -0
  13. package/dist/composer/PastedTextChip.spec.js.map +1 -0
  14. package/dist/composer/PromptComposer.d.ts.map +1 -1
  15. package/dist/composer/PromptComposer.js +26 -5
  16. package/dist/composer/PromptComposer.js.map +1 -1
  17. package/dist/composer/TiptapComposer.d.ts +5 -3
  18. package/dist/composer/TiptapComposer.d.ts.map +1 -1
  19. package/dist/composer/TiptapComposer.js +291 -80
  20. package/dist/composer/TiptapComposer.js.map +1 -1
  21. package/dist/composer/TiptapComposer.spec.js +60 -3
  22. package/dist/composer/TiptapComposer.spec.js.map +1 -1
  23. package/dist/composer/VoiceButton.d.ts.map +1 -1
  24. package/dist/composer/VoiceButton.js +24 -5
  25. package/dist/composer/VoiceButton.js.map +1 -1
  26. package/dist/composer/runtime-adapters.d.ts +1 -0
  27. package/dist/composer/runtime-adapters.d.ts.map +1 -1
  28. package/dist/composer/runtime-adapters.js +8 -1
  29. package/dist/composer/runtime-adapters.js.map +1 -1
  30. package/dist/composer/runtime-adapters.spec.js +15 -0
  31. package/dist/composer/runtime-adapters.spec.js.map +1 -1
  32. package/dist/composer/useRealtimeVoiceMode.d.ts.map +1 -1
  33. package/dist/composer/useRealtimeVoiceMode.js +204 -68
  34. package/dist/composer/useRealtimeVoiceMode.js.map +1 -1
  35. package/dist/composer/useRealtimeVoiceMode.spec.js +27 -1
  36. package/dist/composer/useRealtimeVoiceMode.spec.js.map +1 -1
  37. package/dist/context-ui/ContextMeter.d.ts +3 -2
  38. package/dist/context-ui/ContextMeter.d.ts.map +1 -1
  39. package/dist/context-ui/ContextMeter.js +23 -3
  40. package/dist/context-ui/ContextMeter.js.map +1 -1
  41. package/dist/context-ui/ContextMeter.spec.d.ts +2 -0
  42. package/dist/context-ui/ContextMeter.spec.d.ts.map +1 -0
  43. package/dist/context-ui/ContextMeter.spec.js +52 -0
  44. package/dist/context-ui/ContextMeter.spec.js.map +1 -0
  45. package/dist/context-ui/ContextSegmentRow.d.ts +5 -3
  46. package/dist/context-ui/ContextSegmentRow.d.ts.map +1 -1
  47. package/dist/context-ui/ContextSegmentRow.js +74 -7
  48. package/dist/context-ui/ContextSegmentRow.js.map +1 -1
  49. package/dist/context-ui/ContextTreemap.d.ts +3 -2
  50. package/dist/context-ui/ContextTreemap.d.ts.map +1 -1
  51. package/dist/context-ui/ContextTreemap.js +5 -2
  52. package/dist/context-ui/ContextTreemap.js.map +1 -1
  53. package/dist/context-ui/ContextXRayPanel.d.ts +3 -2
  54. package/dist/context-ui/ContextXRayPanel.d.ts.map +1 -1
  55. package/dist/context-ui/ContextXRayPanel.js +112 -23
  56. package/dist/context-ui/ContextXRayPanel.js.map +1 -1
  57. package/dist/context-ui/types.d.ts +2 -0
  58. package/dist/context-ui/types.d.ts.map +1 -1
  59. package/dist/context-ui/types.js +7 -1
  60. package/dist/context-ui/types.js.map +1 -1
  61. package/package.json +2 -2
  62. package/src/composer/ComposerPlusMenu.tsx +170 -52
  63. package/src/composer/MentionPopover.tsx +43 -7
  64. package/src/composer/PastedTextChip.spec.tsx +58 -0
  65. package/src/composer/PastedTextChip.tsx +35 -7
  66. package/src/composer/PromptComposer.tsx +28 -7
  67. package/src/composer/TiptapComposer.spec.ts +90 -3
  68. package/src/composer/TiptapComposer.tsx +341 -82
  69. package/src/composer/VoiceButton.tsx +36 -11
  70. package/src/composer/runtime-adapters.spec.tsx +19 -0
  71. package/src/composer/runtime-adapters.tsx +12 -2
  72. package/src/composer/useRealtimeVoiceMode.spec.ts +34 -0
  73. package/src/composer/useRealtimeVoiceMode.tsx +219 -69
  74. package/src/context-ui/ContextMeter.spec.tsx +73 -0
  75. package/src/context-ui/ContextMeter.tsx +34 -4
  76. package/src/context-ui/ContextSegmentRow.tsx +111 -22
  77. package/src/context-ui/ContextTreemap.tsx +7 -1
  78. package/src/context-ui/ContextXRayPanel.tsx +138 -24
  79. package/src/context-ui/types.ts +14 -0
@@ -17,14 +17,49 @@ import type {
17
17
  ContextSegmentStatus,
18
18
  ContextSegmentViewData,
19
19
  ContextSystemSectionViewData,
20
+ ContextTranslate,
20
21
  } from "./types.js";
22
+ import { fallbackContextTranslate } from "./types.js";
21
23
 
22
24
  interface Group {
23
25
  name: string;
26
+ label: string;
24
27
  tokens: number;
25
28
  segments: ContextSegmentViewData[];
26
29
  }
27
30
 
31
+ function groupLabel(name: string, translate: ContextTranslate): string {
32
+ if (name === "Pinned")
33
+ return translate("agentChat.contextXray.groups.pinned", {
34
+ defaultValue: name,
35
+ });
36
+ if (name === "Tool results")
37
+ return translate("agentChat.contextXray.groups.toolResults", {
38
+ defaultValue: name,
39
+ });
40
+ if (name === "Files read")
41
+ return translate("agentChat.contextXray.groups.filesRead", {
42
+ defaultValue: name,
43
+ });
44
+ if (name === "Conversation")
45
+ return translate("agentChat.contextXray.groups.conversation", {
46
+ defaultValue: name,
47
+ });
48
+ if (name === "Thinking")
49
+ return translate("agentChat.contextXray.groups.thinking", {
50
+ defaultValue: name,
51
+ });
52
+ if (name === "Evicted")
53
+ return translate("agentChat.contextXray.groups.evicted", {
54
+ defaultValue: name,
55
+ });
56
+ if (name === "Task & instructions")
57
+ return translate("agentChat.contextXray.groups.taskInstructions", {
58
+ defaultValue: name,
59
+ });
60
+ return name;
61
+ }
62
+
28
63
  function applyOptimisticStatus(
29
64
  segments: ContextSegmentViewData[],
30
65
  optimistic: Map<string, ContextSegmentStatus>,
@@ -37,7 +72,10 @@ function applyOptimisticStatus(
37
72
  );
38
73
  }
39
74
 
40
- function groupedSegments(segments: ContextSegmentViewData[]): Group[] {
75
+ function groupedSegments(
76
+ segments: ContextSegmentViewData[],
77
+ translate: ContextTranslate,
78
+ ): Group[] {
41
79
  const map = new Map<string, Group>();
42
80
  for (const segment of segments) {
43
81
  const name =
@@ -46,7 +84,12 @@ function groupedSegments(segments: ContextSegmentViewData[]): Group[] {
46
84
  : segment.status === "evicted"
47
85
  ? "Evicted"
48
86
  : segment.group;
49
- const group = map.get(name) ?? { name, tokens: 0, segments: [] };
87
+ const group = map.get(name) ?? {
88
+ name,
89
+ label: groupLabel(name, translate),
90
+ tokens: 0,
91
+ segments: [],
92
+ };
50
93
  group.tokens += segment.tokenCount;
51
94
  group.segments.push(segment);
52
95
  map.set(name, group);
@@ -68,21 +111,35 @@ function groupedSegments(segments: ContextSegmentViewData[]): Group[] {
68
111
  });
69
112
  }
70
113
 
71
- function sourceLabel(section: ContextSystemSectionViewData) {
114
+ function sourceLabel(
115
+ section: ContextSystemSectionViewData,
116
+ translate: ContextTranslate,
117
+ ) {
118
+ const scope = section.sourceRef?.scope;
119
+ const localizedScope =
120
+ scope === "framework"
121
+ ? translate("agentChat.contextXray.framework", {
122
+ defaultValue: "framework",
123
+ })
124
+ : scope;
72
125
  return (
73
126
  section.sourceRef?.path ??
74
127
  section.sourceRef?.resourceId ??
75
- section.sourceRef?.scope ??
76
- "framework"
128
+ localizedScope ??
129
+ translate("agentChat.contextXray.framework", {
130
+ defaultValue: "framework",
131
+ })
77
132
  );
78
133
  }
79
134
 
80
135
  function SystemSectionRow({
81
136
  section,
82
137
  totalTokens,
138
+ translate,
83
139
  }: {
84
140
  section: ContextSystemSectionViewData;
85
141
  totalTokens: number;
142
+ translate: ContextTranslate;
86
143
  }) {
87
144
  const share =
88
145
  totalTokens > 0 ? Math.round((section.tokenCount / totalTokens) * 100) : 0;
@@ -96,9 +153,17 @@ function SystemSectionRow({
96
153
  {section.label}
97
154
  </div>
98
155
  <div className="truncate text-[11px] text-muted-foreground">
99
- {sourceLabel(section)} · {formatContextTokens(section.tokenCount)}{" "}
100
- tokens · {share}%
101
- {section.tokenMethod === "estimate" ? " · estimated" : ""}
156
+ {sourceLabel(section, translate)} ·{" "}
157
+ {formatContextTokens(section.tokenCount)}{" "}
158
+ {translate("agentChat.contextXray.tokensShare", {
159
+ defaultValue: "tokens · {{share}}%",
160
+ share,
161
+ })}
162
+ {section.tokenMethod === "estimate"
163
+ ? translate("agentChat.contextXray.estimatedSuffix", {
164
+ defaultValue: " · estimated",
165
+ })
166
+ : ""}
102
167
  </div>
103
168
  {section.preview ? (
104
169
  <div className="mt-0.5 line-clamp-2 text-[11px] text-muted-foreground/80">
@@ -120,6 +185,7 @@ export function ContextXRayPanelView({
120
185
  governanceLabels = {},
121
186
  systemOrderedLabel = "System · ordered, not evictable",
122
187
  titleLabel = "Context X-Ray",
188
+ translate = fallbackContextTranslate,
123
189
  }: {
124
190
  manifest: ContextManifestViewData;
125
191
  contextWindow: number;
@@ -130,6 +196,7 @@ export function ContextXRayPanelView({
130
196
  governanceLabels?: Partial<Record<"required" | "inherited" | "user", string>>;
131
197
  systemOrderedLabel?: string;
132
198
  titleLabel?: string;
199
+ translate?: ContextTranslate;
133
200
  }) {
134
201
  const [mode, setMode] = useState<"list" | "map">("list");
135
202
  const [collapsed, setCollapsed] = useState<Set<string>>(new Set());
@@ -137,7 +204,10 @@ export function ContextXRayPanelView({
137
204
  () => applyOptimisticStatus(manifest.segments, optimistic),
138
205
  [manifest.segments, optimistic],
139
206
  );
140
- const groups = useMemo(() => groupedSegments(segments), [segments]);
207
+ const groups = useMemo(
208
+ () => groupedSegments(segments, translate),
209
+ [segments, translate],
210
+ );
141
211
  const sections = manifest.systemSections ?? [];
142
212
  const systemGroups = useMemo(
143
213
  () =>
@@ -173,13 +243,42 @@ export function ContextXRayPanelView({
173
243
  (segment) => segment.status === "evicted",
174
244
  ).length;
175
245
  const details = [
176
- `${formatContextTokens(headroom)} free`,
177
- system > 0 ? `${formatContextTokens(system)} system` : null,
178
- `${formatContextTokens(conversation)} conversation`,
179
- pinned > 0 ? `${pinned} pinned` : null,
180
- evicted > 0 ? `${evicted} evicted` : null,
181
- manifest.tokenCountMethod === "estimate" ? "estimated" : null,
182
- !manifest.enforceable ? "advisory" : null,
246
+ translate("agentChat.contextXray.free", {
247
+ defaultValue: "{{count}} free",
248
+ count: formatContextTokens(headroom),
249
+ }),
250
+ system > 0
251
+ ? translate("agentChat.contextXray.system", {
252
+ defaultValue: "{{count}} system",
253
+ count: formatContextTokens(system),
254
+ })
255
+ : null,
256
+ translate("agentChat.contextXray.conversation", {
257
+ defaultValue: "{{count}} conversation",
258
+ count: formatContextTokens(conversation),
259
+ }),
260
+ pinned > 0
261
+ ? translate("agentChat.contextXray.pinned", {
262
+ defaultValue: "{{count}} pinned",
263
+ count: pinned,
264
+ })
265
+ : null,
266
+ evicted > 0
267
+ ? translate("agentChat.contextXray.evicted", {
268
+ defaultValue: "{{count}} evicted",
269
+ count: evicted,
270
+ })
271
+ : null,
272
+ manifest.tokenCountMethod === "estimate"
273
+ ? translate("agentChat.contextXray.estimated", {
274
+ defaultValue: "estimated",
275
+ })
276
+ : null,
277
+ !manifest.enforceable
278
+ ? translate("agentChat.contextXray.advisory", {
279
+ defaultValue: "advisory",
280
+ })
281
+ : null,
183
282
  ].filter((item): item is string => Boolean(item));
184
283
  const toggle = (key: string) =>
185
284
  setCollapsed((current) => {
@@ -201,7 +300,7 @@ export function ContextXRayPanelView({
201
300
  </div>
202
301
  <div className="mt-2 h-1 overflow-hidden rounded-full bg-muted/70">
203
302
  <div
204
- className="h-full w-full origin-left rounded-full bg-foreground transition-transform duration-200"
303
+ className="h-full w-full origin-left rounded-full bg-foreground transition-transform duration-200 rtl:origin-right"
205
304
  style={{ transform: `scaleX(${Math.min(1, pct / 100)})` }}
206
305
  />
207
306
  </div>
@@ -224,7 +323,9 @@ export function ContextXRayPanelView({
224
323
  <button
225
324
  type="button"
226
325
  onClick={() => setMode("list")}
227
- aria-label="Show context list"
326
+ aria-label={translate("agentChat.contextXray.showList", {
327
+ defaultValue: "Show context list",
328
+ })}
228
329
  className={cn(
229
330
  "flex size-7 cursor-pointer items-center justify-center rounded text-muted-foreground",
230
331
  mode === "list"
@@ -235,14 +336,20 @@ export function ContextXRayPanelView({
235
336
  <IconListDetails className="h-3.5 w-3.5" />
236
337
  </button>
237
338
  </TooltipTrigger>
238
- <TooltipContent>List</TooltipContent>
339
+ <TooltipContent>
340
+ {translate("agentChat.contextXray.list", {
341
+ defaultValue: "List",
342
+ })}
343
+ </TooltipContent>
239
344
  </Tooltip>
240
345
  <Tooltip>
241
346
  <TooltipTrigger asChild>
242
347
  <button
243
348
  type="button"
244
349
  onClick={() => setMode("map")}
245
- aria-label="Show context map"
350
+ aria-label={translate("agentChat.contextXray.showMap", {
351
+ defaultValue: "Show context map",
352
+ })}
246
353
  className={cn(
247
354
  "flex size-7 cursor-pointer items-center justify-center rounded text-muted-foreground",
248
355
  mode === "map"
@@ -253,7 +360,11 @@ export function ContextXRayPanelView({
253
360
  <IconChartTreemap className="h-3.5 w-3.5" />
254
361
  </button>
255
362
  </TooltipTrigger>
256
- <TooltipContent>Map</TooltipContent>
363
+ <TooltipContent>
364
+ {translate("agentChat.contextXray.map", {
365
+ defaultValue: "Map",
366
+ })}
367
+ </TooltipContent>
257
368
  </Tooltip>
258
369
  </div>
259
370
  </div>
@@ -261,6 +372,7 @@ export function ContextXRayPanelView({
261
372
  <ContextTreemapView
262
373
  segments={segments}
263
374
  systemSections={sections}
375
+ translate={translate}
264
376
  onSelect={(id) => {
265
377
  if (segments.some((segment) => segment.segmentId === id))
266
378
  setCollapsed(new Set());
@@ -281,7 +393,7 @@ export function ContextXRayPanelView({
281
393
  <button
282
394
  type="button"
283
395
  onClick={() => toggle(key)}
284
- className="flex w-full cursor-pointer items-center gap-2 rounded-sm px-1.5 py-2 text-left hover:bg-accent/35"
396
+ className="flex w-full cursor-pointer items-center gap-2 rounded-sm px-1.5 py-2 text-start hover:bg-accent/35"
285
397
  >
286
398
  {isCollapsed ? (
287
399
  <IconChevronRight className="h-3.5 w-3.5 text-muted-foreground" />
@@ -313,6 +425,7 @@ export function ContextXRayPanelView({
313
425
  key={section.segmentId}
314
426
  section={section}
315
427
  totalTokens={manifest.totalTokens}
428
+ translate={translate}
316
429
  />
317
430
  ))}
318
431
  </div>
@@ -329,7 +442,7 @@ export function ContextXRayPanelView({
329
442
  <button
330
443
  type="button"
331
444
  onClick={() => toggle(group.name)}
332
- className="flex w-full cursor-pointer items-center gap-2 rounded-sm px-1.5 py-2 text-left hover:bg-accent/35"
445
+ className="flex w-full cursor-pointer items-center gap-2 rounded-sm px-1.5 py-2 text-start hover:bg-accent/35"
333
446
  >
334
447
  {isCollapsed ? (
335
448
  <IconChevronRight className="h-3.5 w-3.5 text-muted-foreground" />
@@ -343,7 +456,7 @@ export function ContextXRayPanelView({
343
456
  )}
344
457
  />
345
458
  <span className="min-w-0 flex-1 truncate text-xs font-medium">
346
- {group.name}
459
+ {group.label}
347
460
  </span>
348
461
  <span className="text-[11px] text-muted-foreground">
349
462
  {formatContextTokens(group.tokens)}
@@ -362,6 +475,7 @@ export function ContextXRayPanelView({
362
475
  onPin={() => onPin(segment.segmentId)}
363
476
  onEvict={() => onEvict(segment.segmentId)}
364
477
  onRestore={() => onRestore(segment.segmentId)}
478
+ translate={translate}
365
479
  />
366
480
  ))}
367
481
  </div>
@@ -41,3 +41,17 @@ export interface ContextManifestViewData {
41
41
  systemTokens: number;
42
42
  conversationTokens: number;
43
43
  }
44
+
45
+ export type ContextTranslate = (
46
+ key: string,
47
+ options?: Record<string, unknown>,
48
+ ) => string;
49
+
50
+ export const fallbackContextTranslate: ContextTranslate = (key, options) => {
51
+ const template =
52
+ typeof options?.defaultValue === "string" ? options.defaultValue : key;
53
+ return template.replace(/{{\s*([\w$.-]+)\s*}}/g, (match, name: string) => {
54
+ const value = options?.[name];
55
+ return value == null ? match : String(value);
56
+ });
57
+ };