@steerable/agent-ui 0.6.73 → 0.7.1

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.
@@ -22,6 +22,8 @@ export interface ToolExecutionCardProps {
22
22
  /** Header body click (chevron still toggles expand). */
23
23
  onActivate?: () => void;
24
24
  activateTitle?: string;
25
+ /** Short status suffix, such as a session-allow mark. */
26
+ note?: string;
25
27
  }
26
28
  export declare const ToolExecutionCard: React.FC<ToolExecutionCardProps>;
27
29
  export default ToolExecutionCard;
@@ -17,6 +17,13 @@ const STATUS_LABEL = {
17
17
  failed: '失败',
18
18
  cancelled: '已取消',
19
19
  };
20
+ function formatToolDuration(ms) {
21
+ if (!Number.isFinite(ms) || ms < 0)
22
+ return '';
23
+ if (ms < 10_000)
24
+ return `${(Math.round(ms / 100) / 10).toFixed(1)}s`;
25
+ return `${Math.round(ms / 1000)}s`;
26
+ }
20
27
  const STATUS_TONE = {
21
28
  pending: 'text-[var(--agent-muted-foreground,#6b7280)]',
22
29
  running: 'text-amber-600',
@@ -51,11 +58,12 @@ function defaultRender(value) {
51
58
  }
52
59
  return (_jsx("pre", { className: "whitespace-pre-wrap break-words rounded bg-[var(--agent-muted,#f3f4f6)] px-2 py-1.5 text-[11px] text-[var(--agent-foreground,#111827)]", children: text }));
53
60
  }
