@datalayer/agent-runtimes 0.0.11 → 1.0.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.
Files changed (142) hide show
  1. package/README.md +2 -2
  2. package/lib/Agent.d.ts +29 -0
  3. package/lib/Agent.js +131 -0
  4. package/lib/AgentLexical.d.ts +33 -0
  5. package/lib/AgentLexical.js +295 -0
  6. package/lib/AgentNotebook.d.ts +19 -0
  7. package/lib/AgentNotebook.js +192 -0
  8. package/lib/agent-lexical-main.d.ts +1 -0
  9. package/lib/agent-lexical-main.js +11 -0
  10. package/lib/agent-main.d.ts +1 -0
  11. package/lib/agent-main.js +11 -0
  12. package/lib/agent-notebook-main.d.ts +1 -0
  13. package/lib/agent-notebook-main.js +12 -0
  14. package/lib/components/AgentConfiguration.d.ts +4 -22
  15. package/lib/components/AgentConfiguration.js +8 -8
  16. package/lib/components/chat/components/AgentDetails.d.ts +3 -1
  17. package/lib/components/chat/components/AgentDetails.js +6 -6
  18. package/lib/components/chat/components/Chat.d.ts +29 -3
  19. package/lib/components/chat/components/Chat.js +64 -59
  20. package/lib/components/chat/components/ChatFloating.d.ts +34 -12
  21. package/lib/components/chat/components/ChatFloating.js +54 -21
  22. package/lib/components/chat/components/ChatInline.d.ts +5 -1
  23. package/lib/components/chat/components/ChatInline.js +8 -1
  24. package/lib/components/chat/components/ChatSidebar.d.ts +6 -1
  25. package/lib/components/chat/components/ChatSidebar.js +2 -2
  26. package/lib/components/chat/components/ChatStandalone.d.ts +6 -1
  27. package/lib/components/chat/components/ChatStandalone.js +2 -2
  28. package/lib/components/chat/components/base/ChatBase.d.ts +49 -8
  29. package/lib/components/chat/components/base/ChatBase.js +544 -149
  30. package/lib/components/chat/components/base/InputPrompt.d.ts +42 -0
  31. package/lib/components/chat/components/base/InputPrompt.js +131 -0
  32. package/lib/components/chat/components/index.d.ts +3 -3
  33. package/lib/components/chat/components/index.js +1 -1
  34. package/lib/components/chat/components/parts/ReasoningPart.js +2 -4
  35. package/lib/components/chat/components/parts/TextPart.js +2 -70
  36. package/lib/components/chat/components/styles/streamdownStyles.d.ts +23 -0
  37. package/lib/components/chat/components/styles/streamdownStyles.js +319 -0
  38. package/lib/components/chat/index.d.ts +1 -1
  39. package/lib/components/chat/index.js +1 -1
  40. package/lib/components/chat/inference/DatalayerInferenceProvider.js +16 -12
  41. package/lib/components/chat/inference/SelfHostedInferenceProvider.js +16 -12
  42. package/lib/components/chat/protocols/AGUIAdapter.d.ts +10 -3
  43. package/lib/components/chat/protocols/AGUIAdapter.js +123 -44
  44. package/lib/components/chat/types/tool.d.ts +5 -2
  45. package/lib/components/index.d.ts +1 -18
  46. package/lib/components/index.js +0 -9
  47. package/lib/config/index.d.ts +0 -4
  48. package/lib/config/index.js +0 -4
  49. package/lib/examples/A2UiRestaurantExample.js +1 -1
  50. package/lib/examples/AgentRuntimeChatExample.d.ts +15 -0
  51. package/lib/examples/AgentRuntimeChatExample.js +126 -0
  52. package/lib/examples/{AgentSpaceFormExample.d.ts → AgentRuntimeFormExample.d.ts} +3 -3
  53. package/lib/examples/{AgentSpaceFormExample.js → AgentRuntimeFormExample.js} +10 -8
  54. package/lib/examples/AgentRuntimeLexical2Example.d.ts +0 -1
  55. package/lib/examples/AgentRuntimeLexical2Example.js +0 -1
  56. package/lib/examples/AgentRuntimeLexicalExample.d.ts +0 -1
  57. package/lib/examples/AgentRuntimeLexicalExample.js +6 -4
  58. package/lib/examples/AgentRuntimeLexicalSidebarExample.d.ts +0 -1
  59. package/lib/examples/AgentRuntimeLexicalSidebarExample.js +8 -2
  60. package/lib/examples/AgentRuntimeNotebookExample.js +6 -5
  61. package/lib/examples/CopilotKitLexicalExample.d.ts +0 -1
  62. package/lib/examples/CopilotKitLexicalExample.js +0 -1
  63. package/lib/examples/CopilotKitNotebookExample.js +2 -2
  64. package/lib/examples/JupyterNotebookExample.js +2 -2
  65. package/lib/{components → examples/components}/Header.d.ts +2 -1
  66. package/lib/{components → examples/components}/HeaderControls.js +1 -1
  67. package/lib/{components → examples/components}/LexicalEditor.d.ts +6 -1
  68. package/lib/{components → examples/components}/LexicalEditor.js +4 -4
  69. package/lib/{components → examples/components}/MainContent.d.ts +1 -1
  70. package/lib/{components → examples/components}/MainContent.js +7 -5
  71. package/lib/examples/components/index.d.ts +16 -0
  72. package/lib/examples/components/index.js +13 -0
  73. package/lib/examples/example-selector.js +2 -1
  74. package/lib/examples/index.d.ts +1 -1
  75. package/lib/examples/index.js +1 -1
  76. package/lib/examples/main.js +2 -2
  77. package/lib/examples/stores/examplesStore.d.ts +2 -23
  78. package/lib/index.d.ts +2 -1
  79. package/lib/index.js +1 -0
  80. package/lib/lexical/ChatInlinePlugin.d.ts +13 -2
  81. package/lib/lexical/ChatInlinePlugin.js +66 -183
  82. package/lib/lexical/index.d.ts +1 -0
  83. package/lib/lexical/index.js +1 -0
  84. package/lib/lexical/useChatInlineToolbarItems.d.ts +35 -0
  85. package/lib/lexical/useChatInlineToolbarItems.js +91 -0
  86. package/lib/runtime/useAgentRuntime.d.ts +1 -1
  87. package/lib/runtime/useAgentRuntime.js +1 -1
  88. package/lib/{config/agents/code-ai → specs/agents/codeai}/agents.d.ts +5 -2
  89. package/lib/specs/agents/codeai/agents.js +151 -0
  90. package/lib/{config → specs}/agents/codemode-paper/agents.d.ts +4 -2
  91. package/lib/{config → specs}/agents/codemode-paper/agents.js +39 -19
  92. package/lib/{config → specs}/agents/datalayer-ai/agents.d.ts +4 -2
  93. package/lib/{config → specs}/agents/datalayer-ai/agents.js +17 -2
  94. package/lib/{config → specs}/agents/index.d.ts +3 -1
  95. package/lib/{config → specs}/agents/index.js +12 -3
  96. package/lib/{config → specs}/envvars.d.ts +1 -0
  97. package/lib/{config → specs}/envvars.js +10 -0
  98. package/lib/specs/index.d.ts +5 -0
  99. package/lib/specs/index.js +9 -0
  100. package/lib/{config → specs}/mcpServers.d.ts +2 -1
  101. package/lib/{config → specs}/mcpServers.js +23 -1
  102. package/lib/specs/models.d.ts +68 -0
  103. package/lib/specs/models.js +239 -0
  104. package/lib/state/substates/AIAgentState.d.ts +0 -1
  105. package/lib/tools/adapters/agent-runtimes/AgentRuntimesToolAdapter.d.ts +11 -22
  106. package/lib/tools/adapters/agent-runtimes/AgentRuntimesToolAdapter.js +5 -5
  107. package/lib/tools/adapters/agent-runtimes/lexicalHooks.d.ts +6 -6
  108. package/lib/tools/adapters/agent-runtimes/lexicalHooks.js +4 -4
  109. package/lib/tools/adapters/agent-runtimes/notebookHooks.d.ts +6 -6
  110. package/lib/tools/adapters/agent-runtimes/notebookHooks.js +4 -4
  111. package/lib/{types.d.ts → types/Types.d.ts} +32 -6
  112. package/lib/types/index.d.ts +1 -0
  113. package/lib/types/index.js +1 -0
  114. package/package.json +11 -5
  115. package/scripts/codegen/generate_agents.py +53 -13
  116. package/scripts/codegen/generate_envvars.py +1 -1
  117. package/scripts/codegen/generate_mcp_servers.py +5 -5
  118. package/scripts/codegen/generate_models.py +486 -0
  119. package/scripts/codegen/generate_skills.py +2 -2
  120. package/style/primer-primitives.css +22 -0
  121. package/lib/components/chat/components/elements/ChatInputPrompt.d.ts +0 -37
  122. package/lib/components/chat/components/elements/ChatInputPrompt.js +0 -150
  123. package/lib/config/agents/code-ai/agents.js +0 -70
  124. /package/lib/{components → examples/components}/FooterMetrics.d.ts +0 -0
  125. /package/lib/{components → examples/components}/FooterMetrics.js +0 -0
  126. /package/lib/{components → examples/components}/Header.js +0 -0
  127. /package/lib/{components → examples/components}/HeaderControls.d.ts +0 -0
  128. /package/lib/{components → examples/components}/MockFileBrowser.d.ts +0 -0
  129. /package/lib/{components → examples/components}/MockFileBrowser.js +0 -0
  130. /package/lib/{components → examples/components}/SessionTabs.d.ts +0 -0
  131. /package/lib/{components → examples/components}/SessionTabs.js +0 -0
  132. /package/lib/{components → examples/components}/TimeTravel.d.ts +0 -0
  133. /package/lib/{components → examples/components}/TimeTravel.js +0 -0
  134. /package/lib/{config/agents/code-ai → specs/agents/codeai}/index.d.ts +0 -0
  135. /package/lib/{config/agents/code-ai → specs/agents/codeai}/index.js +0 -0
  136. /package/lib/{config → specs}/agents/codemode-paper/index.d.ts +0 -0
  137. /package/lib/{config → specs}/agents/codemode-paper/index.js +0 -0
  138. /package/lib/{config → specs}/agents/datalayer-ai/index.d.ts +0 -0
  139. /package/lib/{config → specs}/agents/datalayer-ai/index.js +0 -0
  140. /package/lib/{config → specs}/skills.d.ts +0 -0
  141. /package/lib/{config → specs}/skills.js +0 -0
  142. /package/lib/{types.js → types/Types.js} +0 -0
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Props for the InputPrompt component.
3
+ */
4
+ export interface InputPromptProps {
5
+ /** Placeholder text for the textarea */
6
+ placeholder?: string;
7
+ /** Whether the input is in a loading/sending state */
8
+ isLoading?: boolean;
9
+ /** Callback when a message is submitted */
10
+ onSend: (message: string) => void;
11
+ /** Callback when the stop button is clicked */
12
+ onStop?: () => void;
13
+ /** Auto-focus the input on mount */
14
+ autoFocus?: boolean;
15
+ /** Trigger value change to refocus input */
16
+ focusTrigger?: number;
17
+ /** Whether to show a border on top */
18
+ showBorderTop?: boolean;
19
+ /** Whether to use subtle background */
20
+ showBackground?: boolean;
21
+ /** Custom padding (default: 3) */
22
+ padding?: number;
23
+ /** Whether the prompt is disabled */
24
+ disabled?: boolean;
25
+ /** Additional sx props for the outer container */
26
+ sx?: Record<string, unknown>;
27
+ /** Controlled input value (external state) */
28
+ value?: string;
29
+ /** Controlled input onChange (external state) */
30
+ onChange?: (value: string) => void;
31
+ }
32
+ /**
33
+ * InputPrompt — A standalone chat input with send button.
34
+ *
35
+ * Features:
36
+ * - Auto-resizing textarea (min 40px, max 120px)
37
+ * - Enter to send, Shift+Enter for newline
38
+ * - Send / Stop toggle based on loading state
39
+ * - Auto-focus support
40
+ */
41
+ export declare function InputPrompt({ placeholder, isLoading, onSend, onStop, autoFocus, focusTrigger, showBorderTop, showBackground, padding, disabled, sx, value: controlledValue, onChange: controlledOnChange, }: InputPromptProps): import("react/jsx-runtime").JSX.Element;
42
+ export default InputPrompt;
@@ -0,0 +1,131 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /*
3
+ * Copyright (c) 2025-2026 Datalayer, Inc.
4
+ * Distributed under the terms of the Modified BSD License.
5
+ */
6
+ /**
7
+ * InputPrompt - Standalone input prompt component extracted from ChatBase.
8
+ *
9
+ * Provides a textarea with a send/stop button, auto-resize behavior,
10
+ * and keyboard shortcuts (Enter to send, Shift+Enter for newline).
11
+ *
12
+ * Can be used independently of ChatBase for embedding a prompt input
13
+ * in any context (e.g. landing pages, home screens).
14
+ *
15
+ * @module components/chat/components/base/InputPrompt
16
+ */
17
+ import { useCallback, useEffect, useRef, useState, } from 'react';
18
+ import { Textarea, IconButton } from '@primer/react';
19
+ import { Box } from '@datalayer/primer-addons';
20
+ import { PaperAirplaneIcon, SquareCircleIcon } from '@primer/octicons-react';
21
+ /**
22
+ * InputPrompt — A standalone chat input with send button.
23
+ *
24
+ * Features:
25
+ * - Auto-resizing textarea (min 40px, max 120px)
26
+ * - Enter to send, Shift+Enter for newline
27
+ * - Send / Stop toggle based on loading state
28
+ * - Auto-focus support
29
+ */
30
+ export function InputPrompt({ placeholder = 'Type a message...', isLoading = false, onSend, onStop, autoFocus = false, focusTrigger, showBorderTop = true, showBackground = true, padding = 3, disabled = false, sx, value: controlledValue, onChange: controlledOnChange, }) {
31
+ // Internal state (used when not controlled)
32
+ const [internalInput, setInternalInput] = useState('');
33
+ const input = controlledValue !== undefined ? controlledValue : internalInput;
34
+ const setInput = controlledOnChange !== undefined ? controlledOnChange : setInternalInput;
35
+ const inputRef = useRef(null);
36
+ // Auto-focus on mount
37
+ useEffect(() => {
38
+ if (autoFocus && inputRef.current) {
39
+ const timeoutId = setTimeout(() => {
40
+ inputRef.current?.focus();
41
+ }, 100);
42
+ return () => clearTimeout(timeoutId);
43
+ }
44
+ }, [autoFocus]);
45
+ // Refocus when focusTrigger changes
46
+ useEffect(() => {
47
+ if (focusTrigger !== undefined && focusTrigger > 0 && inputRef.current) {
48
+ const timeoutId = setTimeout(() => {
49
+ inputRef.current?.focus();
50
+ }, 150);
51
+ return () => clearTimeout(timeoutId);
52
+ }
53
+ }, [focusTrigger]);
54
+ // Track previous loading state to detect when loading completes
55
+ const wasLoadingRef = useRef(false);
56
+ // Refocus input when loading completes
57
+ useEffect(() => {
58
+ if (wasLoadingRef.current && !isLoading && inputRef.current) {
59
+ const timeoutId = setTimeout(() => {
60
+ inputRef.current?.focus();
61
+ }, 50);
62
+ return () => clearTimeout(timeoutId);
63
+ }
64
+ wasLoadingRef.current = isLoading;
65
+ }, [isLoading]);
66
+ // Auto-resize textarea based on content
67
+ const adjustTextareaHeight = useCallback(() => {
68
+ const textarea = inputRef.current;
69
+ if (textarea) {
70
+ textarea.style.height = 'auto';
71
+ const maxHeight = 120;
72
+ const minHeight = 40;
73
+ const newHeight = Math.min(Math.max(textarea.scrollHeight, minHeight), maxHeight);
74
+ textarea.style.height = `${newHeight}px`;
75
+ textarea.style.overflowY =
76
+ textarea.scrollHeight > maxHeight ? 'auto' : 'hidden';
77
+ }
78
+ }, []);
79
+ // Adjust textarea height when input changes
80
+ useEffect(() => {
81
+ adjustTextareaHeight();
82
+ }, [input, adjustTextareaHeight]);
83
+ // Ensure textarea has a minimum height on mount
84
+ useEffect(() => {
85
+ const timer = setTimeout(adjustTextareaHeight, 0);
86
+ return () => clearTimeout(timer);
87
+ }, [adjustTextareaHeight]);
88
+ // Send handler
89
+ const handleSend = useCallback(() => {
90
+ if (!input.trim() || isLoading || disabled)
91
+ return;
92
+ const message = input.trim();
93
+ // Only clear input if not controlled externally
94
+ if (controlledValue === undefined) {
95
+ setInput('');
96
+ }
97
+ onSend(message);
98
+ }, [input, isLoading, disabled, onSend, setInput, controlledValue]);
99
+ // Stop handler
100
+ const handleStop = useCallback(() => {
101
+ onStop?.();
102
+ }, [onStop]);
103
+ // Keyboard handler
104
+ const handleKeyDown = useCallback((e) => {
105
+ if (e.key === 'Enter' && !e.shiftKey) {
106
+ e.preventDefault();
107
+ handleSend();
108
+ }
109
+ }, [handleSend]);
110
+ return (_jsx(Box, { sx: sx, children: _jsx(Box, { sx: {
111
+ p: padding,
112
+ ...(showBorderTop && {
113
+ borderTop: '1px solid',
114
+ borderColor: 'border.default',
115
+ }),
116
+ ...(showBackground && {
117
+ bg: 'canvas.subtle',
118
+ }),
119
+ }, children: _jsxs(Box, { sx: { display: 'flex', gap: 2, alignItems: 'flex-end' }, children: [_jsx(Textarea, { ref: inputRef, value: input, onChange: e => {
120
+ setInput(e.target.value);
121
+ }, onKeyDown: handleKeyDown, placeholder: placeholder, disabled: isLoading || disabled, sx: {
122
+ flex: 1,
123
+ resize: 'none',
124
+ minHeight: '40px',
125
+ maxHeight: '120px',
126
+ overflow: 'hidden',
127
+ transition: 'height 0.1s ease-out',
128
+ py: '2px',
129
+ }, rows: 1 }), isLoading ? (_jsx(IconButton, { icon: SquareCircleIcon, "aria-label": "Stop", onClick: handleStop, sx: { alignSelf: 'flex-end' } })) : (_jsx(IconButton, { icon: PaperAirplaneIcon, "aria-label": "Send", onClick: handleSend, disabled: !input.trim() || disabled, sx: { alignSelf: 'flex-end' } }))] }) }) }));
130
+ }
131
+ export default InputPrompt;
@@ -4,10 +4,10 @@
4
4
  * @module components/chat/components
