@aphrody/m3-ai 3.3.1 → 3.3.4

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.
Files changed (48) hide show
  1. package/README.md +7 -7
  2. package/dist/A2APeerInspector.d.ts +41 -0
  3. package/dist/A2APeerInspector.d.ts.map +1 -0
  4. package/dist/A2ATaskTimeline.d.ts +28 -0
  5. package/dist/A2ATaskTimeline.d.ts.map +1 -0
  6. package/dist/AgUiEventStream.d.ts +87 -0
  7. package/dist/AgUiEventStream.d.ts.map +1 -0
  8. package/dist/GeminiAccountMenu.d.ts +55 -0
  9. package/dist/GeminiAccountMenu.d.ts.map +1 -0
  10. package/dist/GeminiPersonalContextEdit.d.ts +29 -0
  11. package/dist/GeminiPersonalContextEdit.d.ts.map +1 -0
  12. package/dist/GoogleSpotlightBar.d.ts +32 -0
  13. package/dist/GoogleSpotlightBar.d.ts.map +1 -0
  14. package/dist/Markdown.d.ts +2 -1
  15. package/dist/Markdown.d.ts.map +1 -1
  16. package/dist/McpAppCard.d.ts +24 -0
  17. package/dist/McpAppCard.d.ts.map +1 -0
  18. package/dist/ModelSelector.d.ts.map +1 -1
  19. package/dist/TaskRow.d.ts.map +1 -1
  20. package/dist/ToolCall.d.ts.map +1 -1
  21. package/dist/index.d.ts +15 -0
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +3629 -1950
  24. package/dist/index.js.map +32 -1
  25. package/package.json +17 -20
  26. package/src/A2APeerInspector.tsx +378 -0
  27. package/src/A2ATaskTimeline.tsx +218 -0
  28. package/src/AgUiEventStream.ts +488 -0
  29. package/src/ChatComposer.tsx +239 -0
  30. package/src/GeminiAccountMenu.tsx +212 -0
  31. package/src/GeminiPersonalContextEdit.tsx +147 -0
  32. package/src/GoogleSpotlightBar.tsx +165 -0
  33. package/src/InlineBranchCard.tsx +97 -0
  34. package/src/InlineWorkerCard.tsx +182 -0
  35. package/src/Markdown.tsx +701 -0
  36. package/src/McpAppCard.tsx +161 -0
  37. package/src/MessageBubble.tsx +95 -0
  38. package/src/ModelSelector.tsx +300 -0
  39. package/src/TaskCreateForm.tsx +123 -0
  40. package/src/TaskDetail.tsx +224 -0
  41. package/src/TaskList.tsx +136 -0
  42. package/src/TaskPriorityIcon.tsx +39 -0
  43. package/src/TaskRow.tsx +177 -0
  44. package/src/TaskStatusIcon.tsx +39 -0
  45. package/src/ToolCall.tsx +639 -0
  46. package/src/index.ts +107 -0
  47. package/src/internal.tsx +107 -0
  48. package/src/types.ts +212 -0
