@candor-ui/react 1.5.0 → 1.8.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.
- package/dist/adapters/ag-ui.d.ts +24 -24
- package/dist/adapters/ai-sdk.d.ts +6 -6
- package/dist/adapters/claude-agent-sdk.d.ts +51 -34
- package/dist/adapters/claude-agent-sdk.js +46 -2
- package/dist/adapters/claude-agent-server.d.ts +34 -34
- package/dist/adapters/use-ag-ui.d.ts +6 -6
- package/dist/adapters/use-ag-ui.js +14 -2
- package/dist/adapters/use-candor-chat.d.ts +1 -1
- package/dist/adapters/use-candor-chat.js +1 -1
- package/dist/adapters/use-claude-agent.d.ts +10 -10
- package/dist/adapters/use-claude-agent.js +1 -1
- package/dist/blocks/copy-field.d.ts +1 -1
- package/dist/blocks/copy-field.js +1 -1
- package/dist/blocks/degraded-panel.d.ts +5 -5
- package/dist/blocks/locale.d.ts +6 -6
- package/dist/blocks/locked.d.ts +8 -8
- package/dist/blocks/relative-time.d.ts +6 -6
- package/dist/blocks/status-dot.d.ts +3 -3
- package/dist/blocks/step-list.d.ts +3 -3
- package/dist/blocks/streaming-text.d.ts +3 -3
- package/dist/chat/agent-avatar.d.ts +4 -4
- package/dist/chat/ai-disclosure.d.ts +5 -5
- package/dist/chat/ai-disclosure.js +1 -1
- package/dist/chat/attachment-preview.d.ts +6 -6
- package/dist/chat/attachment-preview.js +1 -1
- package/dist/chat/card-registry.js +1 -1
- package/dist/chat/citation.d.ts +3 -3
- package/dist/chat/citation.js +3 -3
- package/dist/chat/composer.d.ts +37 -20
- package/dist/chat/composer.js +13 -6
- package/dist/chat/context-meter.d.ts +1 -1
- package/dist/chat/context-meter.js +1 -1
- package/dist/chat/entity-chip.d.ts +3 -3
- package/dist/chat/entity-chip.js +1 -1
- package/dist/chat/folded-turns.d.ts +11 -6
- package/dist/chat/folded-turns.js +2 -2
- package/dist/chat/message-actions.d.ts +6 -6
- package/dist/chat/message-actions.js +1 -1
- package/dist/chat/message-content.d.ts +13 -7
- package/dist/chat/message-content.js +10 -5
- package/dist/chat/message.d.ts +64 -37
- package/dist/chat/message.js +17 -11
- package/dist/chat/payload.d.ts +4 -4
- package/dist/chat/payload.js +2 -2
- package/dist/chat/permission-prompt.d.ts +23 -23
- package/dist/chat/prompt-suggestions.d.ts +4 -4
- package/dist/chat/prompt-suggestions.js +1 -1
- package/dist/chat/reasoning.d.ts +3 -3
- package/dist/chat/reasoning.js +1 -1
- package/dist/chat/thread-divider.d.ts +3 -3
- package/dist/chat/thread-event.d.ts +10 -5
- package/dist/chat/thread-event.js +3 -2
- package/dist/chat/thread.d.ts +23 -7
- package/dist/chat/thread.js +28 -5
- package/dist/chat/tool-call.d.ts +2 -2
- package/dist/chat/tool-call.js +2 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/lib/chat.d.ts +42 -42
- package/dist/lib/know.d.ts +14 -12
- package/dist/lib/mcp-input.d.ts +316 -0
- package/dist/lib/mcp-input.js +369 -0
- package/dist/lib/render-prop.d.ts +4 -4
- package/dist/lib/safe-markdown.d.ts +1 -1
- package/dist/lib/status.d.ts +21 -0
- package/dist/lib/status.js +17 -0
- package/dist/lib/use-shortcut.d.ts +1 -1
- package/dist/lib/use-virtual-list.d.ts +6 -6
- package/dist/styles.css +4 -1
- package/dist/ui/button.d.ts +1 -1
- package/dist/ui/button.js +1 -1
- package/package.json +1 -1
package/dist/chat/entity-chip.js
CHANGED
|
@@ -81,6 +81,6 @@ function EntityChip({ entity, onOpen, onRemove, className, }) {
|
|
|
81
81
|
: t("title", { noun, name: entity.name });
|
|
82
82
|
const body = (_jsxs(_Fragment, { children: [_jsx(Icon, { "aria-hidden": true, className: "size-3 shrink-0 text-muted-foreground" }), _jsx("span", { className: "truncate", children: shown }), _jsxs("span", { className: "sr-only", children: [" (", title, ")"] })] }));
|
|
83
83
|
const base = "inline-flex max-w-full items-center gap-1 rounded-sm border bg-card px-1.5 py-px align-baseline font-mono text-[0.92em] leading-[1.35] text-foreground";
|
|
84
|
-
return (_jsxs("span", { "data-slot": "entity-chip", "data-kind": entity.kind, title: title, className: cn("inline-flex max-w-full min-w-0 items-center sm:max-w-64", className), children: [onOpen ? (_jsx("button", { type: "button", onClick: () => onOpen(entity), className: cn(base, "cursor-pointer transition-colors duration-150 hover:border-border-strong hover:bg-accent focus-visible:ring-[3px] focus-visible:ring-ring/
|
|
84
|
+
return (_jsxs("span", { "data-slot": "entity-chip", "data-kind": entity.kind, title: title, className: cn("inline-flex max-w-full min-w-0 items-center sm:max-w-64", className), children: [onOpen ? (_jsx("button", { type: "button", onClick: () => onOpen(entity), className: cn(base, "cursor-pointer transition-colors duration-150 hover:border-border-strong hover:bg-accent focus-visible:ring-[3px] focus-visible:ring-ring/80 outline-none"), children: body })) : (_jsx("span", { className: base, children: body })), onRemove && (_jsx("button", { type: "button", "aria-label": t("remove", { name: shown }), onClick: () => onRemove(entity), className: "relative after:absolute after:-inset-1 -ms-px rounded-e-sm border border-s-0 bg-card px-1 py-px text-faint-foreground hover:text-foreground", children: "\u00D7" }))] }));
|
|
85
85
|
}
|
|
86
86
|
export { EntityChip, EntityKindsProvider, useEntityKinds };
|
|
@@ -15,19 +15,24 @@ export declare const foldedTurnsStrings: {
|
|
|
15
15
|
* versions and compared them". The line says how many turns are inside and opens them in place; `summary` is yours
|
|
16
16
|
* (a sentence, a count of tool calls, a cost). Folding never hides that the turns happened.
|
|
17
17
|
*/
|
|
18
|
-
declare function FoldedTurns({ count, summary, defaultOpen, open, onOpenChange, children, className, }: {
|
|
18
|
+
declare function FoldedTurns({ count, summary, defaultOpen, open, onOpenChange, header, children, className, }: {
|
|
19
19
|
/** How many turns are inside, for the button ("Show 12 turns"). */
|
|
20
20
|
count: number;
|
|
21
21
|
/** What happened in them, shown on the folded line: text or your own small summary. */
|
|
22
|
-
summary?: React.ReactNode;
|
|
22
|
+
summary?: React.ReactNode | undefined;
|
|
23
23
|
/** Start open. */
|
|
24
|
-
defaultOpen?: boolean;
|
|
24
|
+
defaultOpen?: boolean | undefined;
|
|
25
25
|
/** Controlled open state. */
|
|
26
|
-
open?: boolean;
|
|
26
|
+
open?: boolean | undefined;
|
|
27
27
|
/** Called when a person opens or closes it. */
|
|
28
|
-
onOpenChange?: (open: boolean) => void;
|
|
28
|
+
onOpenChange?: ((open: boolean) => void) | undefined;
|
|
29
|
+
/**
|
|
30
|
+
* Your own folded line instead of the dashed one: a card with a title, how it ended, its cost, actions. The
|
|
31
|
+
* Show/Hide button follows it, so the turns can still be opened.
|
|
32
|
+
*/
|
|
33
|
+
header?: React.ReactNode | undefined;
|
|
29
34
|
/** The turns, usually Messages. */
|
|
30
35
|
children: React.ReactNode;
|
|
31
|
-
className?: string;
|
|
36
|
+
className?: string | undefined;
|
|
32
37
|
}): React.JSX.Element;
|
|
33
38
|
export { FoldedTurns };
|
|
@@ -15,7 +15,7 @@ export const foldedTurnsStrings = {
|
|
|
15
15
|
* versions and compared them". The line says how many turns are inside and opens them in place; `summary` is yours
|
|
16
16
|
* (a sentence, a count of tool calls, a cost). Folding never hides that the turns happened.
|
|
17
17
|
*/
|
|
18
|
-
function FoldedTurns({ count, summary, defaultOpen = false, open, onOpenChange, children, className, }) {
|
|
18
|
+
function FoldedTurns({ count, summary, defaultOpen = false, open, onOpenChange, header, children, className, }) {
|
|
19
19
|
const t = useStrings("foldedTurns", foldedTurnsStrings);
|
|
20
20
|
const [own, setOwn] = React.useState(defaultOpen);
|
|
21
21
|
const isOpen = open ?? own;
|
|
@@ -24,6 +24,6 @@ function FoldedTurns({ count, summary, defaultOpen = false, open, onOpenChange,
|
|
|
24
24
|
setOwn(next);
|
|
25
25
|
onOpenChange?.(next);
|
|
26
26
|
};
|
|
27
|
-
return (_jsxs(Collapsible, { open: isOpen, onOpenChange: set, "data-slot": "folded-turns", className: cn("group/folded flex flex-col gap-7", className), children: [_jsxs("div", { className: "flex flex-wrap items-center gap-x-3 gap-y-1 rounded-lg border border-dashed px-3 py-2
|
|
27
|
+
return (_jsxs(Collapsible, { open: isOpen, onOpenChange: set, "data-slot": "folded-turns", className: cn("group/folded flex flex-col gap-7", className), children: [_jsxs("div", { "data-slot": "folded-turns-line", className: cn("flex flex-wrap items-center gap-x-3 gap-y-1 text-sm", header ? "flex-col items-stretch" : "rounded-lg border border-dashed px-3 py-2"), children: [header ?? (summary && _jsx("div", { className: "min-w-0 flex-1 text-muted-foreground", children: summary })), _jsxs(CollapsibleTrigger, { className: cn("relative after:absolute after:inset-x-0 after:-inset-y-0.5 ms-auto inline-flex items-center gap-1 rounded-md px-1.5 py-0.5 text-xs font-medium text-accent-text outline-none hover:bg-accent focus-visible:ring-[3px] focus-visible:ring-ring/80", header && "self-end"), children: [_jsx(ChevronRight, { "aria-hidden": true, className: "rtl:-scale-x-100 size-3.5 transition-transform duration-200 group-data-[state=open]/folded:[transform:rotate(90deg)]" }), t(isOpen ? "hide" : "show", { count })] })] }), _jsx(CollapsibleContent, { className: "flex flex-col gap-7", children: children })] }));
|
|
28
28
|
}
|
|
29
29
|
export { FoldedTurns };
|
|
@@ -16,15 +16,15 @@ export type Rating = "up" | "down" | null;
|
|
|
16
16
|
*/
|
|
17
17
|
declare function MessageActions({ text, onRetry, rating, onRate, meta, className, }: {
|
|
18
18
|
/** What Copy copies; without it there's no Copy. */
|
|
19
|
-
text?: string;
|
|
19
|
+
text?: string | undefined;
|
|
20
20
|
/** Shows Retry. */
|
|
21
|
-
onRetry?: () => void;
|
|
21
|
+
onRetry?: (() => void) | undefined;
|
|
22
22
|
/** The current rating: up, down or none. */
|
|
23
|
-
rating?: Rating;
|
|
23
|
+
rating?: Rating | undefined;
|
|
24
24
|
/** Shows thumbs up and down. */
|
|
25
|
-
onRate?: (rating: Rating) => void;
|
|
25
|
+
onRate?: ((rating: Rating) => void) | undefined;
|
|
26
26
|
/** Facts after the actions, e.g. the model and cost. */
|
|
27
|
-
meta?: React.ReactNode;
|
|
28
|
-
className?: string;
|
|
27
|
+
meta?: React.ReactNode | undefined;
|
|
28
|
+
className?: string | undefined;
|
|
29
29
|
}): React.JSX.Element;
|
|
30
30
|
export { MessageActions };
|
|
@@ -16,7 +16,7 @@ export const messageActionsStrings = {
|
|
|
16
16
|
bad: "Bad answer",
|
|
17
17
|
};
|
|
18
18
|
function ActionButton({ label, onClick, pressed, children, }) {
|
|
19
|
-
return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", "aria-label": label, "aria-pressed": pressed, onClick: onClick, className: "flex size-7 items-center justify-center rounded-md text-faint-foreground transition-colors duration-150 outline-none hover:bg-accent hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/
|
|
19
|
+
return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", "aria-label": label, "aria-pressed": pressed, onClick: onClick, className: "flex size-7 items-center justify-center rounded-md text-faint-foreground transition-colors duration-150 outline-none hover:bg-accent hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/80 aria-pressed:text-accent-text [&_svg]:size-3.5", children: children }) }), _jsx(TooltipContent, { children: label })] }));
|
|
20
20
|
}
|
|
21
21
|
/**
|
|
22
22
|
* Copy, retry and rate under an agent's reply. Each action appears only when
|
|
@@ -15,19 +15,25 @@ declare function Inline({ nodes, }: {
|
|
|
15
15
|
/** Inline nodes: text, strong, code, entities, citations. */
|
|
16
16
|
nodes: InlineNode[];
|
|
17
17
|
}): React.JSX.Element;
|
|
18
|
-
/**
|
|
19
|
-
|
|
18
|
+
/**
|
|
19
|
+
* A message's blocks, in order. Build them from text with `plainBlocks(text)` for a person's words (newlines kept, no
|
|
20
|
+
* markdown) and `markdownBlocks(text)` for an agent's answer, both from `safe-markdown`, which installs with this item. Import them from there: they run on the server too. A
|
|
21
|
+
* model's links show as text, never as clickable links.
|
|
22
|
+
*/
|
|
23
|
+
declare function MessageContent({ blocks, sources, onOpenEntity, onNavigate, onOpenAttachment, bareCode, className, }: {
|
|
20
24
|
/** The reply as typed blocks: paragraphs, lists, payloads, tool calls, cards, attachments. */
|
|
21
25
|
blocks: MessageBlock[];
|
|
22
26
|
/** Sources the blocks cite by marker. */
|
|
23
|
-
sources?: MessageSource[];
|
|
27
|
+
sources?: MessageSource[] | undefined;
|
|
24
28
|
/** Makes entity chips open their thing. */
|
|
25
|
-
onOpenEntity?: (entity: EntityRef) => void;
|
|
29
|
+
onOpenEntity?: ((entity: EntityRef) => void) | undefined;
|
|
26
30
|
/** Follows in-app links; links from a model are never rendered. */
|
|
27
|
-
onNavigate?: (to: string) => void;
|
|
31
|
+
onNavigate?: ((to: string) => void) | undefined;
|
|
28
32
|
/** Makes attachment tiles buttons that open their file. */
|
|
29
|
-
onOpenAttachment?: (attachment: Attachment) => void;
|
|
30
|
-
|
|
33
|
+
onOpenAttachment?: ((attachment: Attachment) => void) | undefined;
|
|
34
|
+
/** Code and other payload blocks without their frame and title bar (Payload's `bare`). */
|
|
35
|
+
bareCode?: boolean | undefined;
|
|
36
|
+
className?: string | undefined;
|
|
31
37
|
}): React.JSX.Element;
|
|
32
38
|
/** Plain text of a message, for copy. Citations become [n]; entities their API name. */
|
|
33
39
|
export declare function blocksToText(blocks: MessageBlock[], sources?: MessageSource[]): string;
|
|
@@ -42,7 +42,7 @@ function Inline({ nodes, }) {
|
|
|
42
42
|
case "orgData":
|
|
43
43
|
return (_jsx("span", { title: n.source ? t("measuredFrom", { environment: terms.environment, source: n.source }) : t("measured", { environment: terms.environment }), className: "font-medium tabular-nums text-foreground", children: n.text }, i));
|
|
44
44
|
case "provisional":
|
|
45
|
-
return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("button", { type: "button", "data-provisional": true, className: "inline rounded-xs text-start text-provisional underline decoration-provisional/50 decoration-dotted underline-offset-[3px] outline-none focus-visible:ring-[3px] focus-visible:ring-ring/
|
|
45
|
+
return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("button", { type: "button", "data-provisional": true, className: "inline rounded-xs text-start text-provisional underline decoration-provisional/50 decoration-dotted underline-offset-[3px] outline-none focus-visible:ring-[3px] focus-visible:ring-ring/80", children: [_jsx(Inline, { nodes: n.nodes }), _jsx("span", { className: "sr-only", children: t("notVerified") })] }) }), _jsx(TooltipContent, { children: n.reason ?? t("provisional", { environment: terms.environment }) })] }, i));
|
|
46
46
|
case "citation":
|
|
47
47
|
return _jsx(Citation, { source: ctx.sources.get(n.sourceId) }, i);
|
|
48
48
|
case "entity":
|
|
@@ -62,6 +62,7 @@ function AttachmentBlock({ files }) {
|
|
|
62
62
|
return _jsx(AttachmentList, { attachments: files, onOpen: ctx.onOpenAttachment });
|
|
63
63
|
}
|
|
64
64
|
function Block({ block, }) {
|
|
65
|
+
const { bareCode } = React.useContext(ContentContext);
|
|
65
66
|
switch (block.kind) {
|
|
66
67
|
case "paragraph":
|
|
67
68
|
return (_jsx("p", { children: _jsx(Inline, { nodes: block.nodes }) }));
|
|
@@ -79,7 +80,7 @@ function Block({ block, }) {
|
|
|
79
80
|
return (_jsx(List, { className: cn("flex flex-col gap-1 ps-5", block.ordered ? "list-decimal" : "list-disc marker:text-faint-foreground"), children: block.items.map((item, i) => (_jsx("li", { className: "ps-0.5", children: _jsx(Inline, { nodes: item }) }, i))) }));
|
|
80
81
|
}
|
|
81
82
|
case "payload":
|
|
82
|
-
return _jsx(Payload, { language: block.language, text: block.text, title: block.title });
|
|
83
|
+
return _jsx(Payload, { language: block.language, text: block.text, title: block.title, bare: bareCode });
|
|
83
84
|
case "tools":
|
|
84
85
|
return _jsx(ToolCallGroup, { calls: block.calls });
|
|
85
86
|
case "degraded":
|
|
@@ -90,9 +91,13 @@ function Block({ block, }) {
|
|
|
90
91
|
return _jsx(AttachmentBlock, { files: block.files });
|
|
91
92
|
}
|
|
92
93
|
}
|
|
93
|
-
/**
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
/**
|
|
95
|
+
* A message's blocks, in order. Build them from text with `plainBlocks(text)` for a person's words (newlines kept, no
|
|
96
|
+
* markdown) and `markdownBlocks(text)` for an agent's answer, both from `safe-markdown`, which installs with this item. Import them from there: they run on the server too. A
|
|
97
|
+
* model's links show as text, never as clickable links.
|
|
98
|
+
*/
|
|
99
|
+
function MessageContent({ blocks, sources = [], onOpenEntity, onNavigate, onOpenAttachment, bareCode, className, }) {
|
|
100
|
+
const ctx = React.useMemo(() => ({ sources: new Map(sources.map((s) => [s.id, s])), onOpenEntity, onNavigate, onOpenAttachment, bareCode }), [sources, onOpenEntity, onNavigate, onOpenAttachment, bareCode]);
|
|
96
101
|
return (_jsx(ContentContext.Provider, { value: ctx, children: _jsx("div", { "data-slot": "message-content", className: cn("flex flex-col gap-3 text-prose leading-relaxed", className), children: blocks.map((b, i) => (_jsx(Block, { block: b }, i))) }) }));
|
|
97
102
|
}
|
|
98
103
|
/** Plain text of a message, for copy. Citations become [n]; entities their API name. */
|
package/dist/chat/message.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type * as React from "react";
|
|
2
|
+
import type { DateStyle } from "../blocks/locale.js";
|
|
2
3
|
import type { Attachment, EntityRef, Message as MessageData } from "../lib/chat.js";
|
|
3
4
|
import { type Rating } from "./message-actions.js";
|
|
4
5
|
/** Message's fixed words; override them under `message` in LocaleProvider's `strings`. */
|
|
@@ -16,7 +17,8 @@ export declare const messageStrings: {
|
|
|
16
17
|
/**
|
|
17
18
|
* One message in a thread.
|
|
18
19
|
*
|
|
19
|
-
* - A person's message sits right, on the user surface
|
|
20
|
+
* - A person's message sits right, on the user surface, with their name and
|
|
21
|
+
* time under it (`meta` hides or replaces that line).
|
|
20
22
|
* - An agent's sits left, under its avatar, name and role, with reasoning above
|
|
21
23
|
* the answer, sources and actions below. While streaming, a caret follows the
|
|
22
24
|
* last block; an interrupted reply keeps what arrived and says it stopped.
|
|
@@ -25,92 +27,117 @@ export declare const messageStrings: {
|
|
|
25
27
|
* - A system line is centred and quiet.
|
|
26
28
|
* - A reply a person checked (or edited) before it went out can say so in a
|
|
27
29
|
* caption under it, so a reader knows a person stood behind it.
|
|
30
|
+
* - Times are relative ("5 minutes ago") unless `timeFormat` asks for an
|
|
31
|
+
* absolute "time", "date" or "datetime" in the locale.
|
|
32
|
+
*
|
|
33
|
+
* Build `blocks` with `plainBlocks(text)` for a person's words and
|
|
34
|
+
* `markdownBlocks(text)` for an agent's, from `safe-markdown`.
|
|
28
35
|
*/
|
|
29
|
-
declare function Message({ message, onOpenEntity, onNavigate, onOpenAttachment, onRetry, onContinue, rating, onRate, reviewedBy, actions, className, }: {
|
|
36
|
+
declare function Message({ message, onOpenEntity, onNavigate, onOpenAttachment, onRetry, onContinue, rating, onRate, reviewedBy, footer, actions, meta, timeFormat, density, bareCode, className, }: {
|
|
30
37
|
/** The message: author, status, blocks, and optional reasoning, sources and attribution. */
|
|
31
38
|
message: MessageData;
|
|
32
39
|
/** Makes entity chips open their thing. */
|
|
33
|
-
onOpenEntity?: (entity: EntityRef) => void;
|
|
40
|
+
onOpenEntity?: ((entity: EntityRef) => void) | undefined;
|
|
34
41
|
/** Follows in-app links. */
|
|
35
|
-
onNavigate?: (to: string) => void;
|
|
42
|
+
onNavigate?: ((to: string) => void) | undefined;
|
|
36
43
|
/** Makes attachment tiles buttons that open their file. */
|
|
37
|
-
onOpenAttachment?: (attachment: Attachment) => void;
|
|
44
|
+
onOpenAttachment?: ((attachment: Attachment) => void) | undefined;
|
|
38
45
|
/** Shows Retry on a failed or finished reply. */
|
|
39
|
-
onRetry?: () => void;
|
|
46
|
+
onRetry?: (() => void) | undefined;
|
|
40
47
|
/** Shows Continue on an interrupted reply. */
|
|
41
|
-
onContinue?: () => void;
|
|
48
|
+
onContinue?: (() => void) | undefined;
|
|
42
49
|
/** The current rating of an agent reply. */
|
|
43
|
-
rating?: Rating;
|
|
50
|
+
rating?: Rating | undefined;
|
|
44
51
|
/** Shows thumbs up and down under agent replies. */
|
|
45
|
-
onRate?: (rating: Rating) => void;
|
|
52
|
+
onRate?: ((rating: Rating) => void) | undefined;
|
|
46
53
|
/** A person who checked this agent reply before it was sent: "Checked by Sam", or "Edited by Sam" when they changed it. */
|
|
47
54
|
reviewedBy?: {
|
|
48
55
|
name: string;
|
|
49
|
-
at?: string;
|
|
50
|
-
edited?: boolean;
|
|
51
|
-
};
|
|
56
|
+
at?: string | undefined;
|
|
57
|
+
edited?: boolean | undefined;
|
|
58
|
+
} | undefined;
|
|
59
|
+
/** More lines under an agent reply, after who checked it and above the actions row: e.g. MemoryUsed. */
|
|
60
|
+
footer?: React.ReactNode | undefined;
|
|
52
61
|
/**
|
|
53
62
|
* The row under an agent reply (copy, retry, rating). `false` hides it; a node replaces it, e.g. your own buttons.
|
|
54
63
|
* Model and cost still show, on their own line. To rebuild a message, use MessageHeader, MessageBody and
|
|
55
64
|
* MessageFooter.
|
|
56
65
|
*/
|
|
57
|
-
actions?: false | React.ReactNode;
|
|
58
|
-
|
|
66
|
+
actions?: false | React.ReactNode | undefined;
|
|
67
|
+
/** The line under a person's own message: their name and when they sent it. `false` hides it; a node replaces it. */
|
|
68
|
+
meta?: false | React.ReactNode | undefined;
|
|
69
|
+
/** How times show: "relative" (the default, "5 minutes ago") or an absolute "time", "date" or "datetime" in the locale. */
|
|
70
|
+
timeFormat?: "relative" | DateStyle | undefined;
|
|
71
|
+
/** "compact" draws the header row smaller: a 12px name in a 24px row, for dense layouts. Defaults to "default". */
|
|
72
|
+
density?: "default" | "compact" | undefined;
|
|
73
|
+
/** Code and other payload blocks without their frame (Payload's `bare`). */
|
|
74
|
+
bareCode?: boolean | undefined;
|
|
75
|
+
className?: string | undefined;
|
|
59
76
|
}): React.JSX.Element;
|
|
60
77
|
/** The row above a reply: who sent it, a detail (their specialty or team), and when. */
|
|
61
|
-
declare function MessageHeader({ name, detail, createdAt, children, className, }: {
|
|
78
|
+
declare function MessageHeader({ name, detail, createdAt, timeFormat, density, children, className, }: {
|
|
62
79
|
/** The sender's displayed name. */
|
|
63
80
|
name: string;
|
|
64
81
|
/** A quieter detail after the name: an agent's specialty, a person's team. */
|
|
65
|
-
detail?: string;
|
|
66
|
-
/** When it was sent; shown as a relative time. */
|
|
67
|
-
createdAt?: string;
|
|
82
|
+
detail?: string | undefined;
|
|
83
|
+
/** When it was sent; shown as a relative time unless `timeFormat` says otherwise. */
|
|
84
|
+
createdAt?: string | undefined;
|
|
85
|
+
/** "relative" (the default) or an absolute "time", "date" or "datetime" in the locale. */
|
|
86
|
+
timeFormat?: "relative" | DateStyle | undefined;
|
|
87
|
+
/** "compact": a 12px name in a 24px row. Defaults to "default" (14px in 28px). */
|
|
88
|
+
density?: "default" | "compact" | undefined;
|
|
68
89
|
/** Anything else for the row, after the time (a badge, a menu). */
|
|
69
|
-
children?: React.ReactNode;
|
|
70
|
-
className?: string;
|
|
90
|
+
children?: React.ReactNode | undefined;
|
|
91
|
+
className?: string | undefined;
|
|
71
92
|
}): React.JSX.Element;
|
|
72
93
|
/** A reply's content: its reasoning, then its blocks, with a caret after the last one while it streams. */
|
|
73
|
-
declare function MessageBody({ message, onOpenEntity, onNavigate, onOpenAttachment, className, }: {
|
|
94
|
+
declare function MessageBody({ message, onOpenEntity, onNavigate, onOpenAttachment, bareCode, className, }: {
|
|
74
95
|
/** The message whose reasoning and blocks to show. */
|
|
75
96
|
message: MessageData;
|
|
76
97
|
/** Makes entity chips open their thing. */
|
|
77
|
-
onOpenEntity?: (entity: EntityRef) => void;
|
|
98
|
+
onOpenEntity?: ((entity: EntityRef) => void) | undefined;
|
|
78
99
|
/** Follows in-app links. */
|
|
79
|
-
onNavigate?: (to: string) => void;
|
|
100
|
+
onNavigate?: ((to: string) => void) | undefined;
|
|
80
101
|
/** Makes attachment tiles buttons that open their file. */
|
|
81
|
-
onOpenAttachment?: (attachment: Attachment) => void;
|
|
82
|
-
|
|
102
|
+
onOpenAttachment?: ((attachment: Attachment) => void) | undefined;
|
|
103
|
+
/** Code and other payload blocks without their frame. */
|
|
104
|
+
bareCode?: boolean | undefined;
|
|
105
|
+
className?: string | undefined;
|
|
83
106
|
}): React.JSX.Element;
|
|
84
107
|
/** Model and cost, on a line of their own: what the actions row shows, for when it's hidden or replaced. */
|
|
85
108
|
declare function MessageAttribution({ attribution, className, }: {
|
|
86
109
|
/** The service's measured values; nothing shows when both are absent. */
|
|
87
|
-
attribution?: MessageData["attribution"];
|
|
88
|
-
className?: string;
|
|
110
|
+
attribution?: MessageData["attribution"] | undefined;
|
|
111
|
+
className?: string | undefined;
|
|
89
112
|
}): React.JSX.Element | null;
|
|
90
113
|
/**
|
|
91
114
|
* What sits under a reply: that it stopped or failed, its sources, who checked it, then the actions row with model
|
|
92
115
|
* and cost. `actions={false}` hides the row and a node replaces it; either way the model and cost stay, on their own
|
|
93
116
|
* line, because a reader should always see what produced the answer.
|
|
94
117
|
*/
|
|
95
|
-
declare function MessageFooter({ message, onRetry, onContinue, rating, onRate, reviewedBy, actions, className, }: {
|
|
118
|
+
declare function MessageFooter({ message, onRetry, onContinue, rating, onRate, reviewedBy, footer, actions, timeFormat, className, }: {
|
|
96
119
|
/** The message the footer belongs to. */
|
|
97
120
|
message: MessageData;
|
|
98
121
|
/** Shows Retry on a failed or finished reply. */
|
|
99
|
-
onRetry?: () => void;
|
|
122
|
+
onRetry?: (() => void) | undefined;
|
|
100
123
|
/** Shows Continue on an interrupted reply. */
|
|
101
|
-
onContinue?: () => void;
|
|
124
|
+
onContinue?: (() => void) | undefined;
|
|
102
125
|
/** The current rating. */
|
|
103
|
-
rating?: Rating;
|
|
126
|
+
rating?: Rating | undefined;
|
|
104
127
|
/** Shows thumbs up and down. */
|
|
105
|
-
onRate?: (rating: Rating) => void;
|
|
128
|
+
onRate?: ((rating: Rating) => void) | undefined;
|
|
106
129
|
/** A person who checked the reply before it was sent. */
|
|
107
130
|
reviewedBy?: {
|
|
108
131
|
name: string;
|
|
109
|
-
at?: string;
|
|
110
|
-
edited?: boolean;
|
|
111
|
-
};
|
|
132
|
+
at?: string | undefined;
|
|
133
|
+
edited?: boolean | undefined;
|
|
134
|
+
} | undefined;
|
|
135
|
+
/** More lines after who checked it and above the actions row: e.g. MemoryUsed. */
|
|
136
|
+
footer?: React.ReactNode | undefined;
|
|
112
137
|
/** `false` hides the actions row, a node replaces it; model and cost still show. */
|
|
113
|
-
actions?: false | React.ReactNode;
|
|
114
|
-
|
|
138
|
+
actions?: false | React.ReactNode | undefined;
|
|
139
|
+
/** How the reviewer's time shows: "relative" (the default) or an absolute "time", "date" or "datetime". */
|
|
140
|
+
timeFormat?: "relative" | DateStyle | undefined;
|
|
141
|
+
className?: string | undefined;
|
|
115
142
|
}): React.JSX.Element;
|
|
116
143
|
export { Message, MessageHeader, MessageBody, MessageFooter, MessageAttribution };
|
package/dist/chat/message.js
CHANGED
|
@@ -26,7 +26,8 @@ export const messageStrings = {
|
|
|
26
26
|
/**
|
|
27
27
|
* One message in a thread.
|
|
28
28
|
*
|
|
29
|
-
* - A person's message sits right, on the user surface
|
|
29
|
+
* - A person's message sits right, on the user surface, with their name and
|
|
30
|
+
* time under it (`meta` hides or replaces that line).
|
|
30
31
|
* - An agent's sits left, under its avatar, name and role, with reasoning above
|
|
31
32
|
* the answer, sources and actions below. While streaming, a caret follows the
|
|
32
33
|
* last block; an interrupted reply keeps what arrived and says it stopped.
|
|
@@ -35,8 +36,13 @@ export const messageStrings = {
|
|
|
35
36
|
* - A system line is centred and quiet.
|
|
36
37
|
* - A reply a person checked (or edited) before it went out can say so in a
|
|
37
38
|
* caption under it, so a reader knows a person stood behind it.
|
|
39
|
+
* - Times are relative ("5 minutes ago") unless `timeFormat` asks for an
|
|
40
|
+
* absolute "time", "date" or "datetime" in the locale.
|
|
41
|
+
*
|
|
42
|
+
* Build `blocks` with `plainBlocks(text)` for a person's words and
|
|
43
|
+
* `markdownBlocks(text)` for an agent's, from `safe-markdown`.
|
|
38
44
|
*/
|
|
39
|
-
function Message({ message, onOpenEntity, onNavigate, onOpenAttachment, onRetry, onContinue, rating, onRate, reviewedBy, actions, className, }) {
|
|
45
|
+
function Message({ message, onOpenEntity, onNavigate, onOpenAttachment, onRetry, onContinue, rating, onRate, reviewedBy, footer, actions, meta, timeFormat, density = "default", bareCode, className, }) {
|
|
40
46
|
const { author } = message;
|
|
41
47
|
const roleOf = useAgentRoles();
|
|
42
48
|
const t = useStrings("message", messageStrings);
|
|
@@ -44,24 +50,24 @@ function Message({ message, onOpenEntity, onNavigate, onOpenAttachment, onRetry,
|
|
|
44
50
|
return (_jsx(ThreadEvent, { "data-slot": "message", "data-role": "system", className: className, children: _jsx(MessageContent, { blocks: message.blocks, className: "text-xs leading-normal" }) }));
|
|
45
51
|
}
|
|
46
52
|
if (author.role === "user") {
|
|
47
|
-
return (_jsx("div", { "data-slot": "message", "data-role": "user", className: cn("flex justify-end ps-10 sm:ps-24 animate-rise-in", className), children: _jsxs("div", { className: "flex max-w-full flex-col items-end gap-1", children: [_jsx("div", { className: "rounded-xl rounded-ee-sm bg-surface-user px-3.5 py-2.5", children: _jsx(MessageContent, { blocks: message.blocks, onOpenEntity: onOpenEntity, onNavigate: onNavigate, onOpenAttachment: onOpenAttachment, className: "gap-2" }) }), _jsxs("span", { className: "px-1 text-2xs text-faint-foreground", children: [author.name ?? t("you"), message.createdAt && (_jsxs(_Fragment, { children: [" · ", _jsx(RelativeTime, { date: message.createdAt })] }))] })] }) }));
|
|
53
|
+
return (_jsx("div", { "data-slot": "message", "data-role": "user", className: cn("flex justify-end ps-10 sm:ps-24 animate-rise-in", className), children: _jsxs("div", { className: "flex max-w-full flex-col items-end gap-1", children: [_jsx("div", { className: "rounded-xl rounded-ee-sm bg-surface-user px-3.5 py-2.5", children: _jsx(MessageContent, { blocks: message.blocks, onOpenEntity: onOpenEntity, onNavigate: onNavigate, onOpenAttachment: onOpenAttachment, bareCode: bareCode, className: "gap-2" }) }), meta === undefined ? (_jsxs("span", { "data-slot": "message-meta", className: "px-1 text-2xs text-faint-foreground", children: [author.name ?? t("you"), message.createdAt && (_jsxs(_Fragment, { children: [" · ", _jsx(RelativeTime, { date: message.createdAt, format: timeFormat })] }))] })) : (meta)] }) }));
|
|
48
54
|
}
|
|
49
55
|
if (author.role === "person") {
|
|
50
|
-
return (_jsxs("article", { "data-slot": "message", "data-role": "person", "aria-label": author.team ? t("personLabel", { name: author.name, team: author.team }) : author.name, className: cn("flex gap-3 animate-rise-in", className), children: [_jsx("span", { "aria-hidden": true, className: "mt-px flex size-7 shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground", children: _jsx(UserRound, { className: "size-4" }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx(MessageHeader, { name: author.name, detail: author.team, createdAt: message.createdAt }), _jsx(MessageContent, { blocks: message.blocks, sources: message.sources, onOpenEntity: onOpenEntity, onNavigate: onNavigate, onOpenAttachment: onOpenAttachment, className: "mt-1" })] })] }));
|
|
56
|
+
return (_jsxs("article", { "data-slot": "message", "data-role": "person", "aria-label": author.team ? t("personLabel", { name: author.name, team: author.team }) : author.name, className: cn("flex gap-3 animate-rise-in", className), children: [_jsx("span", { "aria-hidden": true, className: "mt-px flex size-7 shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground", children: _jsx(UserRound, { className: "size-4" }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx(MessageHeader, { name: author.name, detail: author.team, createdAt: message.createdAt, timeFormat: timeFormat, density: density }), _jsx(MessageContent, { blocks: message.blocks, sources: message.sources, onOpenEntity: onOpenEntity, onNavigate: onNavigate, onOpenAttachment: onOpenAttachment, bareCode: bareCode, className: "mt-1" })] })] }));
|
|
51
57
|
}
|
|
52
58
|
const { agent } = author;
|
|
53
59
|
const streaming = message.status === "streaming";
|
|
54
|
-
return (_jsxs("article", { "data-slot": "message", "data-role": "agent", "data-status": message.status, "aria-busy": streaming, "aria-label": t("agentLabel", { name: agent.name, noun: roleOf(agent.role).noun }), className: cn("group/message flex gap-3 animate-rise-in", className), children: [_jsx(AgentAvatar, { agent: agent, className: "mt-px" }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx(MessageHeader, { name: agent.name, detail: agent.specialty, createdAt: message.createdAt }), _jsxs("div", { className: "mt-1 flex flex-col gap-3", children: [_jsx(MessageBody, { message: message, onOpenEntity: onOpenEntity, onNavigate: onNavigate, onOpenAttachment: onOpenAttachment }), _jsx(MessageFooter, { message: message, onRetry: onRetry, onContinue: onContinue, rating: rating, onRate: onRate, reviewedBy: reviewedBy, actions: actions })] })] })] }));
|
|
60
|
+
return (_jsxs("article", { "data-slot": "message", "data-role": "agent", "data-status": message.status, "aria-busy": streaming, "aria-label": t("agentLabel", { name: agent.name, noun: roleOf(agent.role).noun }), className: cn("group/message flex gap-3 animate-rise-in", className), children: [_jsx(AgentAvatar, { agent: agent, className: "mt-px" }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx(MessageHeader, { name: agent.name, detail: agent.specialty, createdAt: message.createdAt, timeFormat: timeFormat, density: density }), _jsxs("div", { className: "mt-1 flex flex-col gap-3", children: [_jsx(MessageBody, { message: message, onOpenEntity: onOpenEntity, onNavigate: onNavigate, onOpenAttachment: onOpenAttachment, bareCode: bareCode }), _jsx(MessageFooter, { message: message, onRetry: onRetry, onContinue: onContinue, rating: rating, onRate: onRate, reviewedBy: reviewedBy, footer: footer, actions: actions, timeFormat: timeFormat })] })] })] }));
|
|
55
61
|
}
|
|
56
62
|
/** The row above a reply: who sent it, a detail (their specialty or team), and when. */
|
|
57
|
-
function MessageHeader({ name, detail, createdAt, children, className, }) {
|
|
58
|
-
return (_jsxs("header", { "data-slot": "message-header", className: cn("flex
|
|
63
|
+
function MessageHeader({ name, detail, createdAt, timeFormat, density = "default", children, className, }) {
|
|
64
|
+
return (_jsxs("header", { "data-slot": "message-header", "data-density": density, className: cn("flex items-center gap-2", density === "compact" ? "h-6" : "h-7", className), children: [_jsx("span", { className: cn("font-semibold", density === "compact" ? "text-xs" : "text-sm"), children: name }), detail && _jsx("span", { className: cn("truncate text-muted-foreground", density === "compact" ? "text-2xs" : "text-xs"), children: detail }), createdAt && (_jsx("span", { className: cn("text-faint-foreground", density === "compact" ? "text-2xs" : "text-xs"), children: _jsx(RelativeTime, { date: createdAt, format: timeFormat }) })), children] }));
|
|
59
65
|
}
|
|
60
66
|
/** A reply's content: its reasoning, then its blocks, with a caret after the last one while it streams. */
|
|
61
|
-
function MessageBody({ message, onOpenEntity, onNavigate, onOpenAttachment, className, }) {
|
|
67
|
+
function MessageBody({ message, onOpenEntity, onNavigate, onOpenAttachment, bareCode, className, }) {
|
|
62
68
|
const streaming = message.status === "streaming";
|
|
63
69
|
const thinking = streaming && message.blocks.length === 0;
|
|
64
|
-
return (_jsxs("div", { "data-slot": "message-body", className: cn("flex flex-col gap-3", className), children: [message.reasoning && message.reasoning.length > 0 && _jsx(Reasoning, { entries: message.reasoning, thinking: thinking, thoughtFor: message.thoughtFor }), message.blocks.length > 0 && (_jsxs("div", { className: "relative", children: [_jsx(MessageContent, { blocks: message.blocks, sources: message.sources, onOpenEntity: onOpenEntity, onNavigate: onNavigate, onOpenAttachment: onOpenAttachment }), streaming && _jsx("span", { "aria-hidden": true, className: "ms-0.5 inline-block h-[1.05em] w-[2px] translate-y-[0.18em] rounded-full bg-primary animate-caret" })] }))] }));
|
|
70
|
+
return (_jsxs("div", { "data-slot": "message-body", className: cn("flex flex-col gap-3", className), children: [message.reasoning && message.reasoning.length > 0 && _jsx(Reasoning, { entries: message.reasoning, thinking: thinking, thoughtFor: message.thoughtFor }), message.blocks.length > 0 && (_jsxs("div", { className: "relative", children: [_jsx(MessageContent, { blocks: message.blocks, sources: message.sources, onOpenEntity: onOpenEntity, onNavigate: onNavigate, onOpenAttachment: onOpenAttachment, bareCode: bareCode }), streaming && _jsx("span", { "aria-hidden": true, className: "ms-0.5 inline-block h-[1.05em] w-[2px] translate-y-[0.18em] rounded-full bg-primary animate-caret" })] }))] }));
|
|
65
71
|
}
|
|
66
72
|
/** Model and cost, on a line of their own: what the actions row shows, for when it's hidden or replaced. */
|
|
67
73
|
function MessageAttribution({ attribution, className, }) {
|
|
@@ -75,11 +81,11 @@ function MessageAttribution({ attribution, className, }) {
|
|
|
75
81
|
* and cost. `actions={false}` hides the row and a node replaces it; either way the model and cost stay, on their own
|
|
76
82
|
* line, because a reader should always see what produced the answer.
|
|
77
83
|
*/
|
|
78
|
-
function MessageFooter({ message, onRetry, onContinue, rating, onRate, reviewedBy, actions, className, }) {
|
|
84
|
+
function MessageFooter({ message, onRetry, onContinue, rating, onRate, reviewedBy, footer, actions, timeFormat, className, }) {
|
|
79
85
|
const t = useStrings("message", messageStrings);
|
|
80
86
|
const streaming = message.status === "streaming";
|
|
81
87
|
const settled = !streaming && message.status !== "failed";
|
|
82
88
|
const meta = [message.attribution?.model, message.attribution?.cost].filter(Boolean).join(" · ");
|
|
83
|
-
return (_jsxs("div", { "data-slot": "message-footer", className: cn("flex flex-col gap-3 empty:hidden", className), children: [message.status === "interrupted" && (_jsxs("div", { className: "flex flex-wrap items-center gap-2 text-xs text-muted-foreground", children: [_jsx(CircleStop, { "aria-hidden": true, className: "size-3.5" }), t("interrupted"), onContinue && (_jsx("button", { type: "button", onClick: onContinue, className: "relative after:absolute after:inset-x-0 after:-inset-y-1 font-medium text-accent-text hover:underline", children: t("continue") }))] })), message.status === "failed" && _jsx(DegradedPanel, { reason: t("failed"), missing: t("failedMissing"), onRetry: onRetry }), !streaming && message.sources && message.sources.length > 0 && _jsx(SourceList, { sources: message.sources }), reviewedBy && (_jsxs("p", { "data-slot": "message-reviewed", className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [_jsx(UserCheck, { "aria-hidden": true, className: "size-3.5" }), t(reviewedBy.edited ? "editedBy" : "checkedBy", { name: reviewedBy.name }), reviewedBy.at && (_jsxs(_Fragment, { children: [" · ", _jsx(RelativeTime, { date: reviewedBy.at })] }))] })), settled && actions === undefined && (_jsx(MessageActions, { text: blocksToText(message.blocks, message.sources), onRetry: onRetry, rating: rating, onRate: onRate, meta: meta || undefined, className: "-ms-1.5 opacity-100 transition-opacity duration-150 sm:opacity-0 sm:group-hover/message:opacity-100 sm:group-focus-within/message:opacity-100" })), settled && actions !== undefined && actions !== false && actions, settled && actions !== undefined && _jsx(MessageAttribution, { attribution: message.attribution })] }));
|
|
89
|
+
return (_jsxs("div", { "data-slot": "message-footer", className: cn("flex flex-col gap-3 empty:hidden", className), children: [message.status === "interrupted" && (_jsxs("div", { className: "flex flex-wrap items-center gap-2 text-xs text-muted-foreground", children: [_jsx(CircleStop, { "aria-hidden": true, className: "size-3.5" }), t("interrupted"), onContinue && (_jsx("button", { type: "button", onClick: onContinue, className: "relative after:absolute after:inset-x-0 after:-inset-y-1 font-medium text-accent-text hover:underline", children: t("continue") }))] })), message.status === "failed" && _jsx(DegradedPanel, { reason: t("failed"), missing: t("failedMissing"), onRetry: onRetry }), !streaming && message.sources && message.sources.length > 0 && _jsx(SourceList, { sources: message.sources }), reviewedBy && (_jsxs("p", { "data-slot": "message-reviewed", className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [_jsx(UserCheck, { "aria-hidden": true, className: "size-3.5" }), t(reviewedBy.edited ? "editedBy" : "checkedBy", { name: reviewedBy.name }), reviewedBy.at && (_jsxs(_Fragment, { children: [" · ", _jsx(RelativeTime, { date: reviewedBy.at, format: timeFormat })] }))] })), footer, settled && actions === undefined && (_jsx(MessageActions, { text: blocksToText(message.blocks, message.sources), onRetry: onRetry, rating: rating, onRate: onRate, meta: meta || undefined, className: "-ms-1.5 opacity-100 transition-opacity duration-150 sm:opacity-0 sm:group-hover/message:opacity-100 sm:group-focus-within/message:opacity-100" })), settled && actions !== undefined && actions !== false && actions, settled && actions !== undefined && _jsx(MessageAttribution, { attribution: message.attribution })] }));
|
|
84
90
|
}
|
|
85
91
|
export { Message, MessageHeader, MessageBody, MessageFooter, MessageAttribution };
|
package/dist/chat/payload.d.ts
CHANGED
|
@@ -23,11 +23,11 @@ declare function Payload({ language, text, title, bare, highlight, className, }:
|
|
|
23
23
|
/** The code or query, shown as text. */
|
|
24
24
|
text: string;
|
|
25
25
|
/** What it is, e.g. "The query I ran". Not shown when `bare`. */
|
|
26
|
-
title?: string;
|
|
26
|
+
title?: string | undefined;
|
|
27
27
|
/** Just the code: no border, language label or copy button, for inside something that has them. */
|
|
28
|
-
bare?: boolean;
|
|
28
|
+
bare?: boolean | undefined;
|
|
29
29
|
/** Colour the code by its syntax. Left out, it follows the nearest `data-syntax` attribute (off by default). */
|
|
30
|
-
highlight?: boolean;
|
|
31
|
-
className?: string;
|
|
30
|
+
highlight?: boolean | undefined;
|
|
31
|
+
className?: string | undefined;
|
|
32
32
|
}): React.JSX.Element;
|
|
33
33
|
export { Payload };
|
package/dist/chat/payload.js
CHANGED
|
@@ -42,9 +42,9 @@ function Payload({ language, text, title, bare = false, highlight, className, })
|
|
|
42
42
|
return (
|
|
43
43
|
// It scrolls on its own, so it takes focus: keyboard users can scroll long output.
|
|
44
44
|
// oxlint-disable-next-line jsx-a11y/no-noninteractive-tabindex
|
|
45
|
-
_jsx("pre", { "data-slot": "payload", "data-bare": "", "data-language": language, "data-syntax": syntax, tabIndex: 0, className: cn("max-h-80 overflow-auto rounded-md bg-sunken outline-none focus-visible:ring-[3px] focus-visible:ring-ring/
|
|
45
|
+
_jsx("pre", { "data-slot": "payload", "data-bare": "", "data-language": language, "data-syntax": syntax, tabIndex: 0, className: cn("max-h-80 overflow-auto rounded-md bg-sunken outline-none focus-visible:ring-[3px] focus-visible:ring-ring/80 focus-visible:ring-inset px-3 py-2.5 font-mono text-xs leading-relaxed text-foreground", className), children: code }));
|
|
46
46
|
}
|
|
47
|
-
return (_jsxs("figure", { "data-slot": "payload", "data-language": language, "data-syntax": syntax, className: cn("overflow-hidden rounded-lg border bg-sunken", className), children: [_jsxs("figcaption", { className: "flex items-center justify-between gap-2 border-b px-3 py-1.5", children: [_jsxs("span", { className: "truncate text-xs text-muted-foreground", children: [_jsx("span", { className: "font-medium text-foreground", children: languageLabel(language, t) }), title && _jsxs("span", { children: [" \u00B7 ", title] })] }), _jsx("button", { type: "button", onClick: () => copy(text), "aria-live": "polite", className: "relative after:absolute after:inset-x-0 after:-inset-y-0.5 inline-flex items-center gap-1 rounded-sm px-1.5 py-0.5 text-xs text-muted-foreground transition-colors duration-150 outline-none hover:bg-accent hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/
|
|
47
|
+
return (_jsxs("figure", { "data-slot": "payload", "data-language": language, "data-syntax": syntax, className: cn("overflow-hidden rounded-lg border bg-sunken", className), children: [_jsxs("figcaption", { className: "flex items-center justify-between gap-2 border-b px-3 py-1.5", children: [_jsxs("span", { className: "truncate text-xs text-muted-foreground", children: [_jsx("span", { className: "font-medium text-foreground", children: languageLabel(language, t) }), title && _jsxs("span", { children: [" \u00B7 ", title] })] }), _jsx("button", { type: "button", onClick: () => copy(text), "aria-live": "polite", className: "relative after:absolute after:inset-x-0 after:-inset-y-0.5 inline-flex items-center gap-1 rounded-sm px-1.5 py-0.5 text-xs text-muted-foreground transition-colors duration-150 outline-none hover:bg-accent hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/80", children: state === "copied" ? (_jsxs(_Fragment, { children: [_jsx(Check, { className: "size-3 text-success-text" }), " ", t("copied")] })) : state === "failed" ? (_jsxs(_Fragment, { children: [_jsx(X, { className: "size-3 text-destructive-text" }), " ", t("copyFailed")] })) : (_jsxs(_Fragment, { children: [_jsx(Copy, { className: "size-3" }), " ", t("copy")] })) })] }), _jsx("pre", { tabIndex: 0, className: "max-h-80 overflow-auto px-3 py-2.5 font-mono text-xs leading-relaxed text-foreground outline-none focus-visible:ring-[3px] focus-visible:ring-ring/80 focus-visible:ring-inset", children: code })] }));
|
|
48
48
|
}
|
|
49
49
|
/** The code as token spans. Each token is a text child, so nothing in it is parsed as markup. */
|
|
50
50
|
function Code({ text, language }) {
|
|
@@ -51,20 +51,20 @@ export type PermissionSuggestion = {
|
|
|
51
51
|
/** What it covers, as the source writes it: `Bash(npm test:*)`, a mode's name, directories. Shown as code. */
|
|
52
52
|
what: string;
|
|
53
53
|
/** Where it's kept: "session", "local" (this project, this computer), "project" (shared), "user", or the source's own word. */
|
|
54
|
-
scope?: string;
|
|
54
|
+
scope?: string | undefined;
|
|
55
55
|
};
|
|
56
56
|
/** A question the agent asks through the prompt: pick one or more labels, or answer in its own words. */
|
|
57
57
|
export type PermissionQuestion = {
|
|
58
58
|
id: string;
|
|
59
59
|
prompt: string;
|
|
60
|
-
tag?: string;
|
|
60
|
+
tag?: string | undefined;
|
|
61
61
|
options: {
|
|
62
62
|
id: string;
|
|
63
63
|
label: string;
|
|
64
|
-
detail?: string;
|
|
64
|
+
detail?: string | undefined;
|
|
65
65
|
}[];
|
|
66
66
|
multiple: boolean;
|
|
67
|
-
other?: boolean;
|
|
67
|
+
other?: boolean | undefined;
|
|
68
68
|
};
|
|
69
69
|
/** A tool call waiting on a person, in the shape the adapters give (ClaudeApproval fits it). */
|
|
70
70
|
export type PermissionRequest = {
|
|
@@ -72,35 +72,35 @@ export type PermissionRequest = {
|
|
|
72
72
|
tool: string;
|
|
73
73
|
input: unknown;
|
|
74
74
|
/** The source's own sentence for the request: "Claude wants to run npm test". */
|
|
75
|
-
title?: string;
|
|
76
|
-
description?: string;
|
|
75
|
+
title?: string | undefined;
|
|
76
|
+
description?: string | undefined;
|
|
77
77
|
/** Why it reached a person (no rule allowed it, a safety check, a path outside the project). */
|
|
78
|
-
reason?: string;
|
|
79
|
-
blockedPath?: string;
|
|
78
|
+
reason?: string | undefined;
|
|
79
|
+
blockedPath?: string | undefined;
|
|
80
80
|
/** Put the focus on Deny: the request grants more than it looks. */
|
|
81
|
-
defaultToNo?: boolean;
|
|
81
|
+
defaultToNo?: boolean | undefined;
|
|
82
82
|
/** Set when a subagent asked. */
|
|
83
|
-
agentId?: string;
|
|
83
|
+
agentId?: string | undefined;
|
|
84
84
|
mcpServer?: {
|
|
85
85
|
name: string;
|
|
86
86
|
source: string;
|
|
87
|
-
};
|
|
87
|
+
} | undefined;
|
|
88
88
|
/** The questions, when the request is the agent asking rather than a tool to allow. */
|
|
89
|
-
questions?: PermissionQuestion[];
|
|
89
|
+
questions?: PermissionQuestion[] | undefined;
|
|
90
90
|
/** False when the server won't accept an edited input for this call: no Edit is offered, whatever `editable` says. */
|
|
91
|
-
editable?: boolean;
|
|
91
|
+
editable?: boolean | undefined;
|
|
92
92
|
};
|
|
93
93
|
export type PermissionAnswer = {
|
|
94
94
|
/** The input as edited, when the person changed it. */
|
|
95
|
-
updatedInput?: Record<string, unknown
|
|
95
|
+
updatedInput?: Record<string, unknown> | undefined;
|
|
96
96
|
/** The suggestions the person ticked, by index. */
|
|
97
|
-
alwaysAllow?: number[];
|
|
97
|
+
alwaysAllow?: number[] | undefined;
|
|
98
98
|
/** Answers to `questions`. */
|
|
99
99
|
answers?: {
|
|
100
100
|
questionId: string;
|
|
101
|
-
choice?: string[];
|
|
102
|
-
text?: string;
|
|
103
|
-
}[];
|
|
101
|
+
choice?: string[] | undefined;
|
|
102
|
+
text?: string | undefined;
|
|
103
|
+
}[] | undefined;
|
|
104
104
|
};
|
|
105
105
|
/**
|
|
106
106
|
* A tool call waiting for a person's go-ahead: what it will do, why it reached them, and the permission mode the
|
|
@@ -113,17 +113,17 @@ declare function PermissionPrompt({ request, mode, suggestions, editable, onAllo
|
|
|
113
113
|
/** The waiting request. */
|
|
114
114
|
request: PermissionRequest;
|
|
115
115
|
/** The run's permission mode, as the SDK names it ("default", "acceptEdits", "plan", "auto"…). Left out, it isn't shown. */
|
|
116
|
-
mode?: string;
|
|
116
|
+
mode?: string | undefined;
|
|
117
117
|
/** "Don't ask again" rules to offer. None is ticked. */
|
|
118
|
-
suggestions?: PermissionSuggestion[];
|
|
118
|
+
suggestions?: PermissionSuggestion[] | undefined;
|
|
119
119
|
/** Let the person edit the input as JSON before allowing it. */
|
|
120
|
-
editable?: boolean;
|
|
120
|
+
editable?: boolean | undefined;
|
|
121
121
|
/** Called with the edited input, the ticked rules or the answers. */
|
|
122
122
|
onAllow: (answer: PermissionAnswer) => void;
|
|
123
123
|
/** Called when the person denies it (or won't answer the questions). */
|
|
124
124
|
onDeny: () => void;
|
|
125
125
|
/** The answer is being sent: both buttons wait. */
|
|
126
|
-
busy?: boolean;
|
|
127
|
-
className?: string;
|
|
126
|
+
busy?: boolean | undefined;
|
|
127
|
+
className?: string | undefined;
|
|
128
128
|
}): React.JSX.Element;
|
|
129
129
|
export { PermissionPrompt };
|
|
@@ -14,11 +14,11 @@ declare function PromptSuggestions({ suggestions, onChoose, label: labelProp, lo
|
|
|
14
14
|
/** Called with the chosen one; put it in the composer to edit rather than sending it. */
|
|
15
15
|
onChoose: (suggestion: PromptSuggestion) => void;
|
|
16
16
|
/** The heading above the suggestions; "Try asking" by default. */
|
|
17
|
-
label?: string;
|
|
17
|
+
label?: string | undefined;
|
|
18
18
|
/** Shows placeholders while suggestions load. */
|
|
19
|
-
loading?: boolean;
|
|
19
|
+
loading?: boolean | undefined;
|
|
20
20
|
/** Compact chips, or larger cards for an empty thread. */
|
|
21
|
-
variant?: "chips" | "cards";
|
|
22
|
-
className?: string;
|
|
21
|
+
variant?: "chips" | "cards" | undefined;
|
|
22
|
+
className?: string | undefined;
|
|
23
23
|
}): import("react").JSX.Element | null;
|
|
24
24
|
export { PromptSuggestions };
|
|
@@ -20,6 +20,6 @@ function PromptSuggestions({ suggestions, onChoose, label: labelProp, loading =
|
|
|
20
20
|
return null;
|
|
21
21
|
return (_jsxs("section", { "data-slot": "prompt-suggestions", "aria-label": label, className: cn("flex flex-col gap-2", className), children: [_jsxs("p", { className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [_jsx(Sparkles, { "aria-hidden": true, className: "size-3" }), " ", label] }), _jsx("div", { className: cn(variant === "cards" ? "grid gap-2 sm:grid-cols-2" : "flex flex-wrap gap-1.5"), children: loading
|
|
22
22
|
? Array.from({ length: variant === "cards" ? 4 : 3 }, (_, i) => (_jsx(Skeleton, { className: variant === "cards" ? "h-16 rounded-xl" : "h-8 w-44 rounded-lg" }, i)))
|
|
23
|
-
: suggestions.map((s) => variant === "cards" ? (_jsxs("button", { type: "button", onClick: () => onChoose(s), className: "group/suggestion flex items-start justify-between gap-3 rounded-xl border bg-card p-3 text-start text-sm transition-[border-color,box-shadow,transform] duration-150 ease-standard outline-none hover:border-border-strong hover:shadow-raised active:scale-[0.99] focus-visible:ring-[3px] focus-visible:ring-ring/
|
|
23
|
+
: suggestions.map((s) => variant === "cards" ? (_jsxs("button", { type: "button", onClick: () => onChoose(s), className: "group/suggestion flex items-start justify-between gap-3 rounded-xl border bg-card p-3 text-start text-sm transition-[border-color,box-shadow,transform] duration-150 ease-standard outline-none hover:border-border-strong hover:shadow-raised active:scale-[0.99] focus-visible:ring-[3px] focus-visible:ring-ring/80", children: [_jsx("span", { children: s.text }), _jsx(ArrowUpRight, { "aria-hidden": true, className: "size-3.5 shrink-0 text-faint-foreground transition-colors group-hover/suggestion:text-accent-text" })] }, s.id)) : (_jsx("button", { type: "button", onClick: () => onChoose(s), className: "rounded-lg border bg-card px-3 py-1.5 text-sm text-muted-foreground transition-colors duration-150 outline-none hover:border-border-strong hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/80", children: s.text }, s.id))) })] }));
|
|
24
24
|
}
|
|
25
25
|
export { PromptSuggestions };
|