@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,164 @@
1
+ "use client";
2
+
3
+ import { AgentActivity } from "./agent-activity.client.mjs";
4
+ import { ChatMessage, ChatMessageContent, ChatMessageParts } from "./chat-message.client.mjs";
5
+ import { cn } from "@tulip-systems/core/lib";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ import { Message, MessageContent } from "@tulip-systems/core/components";
8
+ import { createContext, useContext, useMemo } from "react";
9
+ import { MessageScroller, MessageScrollerButton, MessageScrollerContent, MessageScrollerItem, MessageScrollerProvider, MessageScrollerViewport } from "@tulip-systems/core/components/client";
10
+
11
+ //#region src/chat/components/chat-thread.client.tsx
12
+ const ChatThreadContext = createContext({});
13
+ /**
14
+ * Provides shared thread state for all chat thread slots.
15
+ * Use it to configure chat status and scroll behavior once.
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * <ChatThread status={status}>
20
+ * {messages.length === 0 && <EmptyState />}
21
+ *
22
+ * {messages.length > 0 && (
23
+ * <ChatThreadContent>
24
+ * {messages.map((message) => (
25
+ * <ChatThreadMessage key={message.id} message={message} />
26
+ * ))}
27
+ * <ChatThreadActivity />
28
+ * </ChatThreadContent>
29
+ * )}
30
+ * </ChatThread>
31
+ * ```
32
+ */
33
+ function ChatThread({ status = "ready", autoScroll = true, defaultScrollPosition = "end", scrollPreviousItemPeek = 64, className, children, ...props }) {
34
+ const isAssistantResponding = status === "submitted" || status === "streaming";
35
+ const contextValue = useMemo(() => ({
36
+ status,
37
+ isAssistantResponding,
38
+ autoScroll,
39
+ defaultScrollPosition,
40
+ scrollPreviousItemPeek
41
+ }), [
42
+ status,
43
+ isAssistantResponding,
44
+ autoScroll,
45
+ defaultScrollPosition,
46
+ scrollPreviousItemPeek
47
+ ]);
48
+ return /* @__PURE__ */ jsx(ChatThreadContext.Provider, {
49
+ value: contextValue,
50
+ children: /* @__PURE__ */ jsx("div", {
51
+ "data-slot": "chat-thread",
52
+ "data-status": status,
53
+ "data-responding": isAssistantResponding ? true : void 0,
54
+ className: cn("min-h-0 flex-1", className),
55
+ ...props,
56
+ children
57
+ })
58
+ });
59
+ }
60
+ /**
61
+ * Renders the scrollable message area for a chat thread.
62
+ * Place `ChatThreadMessage`, `ChatThreadActivity`, and optional sentinels inside it.
63
+ *
64
+ * @example
65
+ * ```tsx
66
+ * <ChatThreadContent className="px-3">
67
+ * {messages.map((message) => (
68
+ * <ChatThreadMessage key={message.id} message={message} />
69
+ * ))}
70
+ * <ChatThreadActivity />
71
+ * </ChatThreadContent>
72
+ * ```
73
+ */
74
+ function ChatThreadContent({ className, children, ...props }) {
75
+ const { isAssistantResponding, autoScroll, defaultScrollPosition, scrollPreviousItemPeek } = useContext(ChatThreadContext);
76
+ return /* @__PURE__ */ jsx(MessageScrollerProvider, {
77
+ autoScroll,
78
+ defaultScrollPosition,
79
+ scrollPreviousItemPeek,
80
+ children: /* @__PURE__ */ jsxs(MessageScroller, {
81
+ className: "min-h-0 flex-1",
82
+ children: [/* @__PURE__ */ jsx(MessageScrollerViewport, { children: /* @__PURE__ */ jsx(MessageScrollerContent, {
83
+ "aria-busy": isAssistantResponding,
84
+ className: cn("mx-auto w-full max-w-3xl gap-7 px-1 py-4 md:py-6", className),
85
+ ...props,
86
+ children
87
+ }) }), /* @__PURE__ */ jsx(ChatThreadScrollButton, {})]
88
+ })
89
+ });
90
+ }
91
+ /**
92
+ * Renders one AI SDK message using the current `ChatThread` configuration.
93
+ * Use this inside `ChatThreadContent` when mapping over messages.
94
+ *
95
+ * @example
96
+ * ```tsx
97
+ * {messages.map((message) => (
98
+ * <ChatThreadMessage key={message.id} message={message} toolRenderers={toolRenderers} />
99
+ * ))}
100
+ * ```
101
+ */
102
+ function ChatThreadMessage({ message, messageId = message.id, scrollAnchor = message.role === "user", toolRenderers, ...props }) {
103
+ return /* @__PURE__ */ jsx(MessageScrollerItem, {
104
+ messageId,
105
+ scrollAnchor,
106
+ ...props,
107
+ children: /* @__PURE__ */ jsx(ChatMessage, {
108
+ message,
109
+ children: /* @__PURE__ */ jsx(ChatMessageContent, { children: /* @__PURE__ */ jsx(ChatMessageParts, { toolRenderers }) })
110
+ })
111
+ });
112
+ }
113
+ /**
114
+ * Renders the assistant activity indicator while the thread status is `submitted` or `streaming`.
115
+ * It returns nothing when the assistant is not responding.
116
+ *
117
+ * @example
118
+ * ```tsx
119
+ * <ChatThreadActivity />
120
+ * ```
121
+ */
122
+ function ChatThreadActivity({ messageId = "agent-activity", activityClassName, ...props }) {
123
+ const { isAssistantResponding } = useContext(ChatThreadContext);
124
+ if (!isAssistantResponding) return null;
125
+ return /* @__PURE__ */ jsx(MessageScrollerItem, {
126
+ messageId,
127
+ ...props,
128
+ children: /* @__PURE__ */ jsx(Message, {
129
+ align: "start",
130
+ children: /* @__PURE__ */ jsx(MessageContent, { children: /* @__PURE__ */ jsx(AgentActivity, { className: activityClassName }) })
131
+ })
132
+ });
133
+ }
134
+ /**
135
+ * Renders a bottom sentinel item inside the thread scroller.
136
+ * Use it when callers need a stable ref at the end of the message list.
137
+ *
138
+ * @example
139
+ * ```tsx
140
+ * <ChatThreadBottom ref={bottomRef} />
141
+ * ```
142
+ */
143
+ function ChatThreadBottom({ messageId = "bottom-sentinel", scrollAnchor = false, ...props }) {
144
+ return /* @__PURE__ */ jsx(MessageScrollerItem, {
145
+ messageId,
146
+ scrollAnchor,
147
+ children: /* @__PURE__ */ jsx("div", { ...props })
148
+ });
149
+ }
150
+ /**
151
+ * Renders the scroll-to-bottom button for `ChatThreadContent`.
152
+ * `ChatThreadContent` includes this button by default.
153
+ *
154
+ * @example
155
+ * ```tsx
156
+ * <ChatThreadScrollButton />
157
+ * ```
158
+ */
159
+ function ChatThreadScrollButton(props) {
160
+ return /* @__PURE__ */ jsx(MessageScrollerButton, { ...props });
161
+ }
162
+
163
+ //#endregion
164
+ export { ChatThread, ChatThreadActivity, ChatThreadBottom, ChatThreadContent, ChatThreadMessage, ChatThreadScrollButton };
@@ -0,0 +1,23 @@
1
+ import { ChatPart } from "../lib/types.mjs";
2
+ import { ToolClientDefinition } from "../../tools/lib/types.client.mjs";
3
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
4
+ import * as react from "react";
5
+
6
+ //#region src/chat/components/message-part.client.d.ts
7
+ type ChatMessagePartProps = {
8
+ part: ChatPart;
9
+ isUser?: boolean;
10
+ toolRenderers?: ToolClientDefinition[];
11
+ className?: string;
12
+ };
13
+ /**
14
+ * Renders a visible AI SDK message part with a user bubble and plain assistant text.
15
+ */
16
+ declare function ChatMessagePart({
17
+ part,
18
+ isUser,
19
+ toolRenderers,
20
+ className
21
+ }: ChatMessagePartProps): string | number | bigint | boolean | react_jsx_runtime0.JSX.Element | Iterable<react.ReactNode> | Promise<string | number | bigint | boolean | react.ReactPortal | react.ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<react.ReactNode> | null | undefined> | null | undefined;
22
+ //#endregion
23
+ export { ChatMessagePart, ChatMessagePartProps };
@@ -0,0 +1,38 @@
1
+ "use client";
2
+
3
+ import { isToolPart } from "../lib/parts.mjs";
4
+ import { ToolCallCard } from "./tool-call-card.client.mjs";
5
+ import { cn } from "@tulip-systems/core/lib";
6
+ import { jsx } from "react/jsx-runtime";
7
+
8
+ //#region src/chat/components/message-part.client.tsx
9
+ /**
10
+ * Renders a visible AI SDK message part with a user bubble and plain assistant text.
11
+ */
12
+ function ChatMessagePart({ part, isUser = false, toolRenderers, className }) {
13
+ if (part.type === "text") return /* @__PURE__ */ jsx("div", {
14
+ className: cn("max-w-[min(44rem,100%)]", isUser ? "rounded-3xl bg-muted px-4 py-2.5 text-foreground" : "px-1 text-foreground", className),
15
+ children: /* @__PURE__ */ jsx("p", {
16
+ className: "whitespace-pre-wrap text-[15px] leading-7",
17
+ children: part.text
18
+ })
19
+ });
20
+ if (isToolPart(part)) {
21
+ const toolRenderer = getToolRenderer(part, toolRenderers);
22
+ return toolRenderer ? toolRenderer.render(part) : /* @__PURE__ */ jsx(ToolCallCard, { part });
23
+ }
24
+ return null;
25
+ }
26
+ /**
27
+ * Helpers
28
+ */
29
+ function getToolName(part) {
30
+ return part.type.startsWith("tool-") ? part.type.slice(5) : part.type;
31
+ }
32
+ function getToolRenderer(part, toolRenderers) {
33
+ const toolName = getToolName(part);
34
+ return toolRenderers?.find((renderer) => renderer.toolName === toolName);
35
+ }
36
+
37
+ //#endregion
38
+ export { ChatMessagePart };
@@ -0,0 +1,25 @@
1
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
2
+ import { ReactNode } from "react";
3
+
4
+ //#region src/chat/components/starter-prompts.client.d.ts
5
+ type StarterPromptsProps = {
6
+ prompts: string[];
7
+ onSelect: (prompt: string) => void;
8
+ disabled?: boolean;
9
+ label?: ReactNode;
10
+ icon?: ReactNode;
11
+ className?: string;
12
+ };
13
+ /**
14
+ * Renders starter prompt buttons for a new chat state.
15
+ */
16
+ declare function StarterPrompts({
17
+ prompts,
18
+ onSelect,
19
+ disabled,
20
+ label,
21
+ icon,
22
+ className
23
+ }: StarterPromptsProps): react_jsx_runtime0.JSX.Element;
24
+ //#endregion
25
+ export { StarterPrompts, StarterPromptsProps };
@@ -0,0 +1,31 @@
1
+ "use client";
2
+
3
+ import { cn } from "@tulip-systems/core/lib";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+
6
+ //#region src/chat/components/starter-prompts.client.tsx
7
+ /**
8
+ * Renders starter prompt buttons for a new chat state.
9
+ */
10
+ function StarterPrompts({ prompts, onSelect, disabled = false, label, icon, className }) {
11
+ const hasMeta = Boolean(label || icon);
12
+ return /* @__PURE__ */ jsx("div", {
13
+ className: cn("grid w-full gap-2 sm:grid-cols-2", className),
14
+ children: prompts.map((prompt) => /* @__PURE__ */ jsxs("button", {
15
+ type: "button",
16
+ className: "group rounded-2xl border border-border/60 bg-background/80 p-3 text-left shadow-sm backdrop-blur transition-colors hover:bg-muted/40 disabled:cursor-not-allowed disabled:opacity-60",
17
+ disabled,
18
+ onClick: () => onSelect(prompt),
19
+ children: [hasMeta && /* @__PURE__ */ jsxs("div", {
20
+ className: "mb-2 flex items-center gap-2 font-medium text-muted-foreground text-xs uppercase tracking-[0.14em]",
21
+ children: [icon, label]
22
+ }), /* @__PURE__ */ jsx("p", {
23
+ className: "text-foreground/90 text-sm leading-6",
24
+ children: prompt
25
+ })]
26
+ }, prompt))
27
+ });
28
+ }
29
+
30
+ //#endregion
31
+ export { StarterPrompts };
@@ -0,0 +1,29 @@
1
+ import { ToolChatPart } from "../lib/types.mjs";
2
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
3
+ import { ReactNode } from "react";
4
+
5
+ //#region src/chat/components/tool-call-card.client.d.ts
6
+ type ToolCallCardLabels = {
7
+ input?: string;
8
+ output?: string;
9
+ preliminaryOutput?: string;
10
+ };
11
+ type ToolCallCardProps = {
12
+ part: ToolChatPart;
13
+ title?: ReactNode | ((toolName: string, part: ToolChatPart) => ReactNode);
14
+ icon?: ReactNode | ((toolName: string, part: ToolChatPart) => ReactNode);
15
+ labels?: ToolCallCardLabels;
16
+ className?: string;
17
+ };
18
+ /**
19
+ * Renders a streamed AI SDK tool part with input, output, state, and error details.
20
+ */
21
+ declare function ToolCallCard({
22
+ part,
23
+ title,
24
+ icon,
25
+ labels,
26
+ className
27
+ }: ToolCallCardProps): react_jsx_runtime0.JSX.Element;
28
+ //#endregion
29
+ export { ToolCallCard, ToolCallCardLabels, ToolCallCardProps };
@@ -0,0 +1,60 @@
1
+ "use client";
2
+
3
+ import { getDefaultToolTitle, getToolName, stringifyChatValue } from "../lib/parts.mjs";
4
+ import { cn } from "@tulip-systems/core/lib";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+
7
+ //#region src/chat/components/tool-call-card.client.tsx
8
+ /**
9
+ * Renders a streamed AI SDK tool part with input, output, state, and error details.
10
+ */
11
+ function ToolCallCard({ part, title, icon, labels, className }) {
12
+ const toolName = getToolName(part);
13
+ const resolvedTitle = typeof title === "function" ? title(toolName, part) : title;
14
+ const resolvedIcon = typeof icon === "function" ? icon(toolName, part) : icon;
15
+ const inputLabel = labels?.input ?? "Input";
16
+ const outputLabel = part.preliminary ? labels?.preliminaryOutput ?? "Intermediate result" : labels?.output ?? "Result";
17
+ return /* @__PURE__ */ jsxs("div", {
18
+ className: cn("max-w-full rounded-3xl border border-border/60 bg-muted/35 p-3.5 text-sm shadow-sm backdrop-blur-sm", className),
19
+ children: [
20
+ /* @__PURE__ */ jsxs("div", {
21
+ className: "flex items-center gap-2 font-medium text-[11px] text-muted-foreground uppercase tracking-[0.18em]",
22
+ children: [
23
+ resolvedIcon,
24
+ /* @__PURE__ */ jsx("span", { children: resolvedTitle ?? getDefaultToolTitle(toolName) }),
25
+ part.state && /* @__PURE__ */ jsx("span", {
26
+ className: "text-[10px] normal-case tracking-normal",
27
+ children: part.state
28
+ })
29
+ ]
30
+ }),
31
+ part.input !== void 0 && /* @__PURE__ */ jsxs("div", {
32
+ className: "mt-3 space-y-1.5",
33
+ children: [/* @__PURE__ */ jsx("div", {
34
+ className: "font-medium text-[11px] text-muted-foreground uppercase tracking-[0.14em]",
35
+ children: inputLabel
36
+ }), /* @__PURE__ */ jsx("pre", {
37
+ className: "overflow-x-auto whitespace-pre-wrap rounded-2xl bg-background/80 p-3 text-foreground/90 text-xs leading-5",
38
+ children: stringifyChatValue(part.input)
39
+ })]
40
+ }),
41
+ part.output !== void 0 && /* @__PURE__ */ jsxs("div", {
42
+ className: "mt-3 space-y-1.5",
43
+ children: [/* @__PURE__ */ jsx("div", {
44
+ className: "font-medium text-[11px] text-muted-foreground uppercase tracking-[0.14em]",
45
+ children: outputLabel
46
+ }), /* @__PURE__ */ jsx("pre", {
47
+ className: "overflow-x-auto whitespace-pre-wrap rounded-2xl bg-background/80 p-3 text-foreground/90 text-xs leading-5",
48
+ children: stringifyChatValue(part.output)
49
+ })]
50
+ }),
51
+ part.errorText && /* @__PURE__ */ jsx("div", {
52
+ className: "mt-3 rounded-xl border border-red-200 bg-red-50 p-3 text-red-700 text-xs",
53
+ children: part.errorText
54
+ })
55
+ ]
56
+ });
57
+ }
58
+
59
+ //#endregion
60
+ export { ToolCallCard };
@@ -0,0 +1,7 @@
1
+ //#region src/chat/lib/classes.ts
2
+ function cx(...classes) {
3
+ return classes.filter(Boolean).join(" ");
4
+ }
5
+
6
+ //#endregion
7
+ export { cx };
@@ -0,0 +1,10 @@
1
+ import { ChatPart, ToolChatPart } from "./types.mjs";
2
+
3
+ //#region src/chat/lib/parts.d.ts
4
+ declare function isToolPart(part: ChatPart): part is ToolChatPart;
5
+ declare function getToolName(part: ToolChatPart): string;
6
+ declare function getDefaultToolTitle(toolName: string): string;
7
+ declare function stringifyChatValue(value: unknown): string;
8
+ declare function getChatPartKey(messageId: string, part: ChatPart): string;
9
+ //#endregion
10
+ export { getChatPartKey, getDefaultToolTitle, getToolName, isToolPart, stringifyChatValue };
@@ -0,0 +1,25 @@
1
+ //#region src/chat/lib/parts.ts
2
+ function isToolPart(part) {
3
+ return part.type.startsWith("tool-");
4
+ }
5
+ function getToolName(part) {
6
+ return part.type.slice(5);
7
+ }
8
+ function getDefaultToolTitle(toolName) {
9
+ return toolName.replaceAll("_", " ");
10
+ }
11
+ function stringifyChatValue(value) {
12
+ try {
13
+ return JSON.stringify(value, null, 2);
14
+ } catch {
15
+ return String(value);
16
+ }
17
+ }
18
+ function getChatPartKey(messageId, part) {
19
+ if (part.type === "text") return `${messageId}-text-${part.text.slice(0, 40)}`;
20
+ if (isToolPart(part)) return `${messageId}-${part.type}-${stringifyChatValue(part.input ?? part.output ?? part.type).slice(0, 60)}`;
21
+ return `${messageId}-${part.type}`;
22
+ }
23
+
24
+ //#endregion
25
+ export { getChatPartKey, getDefaultToolTitle, getToolName, isToolPart, stringifyChatValue };
@@ -0,0 +1,24 @@
1
+ import { StreamAgentChatOptions } from "./types.mjs";
2
+ import "server-cli-only";
3
+ import * as ai from "ai";
4
+ import * as _orpc_server0 from "@orpc/server";
5
+
6
+ //#region src/chat/lib/stream.server.d.ts
7
+ /**
8
+ * Streams a Tulip agent response as an AI SDK UI message stream.
9
+ * Use this when the caller wants a framework-neutral `ReadableStream`.
10
+ */
11
+ declare function streamAgentChat({
12
+ agent,
13
+ messages,
14
+ abortSignal,
15
+ convertToModelMessagesOptions,
16
+ uiMessageStreamOptions
17
+ }: StreamAgentChatOptions): Promise<ReadableStream<ai.InferUIMessageChunk<ai.UIMessage<unknown, ai.UIDataTypes, ai.UITools>>>>;
18
+ /**
19
+ * Streams a Tulip agent response as an oRPC event iterator.
20
+ * Use this from oRPC procedures that return an AI SDK UI message stream to clients.
21
+ */
22
+ declare function streamAgentChatEventIterator(options: StreamAgentChatOptions): Promise<_orpc_server0.AsyncIteratorClass<ai.InferUIMessageChunk<ai.UIMessage<unknown, ai.UIDataTypes, ai.UITools>>, unknown, unknown>>;
23
+ //#endregion
24
+ export { streamAgentChat, streamAgentChatEventIterator };
@@ -0,0 +1,34 @@
1
+ import "server-cli-only";
2
+ import { convertToModelMessages, toUIMessageStream } from "ai";
3
+ import { streamToEventIterator } from "@orpc/server";
4
+
5
+ //#region src/chat/lib/stream.server.ts
6
+ /**
7
+ * Streams a Tulip agent response as an AI SDK UI message stream.
8
+ * Use this when the caller wants a framework-neutral `ReadableStream`.
9
+ */
10
+ async function streamAgentChat({ agent, messages, abortSignal, convertToModelMessagesOptions, uiMessageStreamOptions }) {
11
+ const modelMessages = await convertToModelMessages(messages, {
12
+ ignoreIncompleteToolCalls: true,
13
+ ...convertToModelMessagesOptions
14
+ });
15
+ const result = await agent.stream({
16
+ messages: modelMessages,
17
+ abortSignal
18
+ });
19
+ return toUIMessageStream({
20
+ ...uiMessageStreamOptions,
21
+ stream: result.stream,
22
+ tools: agent.tools
23
+ });
24
+ }
25
+ /**
26
+ * Streams a Tulip agent response as an oRPC event iterator.
27
+ * Use this from oRPC procedures that return an AI SDK UI message stream to clients.
28
+ */
29
+ async function streamAgentChatEventIterator(options) {
30
+ return streamToEventIterator(await streamAgentChat(options));
31
+ }
32
+
33
+ //#endregion
34
+ export { streamAgentChat, streamAgentChatEventIterator };
@@ -0,0 +1,21 @@
1
+ import { CreatedAgent } from "../../agents/lib/types.mjs";
2
+ import { UIMessage, convertToModelMessages, toUIMessageStream } from "ai";
3
+
4
+ //#region src/chat/lib/types.d.ts
5
+ type ChatPart = UIMessage["parts"][number];
6
+ type ToolChatPart = ChatPart & {
7
+ input?: unknown;
8
+ output?: unknown;
9
+ state?: string;
10
+ preliminary?: boolean;
11
+ errorText?: string;
12
+ };
13
+ type StreamAgentChatOptions = {
14
+ agent: CreatedAgent;
15
+ messages: UIMessage[];
16
+ abortSignal?: AbortSignal;
17
+ convertToModelMessagesOptions?: Parameters<typeof convertToModelMessages>[1];
18
+ uiMessageStreamOptions?: Omit<Parameters<typeof toUIMessageStream>[0], "stream" | "tools">;
19
+ };
20
+ //#endregion
21
+ export { ChatPart, StreamAgentChatOptions, ToolChatPart };
@@ -0,0 +1,3 @@
1
+ import { ChatPart, StreamAgentChatOptions, ToolChatPart } from "./lib/types.mjs";
2
+ import { streamAgentChat, streamAgentChatEventIterator } from "./lib/stream.server.mjs";
3
+ export { ChatPart, StreamAgentChatOptions, ToolChatPart, streamAgentChat, streamAgentChatEventIterator };
@@ -0,0 +1,3 @@
1
+ import { streamAgentChat, streamAgentChatEventIterator } from "./lib/stream.server.mjs";
2
+
3
+ export { streamAgentChat, streamAgentChatEventIterator };
@@ -0,0 +1,3 @@
1
+ import { ChatPart, StreamAgentChatOptions, ToolChatPart } from "./chat/lib/types.mjs";
2
+ import { getChatPartKey, getDefaultToolTitle, getToolName, isToolPart, stringifyChatValue } from "./chat/lib/parts.mjs";
3
+ export { ChatPart, StreamAgentChatOptions, ToolChatPart, getChatPartKey, getDefaultToolTitle, getToolName, isToolPart, stringifyChatValue };
package/dist/chat.mjs ADDED
@@ -0,0 +1,3 @@
1
+ import { getChatPartKey, getDefaultToolTitle, getToolName, isToolPart, stringifyChatValue } from "./chat/lib/parts.mjs";
2
+
3
+ export { getChatPartKey, getDefaultToolTitle, getToolName, isToolPart, stringifyChatValue };
@@ -0,0 +1 @@
1
+ export { };
package/dist/index.mjs ADDED
@@ -0,0 +1 @@
1
+ export { };
@@ -0,0 +1,66 @@
1
+ import { McpResourceContent, McpToolResult } from "./types.mjs";
2
+
3
+ //#region src/mcp/lib/content.d.ts
4
+ /**
5
+ * Creates a plain text MCP tool result.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * resolveMCPTool(getStatus, {
10
+ * content: ({ output }) => text(`Status: ${output.status}`),
11
+ * });
12
+ * ```
13
+ */
14
+ declare function text(value: string, options?: {
15
+ isError?: boolean;
16
+ }): McpToolResult;
17
+ /**
18
+ * Creates a JSON MCP tool result with structured content preserved for clients that support it.
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * resolveMCPTool(createProspect, {
23
+ * content: ({ output }) => json(output, { label: "Created prospect:" }),
24
+ * });
25
+ * ```
26
+ */
27
+ declare function json<TValue>(value: TValue, options?: {
28
+ label?: string;
29
+ isError?: boolean;
30
+ }): McpToolResult<TValue>;
31
+ /**
32
+ * Creates an MCP resource result for text, blob, or URI-backed resources.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * resolveMCPTool(getInvoice, {
37
+ * content: ({ output }) =>
38
+ * resource({ uri: output.uri, mimeType: "application/pdf" }),
39
+ * });
40
+ * ```
41
+ */
42
+ declare function resource(value: McpResourceContent["resource"]): McpToolResult;
43
+ /**
44
+ * Creates a markdown table MCP result and keeps the original rows as structured content.
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * resolveMCPTool(listCustomers, {
49
+ * content: ({ output }) =>
50
+ * table(output.customers, {
51
+ * title: "Customers",
52
+ * columns: ["id", "name"],
53
+ * }),
54
+ * });
55
+ * ```
56
+ */
57
+ declare function table<TRow extends Record<string, unknown>>(rows: TRow[], options?: {
58
+ columns?: Array<keyof TRow & string>;
59
+ emptyText?: string;
60
+ title?: string;
61
+ }): McpToolResult<{
62
+ columns: string[];
63
+ rows: TRow[];
64
+ }>;
65
+ //#endregion
66
+ export { json, resource, table, text };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content.d.mts","names":[],"sources":["../../../src/mcp/lib/content.ts"],"mappings":";;;iBAEgB,WAAA,CAAY,IAAA,UAAc,OAAA;EAAY,OAAA;AAAA,IAAsB,aAAA;AAAA,iBAO5D,WAAA,QAAA,CACd,KAAA,EAAO,MAAA,EACP,OAAA;EAAY,KAAA;EAAgB,OAAA;AAAA,IAC3B,aAAA,CAAc,MAAA;AAAA,iBAeD,eAAA,CAAgB,QAAA,EAAU,kBAAA,eAAiC,aAAA;AAAA,iBAM3D,YAAA,cAA0B,MAAA,kBAAA,CACxC,IAAA,EAAM,IAAA,IACN,OAAA;EACE,OAAA,GAAU,KAAA,OAAY,IAAA;EACtB,SAAA;EACA,KAAA;AAAA,IAED,aAAA;EAAgB,OAAA;EAAmB,IAAA,EAAM,IAAA;AAAA"}