package/src/index.ts ADDED
@@ -0,0 +1,107 @@
1
+ // SPDX-License-Identifier: Apache-2.0 AND MIT
2
+ // Derived from SpaceUI (packages/aphrody-spaceui/packages/ai/src/index.ts), MIT, rebuilt on Material Design 3.
3
+ // @aphrody/m3-ai - AI agent interaction components on Material Design 3
4
+
5
+ // Types
6
+ export type {
7
+ ToolCallStatus,
8
+ ToolCallPair,
9
+ ActionContent,
10
+ TranscriptStep,
11
+ TranscriptItem,
12
+ TaskInfo,
13
+ MemoryInfo,
14
+ CronJobInfo,
15
+ AgentInfo,
16
+ ModelOption,
17
+ TaskStatus,
18
+ TaskPriority,
19
+ Subtask,
20
+ Task,
21
+ } from "./types";
22
+
23
+ export {
24
+ pairTranscriptSteps,
25
+ tryParseJson,
26
+ isErrorResult,
27
+ TASK_STATUS_ORDER,
28
+ TASK_STATUS_LABEL,
29
+ TASK_PRIORITY_LABEL,
30
+ } from "./types";
31
+
32
+ // Components
33
+ export { ToolCall } from "./ToolCall";
34
+ export type { ToolCallProps } from "./ToolCall";
35
+ export { Markdown, CodeBlock, InlineMath, BlockMath } from "./Markdown";
36
+ export type {
37
+ MarkdownProps,
38
+ CodeBlockProps,
39
+ InlineMathProps,
40
+ BlockMathProps,
41
+ } from "./Markdown";
42
+ export { MessageBubble } from "./MessageBubble";
43
+ export type { MessageBubbleProps } from "./MessageBubble";
44
+ export { InlineWorkerCard } from "./InlineWorkerCard";
45
+ export type { InlineWorkerCardProps } from "./InlineWorkerCard";
46
+ export { InlineBranchCard } from "./InlineBranchCard";
47
+ export type { InlineBranchCardProps } from "./InlineBranchCard";
48
+ export { ModelSelector, ModelOptionList, groupModelsByProvider } from "./ModelSelector";
49
+ export type { ModelSelectorProps, ModelOptionListProps } from "./ModelSelector";
50
+ export { ChatComposer } from "./ChatComposer";
51
+ export type { ChatComposerProps } from "./ChatComposer";
52
+
53
+ // Google & Gemini Desktop / Web benchmark components
54
+ export { GoogleSpotlightBar } from "./GoogleSpotlightBar";
55
+ export type { GoogleSpotlightBarProps } from "./GoogleSpotlightBar";
56
+ export {
57
+ GeminiAccountMenu,
58
+ ComposerMoreUploadsMenu,
59
+ } from "./GeminiAccountMenu";
60
+ export type {
61
+ GeminiAccountMenuProps,
62
+ ComposerMoreUploadsMenuProps,
63
+ MenuItem,
64
+ } from "./GeminiAccountMenu";
65
+ export { GeminiPersonalContextEdit } from "./GeminiPersonalContextEdit";
66
+ export type { GeminiPersonalContextEditProps } from "./GeminiPersonalContextEdit";
67
+
68
+
69
+ // Task components
70
+ export { TaskStatusIcon } from "./TaskStatusIcon";
71
+ export type { TaskStatusIconProps } from "./TaskStatusIcon";
72
+ export { TaskPriorityIcon } from "./TaskPriorityIcon";
73
+ export type { TaskPriorityIconProps } from "./TaskPriorityIcon";
74
+ export { TaskRow } from "./TaskRow";
75
+ export type { TaskRowProps } from "./TaskRow";
76
+ export { TaskList } from "./TaskList";
77
+ export type { TaskListProps } from "./TaskList";
78
+ export { TaskDetail } from "./TaskDetail";
79
+ export type { TaskDetailProps } from "./TaskDetail";
80
+ export { TaskCreateForm } from "./TaskCreateForm";
81
+ export type { TaskCreateFormProps, TaskCreateFormData } from "./TaskCreateForm";
82
+
83
+ // AG-UI Protocol & Agent-to-User (A2U) Bridge
84
+ export { EventType } from "@aphrody/ag-ui";
85
+ export {
86
+ AgUiEventAccumulator,
87
+ agUiEventsToTranscriptSteps,
88
+ agUiEventsToTranscriptItems,
89
+ coordEnvelopeToAgUiEvent,
90
+ agUiEventToCoordEnvelope,
91
+ } from "./AgUiEventStream";
92
+ export type {
93
+ CoordEnvelope,
94
+ EnvelopeKind,
95
+ SubagentTrace,
96
+ AgUiStreamState,
97
+ } from "./AgUiEventStream";
98
+
99
+ // Aphrody A2A (Agent-to-Agent) Fleet UI
100
+ export { A2APeerInspector } from "./A2APeerInspector";
101
+ export type { A2APeerInspectorProps, AgentPeer, SendEnvelopePayload } from "./A2APeerInspector";
102
+ export { A2ATaskTimeline } from "./A2ATaskTimeline";
103
+ export type { A2ATaskTimelineProps, TimelineStep } from "./A2ATaskTimeline";
104
+
105
+ // MCP-UI Generative Card
106
+ export { McpAppCard } from "./McpAppCard";
107
+ export type { McpAppCardProps } from "./McpAppCard";
@@ -0,0 +1,107 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Shared Material Design 3 building blocks for @aphrody/m3-ai (internal, not exported).
3
+
4
+ import { m3Durations, m3Easings } from "@aphrody/m3-motion";
5
+ import { clsx } from "clsx";
6
+ import type { ReactNode } from "react";
7
+
8
+ /** The M3 focus indicator (contract: docs/design/SPACEUI-M3-FUSION.md, "States"). */
9
+ export const focusRing =
10
+ "outline-none focus-visible:outline-3 focus-visible:outline-secondary focus-visible:outline-offset-2";
11
+
12
+ /** Expand / collapse: enter on emphasized decelerate, exit on emphasized accelerate. */
13
+ export const expandMotion = {
14
+ initial: { height: 0, opacity: 0 },
15
+ animate: {
16
+ height: "auto",
17
+ opacity: 1,
18
+ transition: { duration: m3Durations.medium2, ease: m3Easings.emphasizedDecelerate },
19
+ },
20
+ exit: {
21
+ height: 0,
22
+ opacity: 0,
23
+ transition: { duration: m3Durations.short4, ease: m3Easings.emphasizedAccelerate },
24
+ },
25
+ } as const;
26
+
27
+ /**
28
+ * Indeterminate M3 circular progress indicator (active indicator on `primary` or the current
29
+ * color, 4 dp track gap omitted at small sizes). Replaces the upstream Grid loader.
30
+ */
31
+ export function CircularIndicator({
32
+ size = 16,
33
+ className,
34
+ label = "Loading",
35
+ }: {
36
+ size?: number;
37
+ className?: string;
38
+ label?: string;
39
+ }) {
40
+ const stroke = size <= 16 ? 2 : size <= 24 ? 3 : 4;
41
+ const r = (size - stroke) / 2;
42
+ const c = 2 * Math.PI * r;
43
+ return (
44
+ <span
45
+ // oxlint-disable-next-line jsx-a11y/prefer-tag-over-role -- M3 circular indeterminate indicator is an animated SVG arc; a native <progress> cannot render it.
46
+ role="progressbar"
47
+ aria-label={label}
48
+ className={clsx("m3-circular-indicator inline-flex shrink-0 text-primary", className)}
49
+ style={{ width: size, height: size }}
50
+ >
51
+ <svg
52
+ width={size}
53
+ height={size}
54
+ viewBox={`0 0 ${size} ${size}`}
55
+ className="animate-spin"
56
+ aria-hidden="true"
57
+ >
58
+ <circle
59
+ cx={size / 2}
60
+ cy={size / 2}
61
+ r={r}
62
+ fill="none"
63
+ stroke="currentColor"
64
+ strokeWidth={stroke}
65
+ strokeLinecap="round"
66
+ strokeDasharray={`${c * 0.7} ${c}`}
67
+ />
68
+ </svg>
69
+ </span>
70
+ );
71
+ }
72
+
73
+ export type ChipTone = "primary" | "success" | "error" | "warning" | "neutral";
74
+
75
+ const chipTones: Record<ChipTone, string> = {
76
+ primary: "bg-primary-container text-on-primary-container",
77
+ success: "bg-success-container text-on-success-container",
78
+ error: "bg-error-container text-on-error-container",
79
+ warning: "bg-warning-container text-on-warning-container",
80
+ neutral: "border border-outline-variant text-on-surface-variant",
81
+ };
82
+
83
+ /** Non-interactive M3 assist chip used as a status label (dense, `rounded-small`). */
84
+ export function StatusChip({
85
+ tone,
86
+ icon,
87
+ children,
88
+ className,
89
+ }: {
90
+ tone: ChipTone;
91
+ icon?: ReactNode;
92
+ children: ReactNode;
93
+ className?: string;
94
+ }) {
95
+ return (
96
+ <span
97
+ className={clsx(
98
+ "inline-flex h-6 shrink-0 items-center gap-1 rounded-small px-2 text-label-medium",
99
+ chipTones[tone],
100
+ className,
101
+ )}
102
+ >
103
+ {icon}
104
+ {children}
105
+ </span>
106
+ );
107
+ }
package/src/types.ts ADDED
@@ -0,0 +1,212 @@
1
+ // SPDX-License-Identifier: Apache-2.0 AND MIT
2
+ // Derived from SpaceUI (packages/aphrody-spaceui/packages/ai/src/types.ts), MIT.
3
+
4
+ // Tool execution types
5
+ export type ToolCallStatus = "running" | "completed" | "error";
6
+
7
+ export interface ToolCallPair {
8
+ id: string;
9
+ name: string;
10
+ argsRaw: string;
11
+ args: Record<string, unknown> | null;
12
+ resultRaw: string | null;
13
+ result: Record<string, unknown> | null;
14
+ status: ToolCallStatus;
15
+ /** Human-readable summary provided by live opencode parts */
16
+ title?: string | null;
17
+ }
18
+
19
+ // Transcript step types — discriminated union matching the real API schema
20
+
21
+ export type ActionContent =
22
+ | { type: "text"; text: string }
23
+ | { type: "tool_call"; id: string; name: string; args: string };
24
+
25
+ export type TranscriptStep =
26
+ | { type: "action"; content: ActionContent[] }
27
+ | { type: "user_text"; text: string }
28
+ | { type: "system_text"; text: string }
29
+ | { type: "tool_result"; call_id: string; name: string; text: string };
30
+
31
+ // Paired transcript item for rendering
32
+
33
+ export type TranscriptItem = { kind: "text"; text: string } | { kind: "tool"; pair: ToolCallPair };
34
+
35
+ // ---------------------------------------------------------------------------
36
+ // Task board types
37
+ // ---------------------------------------------------------------------------
38
+
39
+ export type TaskStatus = "pending_approval" | "backlog" | "ready" | "in_progress" | "done";
40
+ export type TaskPriority = "critical" | "high" | "medium" | "low";
41
+
42
+ export interface Subtask {
43
+ title: string;
44
+ completed: boolean;
45
+ }
46
+
47
+ export interface Task {
48
+ id: string;
49
+ task_number: number;
50
+ title: string;
51
+ description?: string | null;
52
+ status: TaskStatus;
53
+ priority: TaskPriority;
54
+ owner_agent_id: string;
55
+ assigned_agent_id: string;
56
+ subtasks: Subtask[];
57
+ metadata: unknown;
58
+ worker_id?: string | null;
59
+ created_by: string;
60
+ created_at: string;
61
+ updated_at: string;
62
+ completed_at?: string | null;
63
+ }
64
+
65
+ export const TASK_STATUS_ORDER: TaskStatus[] = [
66
+ "in_progress",
67
+ "ready",
68
+ "pending_approval",
69
+ "backlog",
70
+ "done",
71
+ ];
72
+
73
+ export const TASK_STATUS_LABEL: Record<TaskStatus, string> = {
74
+ in_progress: "In Progress",
75
+ ready: "Ready",
76
+ pending_approval: "Pending Approval",
77
+ backlog: "Backlog",
78
+ done: "Done",
79
+ };
80
+
81
+ export const TASK_PRIORITY_LABEL: Record<TaskPriority, string> = {
82
+ critical: "Critical",
83
+ high: "High",
84
+ medium: "Medium",
85
+ low: "Low",
86
+ };
87
+
88
+ // Domain objects
89
+ export interface TaskInfo {
90
+ id: string;
91
+ title: string;
92
+ status: string;
93
+ priority: string;
94
+ assignees: string[];
95
+ conversation_id?: string;
96
+ }
97
+
98
+ export interface MemoryInfo {
99
+ id: string;
100
+ type: string;
101
+ content: string;
102
+ source?: string;
103
+ edges?: Array<{ target: string; relation: string }>;
104
+ }
105
+
106
+ export interface CronJobInfo {
107
+ id: string;
108
+ name: string;
109
+ schedule: string;
110
+ last_run?: string;
111
+ next_run?: string;
112
+ status: string;
113
+ }
114
+
115
+ export interface AgentInfo {
116
+ id: string;
117
+ name: string;
118
+ detail: string;
119
+ status?: string;
120
+ }
121
+
122
+ export interface ModelOption {
123
+ id: string;
124
+ name: string;
125
+ provider: string;
126
+ context_window?: number;
127
+ capabilities?: string[];
128
+ }
129
+
130
+ // ---------------------------------------------------------------------------
131
+ // Helpers
132
+ // ---------------------------------------------------------------------------
133
+
134
+ export function tryParseJson(text: string): Record<string, unknown> | null {
135
+ if (!text || text.trim().length === 0) return null;
136
+ try {
137
+ const parsed = JSON.parse(text);
138
+ if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
139
+ return parsed as Record<string, unknown>;
140
+ }
141
+ return null;
142
+ } catch {
143
+ return null;
144
+ }
145
+ }
146
+
147
+ export function isErrorResult(text: string, parsed: Record<string, unknown> | null): boolean {
148
+ if (parsed?.error) return true;
149
+ if (parsed?.status === "error") return true;
150
+ if (parsed?.success === false) return true;
151
+ if (typeof parsed?.exit_code === "number" && parsed.exit_code !== 0) return true;
152
+ const lower = text.toLowerCase();
153
+ return (
154
+ lower.startsWith("error:") ||
155
+ lower.startsWith("error -") ||
156
+ lower.startsWith("failed:") ||
157
+ lower.startsWith("toolset error:")
158
+ );
159
+ }
160
+
161
+ // ---------------------------------------------------------------------------
162
+ // Transcript → TranscriptItem[] pairing
163
+ // ---------------------------------------------------------------------------
164
+
165
+ /**
166
+ * Walk a flat TranscriptStep[] and pair each tool_call with its tool_result
167
+ * via call_id matching, plus emit standalone text steps. Returns an ordered
168
+ * list of renderable items: text blocks and paired tool calls.
169
+ */
170
+ export function pairTranscriptSteps(steps: TranscriptStep[]): TranscriptItem[] {
171
+ const items: TranscriptItem[] = [];
172
+ const resultsById = new Map<string, { name: string; text: string }>();
173
+
174
+ // First pass: index all tool_result steps by call_id
175
+ for (const step of steps) {
176
+ if (step.type === "tool_result") {
177
+ resultsById.set(step.call_id, { name: step.name, text: step.text });
178
+ }
179
+ }
180
+
181
+ // Second pass: emit items in order
182
+ for (const step of steps) {
183
+ if (step.type === "action") {
184
+ for (const content of step.content) {
185
+ if (content.type === "text") {
186
+ items.push({ kind: "text", text: content.text });
187
+ } else if (content.type === "tool_call") {
188
+ const result = resultsById.get(content.id);
189
+ const parsedArgs = tryParseJson(content.args);
190
+ const parsedResult = result ? tryParseJson(result.text) : null;
191
+
192
+ const hasError = result ? isErrorResult(result.text, parsedResult) : false;
193
+
194
+ items.push({
195
+ kind: "tool",
196
+ pair: {
197
+ id: content.id,
198
+ name: content.name,
199
+ argsRaw: content.args,
200
+ args: parsedArgs,
201
+ resultRaw: result?.text ?? null,
202
+ result: parsedResult,
203
+ status: result ? (hasError ? "error" : "completed") : "running",
204
+ },
205
+ });
206
+ }
207
+ }
208
+ }
209
+ }
210
+
211
+ return items;
212
+ }