5
5
  */
6
6
  export { ChatMessages, type ChatMessagesProps } from './elements/ChatMessages';
7
- export { ChatInputPrompt, type ChatInputPromptProps, } from './elements/ChatInputPrompt';
8
7
  export { ChatSidebar, type ChatSidebarProps } from './ChatSidebar';
9
8
  export { ChatStandalone, type ChatStandaloneProps, type MessageHandler, } from './ChatStandalone';
10
- export { ChatBase, type ChatBaseProps, type ProtocolConfig, type AgentRuntimeConfig, type AvatarConfig, type EmptyStateConfig, type HeaderButtonsConfig, type StreamingMessageOptions, } from './base/ChatBase';
9
+ export { ChatBase, type ChatBaseProps, type ProtocolConfig, type AgentRuntimeConfig, type AvatarConfig, type EmptyStateConfig, type HeaderButtonsConfig, type StreamingMessageOptions, type ChatViewMode, } from './base/ChatBase';
10
+ export { InputPrompt, type InputPromptProps } from './base/InputPrompt';
11
11
  export { AgentDetails, type AgentDetailsProps } from './AgentDetails';
12
12
  export { AgentIdentity, IdentityCard, getTokenStatus, formatDuration, formatExpirationStatus, type AgentIdentityProps, type IdentityCardProps, type TokenStatus, } from './AgentIdentity';
