@ash-cloud/ash-ui 0.1.0 → 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.
package/dist/types.d.ts CHANGED
@@ -287,20 +287,6 @@ interface NormalizedEntry {
287
287
  entryType: NormalizedEntryType;
288
288
  /** Text content for display (plain text or markdown) */
289
289
  content: string;
290
- /**
291
- * Rich content segments (structured approach - preferred over regex transformers).
292
- * When provided, this takes precedence over `content` for rendering.
293
- *
294
- * @example
295
- * ```ts
296
- * richContent: [
297
- * { type: 'text', content: 'Analyzing ' },
298
- * { type: 'mention', name: 'Scene1', color: '#ff0' },
299
- * { type: 'text', content: ' for transitions.' },
300
- * ]
301
- * ```
302
- */
303
- richContent?: RichContent;
304
290
  }
305
291
  declare function isCommandRunAction(action: ActionType): action is CommandRunAction;
306
292
  declare function isFileReadAction(action: ActionType): action is FileReadAction;
@@ -384,134 +370,224 @@ interface FileAttachment {
384
370
  base64: string;
385
371
  }
386
372
  /**
387
- * Display mode for tool calls in the chat interface
373
+ * Message visual style variant
388
374
  *
389
- * - 'inline': Each tool call rendered inline as expandable cards (current behavior)
390
- * - 'compact': Single animated status line that updates with each tool call,
391
- * with accordion to expand and see execution details. Text streams unbroken.
392
- * - 'accordion': Simpler step-based accordion list that accumulates tool calls
393
- * with icons, labels, and durations (like Vidra's ThinkingIndicator).
394
- */
395
- type ToolDisplayMode = 'inline' | 'compact' | 'accordion';
396
- /**
397
- * Configuration for tool display behavior
398
- */
399
- interface ToolDisplayConfig {
400
- /**
401
- * Display mode for tool calls
402
- * @default 'inline'
403
- */
404
- mode: ToolDisplayMode;
405
- /**
406
- * For 'compact' mode: break into a new group every N tool calls
407
- * Set to 0 or undefined to never break (all tool calls in single group)
408
- * @default 0
409
- */
410
- breakEveryNToolCalls?: number;
411
- /**
412
- * Whether tool call groups start expanded
413
- * @default false
414
- */
415
- defaultExpanded?: boolean;
416
- /**
417
- * Animation duration for status line transitions (ms)
418
- * @default 300
419
- */
420
- animationDuration?: number;
421
- }
422
- /**
423
- * Default display configuration
424
- */
425
- declare const DEFAULT_DISPLAY_CONFIG: ToolDisplayConfig;
426
- /**
427
- * A text segment within rich content
428
- */
429
- interface RichTextSegment {
430
- type: 'text';
431
- /** Plain text or markdown content */
432
- content: string;
433
- }
375
+ * - 'bubble': Rounded card with padding and background (default for user messages)
376
+ * - 'plain': No background, just text with subtle styling
377
+ * - 'minimal': Bare text, no decoration
378
+ */
379
+ type MessageVariant = 'bubble' | 'plain' | 'minimal';
434
380
  /**
435
- * A mention/reference segment within rich content
381
+ * Typography scale/density preset
382
+ *
383
+ * - 'dense': Minimal spacing, smallest fonts (12px base) - for maximum information density
384
+ * - 'compact': Tighter spacing, smaller fonts (13px base)
385
+ * - 'default': Standard sizing (14px base)
386
+ * - 'comfortable': More generous spacing (15px base)
436
387
  */
437
- interface RichMentionSegment {
438
- type: 'mention';
439
- /** The mentioned entity name */
440
- name: string;
441
- /** Optional identifier for the entity */
442
- id?: string;
443
- /** Optional color for styling */
444
- color?: string;
445
- /** Optional additional data */
446
- data?: Record<string, unknown>;
447
- }
388
+ type TypographyScale = 'dense' | 'compact' | 'default' | 'comfortable';
448
389
  /**
449
- * A custom component segment within rich content
390
+ * Message role for data attribute targeting
450
391
  */
