@agent-native/core 0.18.1 → 0.19.1
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/README.md +1 -11
- package/dist/a2a/caller-auth.d.ts +1 -0
- package/dist/a2a/caller-auth.d.ts.map +1 -1
- package/dist/a2a/caller-auth.js +1 -1
- package/dist/a2a/caller-auth.js.map +1 -1
- package/dist/a2a/client.d.ts +7 -0
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +3 -0
- package/dist/a2a/client.js.map +1 -1
- package/dist/agent/production-agent.d.ts +1 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +34 -2
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/cli/code-agent-executor.d.ts.map +1 -1
- package/dist/cli/code-agent-executor.js +47 -256
- package/dist/cli/code-agent-executor.js.map +1 -1
- package/dist/cli/connect.d.ts +94 -0
- package/dist/cli/connect.d.ts.map +1 -0
- package/dist/cli/connect.js +443 -0
- package/dist/cli/connect.js.map +1 -0
- package/dist/cli/index.js +16 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp-config-writers.d.ts +71 -0
- package/dist/cli/mcp-config-writers.d.ts.map +1 -0
- package/dist/cli/mcp-config-writers.js +210 -0
- package/dist/cli/mcp-config-writers.js.map +1 -0
- package/dist/client/AgentPanel.d.ts +3 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +4 -4
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +3 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +22 -66
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +4 -1
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/composer/PromptComposer.d.ts +6 -1
- package/dist/client/composer/PromptComposer.d.ts.map +1 -1
- package/dist/client/composer/PromptComposer.js +5 -4
- package/dist/client/composer/PromptComposer.js.map +1 -1
- package/dist/client/composer/TiptapComposer.d.ts +6 -1
- package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/client/composer/TiptapComposer.js +20 -10
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/conversation/AgentConversation.d.ts +18 -0
- package/dist/client/conversation/AgentConversation.d.ts.map +1 -0
- package/dist/client/conversation/AgentConversation.js +94 -0
- package/dist/client/conversation/AgentConversation.js.map +1 -0
- package/dist/client/conversation/AgentConversation.spec.d.ts +2 -0
- package/dist/client/conversation/AgentConversation.spec.d.ts.map +1 -0
- package/dist/client/conversation/AgentConversation.spec.js +69 -0
- package/dist/client/conversation/AgentConversation.spec.js.map +1 -0
- package/dist/client/conversation/index.d.ts +4 -0
- package/dist/client/conversation/index.d.ts.map +1 -0
- package/dist/client/conversation/index.js +3 -0
- package/dist/client/conversation/index.js.map +1 -0
- package/dist/client/conversation/types.d.ts +54 -0
- package/dist/client/conversation/types.d.ts.map +1 -0
- package/dist/client/conversation/types.js +2 -0
- package/dist/client/conversation/types.js.map +1 -0
- package/dist/client/conversation/use-near-bottom-autoscroll.d.ts +15 -0
- package/dist/client/conversation/use-near-bottom-autoscroll.d.ts.map +1 -0
- package/dist/client/conversation/use-near-bottom-autoscroll.js +66 -0
- package/dist/client/conversation/use-near-bottom-autoscroll.js.map +1 -0
- package/dist/client/dynamic-suggestions.d.ts +43 -0
- package/dist/client/dynamic-suggestions.d.ts.map +1 -0
- package/dist/client/dynamic-suggestions.js +344 -0
- package/dist/client/dynamic-suggestions.js.map +1 -0
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +2 -0
- package/dist/client/index.js.map +1 -1
- package/dist/client/resources/ResourceTree.d.ts.map +1 -1
- package/dist/client/resources/ResourceTree.js +2 -2
- package/dist/client/resources/ResourceTree.js.map +1 -1
- package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
- package/dist/client/resources/ResourcesPanel.js +4 -28
- package/dist/client/resources/ResourcesPanel.js.map +1 -1
- package/dist/client/settings/SettingsPanel.js +2 -2
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/code-agents/index.d.ts +1 -0
- package/dist/code-agents/index.d.ts.map +1 -1
- package/dist/code-agents/index.js +1 -0
- package/dist/code-agents/index.js.map +1 -1
- package/dist/code-agents/transcript-normalizer.d.ts +50 -0
- package/dist/code-agents/transcript-normalizer.d.ts.map +1 -0
- package/dist/code-agents/transcript-normalizer.js +356 -0
- package/dist/code-agents/transcript-normalizer.js.map +1 -0
- package/dist/coding-tools/index.d.ts +31 -0
- package/dist/coding-tools/index.d.ts.map +1 -0
- package/dist/coding-tools/index.js +411 -0
- package/dist/coding-tools/index.js.map +1 -0
- package/dist/extensions/schema.d.ts +1 -1
- package/dist/mcp/build-server.d.ts.map +1 -1
- package/dist/mcp/build-server.js +30 -0
- package/dist/mcp/build-server.js.map +1 -1
- package/dist/mcp/builtin-tools.d.ts.map +1 -1
- package/dist/mcp/builtin-tools.js +85 -26
- package/dist/mcp/builtin-tools.js.map +1 -1
- package/dist/mcp/connect-route.d.ts +43 -0
- package/dist/mcp/connect-route.d.ts.map +1 -0
- package/dist/mcp/connect-route.js +744 -0
- package/dist/mcp/connect-route.js.map +1 -0
- package/dist/mcp/connect-store.d.ts +132 -0
- package/dist/mcp/connect-store.d.ts.map +1 -0
- package/dist/mcp/connect-store.js +434 -0
- package/dist/mcp/connect-store.js.map +1 -0
- package/dist/mcp/org-directory.d.ts +83 -0
- package/dist/mcp/org-directory.d.ts.map +1 -0
- package/dist/mcp/org-directory.js +201 -0
- package/dist/mcp/org-directory.js.map +1 -0
- package/dist/mcp/server.d.ts +38 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +208 -77
- package/dist/mcp/server.js.map +1 -1
- package/dist/scripts/dev/index.d.ts +6 -4
- package/dist/scripts/dev/index.d.ts.map +1 -1
- package/dist/scripts/dev/index.js +28 -13
- package/dist/scripts/dev/index.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts +6 -6
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +32 -32
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-teams.js +2 -2
- package/dist/server/agent-teams.js.map +1 -1
- package/dist/server/agents-bundle.d.ts +3 -3
- package/dist/server/agents-bundle.js +5 -5
- package/dist/server/agents-bundle.js.map +1 -1
- package/dist/server/auth.d.ts +17 -0
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +149 -33
- package/dist/server/auth.js.map +1 -1
- package/dist/server/better-auth-instance.d.ts +43 -0
- package/dist/server/better-auth-instance.d.ts.map +1 -1
- package/dist/server/better-auth-instance.js +25 -0
- package/dist/server/better-auth-instance.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts +12 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +42 -0
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/identity-sso-store.d.ts +86 -0
- package/dist/server/identity-sso-store.d.ts.map +1 -0
- package/dist/server/identity-sso-store.js +243 -0
- package/dist/server/identity-sso-store.js.map +1 -0
- package/dist/server/identity-sso.d.ts +78 -0
- package/dist/server/identity-sso.d.ts.map +1 -0
- package/dist/server/identity-sso.js +425 -0
- package/dist/server/identity-sso.js.map +1 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/onboarding-html.d.ts.map +1 -1
- package/dist/server/onboarding-html.js +2 -1
- package/dist/server/onboarding-html.js.map +1 -1
- package/dist/server/sentry.d.ts.map +1 -1
- package/dist/server/sentry.js +17 -2
- package/dist/server/sentry.js.map +1 -1
- package/dist/sharing/schema.d.ts +1 -1
- package/docs/content/client.md +15 -0
- package/docs/content/code-agents-ui.md +25 -4
- package/docs/content/cross-app-sso.md +118 -0
- package/docs/content/drop-in-agent.md +3 -1
- package/docs/content/external-agents.md +130 -51
- package/docs/content/frames.md +1 -1
- package/docs/content/migration-workbench.md +6 -1
- package/package.json +2 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgentConversation.d.ts","sourceRoot":"","sources":["../../../src/client/conversation/AgentConversation.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAgB1B,OAAO,KAAK,EAEV,wBAAwB,EAIzB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,wBAAwB,EAAE,CAAC;IACrC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAED,wBAAgB,iBAAiB,CAAC,EAChC,QAAQ,EACR,OAAe,EACf,KAAK,EACL,SAAiB,EACjB,SAAS,EACT,iBAAiB,EACjB,UAA8B,EAC9B,gBAAgB,EAChB,QAAQ,GACT,EAAE,sBAAsB,2CAoDxB;AAoBD,wBAAgB,4BAA4B,CAAC,EAC3C,OAAO,GACR,EAAE;IACD,OAAO,EAAE,wBAAwB,CAAC;CACnC,2CAkBA"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import ReactMarkdown, { defaultUrlTransform } from "react-markdown";
|
|
3
|
+
import remarkGfm from "remark-gfm";
|
|
4
|
+
import { IconAlertTriangle, IconArrowDown, IconCheck, IconChevronDown, IconCircleX, IconClock, IconExternalLink, IconLoader2, IconTool, } from "@tabler/icons-react";
|
|
5
|
+
import { cn } from "../utils.js";
|
|
6
|
+
import { useNearBottomAutoscroll } from "./use-near-bottom-autoscroll.js";
|
|
7
|
+
export function AgentConversation({ messages, loading = false, error, streaming = false, className, timelineClassName, emptyTitle = "No messages yet", emptyDescription, composer, }) {
|
|
8
|
+
const followKey = `${messages.length}:${messages[messages.length - 1]?.text?.length ?? 0}`;
|
|
9
|
+
const { scrollRef, showScrollToBottom, scrollToBottom } = useNearBottomAutoscroll({
|
|
10
|
+
followKey,
|
|
11
|
+
streaming,
|
|
12
|
+
});
|
|
13
|
+
return (_jsxs("section", { className: cn("agent-conversation", className), children: [error && (_jsxs("div", { className: "agent-conversation__error", role: "alert", children: [_jsx(IconAlertTriangle, { size: 15, strokeWidth: 1.8 }), _jsx("span", { children: error })] })), _jsx("div", { ref: scrollRef, className: cn("agent-conversation__timeline", timelineClassName), children: loading && messages.length === 0 ? (_jsx(ConversationEmpty, { icon: _jsx(IconLoader2, { size: 17, className: "agent-conversation-spin" }), title: "Loading session..." })) : messages.length === 0 ? (_jsx(ConversationEmpty, { icon: _jsx(IconClock, { size: 18 }), title: emptyTitle, description: emptyDescription })) : (messages.map((message) => (_jsx(AgentConversationMessageView, { message: message }, message.id)))) }), showScrollToBottom && (_jsx("button", { type: "button", className: "agent-conversation__scroll-bottom", onClick: scrollToBottom, "aria-label": "Scroll to bottom", children: _jsx(IconArrowDown, { size: 15, strokeWidth: 1.9 }) })), composer] }));
|
|
14
|
+
}
|
|
15
|
+
function ConversationEmpty({ icon, title, description, }) {
|
|
16
|
+
return (_jsxs("div", { className: "agent-conversation__empty", children: [icon, _jsx("p", { children: title }), description && _jsx("span", { children: description })] }));
|
|
17
|
+
}
|
|
18
|
+
export function AgentConversationMessageView({ message, }) {
|
|
19
|
+
const parts = message.parts ?? legacyPartsForMessage(message);
|
|
20
|
+
return (_jsx("article", { className: cn("agent-conversation-message", `agent-conversation-message--${message.role}`, message.pending && "agent-conversation-message--pending"), children: _jsx("div", { className: "agent-conversation-message__body", children: parts.map((part) => (_jsx(ConversationMessagePartView, { part: part }, part.id))) }) }));
|
|
21
|
+
}
|
|
22
|
+
function legacyPartsForMessage(message) {
|
|
23
|
+
return [
|
|
24
|
+
...(message.text
|
|
25
|
+
? [
|
|
26
|
+
{
|
|
27
|
+
id: `${message.id}-text`,
|
|
28
|
+
type: "text",
|
|
29
|
+
text: message.text,
|
|
30
|
+
},
|
|
31
|
+
]
|
|
32
|
+
: []),
|
|
33
|
+
...(message.tools ?? []).map((tool) => ({
|
|
34
|
+
id: `${message.id}-tool-${tool.id}`,
|
|
35
|
+
type: "tool",
|
|
36
|
+
tool,
|
|
37
|
+
})),
|
|
38
|
+
...(message.notices ?? []).map((notice) => ({
|
|
39
|
+
id: `${message.id}-notice-${notice.id}`,
|
|
40
|
+
type: "notice",
|
|
41
|
+
notice,
|
|
42
|
+
})),
|
|
43
|
+
...(message.artifacts ?? []).map((artifact) => ({
|
|
44
|
+
id: `${message.id}-artifact-${artifact.id}`,
|
|
45
|
+
type: "artifact",
|
|
46
|
+
artifact,
|
|
47
|
+
})),
|
|
48
|
+
];
|
|
49
|
+
}
|
|
50
|
+
function ConversationMessagePartView({ part, }) {
|
|
51
|
+
return (_jsx("div", { className: cn("agent-conversation-message__part", `agent-conversation-message__part--${part.type}`), children: part.type === "text" ? (_jsx(ConversationMarkdown, { text: part.text })) : part.type === "tool" ? (_jsx(ConversationToolCall, { tool: part.tool })) : part.type === "notice" ? (_jsx(ConversationNotice, { notice: part.notice })) : (_jsx(ConversationArtifact, { artifact: part.artifact })) }));
|
|
52
|
+
}
|
|
53
|
+
function ConversationMarkdown({ text }) {
|
|
54
|
+
return (_jsx("div", { className: "agent-conversation-markdown", children: _jsx(ReactMarkdown, { remarkPlugins: [remarkGfm], urlTransform: (url) => {
|
|
55
|
+
if (url.startsWith("file://"))
|
|
56
|
+
return url;
|
|
57
|
+
return defaultUrlTransform(url);
|
|
58
|
+
}, components: {
|
|
59
|
+
a({ children, href }) {
|
|
60
|
+
return (_jsx("a", { href: href, target: "_blank", rel: "noreferrer", onClick: (event) => openMarkdownLink(event, href), children: children }));
|
|
61
|
+
},
|
|
62
|
+
}, children: text }) }));
|
|
63
|
+
}
|
|
64
|
+
function openMarkdownLink(event, href) {
|
|
65
|
+
if (!href)
|
|
66
|
+
return;
|
|
67
|
+
let url;
|
|
68
|
+
try {
|
|
69
|
+
url = new URL(href, window.location.href);
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (!["http:", "https:", "mailto:", "tel:"].includes(url.protocol))
|
|
75
|
+
return;
|
|
76
|
+
event.preventDefault();
|
|
77
|
+
window.open(url.href, "_blank", "noopener,noreferrer");
|
|
78
|
+
}
|
|
79
|
+
function ConversationToolCall({ tool }) {
|
|
80
|
+
const hasDetails = Boolean(tool.input || tool.result);
|
|
81
|
+
const icon = tool.state === "running" || tool.state === "activity" ? (_jsx(IconLoader2, { size: 14, className: "agent-conversation-spin" })) : tool.state === "errored" ? (_jsx(IconCircleX, { size: 14 })) : (_jsx(IconCheck, { size: 14 }));
|
|
82
|
+
const content = (_jsxs(_Fragment, { children: [_jsx("span", { className: "agent-conversation-tool__icon", children: icon }), _jsx("span", { className: "agent-conversation-tool__name", children: tool.name }), tool.summary && (_jsx("span", { className: "agent-conversation-tool__summary", children: tool.summary }))] }));
|
|
83
|
+
if (!hasDetails) {
|
|
84
|
+
return _jsx("div", { className: "agent-conversation-tool", children: content });
|
|
85
|
+
}
|
|
86
|
+
return (_jsxs("details", { className: "agent-conversation-tool", children: [_jsxs("summary", { children: [content, _jsx(IconChevronDown, { size: 13, className: "agent-conversation-tool__chevron" })] }), _jsxs("div", { className: "agent-conversation-tool__details", children: [tool.input && (_jsxs("pre", { children: [_jsx("strong", { children: "input" }), tool.input] })), tool.result && (_jsxs("pre", { children: [_jsx("strong", { children: "result" }), tool.result] }))] })] }));
|
|
87
|
+
}
|
|
88
|
+
function ConversationNotice({ notice }) {
|
|
89
|
+
return (_jsxs("div", { className: cn("agent-conversation-notice", `agent-conversation-notice--${notice.tone}`), children: [_jsx(IconAlertTriangle, { size: 15 }), _jsxs("div", { children: [notice.title && _jsx("strong", { children: notice.title }), _jsx("span", { children: notice.text })] }), notice.action] }));
|
|
90
|
+
}
|
|
91
|
+
function ConversationArtifact({ artifact, }) {
|
|
92
|
+
return (_jsxs("div", { className: "agent-conversation-artifact", children: [_jsx(IconTool, { size: 14 }), artifact.path ? (_jsx("code", { children: artifact.path })) : (_jsx("span", { children: artifact.label })), artifact.url && (_jsxs("a", { href: artifact.url, target: "_blank", rel: "noreferrer", children: [_jsx(IconExternalLink, { size: 13 }), "Open"] }))] }));
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=AgentConversation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgentConversation.js","sourceRoot":"","sources":["../../../src/client/conversation/AgentConversation.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from \"react\";\nimport ReactMarkdown, { defaultUrlTransform } from \"react-markdown\";\nimport remarkGfm from \"remark-gfm\";\nimport {\n IconAlertTriangle,\n IconArrowDown,\n IconCheck,\n IconChevronDown,\n IconCircleX,\n IconClock,\n IconExternalLink,\n IconLoader2,\n IconTool,\n} from \"@tabler/icons-react\";\nimport { cn } from \"../utils.js\";\nimport { useNearBottomAutoscroll } from \"./use-near-bottom-autoscroll.js\";\nimport type {\n AgentConversationArtifact,\n AgentConversationMessage,\n AgentConversationMessagePart,\n AgentConversationNotice,\n AgentConversationToolCall,\n} from \"./types.js\";\n\nexport interface AgentConversationProps {\n messages: AgentConversationMessage[];\n loading?: boolean;\n error?: string | null;\n streaming?: boolean;\n className?: string;\n timelineClassName?: string;\n emptyTitle?: string;\n emptyDescription?: string;\n composer?: React.ReactNode;\n}\n\nexport function AgentConversation({\n messages,\n loading = false,\n error,\n streaming = false,\n className,\n timelineClassName,\n emptyTitle = \"No messages yet\",\n emptyDescription,\n composer,\n}: AgentConversationProps) {\n const followKey = `${messages.length}:${\n messages[messages.length - 1]?.text?.length ?? 0\n }`;\n const { scrollRef, showScrollToBottom, scrollToBottom } =\n useNearBottomAutoscroll<HTMLDivElement>({\n followKey,\n streaming,\n });\n\n return (\n <section className={cn(\"agent-conversation\", className)}>\n {error && (\n <div className=\"agent-conversation__error\" role=\"alert\">\n <IconAlertTriangle size={15} strokeWidth={1.8} />\n <span>{error}</span>\n </div>\n )}\n <div\n ref={scrollRef}\n className={cn(\"agent-conversation__timeline\", timelineClassName)}\n >\n {loading && messages.length === 0 ? (\n <ConversationEmpty\n icon={<IconLoader2 size={17} className=\"agent-conversation-spin\" />}\n title=\"Loading session...\"\n />\n ) : messages.length === 0 ? (\n <ConversationEmpty\n icon={<IconClock size={18} />}\n title={emptyTitle}\n description={emptyDescription}\n />\n ) : (\n messages.map((message) => (\n <AgentConversationMessageView key={message.id} message={message} />\n ))\n )}\n </div>\n {showScrollToBottom && (\n <button\n type=\"button\"\n className=\"agent-conversation__scroll-bottom\"\n onClick={scrollToBottom}\n aria-label=\"Scroll to bottom\"\n >\n <IconArrowDown size={15} strokeWidth={1.9} />\n </button>\n )}\n {composer}\n </section>\n );\n}\n\nfunction ConversationEmpty({\n icon,\n title,\n description,\n}: {\n icon: React.ReactNode;\n title: string;\n description?: string;\n}) {\n return (\n <div className=\"agent-conversation__empty\">\n {icon}\n <p>{title}</p>\n {description && <span>{description}</span>}\n </div>\n );\n}\n\nexport function AgentConversationMessageView({\n message,\n}: {\n message: AgentConversationMessage;\n}) {\n const parts = message.parts ?? legacyPartsForMessage(message);\n\n return (\n <article\n className={cn(\n \"agent-conversation-message\",\n `agent-conversation-message--${message.role}`,\n message.pending && \"agent-conversation-message--pending\",\n )}\n >\n <div className=\"agent-conversation-message__body\">\n {parts.map((part) => (\n <ConversationMessagePartView key={part.id} part={part} />\n ))}\n </div>\n </article>\n );\n}\n\nfunction legacyPartsForMessage(\n message: AgentConversationMessage,\n): AgentConversationMessagePart[] {\n return [\n ...(message.text\n ? [\n {\n id: `${message.id}-text`,\n type: \"text\" as const,\n text: message.text,\n },\n ]\n : []),\n ...(message.tools ?? []).map((tool) => ({\n id: `${message.id}-tool-${tool.id}`,\n type: \"tool\" as const,\n tool,\n })),\n ...(message.notices ?? []).map((notice) => ({\n id: `${message.id}-notice-${notice.id}`,\n type: \"notice\" as const,\n notice,\n })),\n ...(message.artifacts ?? []).map((artifact) => ({\n id: `${message.id}-artifact-${artifact.id}`,\n type: \"artifact\" as const,\n artifact,\n })),\n ];\n}\n\nfunction ConversationMessagePartView({\n part,\n}: {\n part: AgentConversationMessagePart;\n}) {\n return (\n <div\n className={cn(\n \"agent-conversation-message__part\",\n `agent-conversation-message__part--${part.type}`,\n )}\n >\n {part.type === \"text\" ? (\n <ConversationMarkdown text={part.text} />\n ) : part.type === \"tool\" ? (\n <ConversationToolCall tool={part.tool} />\n ) : part.type === \"notice\" ? (\n <ConversationNotice notice={part.notice} />\n ) : (\n <ConversationArtifact artifact={part.artifact} />\n )}\n </div>\n );\n}\n\nfunction ConversationMarkdown({ text }: { text: string }) {\n return (\n <div className=\"agent-conversation-markdown\">\n <ReactMarkdown\n remarkPlugins={[remarkGfm]}\n urlTransform={(url) => {\n if (url.startsWith(\"file://\")) return url;\n return defaultUrlTransform(url);\n }}\n components={{\n a({ children, href }) {\n return (\n <a\n href={href}\n target=\"_blank\"\n rel=\"noreferrer\"\n onClick={(event) => openMarkdownLink(event, href)}\n >\n {children}\n </a>\n );\n },\n }}\n >\n {text}\n </ReactMarkdown>\n </div>\n );\n}\n\nfunction openMarkdownLink(\n event: React.MouseEvent<HTMLAnchorElement>,\n href: string | undefined,\n) {\n if (!href) return;\n\n let url: URL;\n try {\n url = new URL(href, window.location.href);\n } catch {\n return;\n }\n\n if (![\"http:\", \"https:\", \"mailto:\", \"tel:\"].includes(url.protocol)) return;\n event.preventDefault();\n window.open(url.href, \"_blank\", \"noopener,noreferrer\");\n}\n\nfunction ConversationToolCall({ tool }: { tool: AgentConversationToolCall }) {\n const hasDetails = Boolean(tool.input || tool.result);\n const icon =\n tool.state === \"running\" || tool.state === \"activity\" ? (\n <IconLoader2 size={14} className=\"agent-conversation-spin\" />\n ) : tool.state === \"errored\" ? (\n <IconCircleX size={14} />\n ) : (\n <IconCheck size={14} />\n );\n\n const content = (\n <>\n <span className=\"agent-conversation-tool__icon\">{icon}</span>\n <span className=\"agent-conversation-tool__name\">{tool.name}</span>\n {tool.summary && (\n <span className=\"agent-conversation-tool__summary\">{tool.summary}</span>\n )}\n </>\n );\n\n if (!hasDetails) {\n return <div className=\"agent-conversation-tool\">{content}</div>;\n }\n\n return (\n <details className=\"agent-conversation-tool\">\n <summary>\n {content}\n <IconChevronDown\n size={13}\n className=\"agent-conversation-tool__chevron\"\n />\n </summary>\n <div className=\"agent-conversation-tool__details\">\n {tool.input && (\n <pre>\n <strong>input</strong>\n {tool.input}\n </pre>\n )}\n {tool.result && (\n <pre>\n <strong>result</strong>\n {tool.result}\n </pre>\n )}\n </div>\n </details>\n );\n}\n\nfunction ConversationNotice({ notice }: { notice: AgentConversationNotice }) {\n return (\n <div\n className={cn(\n \"agent-conversation-notice\",\n `agent-conversation-notice--${notice.tone}`,\n )}\n >\n <IconAlertTriangle size={15} />\n <div>\n {notice.title && <strong>{notice.title}</strong>}\n <span>{notice.text}</span>\n </div>\n {notice.action}\n </div>\n );\n}\n\nfunction ConversationArtifact({\n artifact,\n}: {\n artifact: AgentConversationArtifact;\n}) {\n return (\n <div className=\"agent-conversation-artifact\">\n <IconTool size={14} />\n {artifact.path ? (\n <code>{artifact.path}</code>\n ) : (\n <span>{artifact.label}</span>\n )}\n {artifact.url && (\n <a href={artifact.url} target=\"_blank\" rel=\"noreferrer\">\n <IconExternalLink size={13} />\n Open\n </a>\n )}\n </div>\n );\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgentConversation.spec.d.ts","sourceRoot":"","sources":["../../../src/client/conversation/AgentConversation.spec.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// @vitest-environment happy-dom
|
|
3
|
+
import { act } from "react";
|
|
4
|
+
import { createRoot } from "react-dom/client";
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
6
|
+
import { AgentConversationMessageView } from "./AgentConversation.js";
|
|
7
|
+
describe("AgentConversationMessageView", () => {
|
|
8
|
+
let container;
|
|
9
|
+
let root;
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
|
|
12
|
+
container = document.createElement("div");
|
|
13
|
+
document.body.appendChild(container);
|
|
14
|
+
root = createRoot(container);
|
|
15
|
+
});
|
|
16
|
+
afterEach(() => {
|
|
17
|
+
act(() => {
|
|
18
|
+
root.unmount();
|
|
19
|
+
});
|
|
20
|
+
container.remove();
|
|
21
|
+
vi.unstubAllGlobals();
|
|
22
|
+
});
|
|
23
|
+
it("renders text and tool parts in transcript order", () => {
|
|
24
|
+
act(() => {
|
|
25
|
+
root.render(_jsx(AgentConversationMessageView, { message: {
|
|
26
|
+
id: "message-1",
|
|
27
|
+
role: "assistant",
|
|
28
|
+
parts: [
|
|
29
|
+
{ id: "text-1", type: "text", text: "Before tool." },
|
|
30
|
+
{
|
|
31
|
+
id: "tool-1",
|
|
32
|
+
type: "tool",
|
|
33
|
+
tool: {
|
|
34
|
+
id: "tool-1",
|
|
35
|
+
name: "list_files",
|
|
36
|
+
state: "completed",
|
|
37
|
+
summary: "finished",
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
{ id: "text-2", type: "text", text: "After tool." },
|
|
41
|
+
],
|
|
42
|
+
} }));
|
|
43
|
+
});
|
|
44
|
+
expect(container.textContent).toMatch(/Before tool\.\s*list_files\s*finished\s*After tool\./);
|
|
45
|
+
});
|
|
46
|
+
it("opens markdown links in a new external window", () => {
|
|
47
|
+
const open = vi
|
|
48
|
+
.spyOn(window, "open")
|
|
49
|
+
.mockImplementation(() => null);
|
|
50
|
+
act(() => {
|
|
51
|
+
root.render(_jsx(AgentConversationMessageView, { message: {
|
|
52
|
+
id: "message-1",
|
|
53
|
+
role: "assistant",
|
|
54
|
+
parts: [
|
|
55
|
+
{
|
|
56
|
+
id: "text-1",
|
|
57
|
+
type: "text",
|
|
58
|
+
text: "[Builder](https://builder.io/docs)",
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
} }));
|
|
62
|
+
});
|
|
63
|
+
container
|
|
64
|
+
.querySelector("a")
|
|
65
|
+
?.dispatchEvent(new MouseEvent("click", { bubbles: true, cancelable: true }));
|
|
66
|
+
expect(open).toHaveBeenCalledWith("https://builder.io/docs", "_blank", "noopener,noreferrer");
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
//# sourceMappingURL=AgentConversation.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgentConversation.spec.js","sourceRoot":"","sources":["../../../src/client/conversation/AgentConversation.spec.tsx"],"names":[],"mappings":";AAAA,gCAAgC;AAEhC,OAAc,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AACnC,OAAO,EAAE,UAAU,EAAa,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AAEtE,QAAQ,CAAC,8BAA8B,EAAE,GAAG,EAAE;IAC5C,IAAI,SAAyB,CAAC;IAC9B,IAAI,IAAU,CAAC;IAEf,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,CAAC,UAAU,CAAC,0BAA0B,EAAE,IAAI,CAAC,CAAC;QAChD,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAC1C,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;QACrC,IAAI,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,GAAG,CAAC,GAAG,EAAE;YACP,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,CAAC,CAAC,CAAC;QACH,SAAS,CAAC,MAAM,EAAE,CAAC;QACnB,EAAE,CAAC,gBAAgB,EAAE,CAAC;IACxB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,GAAG,CAAC,GAAG,EAAE;YACP,IAAI,CAAC,MAAM,CACT,KAAC,4BAA4B,IAC3B,OAAO,EAAE;oBACP,EAAE,EAAE,WAAW;oBACf,IAAI,EAAE,WAAW;oBACjB,KAAK,EAAE;wBACL,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE;wBACpD;4BACE,EAAE,EAAE,QAAQ;4BACZ,IAAI,EAAE,MAAM;4BACZ,IAAI,EAAE;gCACJ,EAAE,EAAE,QAAQ;gCACZ,IAAI,EAAE,YAAY;gCAClB,KAAK,EAAE,WAAW;gCAClB,OAAO,EAAE,UAAU;6BACpB;yBACF;wBACD,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE;qBACpD;iBACF,GACD,CACH,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,OAAO,CACnC,sDAAsD,CACvD,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,IAAI,GAAG,EAAE;aACZ,KAAK,CAAC,MAAM,EAAE,MAAM,CAAC;aACrB,kBAAkB,CAAC,GAAG,EAAE,CAAC,IAAqB,CAAC,CAAC;QAEnD,GAAG,CAAC,GAAG,EAAE;YACP,IAAI,CAAC,MAAM,CACT,KAAC,4BAA4B,IAC3B,OAAO,EAAE;oBACP,EAAE,EAAE,WAAW;oBACf,IAAI,EAAE,WAAW;oBACjB,KAAK,EAAE;wBACL;4BACE,EAAE,EAAE,QAAQ;4BACZ,IAAI,EAAE,MAAM;4BACZ,IAAI,EAAE,oCAAoC;yBAC3C;qBACF;iBACF,GACD,CACH,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,SAAS;aACN,aAAa,CAAC,GAAG,CAAC;YACnB,EAAE,aAAa,CACb,IAAI,UAAU,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAC7D,CAAC;QAEJ,MAAM,CAAC,IAAI,CAAC,CAAC,oBAAoB,CAC/B,yBAAyB,EACzB,QAAQ,EACR,qBAAqB,CACtB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC","sourcesContent":["// @vitest-environment happy-dom\n\nimport React, { act } from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\nimport { afterEach, beforeEach, describe, expect, it, vi } from \"vitest\";\nimport { AgentConversationMessageView } from \"./AgentConversation.js\";\n\ndescribe(\"AgentConversationMessageView\", () => {\n let container: HTMLDivElement;\n let root: Root;\n\n beforeEach(() => {\n vi.stubGlobal(\"IS_REACT_ACT_ENVIRONMENT\", true);\n container = document.createElement(\"div\");\n document.body.appendChild(container);\n root = createRoot(container);\n });\n\n afterEach(() => {\n act(() => {\n root.unmount();\n });\n container.remove();\n vi.unstubAllGlobals();\n });\n\n it(\"renders text and tool parts in transcript order\", () => {\n act(() => {\n root.render(\n <AgentConversationMessageView\n message={{\n id: \"message-1\",\n role: \"assistant\",\n parts: [\n { id: \"text-1\", type: \"text\", text: \"Before tool.\" },\n {\n id: \"tool-1\",\n type: \"tool\",\n tool: {\n id: \"tool-1\",\n name: \"list_files\",\n state: \"completed\",\n summary: \"finished\",\n },\n },\n { id: \"text-2\", type: \"text\", text: \"After tool.\" },\n ],\n }}\n />,\n );\n });\n\n expect(container.textContent).toMatch(\n /Before tool\\.\\s*list_files\\s*finished\\s*After tool\\./,\n );\n });\n\n it(\"opens markdown links in a new external window\", () => {\n const open = vi\n .spyOn(window, \"open\")\n .mockImplementation(() => null as Window | null);\n\n act(() => {\n root.render(\n <AgentConversationMessageView\n message={{\n id: \"message-1\",\n role: \"assistant\",\n parts: [\n {\n id: \"text-1\",\n type: \"text\",\n text: \"[Builder](https://builder.io/docs)\",\n },\n ],\n }}\n />,\n );\n });\n\n container\n .querySelector(\"a\")\n ?.dispatchEvent(\n new MouseEvent(\"click\", { bubbles: true, cancelable: true }),\n );\n\n expect(open).toHaveBeenCalledWith(\n \"https://builder.io/docs\",\n \"_blank\",\n \"noopener,noreferrer\",\n );\n });\n});\n"]}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { AgentConversation, AgentConversationMessageView, } from "./AgentConversation.js";
|
|
2
|
+
export { useNearBottomAutoscroll } from "./use-near-bottom-autoscroll.js";
|
|
3
|
+
export type { AgentConversationArtifact, AgentConversationMessage, AgentConversationMessagePart, AgentConversationMessageRole, AgentConversationNotice, AgentConversationNoticeTone, AgentConversationToolCall, AgentConversationToolState, } from "./types.js";
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/conversation/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,4BAA4B,GAC7B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAC1E,YAAY,EACV,yBAAyB,EACzB,wBAAwB,EACxB,4BAA4B,EAC5B,4BAA4B,EAC5B,uBAAuB,EACvB,2BAA2B,EAC3B,yBAAyB,EACzB,0BAA0B,GAC3B,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/client/conversation/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,4BAA4B,GAC7B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC","sourcesContent":["export {\n AgentConversation,\n AgentConversationMessageView,\n} from \"./AgentConversation.js\";\nexport { useNearBottomAutoscroll } from \"./use-near-bottom-autoscroll.js\";\nexport type {\n AgentConversationArtifact,\n AgentConversationMessage,\n AgentConversationMessagePart,\n AgentConversationMessageRole,\n AgentConversationNotice,\n AgentConversationNoticeTone,\n AgentConversationToolCall,\n AgentConversationToolState,\n} from \"./types.js\";\n"]}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export type AgentConversationMessageRole = "user" | "assistant" | "system";
|
|
3
|
+
export type AgentConversationToolState = "running" | "completed" | "errored" | "activity";
|
|
4
|
+
export interface AgentConversationToolCall {
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
state: AgentConversationToolState;
|
|
8
|
+
input?: string;
|
|
9
|
+
result?: string;
|
|
10
|
+
summary?: string;
|
|
11
|
+
}
|
|
12
|
+
export type AgentConversationNoticeTone = "info" | "warning" | "error";
|
|
13
|
+
export interface AgentConversationNotice {
|
|
14
|
+
id: string;
|
|
15
|
+
tone: AgentConversationNoticeTone;
|
|
16
|
+
title?: string;
|
|
17
|
+
text: string;
|
|
18
|
+
action?: ReactNode;
|
|
19
|
+
}
|
|
20
|
+
export interface AgentConversationArtifact {
|
|
21
|
+
id: string;
|
|
22
|
+
label: string;
|
|
23
|
+
path?: string;
|
|
24
|
+
url?: string;
|
|
25
|
+
}
|
|
26
|
+
export type AgentConversationMessagePart = {
|
|
27
|
+
id: string;
|
|
28
|
+
type: "text";
|
|
29
|
+
text: string;
|
|
30
|
+
} | {
|
|
31
|
+
id: string;
|
|
32
|
+
type: "tool";
|
|
33
|
+
tool: AgentConversationToolCall;
|
|
34
|
+
} | {
|
|
35
|
+
id: string;
|
|
36
|
+
type: "notice";
|
|
37
|
+
notice: AgentConversationNotice;
|
|
38
|
+
} | {
|
|
39
|
+
id: string;
|
|
40
|
+
type: "artifact";
|
|
41
|
+
artifact: AgentConversationArtifact;
|
|
42
|
+
};
|
|
43
|
+
export interface AgentConversationMessage {
|
|
44
|
+
id: string;
|
|
45
|
+
role: AgentConversationMessageRole;
|
|
46
|
+
text?: string;
|
|
47
|
+
createdAt?: string;
|
|
48
|
+
pending?: boolean;
|
|
49
|
+
parts?: AgentConversationMessagePart[];
|
|
50
|
+
tools?: AgentConversationToolCall[];
|
|
51
|
+
notices?: AgentConversationNotice[];
|
|
52
|
+
artifacts?: AgentConversationArtifact[];
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/client/conversation/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,MAAM,4BAA4B,GAAG,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC;AAE3E,MAAM,MAAM,0BAA0B,GAClC,SAAS,GACT,WAAW,GACX,SAAS,GACT,UAAU,CAAC;AAEf,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,0BAA0B,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,MAAM,2BAA2B,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;AAEvE,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,2BAA2B,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB;AAED,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,4BAA4B,GACpC;IACE,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd,GACD;IACE,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,yBAAyB,CAAC;CACjC,GACD;IACE,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,uBAAuB,CAAC;CACjC,GACD;IACE,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,yBAAyB,CAAC;CACrC,CAAC;AAEN,MAAM,WAAW,wBAAwB;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,4BAA4B,CAAC;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,4BAA4B,EAAE,CAAC;IACvC,KAAK,CAAC,EAAE,yBAAyB,EAAE,CAAC;IACpC,OAAO,CAAC,EAAE,uBAAuB,EAAE,CAAC;IACpC,SAAS,CAAC,EAAE,yBAAyB,EAAE,CAAC;CACzC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/client/conversation/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { ReactNode } from \"react\";\n\nexport type AgentConversationMessageRole = \"user\" | \"assistant\" | \"system\";\n\nexport type AgentConversationToolState =\n | \"running\"\n | \"completed\"\n | \"errored\"\n | \"activity\";\n\nexport interface AgentConversationToolCall {\n id: string;\n name: string;\n state: AgentConversationToolState;\n input?: string;\n result?: string;\n summary?: string;\n}\n\nexport type AgentConversationNoticeTone = \"info\" | \"warning\" | \"error\";\n\nexport interface AgentConversationNotice {\n id: string;\n tone: AgentConversationNoticeTone;\n title?: string;\n text: string;\n action?: ReactNode;\n}\n\nexport interface AgentConversationArtifact {\n id: string;\n label: string;\n path?: string;\n url?: string;\n}\n\nexport type AgentConversationMessagePart =\n | {\n id: string;\n type: \"text\";\n text: string;\n }\n | {\n id: string;\n type: \"tool\";\n tool: AgentConversationToolCall;\n }\n | {\n id: string;\n type: \"notice\";\n notice: AgentConversationNotice;\n }\n | {\n id: string;\n type: \"artifact\";\n artifact: AgentConversationArtifact;\n };\n\nexport interface AgentConversationMessage {\n id: string;\n role: AgentConversationMessageRole;\n text?: string;\n createdAt?: string;\n pending?: boolean;\n parts?: AgentConversationMessagePart[];\n tools?: AgentConversationToolCall[];\n notices?: AgentConversationNotice[];\n artifacts?: AgentConversationArtifact[];\n}\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface UseNearBottomAutoscrollOptions {
|
|
2
|
+
followKey: unknown;
|
|
3
|
+
streaming?: boolean;
|
|
4
|
+
threshold?: number;
|
|
5
|
+
enabled?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function useNearBottomAutoscroll<TElement extends HTMLElement>({ followKey, streaming, threshold, enabled, }: UseNearBottomAutoscrollOptions): {
|
|
8
|
+
scrollRef: import("react").RefObject<TElement>;
|
|
9
|
+
isNearBottomRef: import("react").RefObject<boolean>;
|
|
10
|
+
showScrollToBottom: boolean;
|
|
11
|
+
markNearBottom: () => void;
|
|
12
|
+
scrollToBottom: () => void;
|
|
13
|
+
scrollToBottomAfterPaint: () => void;
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=use-near-bottom-autoscroll.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-near-bottom-autoscroll.d.ts","sourceRoot":"","sources":["../../../src/client/conversation/use-near-bottom-autoscroll.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,8BAA8B;IAC7C,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,SAAS,WAAW,EAAE,EACpE,SAAS,EACT,SAAiB,EACjB,SAAc,EACd,OAAc,GACf,EAAE,8BAA8B;;;;;;;EAkEhC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
+
export function useNearBottomAutoscroll({ followKey, streaming = false, threshold = 40, enabled = true, }) {
|
|
3
|
+
const scrollRef = useRef(null);
|
|
4
|
+
const isNearBottomRef = useRef(true);
|
|
5
|
+
const [showScrollToBottom, setShowScrollToBottom] = useState(false);
|
|
6
|
+
const updateNearBottom = useCallback(() => {
|
|
7
|
+
const el = scrollRef.current;
|
|
8
|
+
if (!el)
|
|
9
|
+
return;
|
|
10
|
+
const nearBottom = el.scrollHeight - el.scrollTop - el.clientHeight < threshold;
|
|
11
|
+
isNearBottomRef.current = nearBottom;
|
|
12
|
+
setShowScrollToBottom(!nearBottom);
|
|
13
|
+
}, [threshold]);
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
const el = scrollRef.current;
|
|
16
|
+
if (!el || !enabled)
|
|
17
|
+
return;
|
|
18
|
+
const onScroll = () => updateNearBottom();
|
|
19
|
+
el.addEventListener("scroll", onScroll, { passive: true });
|
|
20
|
+
updateNearBottom();
|
|
21
|
+
return () => el.removeEventListener("scroll", onScroll);
|
|
22
|
+
}, [enabled, updateNearBottom]);
|
|
23
|
+
const scrollToBottom = useCallback(() => {
|
|
24
|
+
const el = scrollRef.current;
|
|
25
|
+
if (!el)
|
|
26
|
+
return;
|
|
27
|
+
el.scrollTop = el.scrollHeight;
|
|
28
|
+
isNearBottomRef.current = true;
|
|
29
|
+
setShowScrollToBottom(false);
|
|
30
|
+
}, []);
|
|
31
|
+
const scrollToBottomAfterPaint = useCallback(() => {
|
|
32
|
+
scrollToBottom();
|
|
33
|
+
requestAnimationFrame(() => {
|
|
34
|
+
scrollToBottom();
|
|
35
|
+
requestAnimationFrame(scrollToBottom);
|
|
36
|
+
});
|
|
37
|
+
window.setTimeout(scrollToBottom, 80);
|
|
38
|
+
}, [scrollToBottom]);
|
|
39
|
+
const markNearBottom = useCallback(() => {
|
|
40
|
+
isNearBottomRef.current = true;
|
|
41
|
+
setShowScrollToBottom(false);
|
|
42
|
+
}, []);
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
if (!enabled || !isNearBottomRef.current)
|
|
45
|
+
return;
|
|
46
|
+
scrollToBottomAfterPaint();
|
|
47
|
+
}, [enabled, followKey, scrollToBottomAfterPaint]);
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
if (!enabled || !streaming)
|
|
50
|
+
return;
|
|
51
|
+
const id = window.setInterval(() => {
|
|
52
|
+
if (isNearBottomRef.current)
|
|
53
|
+
scrollToBottom();
|
|
54
|
+
}, 100);
|
|
55
|
+
return () => window.clearInterval(id);
|
|
56
|
+
}, [enabled, scrollToBottom, streaming]);
|
|
57
|
+
return {
|
|
58
|
+
scrollRef,
|
|
59
|
+
isNearBottomRef,
|
|
60
|
+
showScrollToBottom,
|
|
61
|
+
markNearBottom,
|
|
62
|
+
scrollToBottom,
|
|
63
|
+
scrollToBottomAfterPaint,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=use-near-bottom-autoscroll.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-near-bottom-autoscroll.js","sourceRoot":"","sources":["../../../src/client/conversation/use-near-bottom-autoscroll.ts"],"names":[],"mappings":"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","sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\n\nexport interface UseNearBottomAutoscrollOptions {\n followKey: unknown;\n streaming?: boolean;\n threshold?: number;\n enabled?: boolean;\n}\n\nexport function useNearBottomAutoscroll<TElement extends HTMLElement>({\n followKey,\n streaming = false,\n threshold = 40,\n enabled = true,\n}: UseNearBottomAutoscrollOptions) {\n const scrollRef = useRef<TElement | null>(null);\n const isNearBottomRef = useRef(true);\n const [showScrollToBottom, setShowScrollToBottom] = useState(false);\n\n const updateNearBottom = useCallback(() => {\n const el = scrollRef.current;\n if (!el) return;\n const nearBottom =\n el.scrollHeight - el.scrollTop - el.clientHeight < threshold;\n isNearBottomRef.current = nearBottom;\n setShowScrollToBottom(!nearBottom);\n }, [threshold]);\n\n useEffect(() => {\n const el = scrollRef.current;\n if (!el || !enabled) return;\n const onScroll = () => updateNearBottom();\n el.addEventListener(\"scroll\", onScroll, { passive: true });\n updateNearBottom();\n return () => el.removeEventListener(\"scroll\", onScroll);\n }, [enabled, updateNearBottom]);\n\n const scrollToBottom = useCallback(() => {\n const el = scrollRef.current;\n if (!el) return;\n el.scrollTop = el.scrollHeight;\n isNearBottomRef.current = true;\n setShowScrollToBottom(false);\n }, []);\n\n const scrollToBottomAfterPaint = useCallback(() => {\n scrollToBottom();\n requestAnimationFrame(() => {\n scrollToBottom();\n requestAnimationFrame(scrollToBottom);\n });\n window.setTimeout(scrollToBottom, 80);\n }, [scrollToBottom]);\n\n const markNearBottom = useCallback(() => {\n isNearBottomRef.current = true;\n setShowScrollToBottom(false);\n }, []);\n\n useEffect(() => {\n if (!enabled || !isNearBottomRef.current) return;\n scrollToBottomAfterPaint();\n }, [enabled, followKey, scrollToBottomAfterPaint]);\n\n useEffect(() => {\n if (!enabled || !streaming) return;\n const id = window.setInterval(() => {\n if (isNearBottomRef.current) scrollToBottom();\n }, 100);\n return () => window.clearInterval(id);\n }, [enabled, scrollToBottom, streaming]);\n\n return {\n scrollRef,\n isNearBottomRef,\n showScrollToBottom,\n markNearBottom,\n scrollToBottom,\n scrollToBottomAfterPaint,\n };\n}\n"]}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { ChatThreadScope } from "./use-chat-threads.js";
|
|
2
|
+
export interface AgentDynamicSuggestionContext {
|
|
3
|
+
navigation: unknown;
|
|
4
|
+
selection: unknown;
|
|
5
|
+
pendingSelection: unknown;
|
|
6
|
+
url: unknown;
|
|
7
|
+
scope?: ChatThreadScope | null;
|
|
8
|
+
}
|
|
9
|
+
export interface AgentDynamicSuggestionsConfig {
|
|
10
|
+
/** Enable/disable dynamic suggestions. Defaults to true. */
|
|
11
|
+
enabled?: boolean;
|
|
12
|
+
/** Maximum number of suggestion chips after merging dynamic + static. */
|
|
13
|
+
max?: number;
|
|
14
|
+
/** Keep the caller-provided static suggestions after dynamic ones. Default true. */
|
|
15
|
+
includeStatic?: boolean;
|
|
16
|
+
/** Optional app-specific deterministic suggestion builder. */
|
|
17
|
+
getSuggestions?: (context: AgentDynamicSuggestionContext) => string[];
|
|
18
|
+
}
|
|
19
|
+
export type AgentDynamicSuggestionsOption = boolean | AgentDynamicSuggestionsConfig;
|
|
20
|
+
interface NormalizedAgentDynamicSuggestionsConfig {
|
|
21
|
+
enabled: boolean;
|
|
22
|
+
max: number;
|
|
23
|
+
includeStatic: boolean;
|
|
24
|
+
getSuggestions?: (context: AgentDynamicSuggestionContext) => string[];
|
|
25
|
+
}
|
|
26
|
+
export declare function normalizeAgentDynamicSuggestionsConfig(option?: AgentDynamicSuggestionsOption): NormalizedAgentDynamicSuggestionsConfig;
|
|
27
|
+
export declare function buildDynamicAgentSuggestions(context: AgentDynamicSuggestionContext): string[];
|
|
28
|
+
export declare function dedupeSuggestions(suggestions: readonly string[]): string[];
|
|
29
|
+
export declare function mergeAgentSuggestions(options: {
|
|
30
|
+
dynamicSuggestions: readonly string[];
|
|
31
|
+
staticSuggestions?: readonly string[];
|
|
32
|
+
includeStatic: boolean;
|
|
33
|
+
max: number;
|
|
34
|
+
}): string[];
|
|
35
|
+
export declare function useAgentDynamicSuggestions(options: {
|
|
36
|
+
staticSuggestions?: readonly string[];
|
|
37
|
+
dynamicSuggestions?: AgentDynamicSuggestionsOption;
|
|
38
|
+
browserTabId?: string;
|
|
39
|
+
scope?: ChatThreadScope | null;
|
|
40
|
+
enabled?: boolean;
|
|
41
|
+
}): string[] | undefined;
|
|
42
|
+
export {};
|
|
43
|
+
//# sourceMappingURL=dynamic-suggestions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dynamic-suggestions.d.ts","sourceRoot":"","sources":["../../src/client/dynamic-suggestions.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAK7D,MAAM,WAAW,6BAA6B;IAC5C,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,6BAA6B;IAC5C,4DAA4D;IAC5D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yEAAyE;IACzE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oFAAoF;IACpF,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,8DAA8D;IAC9D,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,6BAA6B,KAAK,MAAM,EAAE,CAAC;CACvE;AAED,MAAM,MAAM,6BAA6B,GACrC,OAAO,GACP,6BAA6B,CAAC;AAElC,UAAU,uCAAuC;IAC/C,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,EAAE,OAAO,CAAC;IACvB,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,6BAA6B,KAAK,MAAM,EAAE,CAAC;CACvE;AAED,wBAAgB,sCAAsC,CACpD,MAAM,CAAC,EAAE,6BAA6B,GACrC,uCAAuC,CAwBzC;AAyID,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,6BAA6B,GACrC,MAAM,EAAE,CAmFV;AAED,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAY1E;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE;IAC7C,kBAAkB,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,aAAa,EAAE,OAAO,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;CACb,GAAG,MAAM,EAAE,CAWX;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE;IAClD,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,kBAAkB,CAAC,EAAE,6BAA6B,CAAC;IACnD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,GAAG,MAAM,EAAE,GAAG,SAAS,CAsGvB"}
|