@mast-ai/react-ui 0.1.1 → 0.2.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.
@@ -1,6 +1,14 @@
1
1
  import type { ReactNode } from 'react';
2
2
  import type { PendingApproval } from '../approval.js';
3
3
  import type { ConversationEntry, ToolEventEntry } from '../types.js';
4
+ import { type GetToolLabel } from './ToolLabelContext.js';
5
+ /**
6
+ * Slot for replacing only the inline approval card while keeping the default
7
+ * `<ToolCallBlock>` rendering for non-approval tool events. Receives the
8
+ * matching {@link ToolEventEntry} and the live {@link PendingApproval} handle
9
+ * exposing `approve()`, `reject()`, and `respondWith()`.
10
+ */
11
+ export type RenderApproval = (entry: ToolEventEntry, approval: PendingApproval) => ReactNode;
4
12
  /**
5
13
  * Props accepted by {@link AssistantMessage}.
6
14
  */
@@ -28,8 +36,38 @@ export interface AssistantMessageProps {
28
36
  * When this prop is omitted, the library defaults to rendering
29
37
  * `<InlineApproval>` for tool events with a pending approval handle and
30
38
  * `<ToolCallBlock>` otherwise.
39
+ *
40
+ * Takes a back seat to {@link AssistantMessageProps.renderApproval} when
41
+ * both are provided and the entry has a pending approval handle.
31
42
  */
32
43
  renderToolCall?: (entry: ToolEventEntry, approval?: PendingApproval) => ReactNode;
44
+ /**
45
+ * Replaces only the inline approval card. Called once per tool event whose
46
+ * call is awaiting an inline approval decision (i.e. has a matching
47
+ * {@link PendingApproval} handle); non-approval tool events fall through to
48
+ * `renderToolCall` or the default `<ToolCallBlock>`.
49
+ *
50
+ * Use this slot to customise the approval prompt without rebuilding the
51
+ * tool-call rendering for every other event. Takes precedence over
52
+ * `renderToolCall` for entries with a pending approval handle when both
53
+ * are provided.
54
+ */
55
+ renderApproval?: RenderApproval;
56
+ /**
57
+ * Resolves the header label for each {@link ToolEventEntry} rendered inside
58
+ * this message. Forwarded via context to every nested `<ToolCallBlock>`,
59
+ * including those rendered for sub-agent tool calls.
60
+ *
61
+ * Use this for the common case of relabelling delegation-style tools (e.g.
62
+ * `delegate_to_skill` showing the target skill's name) without needing to
63
+ * write a custom `renderToolCall` purely to override `entry.name`.
64
+ *
65
+ * Resolution order inside `<ToolCallBlock>`: explicit `label` prop, then this
66
+ * resolver, then `entry.name`. Returning `undefined` or `null` from the
67
+ * resolver lets the block fall back to `entry.name` for that specific entry,
68
+ * which is useful for selectively overriding only a subset of tool names.
69
+ */
70
+ getToolLabel?: GetToolLabel;
33
71
  }
34
72
  /**
35
73
  * Renders an assistant turn: an optional {@link ThinkingBlock}, zero or more
@@ -41,4 +79,4 @@ export interface AssistantMessageProps {
41
79
  * `renderMessage` (the entire text region) or `renderToolCall` (each tool
42
80
  * invocation) without losing the surrounding wiring.
43
81
  */
44
- export declare function AssistantMessage({ entry, className, renderMessage, renderToolCall, }: AssistantMessageProps): import("react/jsx-runtime").JSX.Element;
82
+ export declare function AssistantMessage({ entry, className, renderMessage, renderToolCall, renderApproval, getToolLabel, }: AssistantMessageProps): import("react/jsx-runtime").JSX.Element;
@@ -2,6 +2,8 @@ import type { ReactNode } from 'react';
2
2
  import type { PendingApproval } from '../approval.js';
3
3
  import type { MentionsConfig } from '../mentions/types.js';
4
4
  import type { ToolEventEntry } from '../types.js';
5
+ import type { RenderApproval } from './AssistantMessage.js';
6
+ import type { GetToolLabel } from './ToolLabelContext.js';
5
7
  /**
6
8
  * Props accepted by {@link ConversationPanel}.
7
9
  */
