@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.
- package/LICENSE +662 -0
- package/dist/agents/lib/definitions.server.d.mts +11 -0
- package/dist/agents/lib/definitions.server.mjs +14 -0
- package/dist/agents/lib/delegation.server.d.mts +15 -0
- package/dist/agents/lib/delegation.server.mjs +28 -0
- package/dist/agents/lib/instructions.server.d.mts +14 -0
- package/dist/agents/lib/instructions.server.mjs +26 -0
- package/dist/agents/lib/types.d.mts +26 -0
- package/dist/agents/server.d.mts +5 -0
- package/dist/agents/server.mjs +5 -0
- package/dist/chat/client.d.mts +10 -0
- package/dist/chat/client.mjs +12 -0
- package/dist/chat/components/agent-activity.client.d.mts +14 -0
- package/dist/chat/components/agent-activity.client.mjs +26 -0
- package/dist/chat/components/assistant-panel.client.d.mts +40 -0
- package/dist/chat/components/assistant-panel.client.mjs +53 -0
- package/dist/chat/components/chat-composer.client.d.mts +160 -0
- package/dist/chat/components/chat-composer.client.mjs +266 -0
- package/dist/chat/components/chat-message.client.d.mts +92 -0
- package/dist/chat/components/chat-message.client.mjs +121 -0
- package/dist/chat/components/chat-thread.client.d.mts +130 -0
- package/dist/chat/components/chat-thread.client.mjs +164 -0
- package/dist/chat/components/message-part.client.d.mts +23 -0
- package/dist/chat/components/message-part.client.mjs +38 -0
- package/dist/chat/components/starter-prompts.client.d.mts +25 -0
- package/dist/chat/components/starter-prompts.client.mjs +31 -0
- package/dist/chat/components/tool-call-card.client.d.mts +29 -0
- package/dist/chat/components/tool-call-card.client.mjs +60 -0
- package/dist/chat/lib/classes.mjs +7 -0
- package/dist/chat/lib/parts.d.mts +10 -0
- package/dist/chat/lib/parts.mjs +25 -0
- package/dist/chat/lib/stream.server.d.mts +24 -0
- package/dist/chat/lib/stream.server.mjs +34 -0
- package/dist/chat/lib/types.d.mts +21 -0
- package/dist/chat/server.d.mts +3 -0
- package/dist/chat/server.mjs +3 -0
- package/dist/chat.d.mts +3 -0
- package/dist/chat.mjs +3 -0
- package/dist/index.d.mts +1 -0
- package/dist/index.mjs +1 -0
- package/dist/mcp/lib/content.d.mts +66 -0
- package/dist/mcp/lib/content.d.mts.map +1 -0
- package/dist/mcp/lib/content.mjs +115 -0
- package/dist/mcp/lib/content.mjs.map +1 -0
- package/dist/mcp/lib/tool-result.server.d.mts +12 -0
- package/dist/mcp/lib/tool-result.server.d.mts.map +1 -0
- package/dist/mcp/lib/tool-result.server.mjs +10 -0
- package/dist/mcp/lib/tool-result.server.mjs.map +1 -0
- package/dist/mcp/lib/types.d.mts +27 -0
- package/dist/mcp/server.d.mts +3 -0
- package/dist/mcp/server.mjs +3 -0
- package/dist/mcp/types.d.mts +27 -0
- package/dist/mcp/types.d.mts.map +1 -0
- package/dist/server/mcp-content.d.mts +44 -0
- package/dist/server/mcp-content.d.mts.map +1 -0
- package/dist/server/mcp-content.mjs +71 -0
- package/dist/server/mcp-content.mjs.map +1 -0
- package/dist/server/tools.d.mts +61 -0
- package/dist/server/tools.d.mts.map +1 -0
- package/dist/server/tools.mjs +47 -0
- package/dist/server/tools.mjs.map +1 -0
- package/dist/server.d.mts +3 -0
- package/dist/server.mjs +4 -0
- package/dist/tools/client.d.mts +3 -0
- package/dist/tools/client.mjs +5 -0
- package/dist/tools/lib/ai-sdk.server.d.mts +12 -0
- package/dist/tools/lib/ai-sdk.server.d.mts.map +1 -0
- package/dist/tools/lib/ai-sdk.server.mjs +38 -0
- package/dist/tools/lib/ai-sdk.server.mjs.map +1 -0
- package/dist/tools/lib/define-tool.server.d.mts +9 -0
- package/dist/tools/lib/define-tool.server.d.mts.map +1 -0
- package/dist/tools/lib/define-tool.server.mjs +13 -0
- package/dist/tools/lib/define-tool.server.mjs.map +1 -0
- package/dist/tools/lib/definitions.client.d.mts +20 -0
- package/dist/tools/lib/definitions.client.mjs +21 -0
- package/dist/tools/lib/definitions.d.mts +16 -0
- package/dist/tools/lib/definitions.d.mts.map +1 -0
- package/dist/tools/lib/definitions.mjs +20 -0
- package/dist/tools/lib/definitions.mjs.map +1 -0
- package/dist/tools/lib/resolvers.d.mts +41 -0
- package/dist/tools/lib/resolvers.d.mts.map +1 -0
- package/dist/tools/lib/resolvers.mjs +43 -0
- package/dist/tools/lib/resolvers.mjs.map +1 -0
- package/dist/tools/lib/types.client.d.mts +13 -0
- package/dist/tools/lib/types.d.mts +33 -0
- package/dist/tools/resolvers/agent.server.d.mts +27 -0
- package/dist/tools/resolvers/agent.server.d.mts.map +1 -0
- package/dist/tools/resolvers/agent.server.mjs +44 -0
- package/dist/tools/resolvers/agent.server.mjs.map +1 -0
- package/dist/tools/resolvers/mcp.server.d.mts +31 -0
- package/dist/tools/resolvers/mcp.server.d.mts.map +1 -0
- package/dist/tools/resolvers/mcp.server.mjs +20 -0
- package/dist/tools/resolvers/mcp.server.mjs.map +1 -0
- package/dist/tools/server.d.mts +5 -0
- package/dist/tools/server.mjs +5 -0
- package/dist/tools/types.d.mts +33 -0
- package/dist/tools/types.d.mts.map +1 -0
- package/package.json +61 -0
- package/src/agents/entry.server.ts +7 -0
- package/src/agents/lib/definitions.server.ts +14 -0
- package/src/agents/lib/delegation.server.ts +33 -0
- package/src/agents/lib/instructions.server.ts +37 -0
- package/src/agents/lib/types.ts +32 -0
- package/src/chat/components/agent-activity.client.tsx +21 -0
- package/src/chat/components/chat-composer.client.tsx +379 -0
- package/src/chat/components/chat-message.client.tsx +166 -0
- package/src/chat/components/chat-thread.client.tsx +242 -0
- package/src/chat/components/message-part.client.tsx +59 -0
- package/src/chat/components/starter-prompts.client.tsx +49 -0
- package/src/chat/components/tool-call-card.client.tsx +78 -0
- package/src/chat/entry.client.ts +18 -0
- package/src/chat/entry.server.ts +5 -0
- package/src/chat/entry.ts +5 -0
- package/src/chat/lib/parts.ts +33 -0
- package/src/chat/lib/stream.server.ts +40 -0
- package/src/chat/lib/types.ts +20 -0
- package/src/entry.ts +24 -0
- package/src/mcp/entry.server.ts +2 -0
- package/src/mcp/lib/content.ts +131 -0
- package/src/mcp/lib/types.ts +28 -0
- package/src/styles.css +1 -0
- package/src/tools/entry.client.ts +7 -0
- package/src/tools/entry.server.ts +11 -0
- package/src/tools/lib/definitions.client.ts +21 -0
- package/src/tools/lib/definitions.ts +24 -0
- package/src/tools/lib/types.client.ts +11 -0
- package/src/tools/lib/types.ts +44 -0
- package/src/tools/resolvers/agent.server.ts +78 -0
- 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,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 };
|
package/dist/chat.d.mts
ADDED
|
@@ -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
package/dist/index.d.mts
ADDED
|
@@ -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"}
|