@tulip-systems/ai 0.11.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 (129) hide show
  1. package/LICENSE +662 -0
  2. package/dist/agents/lib/definitions.server.d.mts +11 -0
  3. package/dist/agents/lib/definitions.server.mjs +14 -0
  4. package/dist/agents/lib/delegation.server.d.mts +15 -0
  5. package/dist/agents/lib/delegation.server.mjs +28 -0
  6. package/dist/agents/lib/instructions.server.d.mts +14 -0
  7. package/dist/agents/lib/instructions.server.mjs +26 -0
  8. package/dist/agents/lib/types.d.mts +26 -0
  9. package/dist/agents/server.d.mts +5 -0
  10. package/dist/agents/server.mjs +5 -0
  11. package/dist/chat/client.d.mts +10 -0
  12. package/dist/chat/client.mjs +12 -0
  13. package/dist/chat/components/agent-activity.client.d.mts +14 -0
  14. package/dist/chat/components/agent-activity.client.mjs +26 -0
  15. package/dist/chat/components/assistant-panel.client.d.mts +40 -0
  16. package/dist/chat/components/assistant-panel.client.mjs +53 -0
  17. package/dist/chat/components/chat-composer.client.d.mts +160 -0
  18. package/dist/chat/components/chat-composer.client.mjs +266 -0
  19. package/dist/chat/components/chat-message.client.d.mts +92 -0
  20. package/dist/chat/components/chat-message.client.mjs +121 -0
  21. package/dist/chat/components/chat-thread.client.d.mts +130 -0
  22. package/dist/chat/components/chat-thread.client.mjs +164 -0
  23. package/dist/chat/components/message-part.client.d.mts +23 -0
  24. package/dist/chat/components/message-part.client.mjs +38 -0
  25. package/dist/chat/components/starter-prompts.client.d.mts +25 -0
  26. package/dist/chat/components/starter-prompts.client.mjs +31 -0
  27. package/dist/chat/components/tool-call-card.client.d.mts +29 -0
  28. package/dist/chat/components/tool-call-card.client.mjs +60 -0
  29. package/dist/chat/lib/classes.mjs +7 -0
  30. package/dist/chat/lib/parts.d.mts +10 -0
  31. package/dist/chat/lib/parts.mjs +25 -0
  32. package/dist/chat/lib/stream.server.d.mts +24 -0
  33. package/dist/chat/lib/stream.server.mjs +34 -0
  34. package/dist/chat/lib/types.d.mts +21 -0
  35. package/dist/chat/server.d.mts +3 -0
  36. package/dist/chat/server.mjs +3 -0
  37. package/dist/chat.d.mts +3 -0
  38. package/dist/chat.mjs +3 -0
  39. package/dist/index.d.mts +1 -0
  40. package/dist/index.mjs +1 -0
  41. package/dist/mcp/lib/content.d.mts +66 -0
  42. package/dist/mcp/lib/content.d.mts.map +1 -0
  43. package/dist/mcp/lib/content.mjs +115 -0
  44. package/dist/mcp/lib/content.mjs.map +1 -0
  45. package/dist/mcp/lib/tool-result.server.d.mts +12 -0
  46. package/dist/mcp/lib/tool-result.server.d.mts.map +1 -0
  47. package/dist/mcp/lib/tool-result.server.mjs +10 -0
  48. package/dist/mcp/lib/tool-result.server.mjs.map +1 -0
  49. package/dist/mcp/lib/types.d.mts +27 -0
  50. package/dist/mcp/server.d.mts +3 -0
  51. package/dist/mcp/server.mjs +3 -0
  52. package/dist/mcp/types.d.mts +27 -0
  53. package/dist/mcp/types.d.mts.map +1 -0
  54. package/dist/server/mcp-content.d.mts +44 -0
  55. package/dist/server/mcp-content.d.mts.map +1 -0
  56. package/dist/server/mcp-content.mjs +71 -0
  57. package/dist/server/mcp-content.mjs.map +1 -0
  58. package/dist/server/tools.d.mts +61 -0
  59. package/dist/server/tools.d.mts.map +1 -0
  60. package/dist/server/tools.mjs +47 -0
  61. package/dist/server/tools.mjs.map +1 -0
  62. package/dist/server.d.mts +3 -0
  63. package/dist/server.mjs +4 -0
  64. package/dist/tools/client.d.mts +3 -0
  65. package/dist/tools/client.mjs +5 -0
  66. package/dist/tools/lib/ai-sdk.server.d.mts +12 -0
  67. package/dist/tools/lib/ai-sdk.server.d.mts.map +1 -0
  68. package/dist/tools/lib/ai-sdk.server.mjs +38 -0
  69. package/dist/tools/lib/ai-sdk.server.mjs.map +1 -0
  70. package/dist/tools/lib/define-tool.server.d.mts +9 -0
  71. package/dist/tools/lib/define-tool.server.d.mts.map +1 -0
  72. package/dist/tools/lib/define-tool.server.mjs +13 -0
  73. package/dist/tools/lib/define-tool.server.mjs.map +1 -0
  74. package/dist/tools/lib/definitions.client.d.mts +20 -0
  75. package/dist/tools/lib/definitions.client.mjs +21 -0
  76. package/dist/tools/lib/definitions.d.mts +16 -0
  77. package/dist/tools/lib/definitions.d.mts.map +1 -0
  78. package/dist/tools/lib/definitions.mjs +20 -0
  79. package/dist/tools/lib/definitions.mjs.map +1 -0
  80. package/dist/tools/lib/resolvers.d.mts +41 -0
  81. package/dist/tools/lib/resolvers.d.mts.map +1 -0
  82. package/dist/tools/lib/resolvers.mjs +43 -0
  83. package/dist/tools/lib/resolvers.mjs.map +1 -0
  84. package/dist/tools/lib/types.client.d.mts +13 -0
  85. package/dist/tools/lib/types.d.mts +33 -0
  86. package/dist/tools/resolvers/agent.server.d.mts +27 -0
  87. package/dist/tools/resolvers/agent.server.d.mts.map +1 -0
  88. package/dist/tools/resolvers/agent.server.mjs +44 -0
  89. package/dist/tools/resolvers/agent.server.mjs.map +1 -0
  90. package/dist/tools/resolvers/mcp.server.d.mts +31 -0
  91. package/dist/tools/resolvers/mcp.server.d.mts.map +1 -0
  92. package/dist/tools/resolvers/mcp.server.mjs +20 -0
  93. package/dist/tools/resolvers/mcp.server.mjs.map +1 -0
  94. package/dist/tools/server.d.mts +5 -0
  95. package/dist/tools/server.mjs +5 -0
  96. package/dist/tools/types.d.mts +33 -0
  97. package/dist/tools/types.d.mts.map +1 -0
  98. package/package.json +61 -0
  99. package/src/agents/entry.server.ts +7 -0
  100. package/src/agents/lib/definitions.server.ts +14 -0
  101. package/src/agents/lib/delegation.server.ts +33 -0
  102. package/src/agents/lib/instructions.server.ts +37 -0
  103. package/src/agents/lib/types.ts +32 -0
  104. package/src/chat/components/agent-activity.client.tsx +21 -0
  105. package/src/chat/components/chat-composer.client.tsx +379 -0
  106. package/src/chat/components/chat-message.client.tsx +166 -0
  107. package/src/chat/components/chat-thread.client.tsx +242 -0
  108. package/src/chat/components/message-part.client.tsx +59 -0
  109. package/src/chat/components/starter-prompts.client.tsx +49 -0
  110. package/src/chat/components/tool-call-card.client.tsx +78 -0
  111. package/src/chat/entry.client.ts +18 -0
  112. package/src/chat/entry.server.ts +5 -0
  113. package/src/chat/entry.ts +5 -0
  114. package/src/chat/lib/parts.ts +33 -0
  115. package/src/chat/lib/stream.server.ts +40 -0
  116. package/src/chat/lib/types.ts +20 -0
  117. package/src/entry.ts +24 -0
  118. package/src/mcp/entry.server.ts +2 -0
  119. package/src/mcp/lib/content.ts +131 -0
  120. package/src/mcp/lib/types.ts +28 -0
  121. package/src/styles.css +1 -0
  122. package/src/tools/entry.client.ts +7 -0
  123. package/src/tools/entry.server.ts +11 -0
  124. package/src/tools/lib/definitions.client.ts +21 -0
  125. package/src/tools/lib/definitions.ts +24 -0
  126. package/src/tools/lib/types.client.ts +11 -0
  127. package/src/tools/lib/types.ts +44 -0
  128. package/src/tools/resolvers/agent.server.ts +78 -0
  129. package/src/tools/resolvers/mcp.server.ts +40 -0