@@ -20,8 +22,25 @@ export interface ConversationPanelProps {
20
22
  * awaiting an inline approval decision.
21
23
  */
22
24
  renderToolCall?: (entry: ToolEventEntry, approval?: PendingApproval) => ReactNode;
25
+ /**
26
+ * Replaces only the inline approval card. Use this slot to customise the
27
+ * approval prompt without rebuilding the rest of the tool-call rendering.
28
+ * Takes precedence over `renderToolCall` for entries with a pending
29
+ * approval handle when both are provided.
30
+ */
31
+ renderApproval?: RenderApproval;
23
32
  /** Replaces the default assistant text renderer for the entire list. */
24
33
  renderMessage?: (text: string) => ReactNode;
34
+ /**
35
+ * Overrides the `<ToolCallBlock>` header label for the entire list. The
36
+ * resolver flows via context so it also applies to nested sub-agent tool
37
+ * calls. Returning `undefined` or `null` for a given entry falls back to
38
+ * `entry.name`.
39
+ *
40
+ * Common use case: relabelling delegation-style tools (e.g.
41
+ * `delegate_to_skill` showing the target skill's name).
42
+ */
43
+ getToolLabel?: GetToolLabel;
25
44
  /** Placeholder text for the {@link ChatInput} field. */
26
45
  inputPlaceholder?: string;
27
46
  /**
@@ -40,4 +59,4 @@ export interface ConversationPanelProps {
40
59
  *
41
60
  * Must be rendered inside an `<AgentProvider>`.
42
61
  */
43
- export declare function ConversationPanel({ theme, className, renderToolCall, renderMessage, inputPlaceholder, mentions, }: ConversationPanelProps): import("react/jsx-runtime").JSX.Element;
62
+ export declare function ConversationPanel({ theme, className, renderToolCall, renderApproval, renderMessage, getToolLabel, inputPlaceholder, mentions, }: ConversationPanelProps): import("react/jsx-runtime").JSX.Element;
@@ -1,6 +1,8 @@
1
1
  import type { ReactNode } from 'react';
2
2
  import type { PendingApproval } from '../approval.js';
3
3
  import type { ConversationEntry, ToolEventEntry } from '../types.js';
4
+ import { type RenderApproval } from './AssistantMessage.js';
5
+ import type { GetToolLabel } from './ToolLabelContext.js';
4
6
  /**
5
7
  * Props accepted by {@link MessageItem}.
6
8
  */
@@ -14,11 +16,21 @@ export interface MessageItemProps {
14
16
  * `'user'`.
15
17
  */
16
18
  renderToolCall?: (entry: ToolEventEntry, approval?: PendingApproval) => ReactNode;
19
+ /**
20
+ * Forwarded to {@link AssistantMessage}. Has no effect when `entry.role` is
21
+ * `'user'`.
22
+ */
23
+ renderApproval?: RenderApproval;
17
24
  /**
18
25
  * Forwarded to {@link AssistantMessage}. Has no effect when `entry.role` is
19
26
  * `'user'`.
20
27
  */
21
28
  renderMessage?: (text: string) => ReactNode;
29
+ /**
30
+ * Forwarded to {@link AssistantMessage}. Has no effect when `entry.role` is
31
+ * `'user'`.
32
+ */
33
+ getToolLabel?: GetToolLabel;
22
34
  }
23
35
  /**
24
36
  * Renders a single {@link ConversationEntry} by dispatching to
@@ -26,4 +38,4 @@ export interface MessageItemProps {
26
38
  *
27
39
  * Used by {@link MessageList} to render each virtualised row.
28
40
  */
29
- export declare function MessageItem({ entry, className, renderToolCall, renderMessage }: MessageItemProps): import("react/jsx-runtime").JSX.Element;
41
+ export declare function MessageItem({ entry, className, renderToolCall, renderApproval, renderMessage, getToolLabel, }: MessageItemProps): import("react/jsx-runtime").JSX.Element;
@@ -1,6 +1,8 @@
1
1
  import type { ReactNode } from 'react';
2
2
  import type { PendingApproval } from '../approval.js';
3
3
  import type { ToolEventEntry } from '../types.js';
4
+ import type { RenderApproval } from './AssistantMessage.js';
5
+ import type { GetToolLabel } from './ToolLabelContext.js';
4
6
  /**
5
7
  * Props accepted by {@link MessageList}.
6
8
  */
@@ -14,11 +16,29 @@ export interface MessageListProps {
14
16
  * decision.
15
17
  */
16
18
  renderToolCall?: (entry: ToolEventEntry, approval?: PendingApproval) => ReactNode;
19
+ /**
20
+ * Forwarded to each {@link MessageItem} so consumers can replace only the
21
+ * inline approval card without overriding the rest of the tool-call
22
+ * rendering. Takes precedence over `renderToolCall` for entries with a
23
+ * pending approval handle when both are provided.
24
+ */
25
+ renderApproval?: RenderApproval;
17
26
  /**
18
27
  * Forwarded to each {@link MessageItem} so consumers can replace the default
19
28
  * assistant text renderer for the entire list.
20
29
  */
21
30
  renderMessage?: (text: string) => ReactNode;
31
+ /**
32
+ * Forwarded to each {@link MessageItem} so consumers can override the
33
+ * `<ToolCallBlock>` header label for the entire list. The resolver is read
34
+ * via context inside `<ToolCallBlock>`, so it also applies to nested
35
+ * sub-agent tool calls.
36
+ *
37
+ * Returning `undefined` or `null` for a given entry falls back to
38
+ * `entry.name`, which is useful for selectively overriding only a subset of
39
+ * tool names.
40
+ */
41
+ getToolLabel?: GetToolLabel;
22
42
  }
23
43
  /**
24
44
  * Scrollable list of {@link ConversationEntry} items rendered with
@@ -35,4 +55,4 @@ export interface MessageListProps {
35
55
  * Reads `messages` from `useAgent()`, so this component must be rendered
36
56
  * inside an `<AgentProvider>`.
37
57
  */
38
- export declare function MessageList({ className, renderToolCall, renderMessage }: MessageListProps): import("react/jsx-runtime").JSX.Element;
58
+ export declare function MessageList({ className, renderToolCall, renderApproval, renderMessage, getToolLabel, }: MessageListProps): import("react/jsx-runtime").JSX.Element;
@@ -1,3 +1,4 @@
1
+ import type { ReactNode } from 'react';
1
2
  import type { ToolEventEntry } from '../types.js';
2
3
  /**
3
4
  * Props accepted by {@link ToolCallBlock}.
@@ -7,5 +8,26 @@ export interface ToolCallBlockProps {
7
8
  entry: ToolEventEntry;
8
9
  /** Optional class added to the root element. */
9
10
  className?: string;
11
+ /**
12
+ * Controls whether the block body (sub-output, nested events, args, result)
13
+ * is open by default. The header (status icon + tool name) is always
14
+ * visible.
15
+ *
16
+ * - `'streaming'` (default): open while `entry.isStreaming` is `true`, then
17
+ * collapses on completion.
18
+ * - `true`: open by default, regardless of streaming state.
19
+ * - `false`: closed by default, regardless of streaming state.
20
+ */
21
+ defaultOpen?: boolean | 'streaming';
22
+ /**
23
+ * Overrides `entry.name` in the header. Useful for delegation-style tools
24
+ * whose interesting label lives in the args (e.g. `delegate_to_skill` should
25
+ * display the target skill's name, not the wrapper tool's name).
26
+ *
27
+ * Takes precedence over the `getToolLabel` resolver supplied via
28
+ * `<AssistantMessage>` / `<MessageList>` / `<ConversationPanel>`. When
29
+ * omitted, falls back to the resolver, then to `entry.name`.
30
+ */
31
+ label?: ReactNode;
10
32
  }