451
- interface RichComponentSegment {
452
- type: 'component';
453
- /** Component type identifier (consumer handles rendering) */
454
- componentType: string;
455
- /** Props to pass to the component */
456
- props: Record<string, unknown>;
392
+ type MessageRole = 'user' | 'assistant' | 'thinking' | 'tool' | 'error' | 'widget';
393
+ /**
394
+ * Metadata to display with a message
395
+ */
396
+ interface MessageMetadata {
397
+ /** Timestamp to display */
398
+ timestamp?: string;
399
+ /** Model name/info to display */
400
+ model?: string;
401
+ /** Custom label */
402
+ label?: string;
403
+ /** Any additional metadata */
404
+ extra?: Record<string, unknown>;
457
405
  }
458
406
  /**
459
- * Union of all rich content segment types
407
+ * Function to render custom message metadata
460
408
  */
461
- type RichContentSegment = RichTextSegment | RichMentionSegment | RichComponentSegment;
409
+ type RenderMetadataFunction = (props: {
410
+ entry: NormalizedEntry;
411
+ metadata?: MessageMetadata;
412
+ }) => ReactNode;
462
413
  /**
463
- * Rich content array - the preferred way to send structured content
414
+ * Custom markdown component overrides
464
415
  *
465
416
  * @example
466
- * ```ts
467
- * const content: RichContent = [
468
- * { type: 'text', content: 'Looking at ' },
469
- * { type: 'mention', name: 'Scene1', color: '#ff0', id: 'seq-1' },
470
- * { type: 'text', content: ' timeline for the transition.' },
471
- * ];
417
+ * ```tsx
418
+ * const components: MarkdownComponents = {
419
+ * h2: ({ children }) => <h2 className="custom-h2">{children}</h2>,
420
+ * code: ({ children, className }) => <CustomCode className={className}>{children}</CustomCode>,
421
+ * };
472
422
  * ```
473
423
  */
474
- type RichContent = RichContentSegment[];
424
+ interface MarkdownComponents {
425
+ h1?: React.ComponentType<{
426
+ children?: ReactNode;
427
+ }>;
428
+ h2?: React.ComponentType<{
429
+ children?: ReactNode;
430
+ }>;
431
+ h3?: React.ComponentType<{
432
+ children?: ReactNode;
433
+ }>;
434
+ h4?: React.ComponentType<{
435
+ children?: ReactNode;
436
+ }>;
437
+ h5?: React.ComponentType<{
438
+ children?: ReactNode;
439
+ }>;
440
+ h6?: React.ComponentType<{
441
+ children?: ReactNode;
442
+ }>;
443
+ p?: React.ComponentType<{
444
+ children?: ReactNode;
445
+ }>;
446
+ a?: React.ComponentType<{
447
+ children?: ReactNode;
448
+ href?: string;
449
+ }>;
450
+ ul?: React.ComponentType<{
451
+ children?: ReactNode;
452
+ }>;
453
+ ol?: React.ComponentType<{
454
+ children?: ReactNode;
455
+ }>;
456
+ li?: React.ComponentType<{
457
+ children?: ReactNode;
458
+ }>;
459
+ code?: React.ComponentType<{
460
+ children?: ReactNode;
461
+ className?: string;
462
+ }>;
463
+ pre?: React.ComponentType<{
464
+ children?: ReactNode;
465
+ }>;
466
+ blockquote?: React.ComponentType<{
467
+ children?: ReactNode;
468
+ }>;
469
+ strong?: React.ComponentType<{
470
+ children?: ReactNode;
471
+ }>;
472
+ em?: React.ComponentType<{
473
+ children?: ReactNode;
474
+ }>;
475
+ hr?: React.ComponentType<Record<string, never>>;
476
+ img?: React.ComponentType<{
477
+ src?: string;
478
+ alt?: string;
479
+ }>;
480
+ table?: React.ComponentType<{
481
+ children?: ReactNode;
482
+ }>;
483
+ thead?: React.ComponentType<{
484
+ children?: ReactNode;
485
+ }>;
486
+ tbody?: React.ComponentType<{
487
+ children?: ReactNode;
488
+ }>;
489
+ tr?: React.ComponentType<{
490
+ children?: ReactNode;
491
+ }>;
492
+ th?: React.ComponentType<{
493
+ children?: ReactNode;
494
+ }>;
495
+ td?: React.ComponentType<{
496
+ children?: ReactNode;
497
+ }>;
498
+ }
499
+ /**
500
+ * Style configuration for message display
501
+ */
502
+ interface MessageStyleConfig {
503
+ /** Variant for user messages */
504
+ userVariant?: MessageVariant;
505
+ /** Variant for assistant messages */
506
+ assistantVariant?: MessageVariant;
507
+ /** Typography/density scale */
508
+ scale?: TypographyScale;
509
+ /** Show timestamps with messages */
510
+ showTimestamp?: boolean;
511
+ /** Show avatars */
512
+ showAvatars?: boolean;
513
+ /** Custom class name for messages */
514
+ messageClassName?: string;
515
+ }
516
+ /**
517
+ * Default style configuration
518
+ */
519
+ declare const DEFAULT_STYLE_CONFIG: MessageStyleConfig;
520
+ /**
521
+ * Tool invocation status - matches AI SDK ToolInvocation
522
+ */
523
+ type ToolInvocationState = 'partial-call' | 'call' | 'result';
524
+ /**
525
+ * Tool invocation - matches AI SDK ToolInvocation type
526
+ */
527
+ interface ToolInvocation {
528
+ /** Tool invocation state */
529
+ state: ToolInvocationState;
530
+ /** Unique tool call ID */
531
+ toolCallId: string;
532
+ /** Tool name */
533
+ toolName: string;
534
+ /** Arguments passed to the tool (parsed JSON) */
535
+ args: Record<string, unknown>;
536
+ /** Result from tool execution (only present when state is 'result') */
537
+ result?: unknown;
538
+ }
539
+ /**
540
+ * AI SDK message role - matches AI SDK Message role
541
+ */
542
+ type AIMessageRole = 'user' | 'assistant' | 'system' | 'data';
475
543
  /**
476
- * Props for rendering a mention segment
544
+ * AI SDK compatible message type
545
+ * This is the primary type used by the new useChat hook
477
546
  */
478
- interface MentionRenderProps {
479
- segment: RichMentionSegment;
547
+ interface Message {
548
+ /** Unique message ID */
549
+ id: string;
550
+ /** Message role */
551
+ role: AIMessageRole;
552
+ /** Message content (text) */
553
+ content: string;
554
+ /** Tool invocations for this message */
555
+ toolInvocations?: ToolInvocation[];
556
+ /** When the message was created */
557
+ createdAt?: Date;
558
+ /** Optional reasoning/thinking content */
559
+ reasoning?: string;
560
+ /** Experimental attachments (for file uploads) */
561
+ experimental_attachments?: MessageAttachment[];
480
562
  }
481
563
  /**
482
- * Props for rendering a custom component segment
564
+ * Message attachment for file uploads
483
565
  */
484
- interface ComponentRenderProps {
485
- segment: RichComponentSegment;
566
+ interface MessageAttachment {
567
+ /** Attachment name */
568
+ name: string;
569
+ /** MIME type */
570
+ contentType: string;
571
+ /** URL to the attachment */
572
+ url: string;
486
573
  }
487
574
  /**
488
- * Custom render functions for rich content segments
575
+ * Convert a NormalizedEntry to an AI SDK Message
489
576
  */
490
- interface RichContentRenderers {
491
- /**
492
- * Render a mention segment. If not provided, renders as styled badge.
493
- */
494
- renderMention?: (props: MentionRenderProps) => ReactNode;
495
- /**
496
- * Render a custom component segment.
497
- */
498
- renderComponent?: (props: ComponentRenderProps) => ReactNode;
499
- }
577
+ declare function normalizedEntryToMessage(entry: NormalizedEntry): Message | null;
500
578
  /**
501
- * A group of consecutive tool calls that are displayed together
502
- * in compact mode. Text content before/after flows around the group.
579
+ * Convert an AI SDK Message to a NormalizedEntry
503
580
  */
504
- interface ToolExecutionGroup {
505
- /** Unique ID for the group */
506
- id: string;
507
- /** Tool calls in this group (in order) */
508
- toolCalls: NormalizedToolCall[];
509
- /** Index of the currently active/latest tool call for status display */
510
- activeIndex: number;
511
- /** Whether all tool calls in this group have completed */
512
- isComplete: boolean;
513
- /** Overall status of the group */
514
- status: 'pending' | 'success' | 'partial_failure' | 'failed';
515
- }
581
+ declare function messageToNormalizedEntry(message: Message): NormalizedEntry;
582
+ /**
583
+ * Convert an array of NormalizedEntry to AI SDK Messages
584
+ * Merges consecutive assistant entries (text + tool calls) into single messages
585
+ */
586
+ declare function normalizedEntriesToMessages(entries: NormalizedEntry[]): Message[];
587
+ /**
588
+ * Convert AI SDK Messages back to NormalizedEntry array
589
+ * Expands tool invocations into separate entries
590
+ */
591
+ declare function messagesToNormalizedEntries(messages: Message[]): NormalizedEntry[];
516
592
 
517
- export { type ActionType, type AgentToolAction, type AssistantMessageEntry, type CommandRunAction, type CommandRunResult, type ComponentRenderProps, DEFAULT_DISPLAY_CONFIG, type ErrorEntry, type FileAttachment, type FileEditAction, type FileReadAction, type FileWriteAction, type GenericToolAction, type GlobAction, type LogCategory, type LogEntry, type LogLevel, type McpToolAction, type MentionRenderProps, type NormalizedEntry, type NormalizedEntryType, type NormalizedToolCall, type RichComponentSegment, type RichContent, type RichContentRenderers, type RichContentSegment, type RichMentionSegment, type RichTextSegment, type SearchAction, type ThinkingEntry, type TodoItem, type TodoStatus, type TodoWriteAction, type ToolCallEntry, type ToolDisplayConfig, type ToolDisplayMode, type ToolExecutionGroup, type ToolResult, type ToolStatus, type UserMessageEntry, type WebFetchAction, type WebSearchAction, type WidgetAction, type WidgetEntry, type WidgetRenderFunction, type WidgetRenderProps, isAgentToolAction, isCommandRunAction, isErrorEntry, isFileEditAction, isFileReadAction, isFileWriteAction, isGenericToolAction, isGlobAction, isMcpToolAction, isSearchAction, isTodoWriteAction, isToolCallEntry, isWebFetchAction, isWebSearchAction, isWidgetEntry };
593
+ export { type AIMessageRole, type ActionType, type AgentToolAction, type AssistantMessageEntry, type CommandRunAction, type CommandRunResult, DEFAULT_STYLE_CONFIG, type ErrorEntry, type FileAttachment, type FileEditAction, type FileReadAction, type FileWriteAction, type GenericToolAction, type GlobAction, type LogCategory, type LogEntry, type LogLevel, type MarkdownComponents, type McpToolAction, type Message, type MessageAttachment, type MessageMetadata, type MessageRole, type MessageStyleConfig, type MessageVariant, type NormalizedEntry, type NormalizedEntryType, type NormalizedToolCall, type RenderMetadataFunction, type SearchAction, type ThinkingEntry, type TodoItem, type TodoStatus, type TodoWriteAction, type ToolCallEntry, type ToolInvocation, type ToolInvocationState, type ToolResult, type ToolStatus, type TypographyScale, type UserMessageEntry, type WebFetchAction, type WebSearchAction, type WidgetAction, type WidgetEntry, type WidgetRenderFunction, type WidgetRenderProps, isAgentToolAction, isCommandRunAction, isErrorEntry, isFileEditAction, isFileReadAction, isFileWriteAction, isGenericToolAction, isGlobAction, isMcpToolAction, isSearchAction, isTodoWriteAction, isToolCallEntry, isWebFetchAction, isWebSearchAction, isWidgetEntry, messageToNormalizedEntry, messagesToNormalizedEntries, normalizedEntriesToMessages, normalizedEntryToMessage };
package/dist/types.js CHANGED
@@ -44,13 +44,246 @@ function isErrorEntry(entry) {
44
44
  function isWidgetEntry(entry) {
45
45
  return entry.type === "widget";
46
46
  }
47
- var DEFAULT_DISPLAY_CONFIG = {
48
- mode: "inline",
49
- breakEveryNToolCalls: 0,
50
- defaultExpanded: false,
51
- animationDuration: 300
47
+ var DEFAULT_STYLE_CONFIG = {
48
+ userVariant: "bubble",
49
+ assistantVariant: "bubble",
50
+ scale: "compact",
51
+ showTimestamp: true,
52
+ showAvatars: true
52
53
  };
54
+ function normalizedEntryToMessage(entry) {
55
+ const { id, entryType, content, timestamp } = entry;
56
+ const createdAt = timestamp ? new Date(timestamp) : void 0;
57
+ switch (entryType.type) {
58
+ case "user_message":
59
+ return {
60
+ id,
61
+ role: "user",
62
+ content,
63
+ createdAt
64
+ };
65
+ case "assistant_message":
66
+ return {
67
+ id,
68
+ role: "assistant",
69
+ content,
70
+ createdAt
71
+ };
72
+ case "thinking":
73
+ return {
74
+ id,
75
+ role: "assistant",
76
+ content: "",
77
+ reasoning: content,
78
+ createdAt
79
+ };
80
+ case "tool_call": {
81
+ const { toolCall } = entryType;
82
+ const toolInvocation = {
83
+ state: toolCall.status === "pending" ? "call" : "result",
84
+ toolCallId: toolCall.id,
85
+ toolName: toolCall.toolName,
86
+ args: toolCall.input || {},
87
+ result: toolCall.output
88
+ };
89
+ return {
90
+ id,
91
+ role: "assistant",
92
+ content: "",
93
+ toolInvocations: [toolInvocation],
94
+ createdAt
95
+ };
96
+ }
97
+ case "error":
98
+ return {
99
+ id,
100
+ role: "system",
101
+ content: `Error: ${entryType.message}${entryType.code ? ` (${entryType.code})` : ""}`,
102
+ createdAt
103
+ };
104
+ case "widget":
105
+ return {
106
+ id,
107
+ role: "data",
108
+ content: JSON.stringify({
109
+ widgetType: entryType.widgetType,
110
+ widgetData: entryType.widgetData
111
+ }),
112
+ createdAt
113
+ };
114
+ default:
115
+ return null;
116
+ }
117
+ }
118
+ function messageToNormalizedEntry(message) {
119
+ const { id, role, content, createdAt, toolInvocations, reasoning } = message;
120
+ const timestamp = createdAt?.toISOString();
121
+ if (toolInvocations && toolInvocations.length > 0) {
122
+ const inv = toolInvocations[0];
123
+ const toolCall = {
124
+ id: inv.toolCallId,
125
+ toolName: inv.toolName,
126
+ actionType: {
127
+ action: "generic_tool",
128
+ toolName: inv.toolName,
129
+ arguments: inv.args,
130
+ result: inv.result ? { type: "json", value: inv.result } : void 0
131
+ },
132
+ status: inv.state === "result" ? "success" : "pending",
133
+ summary: `${inv.toolName}(${Object.keys(inv.args).join(", ")})`,
134
+ input: inv.args,
135
+ output: inv.result
136
+ };
137
+ return {
138
+ id,
139
+ timestamp,
140
+ entryType: { type: "tool_call", toolCall },
141
+ content: toolCall.summary
142
+ };
143
+ }
144
+ if (reasoning) {
145
+ return {
146
+ id,
147
+ timestamp,
148
+ entryType: { type: "thinking" },
149
+ content: reasoning
150
+ };
151
+ }
152
+ if (role === "user") {
153
+ return {
154
+ id,
155
+ timestamp,
156
+ entryType: { type: "user_message" },
157
+ content
158
+ };
159
+ }
160
+ if (role === "assistant") {
161
+ return {
162
+ id,
163
+ timestamp,
164
+ entryType: { type: "assistant_message" },
165
+ content
166
+ };
167
+ }
168
+ if (role === "system") {
169
+ if (content.startsWith("Error:")) {
170
+ return {
171
+ id,
172
+ timestamp,
173
+ entryType: { type: "error", message: content.replace("Error: ", "") },
174
+ content
175
+ };
176
+ }
177
+ return {
178
+ id,
179
+ timestamp,
180
+ entryType: { type: "assistant_message" },
181
+ content
182
+ };
183
+ }
184
+ if (role === "data") {
185
+ try {
186
+ const data = JSON.parse(content);
187
+ if (data.widgetType) {
188
+ return {
189
+ id,
190
+ timestamp,
191
+ entryType: {
192
+ type: "widget",
193
+ widgetType: data.widgetType,
194
+ widgetData: data.widgetData
195
+ },
196
+ content: ""
197
+ };
198
+ }
199
+ } catch {
200
+ }
201
+ return {
202
+ id,
203
+ timestamp,
204
+ entryType: { type: "assistant_message" },
205
+ content
206
+ };
207
+ }
208
+ return {
209
+ id,
210
+ timestamp,
211
+ entryType: { type: "assistant_message" },
212
+ content
213
+ };
214
+ }
215
+ function normalizedEntriesToMessages(entries) {
216
+ const messages = [];
217
+ let currentAssistantMessage = null;
218
+ for (const entry of entries) {
219
+ const message = normalizedEntryToMessage(entry);
220
+ if (!message) continue;
221
+ if (message.role === "assistant") {
222
+ if (currentAssistantMessage) {
223
+ if (message.toolInvocations) {
224
+ currentAssistantMessage.toolInvocations = [
225
+ ...currentAssistantMessage.toolInvocations || [],
226
+ ...message.toolInvocations
227
+ ];
228
+ }
229
+ if (message.content) {
230
+ currentAssistantMessage.content = currentAssistantMessage.content ? `${currentAssistantMessage.content}
231
+ ${message.content}` : message.content;
232
+ }
233
+ if (message.reasoning) {
234
+ currentAssistantMessage.reasoning = currentAssistantMessage.reasoning ? `${currentAssistantMessage.reasoning}
235
+ ${message.reasoning}` : message.reasoning;
236
+ }
237
+ } else {
238
+ currentAssistantMessage = { ...message };
239
+ }
240
+ } else {
241
+ if (currentAssistantMessage) {
242
+ messages.push(currentAssistantMessage);
243
+ currentAssistantMessage = null;
244
+ }
245
+ messages.push(message);
246
+ }
247
+ }
248
+ if (currentAssistantMessage) {
249
+ messages.push(currentAssistantMessage);
250
+ }
251
+ return messages;
252
+ }
253
+ function messagesToNormalizedEntries(messages) {
254
+ const entries = [];
255
+ for (const message of messages) {
256
+ if (message.reasoning) {
257
+ entries.push({
258
+ id: `${message.id}-thinking`,
259
+ timestamp: message.createdAt?.toISOString(),
260
+ entryType: { type: "thinking" },
261
+ content: message.reasoning
262
+ });
263
+ }
264
+ if (message.content || !message.toolInvocations?.length) {
265
+ entries.push(messageToNormalizedEntry({
266
+ ...message,
267
+ toolInvocations: void 0,
268
+ reasoning: void 0
269
+ }));
270
+ }
271
+ if (message.toolInvocations) {
272
+ for (const inv of message.toolInvocations) {
273
+ const toolMessage = {
274
+ id: inv.toolCallId,
275
+ role: "assistant",
276
+ content: "",
277
+ toolInvocations: [inv],
278
+ createdAt: message.createdAt
279
+ };
280
+ entries.push(messageToNormalizedEntry(toolMessage));
281
+ }
282
+ }
283
+ }
284
+ return entries;
285
+ }
53
286
 
54
- export { DEFAULT_DISPLAY_CONFIG, isAgentToolAction, isCommandRunAction, isErrorEntry, isFileEditAction, isFileReadAction, isFileWriteAction, isGenericToolAction, isGlobAction, isMcpToolAction, isSearchAction, isTodoWriteAction, isToolCallEntry, isWebFetchAction, isWebSearchAction, isWidgetEntry };
287
+ export { DEFAULT_STYLE_CONFIG, isAgentToolAction, isCommandRunAction, isErrorEntry, isFileEditAction, isFileReadAction, isFileWriteAction, isGenericToolAction, isGlobAction, isMcpToolAction, isSearchAction, isTodoWriteAction, isToolCallEntry, isWebFetchAction, isWebSearchAction, isWidgetEntry, messageToNormalizedEntry, messagesToNormalizedEntries, normalizedEntriesToMessages, normalizedEntryToMessage };
55
288
  //# sourceMappingURL=types.js.map
56
289
  //# sourceMappingURL=types.js.map