13
13
  export { ContextUsage, type ContextUsageProps, type ContextDetailsResponse, } from './ContextUsage';
@@ -22,5 +22,5 @@ export { MessagePart, type MessagePartProps } from './elements/MessagePart';
22
22
  export { TextPart, type TextPartProps, ReasoningPart, type ReasoningPartProps, ToolPart, type ToolPartProps, DynamicToolPart, type DynamicToolPartProps, } from './parts';
23
23
  export { ToolCallDisplay, type ToolCallDisplayProps } from './display';
24
24
  export { Chat, type ChatProps, type Transport, type Extension } from './Chat';
25
- export { ChatFloating, type ChatFloatingProps, type ToolCallRenderContext, type ToolCallStatus, type RenderToolResult, type RespondCallback, type Suggestion, type RemoteConfig, type ModelConfig, type BuiltinTool, type MCPServerConfig, type MCPServerTool, } from './ChatFloating';
25
+ export { ChatFloating, type ChatFloatingProps, type ToolCallRenderContext, type ToolCallStatus, type RenderToolResult, type RespondCallback, type Suggestion, type RemoteConfig, type ModelConfig, type BuiltinTool, type MCPServerConfig, type MCPServerTool, type ChatViewMode as ChatFloatingViewMode, } from './ChatFloating';
26
26
  export { ChatInline, type ChatInlineProps, type ChatInlineProtocolConfig, } from './ChatInline';