11
- export declare function ToolCallBlock({ entry, className }: ToolCallBlockProps): import("react/jsx-runtime").JSX.Element;
33
+ export declare function ToolCallBlock({ entry, className, defaultOpen, label, }: ToolCallBlockProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,20 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { ToolEventEntry } from '../types.js';
3
+ /**
4
+ * Computes the header label for a {@link ToolEventEntry}. Returning `undefined`
5
+ * (or `null`) lets the consuming `<ToolCallBlock>` fall back to `entry.name`,
6
+ * which is useful for selectively overriding only a subset of tool names.
7
+ */
8
+ export type GetToolLabel = (entry: ToolEventEntry) => ReactNode;
9
+ /**
10
+ * Context written by `<AssistantMessage getToolLabel>` (and parents that
11
+ * forward the prop) and read by `<ToolCallBlock>` to resolve its header label.
12
+ *
13
+ * Resolution order inside `<ToolCallBlock>`:
14
+ *
15
+ * 1. The explicit `label` prop, if provided.
16
+ * 2. The value returned by this context's `getToolLabel`, if defined and the
17
+ * return value is not `null`/`undefined`.
18
+ * 3. `entry.name`.
19
+ */
20
+ export declare const ToolLabelContext: import("react").Context<GetToolLabel | undefined>;
package/dist/context.d.ts CHANGED
@@ -7,8 +7,15 @@ import type { ConversationEntry, IconMap } from './types.js';
7
7
  * Props accepted by {@link AgentProvider}.
8
8
  */
9
9
  export interface AgentProviderProps {
10
- /** The {@link AgentRunner} that will execute agent runs. */
11
- runner: AgentRunner;
10
+ /**
11
+ * The {@link AgentRunner} that will execute agent runs. Pass `null` for the
12
+ * "agent not yet configured" state (e.g. before the user has supplied an
13
+ * API key, signed in, or selected a provider): the provider mounts cleanly,
14
+ * `useAgent()` returns disabled-state defaults, and `<ChatInput>` greys out
15
+ * automatically. Switching from `null` to a real runner does not require
16
+ * remounting; the conversation starts fresh on the next `sendMessage`.
17
+ */
18
+ runner: AgentRunner | null;
12
19
  /** The agent configuration used for every turn. */
13
20
  agent: AgentConfig;
14
21
  /** The subtree that should have access to {@link useAgent}. */
@@ -58,6 +65,21 @@ export interface AgentProviderProps {
58
65
  * a run is cancelled or errors before completion.
59
66
  */
60
67
  onConversationChange?: (history: Message[], entries: ConversationEntry[]) => void;
68
+ /**
69
+ * Forces a theme on the auto-rendered `[data-mast-root]` wrapper. When
70
+ * omitted, the panel follows the OS preference via the default stylesheet's
71
+ * `prefers-color-scheme` media query. Ignored when `disableRoot` is `true`.
72
+ */
73
+ theme?: 'light' | 'dark';
74
+ /**
75
+ * Disable the auto-rendered `<div data-mast-root>` wrapper around `children`.
76
+ * Use this when you want to place `data-mast-root` somewhere else in the
77
+ * tree yourself, e.g. on a chat sidebar's outer container so additional
78
+ * non-library UI inside also picks up the library's CSS variables.
79
+ *
80
+ * Default: `false` (the wrapper is rendered).
81
+ */
82
+ disableRoot?: boolean;
61
83
  }
62
84
  /**
63
85
  * The value exposed by {@link useAgent}.
@@ -95,6 +117,15 @@ export interface UseAgentReturn {
95
117
  * called.
96
118
  */
97
119
  pendingApprovals: PendingApproval[];
120
+ /**
121
+ * `true` when an `AgentRunner` is configured. `false` when `<AgentProvider>`
122
+ * was mounted with `runner={null}` (the "agent not yet configured" state).
123
+ * `<ChatInput>` reads this to disable its textarea and Send button; custom
124
+ * inputs built via `useAgent()` should do the same.
125
+ *
126
+ * When `false`, `sendMessage` is a no-op (it logs a development warning).
127
+ */
128
+ isReady: boolean;
98
129
  }
99
130
  /**
100
131
  * Wraps a subtree with agent context.
@@ -103,7 +134,7 @@ export interface UseAgentReturn {
103
134
  * and drives it with {@link useAgentStream}. Children access the resulting
104
135
  * state through {@link useAgent}.
105
136
  */
106
- export declare function AgentProvider({ runner, agent, children, icons, onApprovalRequired, approvalOverride, initialHistory, initialEntries, onConversationChange, }: AgentProviderProps): import("react/jsx-runtime").JSX.Element;
137
+ export declare function AgentProvider({ runner, agent, children, icons, onApprovalRequired, approvalOverride, initialHistory, initialEntries, onConversationChange, theme, disableRoot, }: AgentProviderProps): import("react/jsx-runtime").JSX.Element;
107
138
  /**
108
139
  * Reads the current agent state from {@link AgentProvider}.
109
140
  *
@@ -99,6 +99,12 @@ export interface UseAgentStreamReturn {
99
99
  * of the conversation. Sub-agent events are captured via `onToolEvent` and
100
100
  * routed to the matching `ToolEventEntry` by tool name.
101
101
  *
102
+ * Pass `null` for `conversation` to model the "agent not yet configured"
103
+ * state — `sendMessage` becomes a no-op (with a development warning),
104
+ * `history` is empty, and `isRunning` is always `false`. The hook switches
105
+ * back to live behaviour once a non-null `conversation` is supplied on a
106
+ * later render.
107
+ *
102
108
  * This hook is consumed by `<AgentProvider>` and is not part of the public API.
103
109
  * It is exported so that it can be used independently in advanced scenarios.
104
110
  *
@@ -128,4 +134,4 @@ export interface UseAgentStreamReturn {
128
134
  * const { entries, sendMessage, cancel, isRunning } = useAgentStream(conversation);
129
135
  * ```
130
136
  */
131
- export declare function useAgentStream(conversation: Conversation, options?: UseAgentStreamOptions): UseAgentStreamReturn;
137
+ export declare function useAgentStream(conversation: Conversation | null, options?: UseAgentStreamOptions): UseAgentStreamReturn;
package/dist/index.d.ts CHANGED
@@ -14,7 +14,8 @@ export type { ToolCallBlockProps } from './components/ToolCallBlock.js';
14
14
  export { UserMessage } from './components/UserMessage.js';
15
15
  export type { UserMessageProps } from './components/UserMessage.js';
16
16
  export { AssistantMessage } from './components/AssistantMessage.js';
17
- export type { AssistantMessageProps } from './components/AssistantMessage.js';
17
+ export type { AssistantMessageProps, RenderApproval } from './components/AssistantMessage.js';
18
+ export type { GetToolLabel } from './components/ToolLabelContext.js';
18
19
  export { ChatInput } from './components/ChatInput.js';
19
20
  export type { ChatInputProps } from './components/ChatInput.js';
20
21
  export { MessageItem } from './components/MessageItem.js';