agentic-ui-kit 0.3.0 → 0.5.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.
@@ -25,6 +25,8 @@ export interface MenuItemProps extends Omit<AriaMenuItemProps, "className" | "ch
25
25
  icon?: ReactNode;
26
26
  /** Second line under the label ("For complex work and everyday tasks"). */
27
27
  description?: ReactNode;
28
+ /** "below" (default) puts the description under the label; "beside" puts it after it on one line. */
29
+ descriptionPlacement?: "below" | "beside";
28
30
  /** Right-aligned detail: the current value of a submenu ("Medium") or a badge. */
29
31
  detail?: ReactNode;
30
32
  /** Keyboard shortcut shown on the right ("⌘U", "P"). */
@@ -33,7 +35,7 @@ export interface MenuItemProps extends Omit<AriaMenuItemProps, "className" | "ch
33
35
  tone?: "default" | "danger";
34
36
  className?: string;
35
37
  }
36
- export declare function MenuItem({ children, icon, description, detail, shortcut, tone, className, ...props }: MenuItemProps): import("react").JSX.Element;
38
+ export declare function MenuItem({ children, icon, description, descriptionPlacement, detail, shortcut, tone, className, ...props }: MenuItemProps): import("react").JSX.Element;
37
39
  export interface MenuSectionProps {
38
40
  children: ReactNode;
39
41
  title?: ReactNode;
@@ -0,0 +1,22 @@
1
+ import type { ReactNode } from "react";
2
+ export interface SegmentedOption<T extends string = string> {
3
+ id: T;
4
+ label: string;
5
+ icon?: ReactNode;
6
+ /** Show only the icon; the label becomes its accessible name and tooltip. */
7
+ iconOnly?: boolean;
8
+ }
9
+ export interface SegmentedControlProps<T extends string = string> {
10
+ /** Accessible name of the group, e.g. "Mode". */
11
+ label: string;
12
+ options: readonly SegmentedOption<T>[];
13
+ value: T;
14
+ onChange: (value: T) => void;
15
+ className?: string;
16
+ }
17
+ /**
18
+ * One of a few options, side by side on a track, like claude.ai's Chat / Cowork switch. Themed with
19
+ * `--chat-segment-track` (default: a shade darker than the surface it sits on) and `--chat-segment-selected`
20
+ * (default `--chat-raised`).
21
+ */
22
+ export declare function SegmentedControl<T extends string>({ label, options, value, onChange, className }: SegmentedControlProps<T>): import("react").JSX.Element;
@@ -2,7 +2,7 @@ import type { Message, Part } from "../../../core/src/index.js";
2
2
  import { type CSSProperties, type ReactNode } from "react";
3
3
  import type { PendingApproval } from "../hooks/use-chat";
4
4
  import { type ComposerProps } from "../components/composer";
5
- import type { Feedback } from "../components/messages";
5
+ import type { Feedback, MessageActions } from "../components/messages";
6
6
  import { type WidgetHost } from "../components/widget-frame";
7
7
  export type Density = "full" | "panel" | "inline";
8
8
  /**
@@ -22,6 +22,10 @@ export interface ChatViewProps {
22
22
  onRetry?: (assistantId: string) => void;
23
23
  onEdit?: (userId: string) => void;
24
24
  onFeedback?: (assistantId: string, feedback: Feedback) => void;
25
+ /** Read aloud button on assistant messages. */
26
+ onReadAloud?: (assistantId: string) => void;
27
+ /** Add your own buttons to each message's action row, or hide copy and the time. */
28
+ messageActions?: MessageActions;
25
29
  renderPart?: (part: Part) => ReactNode;
26
30
  /**
27
31
  * What widgets (sandboxed visuals) may do: the domains they may load, and their callbacks. A widget's
@@ -40,6 +44,11 @@ export interface ChatViewProps {
40
44
  emptyState?: (composer: ReactNode) => ReactNode;
41
45
  /** Small print under the composer. */
42
46
  disclaimer?: ReactNode;
47
+ /**
48
+ * Wraps the composer, on the empty screen and docked under the chat, to put things outside its box:
49
+ * buttons above or beside it, a row of chips under it. `where` says which of the two it is.
50
+ */
51
+ renderComposer?: (composer: ReactNode, where: "empty" | "docked") => ReactNode;
43
52
  /** "full": a page. "panel": a docked side panel. "inline": a small area inside a form. */
44
53
  density?: Density;
45
54
  /** Width of the message column, e.g. "48rem". Users can change it in settings. */
@@ -49,11 +58,14 @@ export interface ChatViewProps {
49
58
  className?: string;
50
59
  }
51
60
  /** A whole chat: header, the conversation, the docked composer. An empty chat shows `emptyState`. */
52
- export declare function ChatView({ messages, busy, onSend, onStop, approvals, onApprove, onRetry, onEdit, onFeedback, renderPart, widgets, header, composer, emptyState, disclaimer, density, contentWidth, contentPadding, className, }: ChatViewProps): import("react").JSX.Element;
61
+ export declare function ChatView({ messages, busy, onSend, onStop, approvals, onApprove, onRetry, onEdit, onFeedback, onReadAloud, messageActions, renderPart, widgets, header, composer, emptyState, disclaimer, renderComposer, density, contentWidth, contentPadding, className, }: ChatViewProps): import("react").JSX.Element;
53
62
  export interface EmptyStateProps {
54
63
  /** "Good evening, Alex". */
55
64
  greeting: ReactNode;
56
- /** Mark left of the greeting, e.g. a logo. */
65
+ /**
66
+ * Mark left of the greeting, e.g. a logo. Its currentColor is --chat-empty-icon (default the accent), for
67
+ * one-color marks; a multi-color logo sets its own fills.
68
+ */
57
69
  icon?: ReactNode;
58
70
  /** The centered composer. */
59
71
  children: ReactNode;
@@ -2,6 +2,8 @@ import type { ReactNode } from "react";
2
2
  export interface SidebarProps {
3
3
  /** Name or logo at the top left; hidden when collapsed. */
4
4
  brand?: ReactNode;
5
+ /** A logo mark left of `brand`, sized 1.25rem. It stays at the top of the collapsed rail. */
6
+ brandIcon?: ReactNode;
5
7
  /** Buttons at the top right next to the collapse toggle, e.g. a mode switch. */
6
8
  headerActions?: ReactNode;
7
9
  /** Fixed items under the header: New chat, Search, Projects… (`SidebarItem`s). */
@@ -13,7 +15,7 @@ export interface SidebarProps {
13
15
  className?: string;
14
16
  }
15
17
  /** The claude.ai sidebar frame. Collapses to an icon rail inside `AppShell`; a drawer on phones. */
16
- export declare function Sidebar({ brand, headerActions, nav, children, footer, className }: SidebarProps): import("react").JSX.Element;
18
+ export declare function Sidebar({ brand, brandIcon, headerActions, nav, children, footer, className }: SidebarProps): import("react").JSX.Element;
17
19
  export interface SidebarItemProps {
18
20
  icon: ReactNode;
19
21
  label: string;
@@ -422,6 +422,25 @@ function parseMessage(text) {
422
422
  if (data.length === 0) return void 0;
423
423
  return JSON.parse(data.join("\n"));
424
424
  }
425
+ // ../core/src/replaces.ts
426
+ /**
427
+ * Updating a visual in place: the drawing tools (show_widget, show_ui, render_ui) take an optional
428
+ * `replaces`, the id of an earlier call of theirs. The kit draws the new call where the old one was (same
429
+ * reply) or folds the old one into a link to the new one (earlier reply). The model sees its own call ids in
430
+ * the history, so keep tool call ids when you send the history back.
431
+ */
432
+ /** The `replaces` input property, shared by the drawing tools. */
433
+ const replacesProperty = {
434
+ type: "string",
435
+ description: "Id of an earlier call of this tool whose visual this one updates in place: after a fix, or when the user asks for a change. Leave it out for a new visual."
436
+ };
437
+ /** One line for a drawing tool's description or guide. */
438
+ const replacesGuide = "To change a visual you already drew (a fix, or the user asks for a change), call the tool again with `replaces` set to that call's id: it is redrawn in place. Never draw a second copy without it.";
439
+ /** The id a drawing tool call replaces, from its (streaming) input; undefined if none. */
440
+ function replacedId(input) {
441
+ const r = input?.replaces;
442
+ return typeof r === "string" && r ? r : void 0;
443
+ }
425
444
  // ../core/src/ui-tree.ts
426
445
  /**
427
446
  * Host-registered components: instead of HTML, the model writes a small tree of components the host
@@ -557,6 +576,7 @@ function renderUiTool(components) {
557
576
  Write a tree: { "root": { "component": "<name>", "props": { ... }, "children": [ ...nodes ] }, "state": { ... } }.
558
577
  "root" is a JSON object, never a string. Only these components exist; a node with an unknown component or
559
578
  props that don't fit is not shown. One visual per answer: don't also draw the same thing another way.
579
+ ${replacesGuide}
560
580
  ${list}
561
581
 
562
582
  Actions: a prop the schema marks as an action takes one of
@@ -577,7 +597,8 @@ Set apart what you added or changed from what was already there.`,
577
597
  state: {
578
598
  type: "object",
579
599
  description: "Starting values of the widget's state."
580
- }
600
+ },
601
+ replaces: replacesProperty
581
602
  },
582
603
  required: ["root"]
583
604
  }
@@ -658,7 +679,7 @@ function checkUiTree(input, components, options = {}) {
658
679
  return {
659
680
  ok,
660
681
  errors,
661
- feedback: ok ? "Shown to the user." : `${bad === 0 ? "Not shown as written" : `Only part of it is shown: ${bad} of ${total} nodes were left out`}. Fix these and call ${toolName} again:\n` + errors.slice(0, 20).map((e) => `- ${e}`).join("\n") + (errors.length > 20 ? `\n- ...and ${errors.length - 20} more` : "")
682
+ feedback: ok ? "Shown to the user." : `${bad === 0 ? "Not shown as written" : `Only part of it is shown: ${bad} of ${total} nodes were left out`}. Fix these and call ${toolName} again with "replaces" set to this call's id, without remarking on the fix to the user:\n` + errors.slice(0, 20).map((e) => `- ${e}`).join("\n") + (errors.length > 20 ? `\n- ...and ${errors.length - 20} more` : "")
662
683
  };
663
684
  }
664
685
  // ../core/src/ui-markup.ts
@@ -1039,13 +1060,16 @@ const showUiToolName = "show_ui";
1039
1060
  function showUiTool(components, name = showUiToolName) {
1040
1061
  return {
1041
1062
  name,
1042
- description: "Show interactive UI inline in your reply, built from the app's components: options to compare, a plan, a checklist, numbers at a glance. Write JSX in `markup`. Keep explaining in text around it; one call per answer unless the user asks for more.\n\n" + markupRules(components),
1063
+ description: "Show interactive UI inline in your reply, built from the app's components: options to compare, a plan, a checklist, numbers at a glance. Write JSX in `markup`. Keep explaining in text around it; one call per answer unless the user asks for more. " + replacesGuide + "\n\n" + markupRules(components),
1043
1064
  inputSchema: {
1044
1065
  type: "object",
1045
- properties: { markup: {
1046
- type: "string",
1047
- description: "JSX of the components above, e.g. <Card title=\"Plan\"><Metric label=\"Total\" value=\"€184\" /></Card>"
1048
- } },
1066
+ properties: {
1067
+ markup: {
1068
+ type: "string",
1069
+ description: "JSX of the components above, e.g. <Card title=\"Plan\"><Metric label=\"Total\" value=\"€184\" /></Card>"
1070
+ },
1071
+ replaces: replacesProperty
1072
+ },
1049
1073
  required: ["markup"]
1050
1074
  }
1051
1075
  };
@@ -1065,7 +1089,7 @@ function checkUiMarkupCode(markup, components, toolName = showUiToolName) {
1065
1089
  return {
1066
1090
  ok,
1067
1091
  errors,
1068
- feedback: ok ? "Shown to the user." : `Not all of it is shown. Fix these and call ${toolName} again:\n` + list(errors)
1092
+ feedback: ok ? "Shown to the user." : `Not all of it is shown. Fix these and call ${toolName} again with "replaces" set to this call's id, without remarking on the fix to the user:\n` + list(errors)
1069
1093
  };
1070
1094
  }
1071
1095
  /**
@@ -1079,4 +1103,4 @@ When a visual helps more than text (options to compare, a plan, a checklist, num
1079
1103
  ${markupRules(components)}
1080
1104
  - Keep explaining in text around the block. One block per answer, unless the user asks for more.`;
1081
1105
  }
1082
- export { salvageJson as A, awaitingToolCalls as C, resolveEffort as D, reduceEvents as E, settleToolCall as O, applyEvent as S, outputTokens as T, formatEvent as _, readUiValue as a, toBlocks as b, uiMarkupGuide as c, isStateRef as d, matchesSchema as f, uiActionSchema as g, schemaErrors as h, parseUiMarkup as i, parsePartialJson as k, uiMarkupLanguage as l, renderUiToolName as m, checkUiMarkupCode as n, showUiTool as o, renderUiTool as p, findUiBlocks as r, showUiToolName as s, checkUiMarkup as t, checkUiTree as u, readEventStream as v, estimateTokens as w, activityTokens as x, isActivityPart as y };
1106
+ export { resolveEffort as A, toBlocks as C, estimateTokens as D, awaitingToolCalls as E, parsePartialJson as M, salvageJson as N, outputTokens as O, isActivityPart as S, applyEvent as T, replacedId as _, readUiValue as a, formatEvent as b, uiMarkupGuide as c, isStateRef as d, matchesSchema as f, uiActionSchema as g, schemaErrors as h, parseUiMarkup as i, settleToolCall as j, reduceEvents as k, uiMarkupLanguage as l, renderUiToolName as m, checkUiMarkupCode as n, showUiTool as o, renderUiTool as p, findUiBlocks as r, showUiToolName as s, checkUiMarkup as t, checkUiTree as u, replacesGuide as v, activityTokens as w, readEventStream as x, replacesProperty as y };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentic-ui-kit",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "React UI kit for LLM chat and agentic apps: streaming messages, tool calls, approvals, themable with CSS variables.",
5
5
  "license": "MIT",
6
6
  "type": "module",