@@ -8,10 +8,10 @@
8
8
  * @module components/chat/components
9
9
  */
10
10
  export { ChatMessages } from './elements/ChatMessages';
11
- export { ChatInputPrompt, } from './elements/ChatInputPrompt';
12
11
  export { ChatSidebar } from './ChatSidebar';
13
12
  export { ChatStandalone, } from './ChatStandalone';
14
13
  export { ChatBase, } from './base/ChatBase';
14
+ export { InputPrompt } from './base/InputPrompt';
15
15
  export { AgentDetails } from './AgentDetails';
16
16
  export { AgentIdentity, IdentityCard, getTokenStatus, formatDuration, formatExpirationStatus, } from './AgentIdentity';
17
17
  export { ContextUsage, } from './ContextUsage';
@@ -14,6 +14,7 @@ import { Text, Button } from '@primer/react';
14
14
  import { Box } from '@datalayer/primer-addons';
15
15
  import { ChevronDownIcon } from '@primer/octicons-react';
16
16
  import { Streamdown } from 'streamdown';
17
+ import { streamdownMarkdownStyles } from '../styles/streamdownStyles';
17
18
  /**
18
19
  * ReasoningPart component for displaying AI reasoning/thinking.
19
20
  *
@@ -59,11 +60,8 @@ export function ReasoningPart({ text, isStreaming }) {
59
60
  borderRadius: 2,
60
61
  border: '1px solid',
61
62
  borderColor: 'border.default',
62
- fontSize: 1,
63
- lineHeight: 1.6,
64
63
  color: 'fg.muted',
65
- '& > *:first-child': { marginTop: 0 },
66
- '& > *:last-child': { marginBottom: 0 },
64
+ ...streamdownMarkdownStyles,
67
65
  }, children: _jsx(Streamdown, { children: text }) }))] }));
68
66
  }
69
67
  export default ReasoningPart;
@@ -3,6 +3,7 @@ import { Text, IconButton } from '@primer/react';
3
3
  import { Box } from '@datalayer/primer-addons';
4
4
  import { CopyIcon, SyncIcon } from '@primer/octicons-react';
5
5
  import { Streamdown } from 'streamdown';
6
+ import { streamdownMarkdownStyles } from '../styles/streamdownStyles';
6
7
  /**
7
8
  * TextPart component for rendering text content with markdown support.
8
9
  *
@@ -33,75 +34,6 @@ export function TextPart({ text, message, isLastPart, onRegenerate, }) {
33
34
  fontSize: 1,
34
35
  color: 'fg.muted',
35
36
  textTransform: 'uppercase',
36
- }, children: message.role === 'user' ? 'You' : 'Assistant' }), message.role === 'assistant' && isLastPart && (_jsxs(Box, { sx: { display: 'flex', gap: 1 }, children: [_jsx(IconButton, { icon: SyncIcon, "aria-label": "Regenerate", size: "small", variant: "invisible", onClick: () => onRegenerate(message.id) }), _jsx(IconButton, { icon: CopyIcon, "aria-label": "Copy", size: "small", variant: "invisible", onClick: () => copy(text) })] }))] }), _jsx(Box, { sx: {
37
- fontSize: 1,
38
- lineHeight: 1.6,
39
- '& > *:first-child': { marginTop: 0 },
40
- '& > *:last-child': { marginBottom: 0 },
41
- '& p': { marginTop: 0, marginBottom: '1em' },
42
- '& h1, & h2, & h3, & h4, & h5, & h6': {
43
- marginTop: '1em',
44
- marginBottom: '0.5em',
45
- fontWeight: 'bold',
46
- },
47
- '& ul, & ol': {
48
- marginTop: '0.5em',
49
- marginBottom: '0.5em',
50
- paddingLeft: '1.2em',
51
- marginLeft: '0.3em',
52
- },
53
- '& li': {
54
- listStylePosition: 'inside',
55
- },
56
- '& code': {
57
- backgroundColor: 'neutral.muted',
58
- padding: '2px 4px',
59
- borderRadius: 1,
60
- fontSize: '0.9em',
61
- fontFamily: 'mono',
62
- },
63
- '& pre': {
64
- backgroundColor: 'canvas.inset',
65
- padding: 3,
66
- borderRadius: 2,
67
- overflow: 'auto',
68
- marginTop: '1em',
69
- marginBottom: '1em',
70
- border: '1px solid',
71
- borderColor: 'border.default',
72
- },
73
- '& pre code': {
74
- backgroundColor: 'transparent',
75
- padding: 0,
76
- fontSize: '0.875em',
77
- },
78
- '& blockquote': {
79
- borderLeft: '3px solid',
80
- borderColor: 'border.default',
81
- paddingLeft: 3,
82
- marginLeft: 0,
83
- color: 'fg.muted',
84
- },
85
- '& a': {
86
- color: 'accent.fg',
87
- textDecoration: 'underline',
88
- },
89
- '& table': {
90
- width: '100%',
91
- borderCollapse: 'collapse',
92
- marginTop: '1em',
93
- marginBottom: '1em',
94
- },
95
- '& th, & td': {
96
- border: '1px solid',
97
- borderColor: 'border.default',
98
- padding: 2,
99
- textAlign: 'left',
100
- },
101
- '& th': {
102
- backgroundColor: 'canvas.subtle',
103
- fontWeight: 'bold',
104
- },
105
- }, children: _jsx(Streamdown, { children: text }) })] }));
37
+ }, children: message.role === 'user' ? 'You' : 'Assistant' }), message.role === 'assistant' && isLastPart && (_jsxs(Box, { sx: { display: 'flex', gap: 1 }, children: [_jsx(IconButton, { icon: SyncIcon, "aria-label": "Regenerate", size: "small", variant: "invisible", onClick: () => onRegenerate(message.id) }), _jsx(IconButton, { icon: CopyIcon, "aria-label": "Copy", size: "small", variant: "invisible", onClick: () => copy(text) })] }))] }), _jsx(Box, { sx: streamdownMarkdownStyles, children: _jsx(Streamdown, { children: text }) })] }));
106
38
  }
107
39
  export default TextPart;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Shared CSS-in-js styles for Streamdown markdown rendering.
3
+ *
4
+ * Streamdown outputs HTML with Tailwind CSS classes (flex, gap-1, p-1, etc.).
5
+ * Since we don't load Tailwind CSS, we provide equivalent styles via
6
+ * Primer's sx prop targeting the Tailwind class names.
7
+ *
8
+ * @module components/chat/components/styles/streamdownStyles
9
+ */
10
+ /** Style object compatible with Primer's sx prop */
11
+ type SxStyles = Record<string, unknown>;
12
+ /**
13
+ * Markdown element styles for Streamdown content.
14
+ * Provides proper formatting for headings, lists, tables, code, etc.
15
+ * Uses Primer theme tokens for colors and spacing.
16
+ */
17
+ export declare const streamdownMarkdownStyles: SxStyles;
18
+ /**
19
+ * Code block specific styles for Streamdown's data-streamdown attributes.
20
+ * These target Streamdown's code block structure.
21
+ */
22
+ export declare const streamdownCodeBlockStyles: SxStyles;
23
+ export {};
@@ -0,0 +1,319 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ /**
6
+ * Tailwind utility class equivalents for Streamdown output.
7
+ * Maps Tailwind class names to CSS properties.
8
+ */
9
+ const tailwindUtilities = {
10
+ // ── Display / Flexbox ──
11
+ '& .flex': { display: 'flex' },
12
+ '& .inline-block': { display: 'inline-block' },
13
+ '& .block': { display: 'block' },
14
+ '& .hidden': { display: 'none' },
15
+ '& .flex-col': { flexDirection: 'column' },
16
+ '& .items-center': { alignItems: 'center' },
17
+ '& .items-start': { alignItems: 'flex-start' },
18
+ '& .justify-center': { justifyContent: 'center' },
19
+ '& .justify-end': { justifyContent: 'flex-end' },
20
+ '& .justify-between': { justifyContent: 'space-between' },
21
+ '& .flex-shrink-0': { flexShrink: 0 },
22
+ // ── Gap / Spacing ──
23
+ '& .gap-1': { gap: '0.25rem' },
24
+ '& .gap-2': { gap: '0.5rem' },
25
+ '& .space-x-2 > * + *': { marginLeft: '0.5rem' },
26
+ '& .space-y-2 > * + *': { marginTop: '0.5rem' },
27
+ '& .space-y-4 > * + *': { marginTop: '1rem' },
28
+ // ── Padding ──
29
+ '& .p-1': { padding: '0.25rem' },
30
+ '& .p-2': { padding: '0.5rem' },
31
+ '& .p-4': { padding: '1rem' },
32
+ '& .px-1': { paddingLeft: '0.25rem', paddingRight: '0.25rem' },
33
+ '& .px-1\\.5': { paddingLeft: '0.375rem', paddingRight: '0.375rem' },
34
+ '& .px-4': { paddingLeft: '1rem', paddingRight: '1rem' },
35
+ '& .py-0\\.5': { paddingTop: '0.125rem', paddingBottom: '0.125rem' },
36
+ '& .py-1': { paddingTop: '0.25rem', paddingBottom: '0.25rem' },
37
+ '& .py-2': { paddingTop: '0.5rem', paddingBottom: '0.5rem' },
38
+ '& .pl-4': { paddingLeft: '1rem' },
39
+ '& .\\!p-0': { padding: '0 !important' },
40
+ '& .p-1\\.5': { padding: '0.375rem' },
41
+ // ── Margin ──
42
+ '& .mt-1': { marginTop: '0.25rem' },
43
+ '& .mt-2': { marginTop: '0.5rem' },
44
+ '& .mt-6': { marginTop: '1.5rem' },
45
+ '& .mb-2': { marginBottom: '0.5rem' },
46
+ '& .my-4': { marginTop: '1rem', marginBottom: '1rem' },
47
+ '& .my-6': { marginTop: '1.5rem', marginBottom: '1.5rem' },
48
+ '& .mr-2': { marginRight: '0.5rem' },
49
+ // ── Sizing ──
50
+ '& .w-full': { width: '100%' },
51
+ '& .h-full': { height: '100%' },
52
+ '& .h-4': { height: '1rem' },
53
+ '& .w-4': { width: '1rem' },
54
+ '& .h-8': { height: '2rem' },
55
+ '& .w-8': { width: '2rem' },
56
+ '& .size-4': { width: '1rem', height: '1rem' },
57
+ '& .max-w-full': { maxWidth: '100%' },
58
+ '& .min-w-\\[120px\\]': { minWidth: '120px' },
59
+ // ── Typography ──
60
+ '& .text-sm': { fontSize: '0.875rem', lineHeight: '1.25rem' },
61
+ '& .text-xs': { fontSize: '0.75rem', lineHeight: '1rem' },
62
+ '& .text-base': { fontSize: '1rem', lineHeight: '1.5rem' },
63
+ '& .text-lg': { fontSize: '1.125rem', lineHeight: '1.75rem' },
64
+ '& .text-xl': { fontSize: '1.25rem', lineHeight: '1.75rem' },
65
+ '& .text-2xl': { fontSize: '1.5rem', lineHeight: '2rem' },
66
+ '& .text-3xl': { fontSize: '1.875rem', lineHeight: '2.25rem' },
67
+ '& .font-semibold': { fontWeight: 600 },
68
+ '& .font-mono': {
69
+ fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace',
70
+ },
71
+ '& .italic': { fontStyle: 'italic' },
72
+ '& .whitespace-normal': { whiteSpace: 'normal' },
73
+ '& .whitespace-pre-wrap': { whiteSpace: 'pre-wrap' },
74
+ // ── Colors (mapped to Primer theme tokens) ──
75
+ '& .text-muted-foreground': { color: 'fg.muted' },
76
+ '& .text-foreground': { color: 'fg.default' },
77
+ '& .text-red-600': { color: '#dc2626' },
78
+ '& .text-red-700': { color: '#b91c1c' },
79
+ '& .text-red-800': { color: '#991b1b' },
80
+ '& .bg-muted': { backgroundColor: 'neutral.muted' },
81
+ '& .bg-red-50': { backgroundColor: '#fef2f2' },
82
+ '& .bg-red-100': { backgroundColor: '#fee2e2' },
83
+ '& .bg-background': { backgroundColor: 'canvas.default' },
84
+ // ── Background opacity variants ──
85
+ '& .bg-muted\\/80': { backgroundColor: 'neutral.muted' },
86
+ '& .bg-muted\\/40': { backgroundColor: 'neutral.muted' },
87
+ '& .bg-background\\/90': { backgroundColor: 'canvas.default' },
88
+ '& .bg-background\\/95': { backgroundColor: 'canvas.default' },
89
+ '& .bg-black\\/10': { backgroundColor: 'rgba(0,0,0,0.1)' },
90
+ // ── Borders ──
91
+ '& .border': { border: '1px solid', borderColor: 'border.default' },
92
+ '& .border-border': { borderColor: 'border.default' },
93
+ '& .border-b': {
94
+ borderBottom: '1px solid',
95
+ borderBottomColor: 'border.default',
96
+ },
97
+ '& .border-t': { borderTop: '1px solid', borderTopColor: 'border.default' },
98
+ '& .border-l-4': {
99
+ borderLeft: '4px solid',
100
+ borderLeftColor: 'border.default',
101
+ },
102
+ '& .border-red-200': { borderColor: '#fecaca' },
103
+ '& .divide-y > * + *': {
104
+ borderTop: '1px solid',
105
+ borderTopColor: 'border.default',
106
+ },
107
+ '& .divide-border > * + *': { borderColor: 'border.default' },
108
+ // ── Border radius ──
109
+ '& .rounded': { borderRadius: '0.25rem' },
110
+ '& .rounded-md': { borderRadius: '0.375rem' },
111
+ '& .rounded-lg': { borderRadius: '0.5rem' },
112
+ '& .rounded-xl': { borderRadius: '0.75rem' },
113
+ '& .rounded-full': { borderRadius: '9999px' },
114
+ // ── Overflow ──
115
+ '& .overflow-hidden': { overflow: 'hidden' },
116
+ '& .overflow-x-auto': { overflowX: 'auto' },
117
+ '& .overflow-auto': { overflow: 'auto' },
118
+ // ── List styles ──
119
+ '& .list-disc': { listStyleType: 'disc' },
120
+ '& .list-decimal': { listStyleType: 'decimal' },
121
+ '& .list-inside': { listStylePosition: 'inside' },
122
+ // ── Cursor ──
123
+ '& .cursor-pointer': { cursor: 'pointer' },
124
+ // ── Position ──
125
+ '& .relative': { position: 'relative' },
126
+ '& .absolute': { position: 'absolute' },
127
+ '& .fixed': { position: 'fixed' },
128
+ '& .inset-0': { top: 0, right: 0, bottom: 0, left: 0 },
129
+ '& .top-4': { top: '1rem' },
130
+ '& .right-0': { right: 0 },
131
+ '& .right-2': { right: '0.5rem' },
132
+ '& .right-4': { right: '1rem' },
133
+ '& .bottom-2': { bottom: '0.5rem' },
134
+ '& .z-10': { zIndex: 10 },
135
+ '& .z-50': { zIndex: 50 },
136
+ // ── Shadow ──
137
+ '& .shadow-sm': { boxShadow: '0 1px 2px 0 rgba(0,0,0,0.05)' },
138
+ '& .shadow-lg': {
139
+ boxShadow: '0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -4px rgba(0,0,0,0.1)',
140
+ },
141
+ // ── Transitions ──
142
+ '& .transition-all': { transition: 'all 150ms ease' },
143
+ '& .transition-colors': {
144
+ transition: 'color 150ms ease, background-color 150ms ease, border-color 150ms ease',
145
+ },
146
+ '& .transition-transform': { transition: 'transform 150ms ease' },
147
+ '& .duration-150': { transitionDuration: '150ms' },
148
+ '& .duration-200': { transitionDuration: '200ms' },
149
+ '& .ease-out': { transitionTimingFunction: 'ease-out' },
150
+ // ── Opacity ──
151
+ '& .opacity-50': { opacity: 0.5 },
152
+ // ── Animation ──
153
+ '& .animate-spin': {
154
+ animation: 'spin 1s linear infinite',
155
+ },
156
+ // ── Hover states ──
157
+ '& .hover\\:text-foreground:hover': { color: 'fg.default' },
158
+ '& .hover\\:bg-muted:hover': { backgroundColor: 'neutral.muted' },
159
+ '& .hover\\:bg-background:hover': { backgroundColor: 'canvas.default' },
160
+ '& .hover\\:block:hover': { display: 'block' },
161
+ '& .group:hover .group-hover\\:block': { display: 'block' },
162
+ // ── Disabled ──
163
+ '& .disabled\\:cursor-not-allowed:disabled': { cursor: 'not-allowed' },
164
+ '& .disabled\\:opacity-50:disabled': { opacity: 0.5 },
165
+ // ── Backdrop ──
166
+ '& .backdrop-blur-sm': { backdropFilter: 'blur(4px)' },
167
+ // ── Misc ──
168
+ '& .pointer-events-none': { pointerEvents: 'none' },
169
+ '& .origin-center': { transformOrigin: 'center' },
170
+ };
171
+ /**
172
+ * Markdown element styles for Streamdown content.
173
+ * Provides proper formatting for headings, lists, tables, code, etc.
174
+ * Uses Primer theme tokens for colors and spacing.
175
+ */
176
+ export const streamdownMarkdownStyles = {
177
+ fontSize: 1,
178
+ lineHeight: 1.5,
179
+ '& > *:first-child': { marginTop: 0 },
180
+ '& > *:last-child': { marginBottom: 0 },
181
+ '& p': { marginTop: 0, marginBottom: '0.75em' },
182
+ '& h1, & h2, & h3, & h4, & h5, & h6': {
183
+ marginTop: '1em',
184
+ marginBottom: '0.5em',
185
+ fontWeight: 'bold',
186
+ },
187
+ '& h1': { fontSize: '1.5em' },
188
+ '& h2': { fontSize: '1.3em' },
189
+ '& h3': { fontSize: '1.15em' },
190
+ '& ul, & ol': {
191
+ marginTop: '0.5em',
192
+ marginBottom: '0.5em',
193
+ paddingInlineStart: '1.25em',
194
+ },
195
+ '& li': {
196
+ paddingInlineStart: '0.25em',
197
+ marginBottom: '0.25em',
198
+ },
199
+ '& code': {
200
+ backgroundColor: 'neutral.muted',
201
+ padding: '2px 4px',
202
+ borderRadius: '4px',
203
+ fontSize: '0.9em',
204
+ fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace',
205
+ },
206
+ '& pre code': {
207
+ backgroundColor: 'transparent',
208
+ padding: 0,
209
+ },
210
+ '& blockquote': {
211
+ borderLeft: '3px solid',
212
+ borderColor: 'border.default',
213
+ paddingLeft: '12px',
214
+ marginLeft: 0,
215
+ marginRight: 0,
216
+ color: 'fg.muted',
217
+ },
218
+ '& a': {
219
+ color: 'accent.fg',
220
+ textDecoration: 'underline',
221
+ },
222
+ '& table': {
223
+ width: '100%',
224
+ borderCollapse: 'collapse',
225
+ marginTop: '0.75em',
226
+ marginBottom: '0.75em',
227
+ fontSize: '0.9em',
228
+ },
229
+ '& th, & td': {
230
+ border: '1px solid',
231
+ borderColor: 'border.default',
232
+ padding: '6px 12px',
233
+ textAlign: 'left',
234
+ },
235
+ '& th': {
236
+ backgroundColor: 'canvas.inset',
237
+ fontWeight: 'bold',
238
+ },
239
+ '& tr:nth-of-type(even)': {
240
+ backgroundColor: 'canvas.inset',
241
+ },
242
+ '& img': {
243
+ maxWidth: '100%',
244
+ borderRadius: '8px',
245
+ },
246
+ '& hr': {
247
+ border: 'none',
248
+ borderTop: '1px solid',
249
+ borderColor: 'border.default',
250
+ marginTop: '1em',
251
+ marginBottom: '1em',
252
+ },
253
+ // Include Tailwind utilities for Streamdown output
254
+ ...tailwindUtilities,
255
+ };
256
+ /**
257
+ * Code block specific styles for Streamdown's data-streamdown attributes.
258
+ * These target Streamdown's code block structure.
259
+ */
260
+ export const streamdownCodeBlockStyles = {
261
+ '& [data-streamdown="code-block"]': {
262
+ borderRadius: '8px',
263
+ border: '1px solid',
264
+ borderColor: 'border.default',
265
+ overflow: 'hidden',
266
+ my: 2,
267
+ },
268
+ '& [data-streamdown="code-block-header"]': {
269
+ display: 'flex',
270
+ alignItems: 'center',
271
+ justifyContent: 'space-between',
272
+ backgroundColor: 'canvas.subtle',
273
+ padding: '8px 12px',
274
+ fontSize: '12px',
275
+ color: 'fg.muted',
276
+ },
277
+ '& [data-streamdown="code-block-header"] button': {
278
+ background: 'none',
279
+ border: 'none',
280
+ cursor: 'pointer',
281
+ padding: '4px',
282
+ color: 'fg.muted',
283
+ borderRadius: '4px',
284
+ '&:hover': {
285
+ backgroundColor: 'neutral.muted',
286
+ color: 'fg.default',
287
+ },
288
+ },
289
+ '& [data-streamdown="code-block-body"]': {
290
+ backgroundColor: 'canvas.subtle',
291
+ padding: '12px',
292
+ margin: 0,
293
+ overflow: 'auto',
294
+ fontSize: '13px',
295
+ lineHeight: 1.5,
296
+ },
297
+ '& [data-streamdown="code-block-body"] code': {
298
+ display: 'block',
299
+ fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace',
300
+ },
301
+ '& [data-streamdown="code-block-body"] code > span.block': {
302
+ display: 'block',
303
+ },
304
+ '& [data-streamdown="code-block-body"] code > span': {
305
+ display: 'block',
306
+ },
307
+ '& pre': {
308
+ whiteSpace: 'pre-wrap',
309
+ wordBreak: 'break-word',
310
+ overflowX: 'auto',
311
+ margin: 0,
312
+ },
313
+ '& pre code': {
314
+ whiteSpace: 'pre-wrap',
315
+ },
316
+ '& code': {
317
+ fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace',
318
+ },
319
+ };