@darqlabs/curator-sdk-react 0.1.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 +21 -0
- package/README.md +205 -0
- package/dist/cjs/CuratorAdapter.d.ts +28 -0
- package/dist/cjs/CuratorAdapter.d.ts.map +1 -0
- package/dist/cjs/CuratorAdapter.js +100 -0
- package/dist/cjs/CuratorAdapter.js.map +1 -0
- package/dist/cjs/CuratorChat.d.ts +70 -0
- package/dist/cjs/CuratorChat.d.ts.map +1 -0
- package/dist/cjs/CuratorChat.js +454 -0
- package/dist/cjs/CuratorChat.js.map +1 -0
- package/dist/cjs/CuratorChatLauncher.d.ts +57 -0
- package/dist/cjs/CuratorChatLauncher.d.ts.map +1 -0
- package/dist/cjs/CuratorChatLauncher.js +134 -0
- package/dist/cjs/CuratorChatLauncher.js.map +1 -0
- package/dist/cjs/CuratorProvider.d.ts +37 -0
- package/dist/cjs/CuratorProvider.d.ts.map +1 -0
- package/dist/cjs/CuratorProvider.js +49 -0
- package/dist/cjs/CuratorProvider.js.map +1 -0
- package/dist/cjs/Markdown.d.ts +16 -0
- package/dist/cjs/Markdown.d.ts.map +1 -0
- package/dist/cjs/Markdown.js +18 -0
- package/dist/cjs/Markdown.js.map +1 -0
- package/dist/cjs/brand.d.ts +26 -0
- package/dist/cjs/brand.d.ts.map +1 -0
- package/dist/cjs/brand.js +47 -0
- package/dist/cjs/brand.js.map +1 -0
- package/dist/cjs/index.d.ts +10 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +17 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/normalizeMarkdown.d.ts +24 -0
- package/dist/cjs/normalizeMarkdown.d.ts.map +1 -0
- package/dist/cjs/normalizeMarkdown.js +111 -0
- package/dist/cjs/normalizeMarkdown.js.map +1 -0
- package/dist/cjs/useCuratorChat.d.ts +79 -0
- package/dist/cjs/useCuratorChat.d.ts.map +1 -0
- package/dist/cjs/useCuratorChat.js +135 -0
- package/dist/cjs/useCuratorChat.js.map +1 -0
- package/dist/esm/CuratorAdapter.d.ts +28 -0
- package/dist/esm/CuratorAdapter.d.ts.map +1 -0
- package/dist/esm/CuratorAdapter.js +97 -0
- package/dist/esm/CuratorAdapter.js.map +1 -0
- package/dist/esm/CuratorChat.d.ts +70 -0
- package/dist/esm/CuratorChat.d.ts.map +1 -0
- package/dist/esm/CuratorChat.js +451 -0
- package/dist/esm/CuratorChat.js.map +1 -0
- package/dist/esm/CuratorChatLauncher.d.ts +57 -0
- package/dist/esm/CuratorChatLauncher.d.ts.map +1 -0
- package/dist/esm/CuratorChatLauncher.js +131 -0
- package/dist/esm/CuratorChatLauncher.js.map +1 -0
- package/dist/esm/CuratorProvider.d.ts +37 -0
- package/dist/esm/CuratorProvider.d.ts.map +1 -0
- package/dist/esm/CuratorProvider.js +44 -0
- package/dist/esm/CuratorProvider.js.map +1 -0
- package/dist/esm/Markdown.d.ts +16 -0
- package/dist/esm/Markdown.d.ts.map +1 -0
- package/dist/esm/Markdown.js +12 -0
- package/dist/esm/Markdown.js.map +1 -0
- package/dist/esm/brand.d.ts +26 -0
- package/dist/esm/brand.d.ts.map +1 -0
- package/dist/esm/brand.js +43 -0
- package/dist/esm/brand.js.map +1 -0
- package/dist/esm/index.d.ts +10 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +6 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/normalizeMarkdown.d.ts +24 -0
- package/dist/esm/normalizeMarkdown.d.ts.map +1 -0
- package/dist/esm/normalizeMarkdown.js +108 -0
- package/dist/esm/normalizeMarkdown.js.map +1 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/useCuratorChat.d.ts +79 -0
- package/dist/esm/useCuratorChat.d.ts.map +1 -0
- package/dist/esm/useCuratorChat.js +132 -0
- package/dist/esm/useCuratorChat.js.map +1 -0
- package/package.json +66 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* <CuratorChatLauncher /> — floating chat bubble that opens an
|
|
4
|
+
* anchored panel containing `<CuratorChat />`. The drop-in shape
|
|
5
|
+
* customers reach for when they want an Intercom-style widget on
|
|
6
|
+
* their site without rolling their own positioning.
|
|
7
|
+
*
|
|
8
|
+
* <CuratorChatLauncher agent="support-bot" placement="bottom-right" />
|
|
9
|
+
*
|
|
10
|
+
* Rendered via a portal to `document.body` so stacking contexts in
|
|
11
|
+
* the consuming app don't trap it. The panel reuses `<CuratorChat />`
|
|
12
|
+
* verbatim — same theming, same hook, same provider context.
|
|
13
|
+
*
|
|
14
|
+
* ESC closes the panel; clicking outside does NOT (intentional — losing
|
|
15
|
+
* chat state on a stray click is the most annoying widget UX there is).
|
|
16
|
+
*/
|
|
17
|
+
import { useCallback, useEffect, useState, } from "react";
|
|
18
|
+
import { createPortal } from "react-dom";
|
|
19
|
+
import { CuratorChat } from "./CuratorChat.js";
|
|
20
|
+
export function CuratorChatLauncher(props) {
|
|
21
|
+
const { placement = "bottom-right", offset = 24, defaultOpen = false, panelWidth = 440, panelHeight = 620, icon, ariaLabel = "Open chat", onOpen, onClose, ...chatProps } = props;
|
|
22
|
+
const [open, setOpen] = useState(defaultOpen);
|
|
23
|
+
// Defer portal mounting until after first client render so SSR
|
|
24
|
+
// frameworks (Next.js, Remix) don't trip on `document` not existing.
|
|
25
|
+
const [mounted, setMounted] = useState(false);
|
|
26
|
+
useEffect(() => setMounted(true), []);
|
|
27
|
+
// ESC closes the panel. Mounted only while open so we don't add a
|
|
28
|
+
// global listener for a usually-idle widget.
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if (!open)
|
|
31
|
+
return;
|
|
32
|
+
const onKey = (e) => {
|
|
33
|
+
if (e.key === "Escape")
|
|
34
|
+
doClose();
|
|
35
|
+
};
|
|
36
|
+
window.addEventListener("keydown", onKey);
|
|
37
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
38
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
39
|
+
}, [open]);
|
|
40
|
+
const doOpen = useCallback(() => {
|
|
41
|
+
setOpen(true);
|
|
42
|
+
onOpen?.();
|
|
43
|
+
}, [onOpen]);
|
|
44
|
+
const doClose = useCallback(() => {
|
|
45
|
+
setOpen(false);
|
|
46
|
+
onClose?.();
|
|
47
|
+
}, [onClose]);
|
|
48
|
+
if (!mounted)
|
|
49
|
+
return null;
|
|
50
|
+
const corner = cornerStyle(placement, offset);
|
|
51
|
+
return createPortal(_jsxs("div", { style: containerStyle, "data-curator-chat-launcher": true, "data-open": open ? "true" : "false", children: [open && (_jsx("div", { role: "dialog", "aria-modal": "false", "aria-label": chatProps.title ?? "Chat", style: {
|
|
52
|
+
...panelStyle,
|
|
53
|
+
...panelAnchor(placement, offset),
|
|
54
|
+
width: panelWidth,
|
|
55
|
+
height: panelHeight,
|
|
56
|
+
}, children: _jsx(CuratorChat, { ...chatProps, onClose: doClose, style: {
|
|
57
|
+
height: "100%",
|
|
58
|
+
borderRadius: "inherit",
|
|
59
|
+
border: "none",
|
|
60
|
+
boxShadow: "none",
|
|
61
|
+
} }) })), _jsx("button", { type: "button", onClick: open ? doClose : doOpen, "aria-label": open ? "Close chat" : ariaLabel, "aria-expanded": open, style: {
|
|
62
|
+
...bubbleStyle,
|
|
63
|
+
...corner,
|
|
64
|
+
}, children: icon ?? (open ? _jsx(CloseGlyph, {}) : _jsx(ChatGlyph, {})) })] }), document.body);
|
|
65
|
+
}
|
|
66
|
+
function ChatGlyph() {
|
|
67
|
+
return (_jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: _jsx("path", { d: "M3 5.5A2.5 2.5 0 0 1 5.5 3h13A2.5 2.5 0 0 1 21 5.5v9A2.5 2.5 0 0 1 18.5 17H9l-4.3 3.4a.75.75 0 0 1-1.2-.59V5.5Z", stroke: "currentColor", strokeWidth: "1.75", strokeLinejoin: "round", fill: "none" }) }));
|
|
68
|
+
}
|
|
69
|
+
function CloseGlyph() {
|
|
70
|
+
return (_jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: _jsx("path", { d: "M6 6 18 18 M18 6 6 18", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }));
|
|
71
|
+
}
|
|
72
|
+
// ── positioning ─────────────────────────────────────────────────
|
|
73
|
+
function cornerStyle(placement, offset) {
|
|
74
|
+
switch (placement) {
|
|
75
|
+
case "bottom-left":
|
|
76
|
+
return { bottom: offset, left: offset };
|
|
77
|
+
case "top-right":
|
|
78
|
+
return { top: offset, right: offset };
|
|
79
|
+
case "top-left":
|
|
80
|
+
return { top: offset, left: offset };
|
|
81
|
+
case "bottom-right":
|
|
82
|
+
default:
|
|
83
|
+
return { bottom: offset, right: offset };
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const PANEL_GAP = 16;
|
|
87
|
+
const BUBBLE_SIZE = 56;
|
|
88
|
+
function panelAnchor(placement, offset) {
|
|
89
|
+
// Anchor the panel above/below the bubble depending on which vertical
|
|
90
|
+
// edge the launcher hugs. Horizontal alignment follows the same edge.
|
|
91
|
+
const vertical = placement === "top-right" || placement === "top-left"
|
|
92
|
+
? { top: offset + BUBBLE_SIZE + PANEL_GAP }
|
|
93
|
+
: { bottom: offset + BUBBLE_SIZE + PANEL_GAP };
|
|
94
|
+
const horizontal = placement === "bottom-left" || placement === "top-left"
|
|
95
|
+
? { left: offset }
|
|
96
|
+
: { right: offset };
|
|
97
|
+
return { ...vertical, ...horizontal };
|
|
98
|
+
}
|
|
99
|
+
// ── styles ──────────────────────────────────────────────────────
|
|
100
|
+
const containerStyle = {
|
|
101
|
+
position: "fixed",
|
|
102
|
+
inset: 0,
|
|
103
|
+
pointerEvents: "none",
|
|
104
|
+
zIndex: 2_147_483_000, // sit above Intercom/Crisp/etc; intentional max-ish
|
|
105
|
+
};
|
|
106
|
+
const bubbleStyle = {
|
|
107
|
+
position: "fixed",
|
|
108
|
+
width: BUBBLE_SIZE,
|
|
109
|
+
height: BUBBLE_SIZE,
|
|
110
|
+
borderRadius: "50%",
|
|
111
|
+
border: "none",
|
|
112
|
+
cursor: "pointer",
|
|
113
|
+
background: "#0f172a",
|
|
114
|
+
color: "#ffffff",
|
|
115
|
+
display: "flex",
|
|
116
|
+
alignItems: "center",
|
|
117
|
+
justifyContent: "center",
|
|
118
|
+
boxShadow: "0 8px 20px rgba(15, 23, 42, 0.25), 0 2px 6px rgba(15, 23, 42, 0.15)",
|
|
119
|
+
pointerEvents: "auto",
|
|
120
|
+
transition: "transform 120ms ease, box-shadow 120ms ease",
|
|
121
|
+
fontFamily: "ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",
|
|
122
|
+
};
|
|
123
|
+
const panelStyle = {
|
|
124
|
+
position: "fixed",
|
|
125
|
+
background: "transparent",
|
|
126
|
+
borderRadius: 16,
|
|
127
|
+
overflow: "hidden",
|
|
128
|
+
boxShadow: "0 20px 50px rgba(15, 23, 42, 0.25), 0 4px 12px rgba(15, 23, 42, 0.12)",
|
|
129
|
+
pointerEvents: "auto",
|
|
130
|
+
};
|
|
131
|
+
//# sourceMappingURL=CuratorChatLauncher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CuratorChatLauncher.js","sourceRoot":"","sources":["../../src/CuratorChatLauncher.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <CuratorProvider> — context provider for a Curator SDK client.
|
|
3
|
+
*
|
|
4
|
+
* const curator = new Curator({ apiKey, project, environment })
|
|
5
|
+
*
|
|
6
|
+
* <CuratorProvider client={curator}>
|
|
7
|
+
* <App />
|
|
8
|
+
* </CuratorProvider>
|
|
9
|
+
*
|
|
10
|
+
* Components beneath the provider can read the client via `useCurator()`
|
|
11
|
+
* or implicitly via `<CuratorChat agent="..." />` / `useCuratorChat({ agent })`.
|
|
12
|
+
*
|
|
13
|
+
* The provider deliberately holds no state of its own — it's a one-line
|
|
14
|
+
* pass-through. Treating the client as plain context (rather than a
|
|
15
|
+
* module-level singleton) keeps tests, SSR, and multi-tenant trees clean.
|
|
16
|
+
*/
|
|
17
|
+
import { type ReactNode } from "react";
|
|
18
|
+
import type { Curator } from "@darqlabs/curator-sdk";
|
|
19
|
+
export interface CuratorProviderProps {
|
|
20
|
+
/** The SDK instance — create once and reuse for the lifetime of the app. */
|
|
21
|
+
client: Curator;
|
|
22
|
+
children: ReactNode;
|
|
23
|
+
}
|
|
24
|
+
export declare function CuratorProvider({ client, children }: CuratorProviderProps): import("react").JSX.Element;
|
|
25
|
+
/**
|
|
26
|
+
* Read the Curator client from context. Throws if no `<CuratorProvider>`
|
|
27
|
+
* is mounted higher in the tree — a hard failure here is friendlier than
|
|
28
|
+
* a silent null that surfaces later as a confusing runtime error.
|
|
29
|
+
*/
|
|
30
|
+
export declare function useCurator(): Curator;
|
|
31
|
+
/**
|
|
32
|
+
* Same as `useCurator()` but returns `null` instead of throwing when no
|
|
33
|
+
* provider is mounted. Useful inside components that want to fall back
|
|
34
|
+
* to a `curator` prop, like `<CuratorChat>`.
|
|
35
|
+
*/
|
|
36
|
+
export declare function useCuratorOrNull(): Curator | null;
|
|
37
|
+
//# sourceMappingURL=CuratorProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CuratorProvider.d.ts","sourceRoot":"","sources":["../../src/CuratorProvider.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAA6B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AACjE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAIpD,MAAM,WAAW,oBAAoB;IACnC,4EAA4E;IAC5E,MAAM,EAAE,OAAO,CAAA;IACf,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED,wBAAgB,eAAe,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,oBAAoB,+BAEzE;AAED;;;;GAIG;AACH,wBAAgB,UAAU,IAAI,OAAO,CASpC;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,GAAG,IAAI,CAEjD"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* <CuratorProvider> — context provider for a Curator SDK client.
|
|
4
|
+
*
|
|
5
|
+
* const curator = new Curator({ apiKey, project, environment })
|
|
6
|
+
*
|
|
7
|
+
* <CuratorProvider client={curator}>
|
|
8
|
+
* <App />
|
|
9
|
+
* </CuratorProvider>
|
|
10
|
+
*
|
|
11
|
+
* Components beneath the provider can read the client via `useCurator()`
|
|
12
|
+
* or implicitly via `<CuratorChat agent="..." />` / `useCuratorChat({ agent })`.
|
|
13
|
+
*
|
|
14
|
+
* The provider deliberately holds no state of its own — it's a one-line
|
|
15
|
+
* pass-through. Treating the client as plain context (rather than a
|
|
16
|
+
* module-level singleton) keeps tests, SSR, and multi-tenant trees clean.
|
|
17
|
+
*/
|
|
18
|
+
import { createContext, useContext } from "react";
|
|
19
|
+
const CuratorContext = createContext(null);
|
|
20
|
+
export function CuratorProvider({ client, children }) {
|
|
21
|
+
return _jsx(CuratorContext.Provider, { value: client, children: children });
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Read the Curator client from context. Throws if no `<CuratorProvider>`
|
|
25
|
+
* is mounted higher in the tree — a hard failure here is friendlier than
|
|
26
|
+
* a silent null that surfaces later as a confusing runtime error.
|
|
27
|
+
*/
|
|
28
|
+
export function useCurator() {
|
|
29
|
+
const client = useContext(CuratorContext);
|
|
30
|
+
if (!client) {
|
|
31
|
+
throw new Error("useCurator() (or a Curator component) was called outside a <CuratorProvider>. " +
|
|
32
|
+
"Wrap your app: <CuratorProvider client={curator}>…</CuratorProvider>.");
|
|
33
|
+
}
|
|
34
|
+
return client;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Same as `useCurator()` but returns `null` instead of throwing when no
|
|
38
|
+
* provider is mounted. Useful inside components that want to fall back
|
|
39
|
+
* to a `curator` prop, like `<CuratorChat>`.
|
|
40
|
+
*/
|
|
41
|
+
export function useCuratorOrNull() {
|
|
42
|
+
return useContext(CuratorContext);
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=CuratorProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CuratorProvider.js","sourceRoot":"","sources":["../../src/CuratorProvider.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,aAAa,EAAE,UAAU,EAAkB,MAAM,OAAO,CAAA;AAGjE,MAAM,cAAc,GAAG,aAAa,CAAiB,IAAI,CAAC,CAAA;AAQ1D,MAAM,UAAU,eAAe,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAwB;IACxE,OAAO,KAAC,cAAc,CAAC,QAAQ,IAAC,KAAK,EAAE,MAAM,YAAG,QAAQ,GAA2B,CAAA;AACrF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,MAAM,GAAG,UAAU,CAAC,cAAc,CAAC,CAAA;IACzC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,gFAAgF;YAC9E,uEAAuE,CAC1E,CAAA;IACH,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO,UAAU,CAAC,cAAc,CAAC,CAAA;AACnC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown renderer for assistant messages.
|
|
3
|
+
*
|
|
4
|
+
* Wraps `react-markdown` with a couple of safe defaults:
|
|
5
|
+
* - Links open in a new tab with rel="noopener noreferrer".
|
|
6
|
+
* - No raw HTML execution (react-markdown's default; documented for
|
|
7
|
+
* clarity).
|
|
8
|
+
*
|
|
9
|
+
* Styling is in CuratorChat.tsx via a `data-curator-md` selector so
|
|
10
|
+
* the rules can target the markdown output without touching the
|
|
11
|
+
* surrounding bubble layout.
|
|
12
|
+
*/
|
|
13
|
+
export declare function Markdown({ content }: {
|
|
14
|
+
content: string;
|
|
15
|
+
}): import("react").JSX.Element;
|
|
16
|
+
//# sourceMappingURL=Markdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Markdown.d.ts","sourceRoot":"","sources":["../../src/Markdown.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAkBH,wBAAgB,QAAQ,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,+BAMxD"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import ReactMarkdown from "react-markdown";
|
|
3
|
+
import { normalizeMarkdown } from "./normalizeMarkdown.js";
|
|
4
|
+
const components = {
|
|
5
|
+
a({ children, ...props }) {
|
|
6
|
+
return (_jsx("a", { ...props, target: "_blank", rel: "noopener noreferrer", children: children }));
|
|
7
|
+
},
|
|
8
|
+
};
|
|
9
|
+
export function Markdown({ content }) {
|
|
10
|
+
return (_jsx("div", { "data-curator-md": true, children: _jsx(ReactMarkdown, { components: components, children: normalizeMarkdown(content) }) }));
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=Markdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Markdown.js","sourceRoot":"","sources":["../../src/Markdown.tsx"],"names":[],"mappings":";AAcA,OAAO,aAAa,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAI1D,MAAM,UAAU,GAAiB;IAC/B,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE;QACtB,OAAO,CACL,eAAO,KAAK,EAAE,MAAM,EAAC,QAAQ,EAAC,GAAG,EAAC,qBAAqB,YACpD,QAAQ,GACP,CACL,CAAA;IACH,CAAC;CACF,CAAA;AAED,MAAM,UAAU,QAAQ,CAAC,EAAE,OAAO,EAAuB;IACvD,OAAO,CACL,iDACE,KAAC,aAAa,IAAC,UAAU,EAAE,UAAU,YAAG,iBAAiB,CAAC,OAAO,CAAC,GAAiB,GAC/E,CACP,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* "Powered by Curator" brand mark + footer used inside `<CuratorChat />`.
|
|
3
|
+
*
|
|
4
|
+
* Inline SVG so no asset fetch, no external dep. Sized to be quiet — it
|
|
5
|
+
* sits at the bottom of the chat panel without competing with content.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Brand footer rendered at the bottom of every chat panel. Deliberately
|
|
9
|
+
* has no props — visibility is not consumer-configurable. Enterprise
|
|
10
|
+
* subscriptions may later unlock hiding, but that gating belongs on the
|
|
11
|
+
* server (key claim or org tier), not in a client-side boolean.
|
|
12
|
+
*/
|
|
13
|
+
export declare function PoweredByCurator(): import("react").JSX.Element;
|
|
14
|
+
/**
|
|
15
|
+
* Curator brand mark — the icosahedron logo. Inlined as a single path
|
|
16
|
+
* so it renders without an asset fetch, and bound to `currentColor` so
|
|
17
|
+
* it inherits the surrounding text color (light vs. dark theme).
|
|
18
|
+
*
|
|
19
|
+
* Path geometry is the same one used across the brand site and in-app
|
|
20
|
+
* TopNav; ported here so `@darqlabs/curator-sdk-react` doesn't depend on the host
|
|
21
|
+
* shipping the SVG asset.
|
|
22
|
+
*/
|
|
23
|
+
export declare function CuratorMark({ size }: {
|
|
24
|
+
size?: number;
|
|
25
|
+
}): import("react").JSX.Element;
|
|
26
|
+
//# sourceMappingURL=brand.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brand.d.ts","sourceRoot":"","sources":["../../src/brand.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH;;;;;GAKG;AACH,wBAAgB,gBAAgB,gCAc/B;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,EAAE,IAAS,EAAE,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,+BAa3D"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
const POWERED_BY_URL = "https://curator.darqlabs.ai";
|
|
3
|
+
/**
|
|
4
|
+
* Brand footer rendered at the bottom of every chat panel. Deliberately
|
|
5
|
+
* has no props — visibility is not consumer-configurable. Enterprise
|
|
6
|
+
* subscriptions may later unlock hiding, but that gating belongs on the
|
|
7
|
+
* server (key claim or org tier), not in a client-side boolean.
|
|
8
|
+
*/
|
|
9
|
+
export function PoweredByCurator() {
|
|
10
|
+
return (_jsxs("a", { href: POWERED_BY_URL, target: "_blank", rel: "noopener noreferrer", style: footerStyle, "aria-label": "Powered by Curator", children: [_jsx("span", { children: "Powered by" }), _jsx(CuratorMark, {}), _jsx("span", { style: wordmarkStyle, children: "Curator" })] }));
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Curator brand mark — the icosahedron logo. Inlined as a single path
|
|
14
|
+
* so it renders without an asset fetch, and bound to `currentColor` so
|
|
15
|
+
* it inherits the surrounding text color (light vs. dark theme).
|
|
16
|
+
*
|
|
17
|
+
* Path geometry is the same one used across the brand site and in-app
|
|
18
|
+
* TopNav; ported here so `@darqlabs/curator-sdk-react` doesn't depend on the host
|
|
19
|
+
* shipping the SVG asset.
|
|
20
|
+
*/
|
|
21
|
+
export function CuratorMark({ size = 14 }) {
|
|
22
|
+
return (_jsx("svg", { width: size, height: size, viewBox: "0 0 512 512", fill: "currentColor", "aria-hidden": "true", style: { flexShrink: 0 }, children: _jsx("path", { d: "M490.421,137.707c-0.085-1.003-0.149-2.005-0.555-2.987c-0.107-0.256-0.32-0.427-0.448-0.683c-0.277-0.533-0.597-0.981-0.96-1.472c-0.725-1.003-1.536-1.835-2.517-2.517c-0.256-0.171-0.363-0.491-0.64-0.64l-224-128c-3.285-1.877-7.296-1.877-10.581,0l-224,128c-0.256,0.171-0.363,0.469-0.619,0.64c-1.024,0.704-1.899,1.557-2.645,2.624c-0.299,0.427-0.597,0.811-0.832,1.28c-0.149,0.277-0.384,0.469-0.512,0.768c-0.469,1.173-0.619,2.389-0.661,3.584c0,0.128-0.107,0.256-0.107,0.384v0.171c0,0.021,0,0.021,0,0.043v234.304c0,0.021,0,0.064,0,0.085v0.064c0,0.213,0.149,0.405,0.171,0.619c0.085,1.493,0.32,2.987,1.045,4.352c0.043,0.085,0.128,0.107,0.171,0.192c0.277,0.491,0.768,0.811,1.131,1.259c0.789,0.981,1.557,1.941,2.603,2.603c0.107,0.064,0.149,0.192,0.235,0.235l224,128c1.664,0.939,3.477,1.408,5.312,1.408s3.648-0.469,5.291-1.408l224-128c0.107-0.064,0.149-0.192,0.256-0.256c0.981-0.597,1.664-1.493,2.411-2.389c0.427-0.512,1.003-0.896,1.323-1.472c0.043-0.064,0.107-0.107,0.149-0.171c0.576-1.109,0.683-2.325,0.853-3.52c0.064-0.491,0.384-0.939,0.384-1.451V138.688C490.677,138.347,490.443,138.048,490.421,137.707z M455.52,136.981l-78.251,31.296L291.211,43.093L455.52,136.981z M256.011,29.504l97.067,141.184H158.944L256.011,29.504z M220.747,43.115l-86.037,125.163L56.48,136.981L220.747,43.115z M42.677,154.432l80.768,32.32L42.677,332.16V154.432z M138.635,203.392l98.325,178.773L49.248,364.288L138.635,203.392z M245.344,482.965l-165.12-94.336l165.12,15.573V482.965z M256.011,372.544l-99.285-180.523h198.571L256.011,372.544z M266.677,482.965v-78.571l165.035-15.723L266.677,482.965z M274.997,382.357l98.411-178.901l89.365,160.853L274.997,382.357z M469.344,332.203l-80.811-145.451l80.811-32.32V332.203z" }) }));
|
|
23
|
+
}
|
|
24
|
+
const footerStyle = {
|
|
25
|
+
display: "inline-flex",
|
|
26
|
+
alignItems: "center",
|
|
27
|
+
gap: 7,
|
|
28
|
+
textDecoration: "none",
|
|
29
|
+
color: "var(--curator-muted)",
|
|
30
|
+
fontSize: 11,
|
|
31
|
+
lineHeight: 1,
|
|
32
|
+
letterSpacing: 0.1,
|
|
33
|
+
padding: "14px 18px",
|
|
34
|
+
alignSelf: "center",
|
|
35
|
+
// No visible border / background — sits as a quiet caption
|
|
36
|
+
opacity: 0.7,
|
|
37
|
+
transition: "opacity 120ms ease",
|
|
38
|
+
};
|
|
39
|
+
const wordmarkStyle = {
|
|
40
|
+
fontWeight: 600,
|
|
41
|
+
color: "var(--curator-text)",
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=brand.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brand.js","sourceRoot":"","sources":["../../src/brand.tsx"],"names":[],"mappings":";AASA,MAAM,cAAc,GAAG,6BAA6B,CAAA;AAEpD;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB;IAC9B,OAAO,CACL,aACE,IAAI,EAAE,cAAc,EACpB,MAAM,EAAC,QAAQ,EACf,GAAG,EAAC,qBAAqB,EACzB,KAAK,EAAE,WAAW,gBACP,oBAAoB,aAE/B,wCAAuB,EACvB,KAAC,WAAW,KAAG,EACf,eAAM,KAAK,EAAE,aAAa,wBAAgB,IACxC,CACL,CAAA;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,EAAE,IAAI,GAAG,EAAE,EAAqB;IAC1D,OAAO,CACL,cACE,KAAK,EAAE,IAAI,EACX,MAAM,EAAE,IAAI,EACZ,OAAO,EAAC,aAAa,EACrB,IAAI,EAAC,cAAc,iBACP,MAAM,EAClB,KAAK,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,YAExB,eAAM,CAAC,EAAC,6oDAA6oD,GAAG,GACppD,CACP,CAAA;AACH,CAAC;AAED,MAAM,WAAW,GAAkB;IACjC,OAAO,EAAE,aAAa;IACtB,UAAU,EAAE,QAAQ;IACpB,GAAG,EAAE,CAAC;IACN,cAAc,EAAE,MAAM;IACtB,KAAK,EAAE,sBAAsB;IAC7B,QAAQ,EAAE,EAAE;IACZ,UAAU,EAAE,CAAC;IACb,aAAa,EAAE,GAAG;IAClB,OAAO,EAAE,WAAW;IACpB,SAAS,EAAE,QAAQ;IACnB,2DAA2D;IAC3D,OAAO,EAAE,GAAG;IACZ,UAAU,EAAE,oBAAoB;CACjC,CAAA;AAED,MAAM,aAAa,GAAkB;IACnC,UAAU,EAAE,GAAG;IACf,KAAK,EAAE,qBAAqB;CAC7B,CAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { CuratorChat } from "./CuratorChat.js";
|
|
2
|
+
export type { CuratorChatProps } from "./CuratorChat.js";
|
|
3
|
+
export { CuratorChatLauncher } from "./CuratorChatLauncher.js";
|
|
4
|
+
export type { CuratorChatLauncherProps, LauncherPlacement, } from "./CuratorChatLauncher.js";
|
|
5
|
+
export { useCuratorChat } from "./useCuratorChat.js";
|
|
6
|
+
export type { ChatBubble, UseCuratorChatOptions, UseCuratorChatResult, SendArgs, } from "./useCuratorChat.js";
|
|
7
|
+
export { CuratorProvider, useCurator, useCuratorOrNull } from "./CuratorProvider.js";
|
|
8
|
+
export type { CuratorProviderProps } from "./CuratorProvider.js";
|
|
9
|
+
export { PoweredByCurator, CuratorMark } from "./brand.js";
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAC9D,YAAY,EACV,wBAAwB,EACxB,iBAAiB,GAClB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AACpD,YAAY,EACV,UAAU,EACV,qBAAqB,EACrB,oBAAoB,EACpB,QAAQ,GACT,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACpF,YAAY,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AAChE,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { CuratorChat } from "./CuratorChat.js";
|
|
2
|
+
export { CuratorChatLauncher } from "./CuratorChatLauncher.js";
|
|
3
|
+
export { useCuratorChat } from "./useCuratorChat.js";
|
|
4
|
+
export { CuratorProvider, useCurator, useCuratorOrNull } from "./CuratorProvider.js";
|
|
5
|
+
export { PoweredByCurator, CuratorMark } from "./brand.js";
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAE9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAA;AAK9D,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAOpD,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAEpF,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pre-pass that tightens chat-friendly markdown without changing prose.
|
|
3
|
+
*
|
|
4
|
+
* 1. Trim, and collapse 3+ blank lines to a single blank line.
|
|
5
|
+
* 2. Collapse blank lines *between list items* so the list stays
|
|
6
|
+
* "tight" (per CommonMark). A blank line anywhere in a list flips
|
|
7
|
+
* the whole thing to "loose," and loose lists wrap every item in
|
|
8
|
+
* a `<p>` — the paragraph margins then make a structured list look
|
|
9
|
+
* like a stack of disconnected sentences. LLMs frequently emit a
|
|
10
|
+
* stray blank line inside a long list, so this is the highest-
|
|
11
|
+
* impact normalization step.
|
|
12
|
+
* 3. When the LLM emits a run of short single-line "facts" separated
|
|
13
|
+
* by blank lines (`Status: Job Closed\n\nCreated At: …\n\nTimeline:
|
|
14
|
+
* …`), merge each run into one paragraph with hard line breaks
|
|
15
|
+
* (` \n`). Markdown then renders the run as a single <p> with
|
|
16
|
+
* <br>s between lines instead of N separate paragraphs.
|
|
17
|
+
*
|
|
18
|
+
* Multi-line paragraphs, list items, headings, code fences, block
|
|
19
|
+
* quotes, and tables are left untouched so real prose, lists, and
|
|
20
|
+
* structured blocks render normally. Blank lines inside fenced code
|
|
21
|
+
* blocks are preserved exactly.
|
|
22
|
+
*/
|
|
23
|
+
export declare function normalizeMarkdown(content: string): string;
|
|
24
|
+
//# sourceMappingURL=normalizeMarkdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalizeMarkdown.d.ts","sourceRoot":"","sources":["../../src/normalizeMarkdown.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAkEH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAyBzD"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pre-pass that tightens chat-friendly markdown without changing prose.
|
|
3
|
+
*
|
|
4
|
+
* 1. Trim, and collapse 3+ blank lines to a single blank line.
|
|
5
|
+
* 2. Collapse blank lines *between list items* so the list stays
|
|
6
|
+
* "tight" (per CommonMark). A blank line anywhere in a list flips
|
|
7
|
+
* the whole thing to "loose," and loose lists wrap every item in
|
|
8
|
+
* a `<p>` — the paragraph margins then make a structured list look
|
|
9
|
+
* like a stack of disconnected sentences. LLMs frequently emit a
|
|
10
|
+
* stray blank line inside a long list, so this is the highest-
|
|
11
|
+
* impact normalization step.
|
|
12
|
+
* 3. When the LLM emits a run of short single-line "facts" separated
|
|
13
|
+
* by blank lines (`Status: Job Closed\n\nCreated At: …\n\nTimeline:
|
|
14
|
+
* …`), merge each run into one paragraph with hard line breaks
|
|
15
|
+
* (` \n`). Markdown then renders the run as a single <p> with
|
|
16
|
+
* <br>s between lines instead of N separate paragraphs.
|
|
17
|
+
*
|
|
18
|
+
* Multi-line paragraphs, list items, headings, code fences, block
|
|
19
|
+
* quotes, and tables are left untouched so real prose, lists, and
|
|
20
|
+
* structured blocks render normally. Blank lines inside fenced code
|
|
21
|
+
* blocks are preserved exactly.
|
|
22
|
+
*/
|
|
23
|
+
const FACT_LINE_MAX = 120;
|
|
24
|
+
const MARKDOWN_BLOCK_START = /^\s*([-*+]\s|\d+\.\s|#{1,6}\s|>\s|```|\||\t)/;
|
|
25
|
+
const LIST_ITEM = /^\s*(?:[-*+]|\d+\.)\s/;
|
|
26
|
+
// "Continuation" of a list item: an indented non-blank line. Captures the
|
|
27
|
+
// case where the previous logical entry is something like
|
|
28
|
+
// ` - Location: 4000 Redondo Beach Ave, ...` and the next item sits
|
|
29
|
+
// at a different indent.
|
|
30
|
+
const LIST_CONTINUATION = /^[ \t]+\S/;
|
|
31
|
+
const CODE_FENCE = /^\s*```/;
|
|
32
|
+
/**
|
|
33
|
+
* Drop blank lines that sit between two list-y lines. A code-fence state
|
|
34
|
+
* machine guards blank lines inside fenced code blocks — those stay.
|
|
35
|
+
*/
|
|
36
|
+
function collapseLooseListBlanks(input) {
|
|
37
|
+
const lines = input.split("\n");
|
|
38
|
+
const out = [];
|
|
39
|
+
let inFence = false;
|
|
40
|
+
for (let i = 0; i < lines.length; i++) {
|
|
41
|
+
const line = lines[i];
|
|
42
|
+
if (CODE_FENCE.test(line)) {
|
|
43
|
+
inFence = !inFence;
|
|
44
|
+
out.push(line);
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (inFence) {
|
|
48
|
+
out.push(line);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (line.trim() === "") {
|
|
52
|
+
// Look back to the most recent non-blank line we've already emitted.
|
|
53
|
+
let prevIdx = out.length - 1;
|
|
54
|
+
while (prevIdx >= 0 && out[prevIdx].trim() === "")
|
|
55
|
+
prevIdx--;
|
|
56
|
+
// Look forward to the next non-blank source line.
|
|
57
|
+
let nextIdx = i + 1;
|
|
58
|
+
while (nextIdx < lines.length && lines[nextIdx].trim() === "")
|
|
59
|
+
nextIdx++;
|
|
60
|
+
if (prevIdx >= 0 && nextIdx < lines.length) {
|
|
61
|
+
const prev = out[prevIdx];
|
|
62
|
+
const next = lines[nextIdx];
|
|
63
|
+
if ((LIST_ITEM.test(prev) || LIST_CONTINUATION.test(prev)) &&
|
|
64
|
+
LIST_ITEM.test(next)) {
|
|
65
|
+
// Drop this blank — the list stays tight.
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
out.push(line);
|
|
71
|
+
}
|
|
72
|
+
return out.join("\n");
|
|
73
|
+
}
|
|
74
|
+
function isShortFact(paragraph) {
|
|
75
|
+
if (paragraph.includes("\n"))
|
|
76
|
+
return false;
|
|
77
|
+
if (paragraph.length > FACT_LINE_MAX)
|
|
78
|
+
return false;
|
|
79
|
+
if (MARKDOWN_BLOCK_START.test(paragraph))
|
|
80
|
+
return false;
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
export function normalizeMarkdown(content) {
|
|
84
|
+
const trimmed = collapseLooseListBlanks(content.trim()).replace(/\n{3,}/g, "\n\n");
|
|
85
|
+
const paragraphs = trimmed.split(/\n\n/);
|
|
86
|
+
const out = [];
|
|
87
|
+
let factRun = [];
|
|
88
|
+
const flushRun = () => {
|
|
89
|
+
if (factRun.length === 0)
|
|
90
|
+
return;
|
|
91
|
+
// ` \n` (two trailing spaces + newline) is markdown's hard line
|
|
92
|
+
// break — renders as <br> instead of a new paragraph.
|
|
93
|
+
out.push(factRun.join(" \n"));
|
|
94
|
+
factRun = [];
|
|
95
|
+
};
|
|
96
|
+
for (const p of paragraphs) {
|
|
97
|
+
if (isShortFact(p)) {
|
|
98
|
+
factRun.push(p);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
flushRun();
|
|
102
|
+
out.push(p);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
flushRun();
|
|
106
|
+
return out.join("\n\n");
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=normalizeMarkdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalizeMarkdown.js","sourceRoot":"","sources":["../../src/normalizeMarkdown.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Headless chat hook for the Curator SDK.
|
|
3
|
+
*
|
|
4
|
+
* Manages a single conversation against a deployed agent. Owns the
|
|
5
|
+
* `Chat` instance from the SDK, exposes the rolling message list, a
|
|
6
|
+
* `send()` action, and the various pending/error states the UI needs.
|
|
7
|
+
*
|
|
8
|
+
* Bring your own UI on top of this hook, or use `<CuratorChat />` for
|
|
9
|
+
* the drop-in styled widget that consumes this hook internally.
|
|
10
|
+
*/
|
|
11
|
+
import type { AssistantMessage, Chat, Curator, CuratorError, Environment, FileAttachment } from "@darqlabs/curator-sdk";
|
|
12
|
+
/** Local message representation — superset of what the SDK returns plus
|
|
13
|
+
* optimistic user messages and inline error markers. */
|
|
14
|
+
export type ChatBubble = {
|
|
15
|
+
kind: "user";
|
|
16
|
+
content: string;
|
|
17
|
+
/** Stable local id; not persisted to the server. */
|
|
18
|
+
localId: string;
|
|
19
|
+
} | {
|
|
20
|
+
kind: "assistant";
|
|
21
|
+
content: string;
|
|
22
|
+
sequence: number;
|
|
23
|
+
stepId: string | null;
|
|
24
|
+
createdAt: string;
|
|
25
|
+
runId: string;
|
|
26
|
+
} | {
|
|
27
|
+
kind: "error";
|
|
28
|
+
message: string;
|
|
29
|
+
localId: string;
|
|
30
|
+
};
|
|
31
|
+
export interface UseCuratorChatOptions {
|
|
32
|
+
/**
|
|
33
|
+
* SDK instance. Optional when a `<CuratorProvider>` is mounted higher
|
|
34
|
+
* in the tree — the hook reads the client from context as a fallback.
|
|
35
|
+
* Pass explicitly to override or to address multiple clients.
|
|
36
|
+
*/
|
|
37
|
+
curator?: Curator;
|
|
38
|
+
/** Deployment slug to address. */
|
|
39
|
+
agent: string;
|
|
40
|
+
/** Override the SDK's default project for this chat. */
|
|
41
|
+
project?: string;
|
|
42
|
+
/** Override the SDK's default environment for this chat. */
|
|
43
|
+
environment?: Environment;
|
|
44
|
+
/** Hit a system-scoped deployment instead of a project-scoped one. */
|
|
45
|
+
system?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Reattach to an existing conversation id instead of opening a fresh one.
|
|
48
|
+
* Useful for resuming across sessions.
|
|
49
|
+
*/
|
|
50
|
+
conversationId?: string;
|
|
51
|
+
/** Fired once per successfully-returned assistant message. */
|
|
52
|
+
onMessage?: (message: AssistantMessage) => void;
|
|
53
|
+
/** Fired on any send-time error (typed SDK error or unknown). */
|
|
54
|
+
onError?: (error: CuratorError | Error) => void;
|
|
55
|
+
}
|
|
56
|
+
export interface SendArgs {
|
|
57
|
+
files?: FileAttachment[];
|
|
58
|
+
/** Override the SDK-default sync-wait timeout for this send. */
|
|
59
|
+
timeoutMs?: number;
|
|
60
|
+
}
|
|
61
|
+
export interface UseCuratorChatResult {
|
|
62
|
+
/** All bubbles, in chronological order. */
|
|
63
|
+
messages: ChatBubble[];
|
|
64
|
+
/** Send a user message and await the assistant's reply. */
|
|
65
|
+
send: (content: string, args?: SendArgs) => Promise<void>;
|
|
66
|
+
/** True while a send is in flight. */
|
|
67
|
+
sending: boolean;
|
|
68
|
+
/** Most recent error, or null. Cleared on the next successful send. */
|
|
69
|
+
error: CuratorError | Error | null;
|
|
70
|
+
/** Underlying SDK `Chat` instance; exposed for advanced use. */
|
|
71
|
+
chat: Chat;
|
|
72
|
+
/** Conversation id, or null until the first send creates one. */
|
|
73
|
+
conversationId: string | null;
|
|
74
|
+
/** Clear the visible message list and detach the current conversation
|
|
75
|
+
* by allocating a fresh Chat. */
|
|
76
|
+
reset: () => void;
|
|
77
|
+
}
|
|
78
|
+
export declare function useCuratorChat(opts: UseCuratorChatOptions): UseCuratorChatResult;
|
|
79
|
+
//# sourceMappingURL=useCuratorChat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCuratorChat.d.ts","sourceRoot":"","sources":["../../src/useCuratorChat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EACV,gBAAgB,EAChB,IAAI,EACJ,OAAO,EACP,YAAY,EACZ,WAAW,EACX,cAAc,EACf,MAAM,uBAAuB,CAAA;AAa9B;yDACyD;AACzD,MAAM,MAAM,UAAU,GAClB;IACE,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,oDAAoD;IACpD,OAAO,EAAE,MAAM,CAAA;CAChB,GACD;IACE,IAAI,EAAE,WAAW,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;CACd,GACD;IACE,IAAI,EAAE,OAAO,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAEL,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,kCAAkC;IAClC,KAAK,EAAE,MAAM,CAAA;IACb,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,4DAA4D;IAC5D,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,sEAAsE;IACtE,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,IAAI,CAAA;IAC/C,iEAAiE;IACjE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,GAAG,KAAK,KAAK,IAAI,CAAA;CAChD;AAED,MAAM,WAAW,QAAQ;IACvB,KAAK,CAAC,EAAE,cAAc,EAAE,CAAA;IACxB,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,oBAAoB;IACnC,2CAA2C;IAC3C,QAAQ,EAAE,UAAU,EAAE,CAAA;IACtB,2DAA2D;IAC3D,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACzD,sCAAsC;IACtC,OAAO,EAAE,OAAO,CAAA;IAChB,uEAAuE;IACvE,KAAK,EAAE,YAAY,GAAG,KAAK,GAAG,IAAI,CAAA;IAClC,gEAAgE;IAChE,IAAI,EAAE,IAAI,CAAA;IACV,iEAAiE;IACjE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B;sCACkC;IAClC,KAAK,EAAE,MAAM,IAAI,CAAA;CAClB;AAQD,wBAAgB,cAAc,CAAC,IAAI,EAAE,qBAAqB,GAAG,oBAAoB,CAgGhF"}
|