@@ -0,0 +1,266 @@
1
+ "use client";
2
+
3
+ import { cn } from "@tulip-systems/core/lib";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { Button, Textarea } from "@tulip-systems/core/components";
6
+ import { ArrowUp, UploadIcon } from "lucide-react";
7
+ import { createContext, useCallback, useContext, useEffect, useMemo, useRef } from "react";
8
+
9
+ //#region src/chat/components/chat-composer.client.tsx
10
+ const ChatComposerContext = createContext({});
11
+ /**
12
+ * Provides the root composer shell and shared state for all chat composer slots.
13
+ * Use it as the controlled boundary for the current draft value and submit handler.
14
+ *
15
+ * @example
16
+ * ```tsx
17
+ * <ChatComposer value={input} onValueChange={setInput} onSubmit={sendMessage}>
18
+ * <ChatComposerInput placeholder="Ask something..." />
19
+ * <ChatComposerToolbar>
20
+ * <ChatComposerActions>
21
+ * <ChatComposerAttachmentButton />
22
+ * </ChatComposerActions>
23
+ * <ChatComposerSubmit />
24
+ * </ChatComposerToolbar>
25
+ * </ChatComposer>
26
+ * ```
27
+ */
28
+ function ChatComposer({ value, onValueChange, onSubmit, disabled = false, status = "ready", statusLabel, className, children, ...props }) {
29
+ const textareaRef = useRef(null);
30
+ const isDisabled = disabled;
31
+ const isSubmitDisabled = disabled || status !== "ready";
32
+ const canSubmit = !isSubmitDisabled && value.trim().length > 0;
33
+ useEffect(() => {
34
+ adjustTextareaHeight(textareaRef.current);
35
+ });
36
+ const submit = useCallback(() => {
37
+ const trimmedValue = value.trim();
38
+ if (!trimmedValue || isSubmitDisabled) return;
39
+ onSubmit(trimmedValue);
40
+ resetTextareaHeight(textareaRef.current);
41
+ }, [
42
+ value,
43
+ isSubmitDisabled,
44
+ onSubmit
45
+ ]);
46
+ const contextValue = useMemo(() => ({
47
+ value,
48
+ onValueChange,
49
+ submit,
50
+ textareaRef,
51
+ disabled,
52
+ canSubmit,
53
+ status,
54
+ statusLabel
55
+ }), [
56
+ value,
57
+ onValueChange,
58
+ submit,
59
+ disabled,
60
+ canSubmit,
61
+ status,
62
+ statusLabel
63
+ ]);
64
+ return /* @__PURE__ */ jsx(ChatComposerContext.Provider, {
65
+ value: contextValue,
66
+ children: /* @__PURE__ */ jsx("form", {
67
+ className: cn("pointer-events-auto mx-auto w-full max-w-3xl", className),
68
+ ...props,
69
+ children: /* @__PURE__ */ jsx("fieldset", {
70
+ "data-disabled": isDisabled ? true : void 0,
71
+ className: "relative flex min-h-28 w-full min-w-0 flex-col rounded-xl border border-input/70 bg-background/80 shadow-[0_12px_40px_rgba(0,0,0,0.08)] outline-none backdrop-blur-xl transition-colors focus-within:border-primary/35 focus-within:ring-3 focus-within:ring-ring/50 data-[disabled=true]:opacity-70",
72
+ children
73
+ })
74
+ })
75
+ });
76
+ }
77
+ /**
78
+ * Renders the auto-growing textarea connected to the nearest `ChatComposer`.
79
+ * Pressing Enter submits the composer, while Shift+Enter inserts a new line.
80
+ *
81
+ * @example
82
+ * ```tsx
83
+ * <ChatComposerInput placeholder="Ask something..." rows={3} />
84
+ * ```
85
+ */
86
+ function ChatComposerInput({ rows = 3, className, onKeyDown, ...props }) {
87
+ const { value, onValueChange, submit, textareaRef, disabled } = useContext(ChatComposerContext);
88
+ return /* @__PURE__ */ jsx(Textarea, {
89
+ ref: textareaRef,
90
+ value,
91
+ onChange: (event) => {
92
+ onValueChange(event.target.value);
93
+ adjustTextareaHeight(event.target);
94
+ },
95
+ onKeyDown: (event) => {
96
+ onKeyDown?.(event);
97
+ if (event.defaultPrevented) return;
98
+ if (event.key === "Enter" && !event.shiftKey && !event.nativeEvent.isComposing) {
99
+ event.preventDefault();
100
+ submit();
101
+ }
102
+ },
103
+ disabled,
104
+ rows,
105
+ className: cn("max-h-[calc(75dvh)] min-h-20 flex-1 resize-none overflow-hidden rounded-none border-0 bg-transparent px-3 pt-3 pb-0 text-base leading-6 shadow-none ring-0 placeholder:text-muted-foreground/70 focus-visible:ring-0 disabled:bg-transparent dark:bg-transparent dark:disabled:bg-transparent", className),
106
+ ...props
107
+ });
108
+ }
109
+ /**
110
+ * Renders the bottom toolbar area for composer actions and the submit button.
111
+ * Place `ChatComposerActions` on the left and `ChatComposerSubmit` on the right.
112
+ *
113
+ * @example
114
+ * ```tsx
115
+ * <ChatComposerToolbar>
116
+ * <ChatComposerActions>
117
+ * <ChatComposerAttachmentButton />
118
+ * </ChatComposerActions>
119
+ * <ChatComposerSubmit />
120
+ * </ChatComposerToolbar>
121
+ * ```
122
+ */
123
+ function ChatComposerToolbar({ className, ...props }) {
124
+ return /* @__PURE__ */ jsx("div", {
125
+ className: cn("flex w-full items-center justify-between gap-2 px-2.5 pt-1 pb-2 text-muted-foreground text-sm", className),
126
+ ...props
127
+ });
128
+ }
129
+ /**
130
+ * Groups secondary composer controls such as attachments, model selection, or status.
131
+ * It keeps action controls aligned together inside `ChatComposerToolbar`.
132
+ *
133
+ * @example
134
+ * ```tsx
135
+ * <ChatComposerActions>
136
+ * <ChatComposerAttachmentButton />
137
+ * <ChatComposerModelSelect>GPT-5.5</ChatComposerModelSelect>
138
+ * <ChatComposerStatus />
139
+ * </ChatComposerActions>
140
+ * ```
141
+ */
142
+ function ChatComposerActions({ className, ...props }) {
143
+ return /* @__PURE__ */ jsx("div", {
144
+ className: cn("flex min-w-0 items-center gap-2", className),
145
+ ...props
146
+ });
147
+ }
148
+ /**
149
+ * Renders an attachment action button for opening a file picker or context picker.
150
+ * It uses a file-upload icon and `Context toevoegen` accessible label by default.
151
+ *
152
+ * @example
153
+ * ```tsx
154
+ * <ChatComposerAttachmentButton onClick={openFilePicker} />
155
+ * ```
156
+ */
157
+ function ChatComposerAttachmentButton({ className, disabled, ...props }) {
158
+ const { disabled: composerDisabled } = useContext(ChatComposerContext);
159
+ return /* @__PURE__ */ jsxs(Button, {
160
+ "aria-label": "Bestanden toevoegen",
161
+ type: "button",
162
+ size: "icon",
163
+ variant: "outline",
164
+ disabled: composerDisabled || disabled,
165
+ className: cn("size-8 rounded-lg p-0 shadow-none", className),
166
+ ...props,
167
+ children: [/* @__PURE__ */ jsx(UploadIcon, { className: "size-4" }), /* @__PURE__ */ jsx("span", {
168
+ className: "sr-only",
169
+ children: "Bestanden toevoegen"
170
+ })]
171
+ });
172
+ }
173
+ /**
174
+ * Renders a compact model selector trigger inside the composer toolbar.
175
+ * Use it as a simple button or compose it with a popover/select in application code.
176
+ *
177
+ * @example
178
+ * ```tsx
179
+ * <ChatComposerModelSelect onClick={openModelMenu}>GPT-5.5</ChatComposerModelSelect>
180
+ * ```
181
+ */
182
+ function ChatComposerModelSelect({ className, disabled, children, ...props }) {
183
+ const { disabled: composerDisabled } = useContext(ChatComposerContext);
184
+ return /* @__PURE__ */ jsx(Button, {
185
+ type: "button",
186
+ variant: "outline",
187
+ size: "sm",
188
+ disabled: composerDisabled || disabled,
189
+ className: cn("h-8 rounded-lg shadow-none", className),
190
+ ...props,
191
+ children: "Select model"
192
+ });
193
+ }
194
+ /**
195
+ * Displays the current composer status from `ChatComposer.status` and `statusLabel`.
196
+ * It renders nothing when no label or children are provided.
197
+ *
198
+ * @example
199
+ * ```tsx
200
+ * <ChatComposer status="streaming" statusLabel="Thinking...">
201
+ * <ChatComposerInput />
202
+ * <ChatComposerToolbar>
203
+ * <ChatComposerActions>
204
+ * <ChatComposerStatus />
205
+ * </ChatComposerActions>
206
+ * <ChatComposerSubmit />
207
+ * </ChatComposerToolbar>
208
+ * </ChatComposer>
209
+ * ```
210
+ */
211
+ function ChatComposerStatus({ className, children, ...props }) {
212
+ const { status, statusLabel } = useContext(ChatComposerContext);
213
+ const content = children ?? statusLabel;
214
+ if (!content) return null;
215
+ return /* @__PURE__ */ jsxs("div", {
216
+ className: cn("line-clamp-1 flex items-center gap-2 text-muted-foreground text-xs opacity-70 data-[status=ready]:opacity-100", className),
217
+ "data-status": status,
218
+ ...props,
219
+ children: [/* @__PURE__ */ jsx("span", { className: cn("size-2 rounded-full", status === "ready" ? "bg-emerald-500" : status === "error" ? "bg-red-500" : "bg-amber-500") }), /* @__PURE__ */ jsx("span", { children: content })]
220
+ });
221
+ }
222
+ /**
223
+ * Renders the primary submit button for the current composer draft.
224
+ * It uses an arrow-up icon by default and disables itself while the composer cannot submit.
225
+ *
226
+ * @example
227
+ * ```tsx
228
+ * <ChatComposerSubmit />
229
+ * ```
230
+ */
231
+ function ChatComposerSubmit({ className, disabled, onClick, ...props }) {
232
+ const { canSubmit, submit, status } = useContext(ChatComposerContext);
233
+ return /* @__PURE__ */ jsxs(Button, {
234
+ type: "button",
235
+ variant: "default",
236
+ size: "icon",
237
+ disabled: !canSubmit || disabled,
238
+ className: cn("size-8 rounded-full p-0 shadow-none", className),
239
+ "aria-label": "Send message",
240
+ onClick: (event) => {
241
+ onClick?.(event);
242
+ if (!event.defaultPrevented) submit();
243
+ },
244
+ ...props,
245
+ children: [/* @__PURE__ */ jsx(ArrowUp, { className: "size-4" }), /* @__PURE__ */ jsx("span", {
246
+ className: "sr-only",
247
+ children: status !== "ready" ? "Wait for response" : "Send message"
248
+ })]
249
+ });
250
+ }
251
+ /**
252
+ * Helpers
253
+ */
254
+ function adjustTextareaHeight(textarea) {
255
+ if (!textarea) return;
256
+ textarea.style.height = "auto";
257
+ textarea.style.height = `${textarea.scrollHeight + 2}px`;
258
+ }
259
+ function resetTextareaHeight(textarea) {
260
+ if (!textarea) return;
261
+ textarea.style.height = "auto";
262
+ textarea.style.height = "8rem";
263
+ }
264
+
265
+ //#endregion
266
+ export { ChatComposer, ChatComposerActions, ChatComposerAttachmentButton, ChatComposerInput, ChatComposerModelSelect, ChatComposerStatus, ChatComposerSubmit, ChatComposerToolbar };
@@ -0,0 +1,92 @@
1
+ import { ChatPart } from "../lib/types.mjs";
2
+ import { ToolClientDefinition } from "../../tools/lib/types.client.mjs";
3
+ import { UIMessage } from "ai";
4
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
5
+ import { Message, MessageContent } from "@tulip-systems/core/components";
6
+ import { ComponentProps } from "react";
7
+
8
+ //#region src/chat/components/chat-message.client.d.ts
9
+ type ChatMessageProps = ComponentProps<typeof Message> & {
10
+ message: UIMessage;
11
+ };
12
+ /**
13
+ * Provides the root message container and message context for all chat message slots.
14
+ * Use it with `ChatMessageContent` and `ChatMessageParts` for the default message layout.
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * <ChatMessage message={message}>
19
+ * <ChatMessageContent>
20
+ * <ChatMessageParts toolRenderers={toolRenderers} />
21
+ * </ChatMessageContent>
22
+ * </ChatMessage>
23
+ * ```
24
+ */
25
+ declare function ChatMessage({
26
+ message,
27
+ children,
28
+ ...props
29
+ }: ChatMessageProps): react_jsx_runtime0.JSX.Element | null;
30
+ /**
31
+ * Renders the content column for a chat message.
32
+ * Place `ChatMessageHeader`, `ChatMessageParts`, and `ChatMessageFooter` inside it.
33
+ *
34
+ * @example
35
+ * ```tsx
36
+ * <ChatMessageContent>
37
+ * <ChatMessageParts toolRenderers={toolRenderers} />
38
+ * </ChatMessageContent>
39
+ * ```
40
+ */
41
+ declare function ChatMessageContent({
42
+ className,
43
+ ...props
44
+ }: ComponentProps<typeof MessageContent>): react_jsx_runtime0.JSX.Element;
45
+ /**
46
+ * Renders a message header slot.
47
+ * If no children are passed, it renders nothing.
48
+ *
49
+ * @example
50
+ * ```tsx
51
+ * <ChatMessageHeader>Assistant</ChatMessageHeader>
52
+ * ```
53
+ */
54
+ declare function ChatMessageHeader({
55
+ className,
56
+ children,
57
+ ...props
58
+ }: ComponentProps<"div">): react_jsx_runtime0.JSX.Element | null;
59
+ /**
60
+ * Renders the visible text and tool parts for the current chat message.
61
+ * Pass `toolRenderers` to customize how known tool calls/results are displayed.
62
+ *
63
+ * @example
64
+ * ```tsx
65
+ * <ChatMessageParts toolRenderers={toolRenderers} />
66
+ * ```
67
+ */
68
+ declare function ChatMessageParts({
69
+ toolRenderers,
70
+ className,
71
+ parts,
72
+ ...props
73
+ }: ComponentProps<"div"> & {
74
+ toolRenderers?: ToolClientDefinition[];
75
+ parts?: ChatPart[];
76
+ }): react_jsx_runtime0.JSX.Element;
77
+ /**
78
+ * Renders a message footer slot.
79
+ * If no children are passed, it renders nothing.
80
+ *
81
+ * @example
82
+ * ```tsx
83
+ * <ChatMessageFooter>Copied</ChatMessageFooter>
84
+ * ```
85
+ */
86
+ declare function ChatMessageFooter({
87
+ className,
88
+ children,
89
+ ...props
90
+ }: ComponentProps<"div">): react_jsx_runtime0.JSX.Element | null;
91
+ //#endregion
92
+ export { ChatMessage, ChatMessageContent, ChatMessageFooter, ChatMessageHeader, ChatMessageParts, ChatMessageProps };
@@ -0,0 +1,121 @@
1
+ "use client";
2
+
3
+ import { getChatPartKey, isToolPart } from "../lib/parts.mjs";
4
+ import { ChatMessagePart } from "./message-part.client.mjs";
5
+ import { cn } from "@tulip-systems/core/lib";
6
+ import { jsx } from "react/jsx-runtime";
7
+ import { Message, MessageContent, MessageFooter, MessageHeader } from "@tulip-systems/core/components";
8
+ import { createContext, useContext, useMemo } from "react";
9
+
10
+ //#region src/chat/components/chat-message.client.tsx
11
+ const ChatMessageContext = createContext({});
12
+ /**
13
+ * Provides the root message container and message context for all chat message slots.
14
+ * Use it with `ChatMessageContent` and `ChatMessageParts` for the default message layout.
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * <ChatMessage message={message}>
19
+ * <ChatMessageContent>
20
+ * <ChatMessageParts toolRenderers={toolRenderers} />
21
+ * </ChatMessageContent>
22
+ * </ChatMessage>
23
+ * ```
24
+ */
25
+ function ChatMessage({ message, children, ...props }) {
26
+ const isUser = message.role === "user";
27
+ const contextValue = useMemo(() => {
28
+ return {
29
+ message,
30
+ isUser,
31
+ visibleParts: message.parts.filter((part) => part.type === "text" || isToolPart(part))
32
+ };
33
+ }, [message, isUser]);
34
+ if (contextValue.visibleParts.length === 0) return null;
35
+ return /* @__PURE__ */ jsx(ChatMessageContext.Provider, {
36
+ value: contextValue,
37
+ children: /* @__PURE__ */ jsx(Message, {
38
+ align: isUser ? "end" : "start",
39
+ ...props,
40
+ children
41
+ })
42
+ });
43
+ }
44
+ /**
45
+ * Renders the content column for a chat message.
46
+ * Place `ChatMessageHeader`, `ChatMessageParts`, and `ChatMessageFooter` inside it.
47
+ *
48
+ * @example
49
+ * ```tsx
50
+ * <ChatMessageContent>
51
+ * <ChatMessageParts toolRenderers={toolRenderers} />
52
+ * </ChatMessageContent>
53
+ * ```
54
+ */
55
+ function ChatMessageContent({ className, ...props }) {
56
+ const { isUser } = useContext(ChatMessageContext);
57
+ return /* @__PURE__ */ jsx(MessageContent, {
58
+ className: cn(isUser && "ml-auto w-fit max-w-[82%] md:max-w-[68%]", className),
59
+ ...props
60
+ });
61
+ }
62
+ /**
63
+ * Renders a message header slot.
64
+ * If no children are passed, it renders nothing.
65
+ *
66
+ * @example
67
+ * ```tsx
68
+ * <ChatMessageHeader>Assistant</ChatMessageHeader>
69
+ * ```
70
+ */
71
+ function ChatMessageHeader({ className, children, ...props }) {
72
+ const { isUser } = useContext(ChatMessageContext);
73
+ if (!children) return null;
74
+ return /* @__PURE__ */ jsx(MessageHeader, {
75
+ className: cn("px-1", isUser && "justify-end", className),
76
+ ...props,
77
+ children
78
+ });
79
+ }
80
+ /**
81
+ * Renders the visible text and tool parts for the current chat message.
82
+ * Pass `toolRenderers` to customize how known tool calls/results are displayed.
83
+ *
84
+ * @example
85
+ * ```tsx
86
+ * <ChatMessageParts toolRenderers={toolRenderers} />
87
+ * ```
88
+ */
89
+ function ChatMessageParts({ toolRenderers, className, parts, ...props }) {
90
+ const { message, isUser, visibleParts } = useContext(ChatMessageContext);
91
+ const resolvedParts = parts ?? visibleParts;
92
+ return /* @__PURE__ */ jsx("div", {
93
+ className: cn("flex max-w-full flex-col gap-2.5", className),
94
+ ...props,
95
+ children: resolvedParts.map((part) => /* @__PURE__ */ jsx(ChatMessagePart, {
96
+ part,
97
+ isUser,
98
+ toolRenderers
99
+ }, getChatPartKey(message.id, part)))
100
+ });
101
+ }
102
+ /**
103
+ * Renders a message footer slot.
104
+ * If no children are passed, it renders nothing.
105
+ *
106
+ * @example
107
+ * ```tsx
108
+ * <ChatMessageFooter>Copied</ChatMessageFooter>
109
+ * ```
110
+ */
111
+ function ChatMessageFooter({ className, children, ...props }) {
112
+ if (!children) return null;
113
+ return /* @__PURE__ */ jsx(MessageFooter, {
114
+ className: cn("px-1", className),
115
+ ...props,
116
+ children
117
+ });
118
+ }
119
+
120
+ //#endregion
121
+ export { ChatMessage, ChatMessageContent, ChatMessageFooter, ChatMessageHeader, ChatMessageParts };
@@ -0,0 +1,130 @@
1
+ import { ToolClientDefinition } from "../../tools/lib/types.client.mjs";
2
+ import { ChatStatus, UIMessage } from "ai";
3
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
4
+ import { ComponentProps } from "react";
5
+ import { MessageScrollerButton, MessageScrollerContent, MessageScrollerItem } from "@tulip-systems/core/components/client";
6
+
7
+ //#region src/chat/components/chat-thread.client.d.ts
8
+ type ChatThreadProps = ComponentProps<"div"> & {
9
+ status?: ChatStatus;
10
+ autoScroll?: boolean;
11
+ defaultScrollPosition?: "start" | "end" | "last-anchor";
12
+ scrollPreviousItemPeek?: number;
13
+ };
14
+ /**
15
+ * Provides shared thread state for all chat thread slots.
16
+ * Use it to configure chat status and scroll behavior once.
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * <ChatThread status={status}>
21
+ * {messages.length === 0 && <EmptyState />}
22
+ *
23
+ * {messages.length > 0 && (
24
+ * <ChatThreadContent>
25
+ * {messages.map((message) => (
26
+ * <ChatThreadMessage key={message.id} message={message} />
27
+ * ))}
28
+ * <ChatThreadActivity />
29
+ * </ChatThreadContent>
30
+ * )}
31
+ * </ChatThread>
32
+ * ```
33
+ */
34
+ declare function ChatThread({
35
+ status,
36
+ autoScroll,
37
+ defaultScrollPosition,
38
+ scrollPreviousItemPeek,
39
+ className,
40
+ children,
41
+ ...props
42
+ }: ChatThreadProps): react_jsx_runtime0.JSX.Element;
43
+ /**
44
+ * Renders the scrollable message area for a chat thread.
45
+ * Place `ChatThreadMessage`, `ChatThreadActivity`, and optional sentinels inside it.
46
+ *
47
+ * @example
48
+ * ```tsx
49
+ * <ChatThreadContent className="px-3">
50
+ * {messages.map((message) => (
51
+ * <ChatThreadMessage key={message.id} message={message} />
52
+ * ))}
53
+ * <ChatThreadActivity />
54
+ * </ChatThreadContent>
55
+ * ```
56
+ */
57
+ declare function ChatThreadContent({
58
+ className,
59
+ children,
60
+ ...props
61
+ }: ComponentProps<typeof MessageScrollerContent>): react_jsx_runtime0.JSX.Element;
62
+ /**
63
+ * Renders one AI SDK message using the current `ChatThread` configuration.
64
+ * Use this inside `ChatThreadContent` when mapping over messages.
65
+ *
66
+ * @example
67
+ * ```tsx
68
+ * {messages.map((message) => (
69
+ * <ChatThreadMessage key={message.id} message={message} toolRenderers={toolRenderers} />
70
+ * ))}
71
+ * ```
72
+ */
73
+ declare function ChatThreadMessage({
74
+ message,
75
+ messageId,
76
+ scrollAnchor,
77
+ toolRenderers,
78
+ ...props
79
+ }: Omit<ComponentProps<typeof MessageScrollerItem>, "children" | "messageId" | "scrollAnchor"> & {
80
+ message: UIMessage;
81
+ messageId?: string;
82
+ scrollAnchor?: boolean;
83
+ toolRenderers?: ToolClientDefinition[];
84
+ }): react_jsx_runtime0.JSX.Element;
85
+ /**
86
+ * Renders the assistant activity indicator while the thread status is `submitted` or `streaming`.
87
+ * It returns nothing when the assistant is not responding.
88
+ *
89
+ * @example
90
+ * ```tsx
91
+ * <ChatThreadActivity />
92
+ * ```
93
+ */
94
+ declare function ChatThreadActivity({
95
+ messageId,
96
+ activityClassName,
97
+ ...props
98
+ }: Omit<ComponentProps<typeof MessageScrollerItem>, "children" | "messageId"> & {
99
+ messageId?: string;
100
+ activityClassName?: string;
101
+ }): react_jsx_runtime0.JSX.Element | null;
102
+ /**
103
+ * Renders a bottom sentinel item inside the thread scroller.
104
+ * Use it when callers need a stable ref at the end of the message list.
105
+ *
106
+ * @example
107
+ * ```tsx
108
+ * <ChatThreadBottom ref={bottomRef} />
109
+ * ```
110
+ */
111
+ declare function ChatThreadBottom({
112
+ messageId,
113
+ scrollAnchor,
114
+ ...props
115
+ }: ComponentProps<"div"> & {
116
+ messageId?: string;
117
+ scrollAnchor?: boolean;
118
+ }): react_jsx_runtime0.JSX.Element;
119
+ /**
120
+ * Renders the scroll-to-bottom button for `ChatThreadContent`.
121
+ * `ChatThreadContent` includes this button by default.
122
+ *
123
+ * @example
124
+ * ```tsx
125
+ * <ChatThreadScrollButton />
126
+ * ```
127
+ */
128
+ declare function ChatThreadScrollButton(props: ComponentProps<typeof MessageScrollerButton>): react_jsx_runtime0.JSX.Element;
129
+ //#endregion
130
+ export { ChatThread, ChatThreadActivity, ChatThreadBottom, ChatThreadContent, ChatThreadMessage, ChatThreadProps, ChatThreadScrollButton };