54
- export const ToolExecutionCard = ({ payload, className, defaultExpanded = false, lead, label, renderArgs, renderOutput, onActivate, activateTitle, }) => {
61
+ export const ToolExecutionCard = ({ payload, className, defaultExpanded = false, lead, label, renderArgs, renderOutput, onActivate, activateTitle, note, }) => {
55
62
  const expandable = payload.expandable !== false;
56
63
  const [expanded, setExpanded] = React.useState(defaultExpanded);
57
64
  const status = (payload.status ?? 'pending');
58
65
  const title = label ?? payload.name;
66
+ const duration = typeof payload.durationMs === 'number' ? formatToolDuration(payload.durationMs) : '';
59
67
  return (_jsxs("div", { className: [
60
68
  'steerable-tool-execution rounded-lg border border-[var(--agent-border,#e5e7eb)] bg-[var(--agent-card-bg,#fff)] text-xs',
61
69
  className,
@@ -64,6 +72,6 @@ export const ToolExecutionCard = ({ payload, className, defaultExpanded = false,
64
72
  onActivate();
65
73
  else if (expandable)
66
74
  setExpanded((v) => !v);
67
- }, className: `flex min-w-0 flex-1 text-left ${onActivate ? 'cursor-pointer hover:bg-[var(--agent-muted,#f3f4f6)]/60' : ''}`, "aria-expanded": onActivate ? undefined : expanded, "aria-label": onActivate ? activateTitle : undefined, title: onActivate ? activateTitle : undefined, "data-testid": onActivate ? 'tool-activate' : undefined, children: _jsxs("span", { className: `flex min-w-0 flex-1 items-center gap-1.5 py-1 pr-2.5 ${expandable ? '' : 'pl-2.5'}`, children: [lead ?? (_jsx(ZapIcon, { size: 12, className: "shrink-0 text-[var(--agent-muted-foreground,#6b7280)]" })), _jsx("span", { className: "shrink-0 font-medium text-[var(--agent-foreground,#111827)]", children: title }), payload.summary && (_jsx("span", { className: "min-w-0 flex-1 truncate text-[var(--agent-muted-foreground,#6b7280)]", children: payload.summary })), _jsxs("span", { className: "ml-auto inline-flex shrink-0 items-center gap-1 whitespace-nowrap", children: [_jsx(StatusIcon, { status: status }), _jsx("span", { className: STATUS_TONE[status], children: STATUS_LABEL[status] }), typeof payload.durationMs === 'number' && (_jsxs("span", { className: "text-[var(--agent-muted-foreground,#9ca3af)]", children: ["\u00B7 ", payload.durationMs, "ms"] }))] })] }) })] }), expandable && expanded && (_jsxs("div", { className: "space-y-1.5 border-t border-[var(--agent-border,#e5e7eb)] px-2.5 py-1.5", children: [payload.args !== undefined && (_jsxs("section", { children: [_jsx("div", { className: "mb-1 text-[10px] uppercase tracking-wider text-[var(--agent-muted-foreground,#6b7280)]", children: "\u8F93\u5165" }), renderArgs ? renderArgs(payload.args) : defaultRender(payload.args)] })), payload.output !== undefined && (_jsxs("section", { children: [_jsx("div", { className: "mb-1 text-[10px] uppercase tracking-wider text-[var(--agent-muted-foreground,#6b7280)]", children: "\u8F93\u51FA" }), renderOutput ? renderOutput(payload.output) : defaultRender(payload.output)] })), payload.error && (_jsxs("section", { children: [_jsx("div", { className: "mb-1 text-[10px] uppercase tracking-wider text-rose-600", children: "\u9519\u8BEF" }), _jsx("pre", { className: "whitespace-pre-wrap break-words rounded bg-rose-50/60 px-2 py-1.5 text-[11px] text-rose-700", children: payload.error })] }))] }))] }));
75
+ }, className: `flex min-w-0 flex-1 text-left ${onActivate ? 'cursor-pointer hover:bg-[var(--agent-muted,#f3f4f6)]/60' : ''}`, "aria-expanded": onActivate ? undefined : expanded, "aria-label": onActivate ? activateTitle : undefined, title: onActivate ? activateTitle : undefined, "data-testid": onActivate ? 'tool-activate' : undefined, children: _jsxs("span", { className: `flex min-w-0 flex-1 items-center gap-1.5 py-1 pr-2.5 ${expandable ? '' : 'pl-2.5'}`, children: [lead ?? (_jsx(ZapIcon, { size: 12, className: "shrink-0 text-[var(--agent-muted-foreground,#6b7280)]" })), _jsx("span", { className: "shrink-0 font-medium text-[var(--agent-foreground,#111827)]", children: title }), payload.summary && (_jsx("span", { className: "min-w-0 flex-1 truncate text-[var(--agent-muted-foreground,#6b7280)]", children: payload.summary })), _jsxs("span", { className: "ml-auto inline-flex shrink-0 items-center gap-1 whitespace-nowrap", children: [_jsx(StatusIcon, { status: status }), _jsx("span", { className: STATUS_TONE[status], children: STATUS_LABEL[status] }), duration && (_jsxs("span", { className: "text-[var(--agent-muted-foreground,#9ca3af)]", children: ["\u00B7 ", duration] })), note && (_jsx("span", { className: "text-[var(--agent-muted-foreground,#6b7280)]", children: note }))] })] }) })] }), expandable && expanded && (_jsxs("div", { className: "space-y-1.5 border-t border-[var(--agent-border,#e5e7eb)] px-2.5 py-1.5", children: [payload.args !== undefined && (_jsxs("section", { children: [_jsx("div", { className: "mb-1 text-[10px] uppercase tracking-wider text-[var(--agent-muted-foreground,#6b7280)]", children: "\u8F93\u5165" }), renderArgs ? renderArgs(payload.args) : defaultRender(payload.args)] })), payload.output !== undefined && (_jsxs("section", { children: [_jsx("div", { className: "mb-1 text-[10px] uppercase tracking-wider text-[var(--agent-muted-foreground,#6b7280)]", children: "\u8F93\u51FA" }), renderOutput ? renderOutput(payload.output) : defaultRender(payload.output)] })), payload.error && (_jsxs("section", { children: [_jsx("div", { className: "mb-1 text-[10px] uppercase tracking-wider text-rose-600", children: "\u9519\u8BEF" }), _jsx("pre", { className: "whitespace-pre-wrap break-words rounded bg-rose-50/60 px-2 py-1.5 text-[11px] text-rose-700", children: payload.error })] }))] }))] }));
68
76
  };
