@agent-native/toolkit 0.13.7 → 0.13.8

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.
@@ -393,7 +393,13 @@
393
393
  border-radius: var(--radius);
394
394
  background: hsl(var(--popover));
395
395
  color: hsl(var(--popover-foreground));
396
- box-shadow: 0 10px 30px hsl(var(--background) / 0.28);
396
+ --agent-shadow: 0 0% 0%;
397
+ --agent-shadow-o: 0.14;
398
+ box-shadow: 0 10px 30px hsl(var(--agent-shadow) / var(--agent-shadow-o));
399
+ }
400
+
401
+ .dark .an-chat-history-row__menu-content {
402
+ --agent-shadow-o: 0.08;
397
403
  }
398
404
 
399
405
  .an-chat-history-row__menu-item {
@@ -47,6 +47,8 @@ export interface RecentEditHighlightsProps {
47
47
  containerRef: RefObject<HTMLElement | null>;
48
48
  /** Highlight lifetime; should match useRecentEdits ttlMs. Default 6000. */
49
49
  ttlMs?: number;
50
+ /** Render the compact outline treatment used by the Slides editor. */
51
+ outlineOnly?: boolean;
50
52
  /** Additional CSS class for the overlay div. */
51
53
  className?: string;
52
54
  }
@@ -57,6 +59,7 @@ interface Highlight {
57
59
  label: string;
58
60
  avatarUrl?: string;
59
61
  isAgent: boolean;
62
+ outlineOnly: boolean;
60
63
  opacity: number;
61
64
  rect: { top: number; left: number; width: number; height: number };
62
65
  }
@@ -64,7 +67,9 @@ interface Highlight {
64
67
  const HighlightItem = memo(function HighlightItem({ h }: { h: Highlight }) {
65
68
  return (
66
69
  <div
67
- aria-label={`${h.label} edited this`}
70
+ aria-label={
71
+ h.isAgent && h.outlineOnly ? h.label : `${h.label} edited this`
72
+ }
68
73
  style={{
69
74
  position: "absolute",
70
75
  top: h.rect.top,
@@ -78,8 +83,12 @@ const HighlightItem = memo(function HighlightItem({ h }: { h: Highlight }) {
78
83
  transition: "opacity 400ms ease-out",
79
84
  outline: `2px solid ${h.color}`,
80
85
  outlineOffset: 2,
81
- backgroundColor: `${h.color}1A`,
82
- boxShadow: `0 0 0 1px ${h.color}33, 0 0 12px ${h.color}40`,
86
+ ...(h.outlineOnly
87
+ ? {}
88
+ : {
89
+ backgroundColor: `${h.color}1A`,
90
+ boxShadow: `0 0 0 1px ${h.color}33, 0 0 12px ${h.color}40`,
91
+ }),
83
92
  }}
84
93
  >
85
94
  <div
@@ -90,8 +99,9 @@ const HighlightItem = memo(function HighlightItem({ h }: { h: Highlight }) {
90
99
  display: "flex",
91
100
  alignItems: "center",
92
101
  gap: 4,
93
- backgroundColor: h.color,
94
- color: "#fff",
102
+ backgroundColor: h.outlineOnly ? "transparent" : h.color,
103
+ border: h.outlineOnly ? `1px solid ${h.color}` : undefined,
104
+ color: h.outlineOnly ? h.color : "hsl(var(--background))",
95
105
  fontSize: 10,
96
106
  fontWeight: 600,
97
107
  padding: "2px 6px",
@@ -125,6 +135,7 @@ export function RecentEditHighlights({
125
135
  resolveRect,
126
136
  containerRef,
127
137
  ttlMs = RECENT_EDIT_TTL_MS,
138
+ outlineOnly = false,
128
139
  className,
129
140
  }: RecentEditHighlightsProps) {
130
141
  const [highlights, setHighlights] = useState<Highlight[]>([]);
@@ -170,14 +181,17 @@ export function RecentEditHighlights({
170
181
  key: `${edit.clientId}:${edit.at}`,
171
182
  color: edit.user.color || "#94a3b8",
172
183
  label: edit.isAgent
173
- ? edit.label
174
- ? `AI — ${edit.label}`
175
- : "AI edited"
184
+ ? outlineOnly
185
+ ? "AI editing"
186
+ : edit.label
187
+ ? `AI — ${edit.label}`
188
+ : "AI edited"
176
189
  : edit.label
177
190
  ? `${edit.user.name} — ${edit.label}`
178
191
  : edit.user.name,
179
192
  avatarUrl: (edit.user as { avatarUrl?: string }).avatarUrl,
180
193
  isAgent: edit.isAgent,
194
+ outlineOnly,
181
195
  opacity,
182
196
  rect: { top, left, width: domRect.width, height: domRect.height },
183
197
  });
@@ -99,6 +99,8 @@ export interface PromptComposerProps {
99
99
  preserveDraftOnSubmit?: boolean;
100
100
  /** Show the model selector (default: true). */
101
101
  showModelSelector?: boolean;
102
+ /** Show the legacy provider-level Auto model option (default: true). */
103
+ showAutoModelOption?: boolean;
102
104
  /** Show the voice dictation button. Defaults to DEFAULT_VOICE_DICTATION_ENABLED. */
103
105
  voiceEnabled?: boolean;
104
106
  /** Show file upload controls and pass submitted files to onSubmit (default: true). */
@@ -472,6 +474,7 @@ function PromptComposerInner({
472
474
  draftScope,
473
475
  preserveDraftOnSubmit = false,
474
476
  showModelSelector = true,
477
+ showAutoModelOption = true,
475
478
  voiceEnabled = DEFAULT_VOICE_DICTATION_ENABLED,
476
479
  attachmentsEnabled = true,
477
480
  plusMenuMode,
@@ -665,6 +668,7 @@ function PromptComposerInner({
665
668
  selectedModel={composerModel}
666
669
  selectedEffort={composerEffort}
667
670
  availableModels={composerModelGroups}
671
+ showAutoModelOption={showAutoModelOption}
668
672
  modelListLoading={composerModelListLoading}
669
673
  onModelChange={handleModelChange}
670
674
  onEffortChange={handleEffortChange}
@@ -62,6 +62,7 @@ describe("createTiptapComposerExtensions", () => {
62
62
  expect(compactComposerModelName("gpt-5-6-terra")).toBe("Terra");
63
63
  expect(compactComposerModelName("openai/gpt-5.6-luna")).toBe("Luna");
64
64
  expect(compactComposerModelName("claude-sonnet-5")).toBe("Sonnet 5");
65
+ expect(compactComposerModelName("codex-cli")).toBe("Codex");
65
66
  expect(compactComposerReasoningEffortLabel("medium")).toBe("Med");
66
67
  expect(compactComposerReasoningEffortLabel("minimal")).toBe("Min");
67
68
  expect(compactComposerReasoningEffortLabel("xhigh")).toBe("XHigh");
@@ -633,12 +633,16 @@ export interface TiptapComposerProps {
633
633
  selectedModel?: string;
634
634
  /** Selected reasoning effort override for this conversation */
635
635
  selectedEffort?: ReasoningEffort;
636
+ /** Show the legacy provider-level Auto model option (default: true). */
637
+ showAutoModelOption?: boolean;
636
638
  /** Available models grouped by provider */
637
639
  availableModels?: Array<{
638
640
  engine: string;
639
641
  label: string;
640
642
  models: string[];
641
643
  configured: boolean;
644
+ statusLabel?: string;
645
+ isSubscription?: boolean;
642
646
  }>;
643
647
  /** Whether the model list is still being resolved. */
644
648
  modelListLoading?: boolean;
@@ -844,7 +848,7 @@ function ModeSelector({
844
848
 
845
849
  const FRIENDLY_MODEL_NAMES: Record<string, string> = {
846
850
  auto: "Default model",
847
- "codex-cli": "ChatGPT subscription",
851
+ "codex-cli": "Codex",
848
852
  "claude-fable-5": "Fable 5",
849
853
  "kimi-k2-5": "Kimi K2.5",
850
854
  "deepseek-v3-1": "DeepSeek v3.1",
@@ -1046,6 +1050,7 @@ function ModelSelector({
1046
1050
  model,
1047
1051
  effort,
1048
1052
  engines,
1053
+ showAutoModelOption = true,
1049
1054
  modelListLoading = false,
1050
1055
  onChange,
1051
1056
  onEffortChange,
@@ -1061,7 +1066,10 @@ function ModelSelector({
1061
1066
  label: string;
1062
1067
  models: string[];
1063
1068
  configured: boolean;
1069
+ statusLabel?: string;
1070
+ isSubscription?: boolean;
1064
1071
  }>;
1072
+ showAutoModelOption?: boolean;
1065
1073
  modelListLoading?: boolean;
1066
1074
  onChange: (model: string, engine: string) => void;
1067
1075
  onEffortChange?: (effort: ReasoningEffort) => void;
@@ -1075,7 +1083,9 @@ function ModelSelector({
1075
1083
  const reasoning = adapters.models?.reasoning;
1076
1084
  const defaultEffort = reasoning?.defaultEffort ?? DEFAULT_REASONING_EFFORT;
1077
1085
  const [open, setOpen] = useState(false);
1078
- const autoModelGroup = engines.find((group) => group.models.includes("auto"));
1086
+ const autoModelGroup = showAutoModelOption
1087
+ ? engines.find((group) => group.models.includes("auto"))
1088
+ : undefined;
1079
1089
  const providerGroups = useMemo(
1080
1090
  () =>
1081
1091
  engines
@@ -1155,12 +1165,16 @@ function ModelSelector({
1155
1165
  const hasConfiguredBuilderModels = providerGroups.some(
1156
1166
  (group) => group.engine === "builder" && group.configured,
1157
1167
  );
1168
+ const hasConnectedSubscription = providerGroups.some(
1169
+ (group) => group.configured && group.isSubscription,
1170
+ );
1158
1171
  const showBuilderCta =
1159
1172
  (builderFlow.hasFetchedStatus ||
1160
1173
  (!providerConnectStatusEnabled && !!onConnectProvider)) &&
1161
1174
  !builderFlow.configured &&
1162
1175
  !builderFlow.envManaged &&
1163
- !hasConfiguredBuilderModels;
1176
+ !hasConfiguredBuilderModels &&
1177
+ !hasConnectedSubscription;
1164
1178
  const onlyConnectPathAvailable = shouldShowOnlyConnectPath(
1165
1179
  showBuilderCta,
1166
1180
  providerGroups,
@@ -1352,6 +1366,17 @@ function ModelSelector({
1352
1366
  const groupKey = `${group.engine}:${group.label}`;
1353
1367
  const isExpanded = expandedGroups.has(groupKey);
1354
1368
  const ChevronIcon = isExpanded ? IconChevronDown : IconChevronRight;
1369
+ const isLocalRuntime =
1370
+ group.engine === "codex-cli" || group.engine === "claude-cli";
1371
+ const canConnectLocalRuntime =
1372
+ isLocalRuntime && Boolean(onConnectLocalRuntime);
1373
+ const statusLabel =
1374
+ group.statusLabel ??
1375
+ (!group.configured
1376
+ ? canConnectLocalRuntime
1377
+ ? "sign in"
1378
+ : "needs API key"
1379
+ : undefined);
1355
1380
  return (
1356
1381
  <div key={groupKey}>
1357
1382
  <div className="flex items-center hover:bg-accent/30">
@@ -1371,21 +1396,24 @@ function ModelSelector({
1371
1396
  </span>
1372
1397
  )}
1373
1398
  </button>
1374
- {!group.configured && (
1399
+ {!group.configured && statusLabel && (
1375
1400
  <button
1376
1401
  type="button"
1377
- className="text-[10px] text-muted-foreground/60 hover:text-foreground cursor-pointer pe-3 py-1.5"
1402
+ className="ms-auto max-w-[9rem] shrink-0 text-end text-[10px] text-muted-foreground/60 hover:text-foreground cursor-pointer pe-3 py-1.5"
1378
1403
  onClick={() =>
1379
- group.engine === "codex-cli" && onConnectLocalRuntime
1404
+ canConnectLocalRuntime
1380
1405
  ? connectLocalRuntime(group.engine)
1381
1406
  : openLlmSettings()
1382
1407
  }
1383
1408
  >
1384
- {group.engine === "codex-cli" && onConnectLocalRuntime
1385
- ? "sign in"
1386
- : "needs API key"}
1409
+ {statusLabel}
1387
1410
  </button>
1388
1411
  )}
1412
+ {group.configured && statusLabel && (
1413
+ <span className="ms-auto max-w-[9rem] shrink-0 pe-3 text-end text-[10px] text-muted-foreground/70">
1414
+ {statusLabel}
1415
+ </span>
1416
+ )}
1389
1417
  </div>
1390
1418
  {isExpanded &&
1391
1419
  models.map((m) => (
@@ -1394,10 +1422,7 @@ function ModelSelector({
1394
1422
  type="button"
1395
1423
  onClick={() => {
1396
1424
  if (!group.configured) {
1397
- if (
1398
- group.engine === "codex-cli" &&
1399
- onConnectLocalRuntime
1400
- ) {
1425
+ if (canConnectLocalRuntime) {
1401
1426
  connectLocalRuntime(group.engine);
1402
1427
  } else {
1403
1428
  openLlmSettings();
@@ -1540,6 +1565,7 @@ export function TiptapComposer({
1540
1565
  voiceEnabled = DEFAULT_VOICE_DICTATION_ENABLED,
1541
1566
  selectedModel,
1542
1567
  selectedEffort,
1568
+ showAutoModelOption = true,
1543
1569
  availableModels,
1544
1570
  modelListLoading,
1545
1571
  onModelChange,
@@ -2985,6 +3011,7 @@ export function TiptapComposer({
2985
3011
  model={selectedModel}
2986
3012
  effort={selectedEffort}
2987
3013
  engines={availableModels}
3014
+ showAutoModelOption={showAutoModelOption}
2988
3015
  modelListLoading={modelListLoading}
2989
3016
  onChange={onModelChange}
2990
3017
  onEffortChange={onEffortChange}
@@ -26,6 +26,10 @@ export interface EngineModelGroup {
26
26
  label: string;
27
27
  models: string[];
28
28
  configured: boolean;
29
+ /** Provider-owned connection state shown at the far edge of the row. */
30
+ statusLabel?: string;
31
+ /** Marks a configured local subscription so setup CTAs can stay hidden. */
32
+ isSubscription?: boolean;
29
33
  }
30
34
 
31
35
  export interface ComposerModelState {