69
77
  export default ToolExecutionCard;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@steerable/agent-ui",
3
- "version": "0.6.73",
3
+ "version": "0.7.1",
4
4
  "description": "Steerable framework Tier 4 — headless React hooks (useAgentSession, useChatStream, useToolCallStatus) and Tailwind-themed components (ChatPanel, MessageList, OrchestrationPlanCard, ToolCallRenderer, SSEStreamView) for embedding Steerable agents in any React app.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://steerableframework.com/storybook/",
@@ -57,7 +57,7 @@
57
57
  "README.md"
58
58
  ],
59
59
  "dependencies": {
60
- "@steerable/agent-protocol": "0.6.73"
60
+ "@steerable/agent-protocol": "0.7.1"
61
61
  },
62
62
  "peerDependencies": {
63
63
  "react": ">=18.0.0",
@@ -30,6 +30,12 @@ const STATUS_LABEL: Record<Status, string> = {
30
30
  cancelled: '已取消',
31
31
  };
32
32
 
33
+ function formatToolDuration(ms: number): string {
34
+ if (!Number.isFinite(ms) || ms < 0) return '';
35
+ if (ms < 10_000) return `${(Math.round(ms / 100) / 10).toFixed(1)}s`;
36
+ return `${Math.round(ms / 1000)}s`;
37
+ }
38
+
33
39
  const STATUS_TONE: Record<Status, string> = {
34
40
  pending: 'text-[var(--agent-muted-foreground,#6b7280)]',
35
41
  running: 'text-amber-600',
@@ -51,6 +57,8 @@ export interface ToolExecutionCardProps {
51
57
  /** Header body click (chevron still toggles expand). */
52
58
  onActivate?: () => void;
53
59
  activateTitle?: string;
60
+ /** Short status suffix, such as a session-allow mark. */
61
+ note?: string;
54
62
  }
55
63
 
56
64
  function StatusIcon({ status }: { status: Status }) {
@@ -94,11 +102,13 @@ export const ToolExecutionCard: React.FC<ToolExecutionCardProps> = ({
94
102
  renderOutput,
95
103
  onActivate,
96
104
  activateTitle,
105
+ note,
97
106
  }) => {
98
107
  const expandable = payload.expandable !== false;
99
108
  const [expanded, setExpanded] = React.useState(defaultExpanded);
100
109
  const status = (payload.status ?? 'pending') as Status;
101
110
  const title = label ?? payload.name;
111
+ const duration = typeof payload.durationMs === 'number' ? formatToolDuration(payload.durationMs) : '';
102
112
 
103
113
  return (
104
114
  <div
@@ -149,8 +159,11 @@ export const ToolExecutionCard: React.FC<ToolExecutionCardProps> = ({
149
159
  <span className="ml-auto inline-flex shrink-0 items-center gap-1 whitespace-nowrap">
150
160
  <StatusIcon status={status} />
151
161
  <span className={STATUS_TONE[status]}>{STATUS_LABEL[status]}</span>
152
- {typeof payload.durationMs === 'number' && (
153
- <span className="text-[var(--agent-muted-foreground,#9ca3af)]">· {payload.durationMs}ms</span>
162
+ {duration && (
163
+ <span className="text-[var(--agent-muted-foreground,#9ca3af)]">· {duration}</span>
164
+ )}
165
+ {note && (
166
+ <span className="text-[var(--agent-muted-foreground,#6b7280)]">{note}</span>
154
167
  )}
155
168
  </span>
156
169
  </span>