@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
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Darq Labs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# @darqlabs/curator-sdk-react
|
|
2
|
+
|
|
3
|
+
Official React components for Curator. Drop in a ready-to-use chat widget that talks to your deployed agents, or wire up your own UI with the headless hook.
|
|
4
|
+
|
|
5
|
+
Powered by [assistant-ui](https://github.com/Yonom/assistant-ui) internals — token-by-token streaming, edit/regenerate primitives, and tool-call extension points are available to consumers who want to go deeper than the drop-in widget.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
// once, at the app root
|
|
9
|
+
import { Curator } from "@darqlabs/curator-sdk"
|
|
10
|
+
import { CuratorProvider } from "@darqlabs/curator-sdk-react"
|
|
11
|
+
|
|
12
|
+
const curator = new Curator({
|
|
13
|
+
apiKey: "CURATOR_API_KEY",
|
|
14
|
+
project: "default",
|
|
15
|
+
environment: "production",
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
export function App() {
|
|
19
|
+
return (
|
|
20
|
+
<CuratorProvider client={curator}>
|
|
21
|
+
<Routes />
|
|
22
|
+
</CuratorProvider>
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// anywhere inside
|
|
27
|
+
import { CuratorChat } from "@darqlabs/curator-sdk-react"
|
|
28
|
+
|
|
29
|
+
export function Support() {
|
|
30
|
+
return <CuratorChat agent="support-bot" />
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Install
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm install @darqlabs/curator-sdk @darqlabs/curator-sdk-react
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
React 18 or 19. Works with Vite, Next.js, Remix, anything with `react` and `react-dom`.
|
|
41
|
+
|
|
42
|
+
## Why pass the client?
|
|
43
|
+
|
|
44
|
+
The components consume a `Curator` instance (built from `@darqlabs/curator-sdk`) rather than an API key. That keeps auth, project / environment defaults, custom fetch, and headers in one place — the same instance can power multiple chats, file uploads, or your own SDK calls.
|
|
45
|
+
|
|
46
|
+
Wrap your tree once with `<CuratorProvider>` and components further down read the client from context automatically. Or pass `curator` explicitly to override (e.g. when one screen needs to talk to a different client).
|
|
47
|
+
|
|
48
|
+
## Drop-in component
|
|
49
|
+
|
|
50
|
+
```tsx
|
|
51
|
+
<CuratorChat
|
|
52
|
+
agent="support-bot"
|
|
53
|
+
// optional — overrides the provider's client
|
|
54
|
+
curator={otherCurator}
|
|
55
|
+
// optional UX
|
|
56
|
+
title="Support"
|
|
57
|
+
placeholder="Ask anything…"
|
|
58
|
+
welcomeMessage="Hi! How can I help?"
|
|
59
|
+
// optional locator overrides
|
|
60
|
+
project="default"
|
|
61
|
+
environment="production"
|
|
62
|
+
conversationId={savedConversationId}
|
|
63
|
+
// optional message actions (both default off)
|
|
64
|
+
enableRetry // ↻ regenerate button under the latest assistant reply
|
|
65
|
+
enableCopy // copy button on assistant messages
|
|
66
|
+
// optional styling
|
|
67
|
+
theme="light" // or "dark"
|
|
68
|
+
className="my-chat"
|
|
69
|
+
style={{ height: 520 }}
|
|
70
|
+
// optional events
|
|
71
|
+
onMessage={(msg) => console.log(msg)}
|
|
72
|
+
onError={(err) => console.error(err)}
|
|
73
|
+
/>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Message actions
|
|
77
|
+
|
|
78
|
+
| Prop | Default | Effect |
|
|
79
|
+
| --- | --- | --- |
|
|
80
|
+
| `enableRetry` | `false` | Shows a ↻ button under the latest assistant message that re-sends the preceding user turn. |
|
|
81
|
+
| `enableCopy` | `false` | Shows a copy button on assistant messages (with a brief check-mark confirmation). |
|
|
82
|
+
|
|
83
|
+
### Theming
|
|
84
|
+
|
|
85
|
+
Two built-in palettes via the `theme` prop (`"light"` / `"dark"`). For finer control, override the design-token CSS variables through the **`style` prop**:
|
|
86
|
+
|
|
87
|
+
```tsx
|
|
88
|
+
<CuratorChat
|
|
89
|
+
agent="support-bot"
|
|
90
|
+
style={{
|
|
91
|
+
["--curator-accent"]: "#2563eb", // agent bubble + send button background
|
|
92
|
+
["--curator-accent-text"]: "#ffffff", // agent bubble + send button text/icon
|
|
93
|
+
["--curator-user-bubble"]: "#f1f5f9", // user bubble background
|
|
94
|
+
["--curator-bg"]: "#fafafa", // chat background
|
|
95
|
+
["--curator-text"]: "#18181b", // primary text
|
|
96
|
+
["--curator-muted"]: "#71717a", // action icons, timestamps, hints
|
|
97
|
+
["--curator-border"]: "rgba(0,0,0,0.08)",
|
|
98
|
+
["--curator-error"]: "#b91c1c",
|
|
99
|
+
["--curator-radius"]: "16px", // container corner radius
|
|
100
|
+
} as React.CSSProperties}
|
|
101
|
+
/>
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
| Token | Controls |
|
|
105
|
+
| --- | --- |
|
|
106
|
+
| `--curator-accent` / `--curator-accent-text` | Agent (assistant) bubble **and** the send button |
|
|
107
|
+
| `--curator-user-bubble` | User bubble background (text uses `--curator-text`) |
|
|
108
|
+
| `--curator-bg` / `--curator-surface` | Chat background / composer + input background |
|
|
109
|
+
| `--curator-muted` | Action icons, welcome text, timestamps |
|
|
110
|
+
| `--curator-border`, `--curator-error`, `--curator-radius` | Borders, error text, container radius |
|
|
111
|
+
|
|
112
|
+
Use the **`style` prop** (not a CSS class or an ancestor rule): the widget sets these variables inline on its own root for the active `theme`, and inline styles win over a class — the `style` prop is applied last, so it's the one override that reliably takes effect. The widget ships no external stylesheet.
|
|
113
|
+
|
|
114
|
+
## Floating launcher
|
|
115
|
+
|
|
116
|
+
For a chat-bubble-in-the-corner widget instead of an inline panel, use `<CuratorChatLauncher />`. Same props as `<CuratorChat />` plus placement controls:
|
|
117
|
+
|
|
118
|
+
```tsx
|
|
119
|
+
import { CuratorChatLauncher } from "@darqlabs/curator-sdk-react"
|
|
120
|
+
|
|
121
|
+
<CuratorChatLauncher
|
|
122
|
+
agent="support-bot"
|
|
123
|
+
placement="bottom-right" // or bottom-left / top-right / top-left
|
|
124
|
+
offset={24} // px from the docked corner
|
|
125
|
+
panelWidth={380}
|
|
126
|
+
panelHeight={560}
|
|
127
|
+
defaultOpen={false}
|
|
128
|
+
// all <CuratorChat /> props are forwarded:
|
|
129
|
+
title="Support"
|
|
130
|
+
theme="light"
|
|
131
|
+
welcomeMessage="Hi! How can I help?"
|
|
132
|
+
/>
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Renders via a portal to `document.body`, so it escapes stacking contexts in the host app. ESC closes the panel; clicking outside doesn't (intentional — keeps chat state from getting lost on a stray click).
|
|
136
|
+
|
|
137
|
+
## Headless hook
|
|
138
|
+
|
|
139
|
+
For full UI control, use `useCuratorChat` directly. `curator` is optional when a `<CuratorProvider>` is in scope:
|
|
140
|
+
|
|
141
|
+
```tsx
|
|
142
|
+
import { useCuratorChat } from "@darqlabs/curator-sdk-react"
|
|
143
|
+
|
|
144
|
+
function MyChat() {
|
|
145
|
+
const { messages, send, sending, error, conversationId } = useCuratorChat({
|
|
146
|
+
agent: "support-bot",
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
return (
|
|
150
|
+
<div>
|
|
151
|
+
{messages.map((m) =>
|
|
152
|
+
m.kind === "user" ? <UserBubble key={m.localId} text={m.content} />
|
|
153
|
+
: m.kind === "assistant" ? <BotBubble key={m.runId} text={m.content} />
|
|
154
|
+
: <ErrorRow key={m.localId} text={m.message} />,
|
|
155
|
+
)}
|
|
156
|
+
{sending && <Typing />}
|
|
157
|
+
<Composer onSubmit={(text) => send(text)} />
|
|
158
|
+
</div>
|
|
159
|
+
)
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
The hook returns:
|
|
164
|
+
|
|
165
|
+
| | |
|
|
166
|
+
| --- | --- |
|
|
167
|
+
| `messages` | Chronological list of bubbles (`user` / `assistant` / `error`). |
|
|
168
|
+
| `send(content, opts?)` | Append a user message and await the assistant's reply. `opts.files` for attachments, `opts.timeoutMs` to override the wait. |
|
|
169
|
+
| `sending` | True while a `send` is in flight. |
|
|
170
|
+
| `error` | Most recent error, or null. Cleared on next successful send. |
|
|
171
|
+
| `chat` | Underlying SDK `Chat` instance. |
|
|
172
|
+
| `conversationId` | Conversation id once one has been created. |
|
|
173
|
+
| `reset()` | Clear visible messages (keeps the same conversation). |
|
|
174
|
+
|
|
175
|
+
## Reading the client directly
|
|
176
|
+
|
|
177
|
+
```tsx
|
|
178
|
+
import { useCurator } from "@darqlabs/curator-sdk-react"
|
|
179
|
+
|
|
180
|
+
function UploadButton() {
|
|
181
|
+
const curator = useCurator()
|
|
182
|
+
return (
|
|
183
|
+
<button onClick={async () => {
|
|
184
|
+
const fileRef = await curator.files.upload({ filename, mimeType, data })
|
|
185
|
+
// …
|
|
186
|
+
}}>
|
|
187
|
+
Upload
|
|
188
|
+
</button>
|
|
189
|
+
)
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Throws a clear error if no `<CuratorProvider>` is mounted higher in the tree.
|
|
194
|
+
|
|
195
|
+
## Errors
|
|
196
|
+
|
|
197
|
+
The hook captures all SDK errors into a friendly `kind: "error"` bubble — auth, agent failures, timeouts, approval-required pauses, etc. — and also exposes the raw error via `error` and the `onError` prop so you can log or surface them however you like.
|
|
198
|
+
|
|
199
|
+
## Security in the browser
|
|
200
|
+
|
|
201
|
+
The chat runs wherever your `Curator` client runs. If you instantiate the client in browser code, the API key ships in your bundle. Recommended patterns:
|
|
202
|
+
|
|
203
|
+
1. **Backend proxy.** Run the SDK on your server; have your frontend call your server. Your server holds the key.
|
|
204
|
+
2. **Trusted internal tools.** Employee dashboards behind SSO are usually fine.
|
|
205
|
+
3. **Server-issued tokens.** Not supported yet — reach out if you need them.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapter that plugs the Curator SDK into assistant-ui's `useLocalRuntime`.
|
|
3
|
+
*
|
|
4
|
+
* Each invocation of `run()` is one user-turn. We pull the latest user
|
|
5
|
+
* message text out of assistant-ui's structured `messages[]`, hand it to
|
|
6
|
+
* `chat.stream(...)`, and yield assistant-ui-shaped updates back as the
|
|
7
|
+
* SDK's stream events flow in.
|
|
8
|
+
*
|
|
9
|
+
* stream.delta → accumulate text, yield partial assistant content
|
|
10
|
+
* stream.done → yield final content + status: complete
|
|
11
|
+
* stream.error → yield friendly text + status: incomplete
|
|
12
|
+
* stream.paused_for_ → yield "contact your administrator" text +
|
|
13
|
+
* approval status: incomplete
|
|
14
|
+
*
|
|
15
|
+
* The Chat handle is constructed once per chat session (one per
|
|
16
|
+
* mounted CuratorChat / launcher panel) so multi-turn context stays
|
|
17
|
+
* intact across runs.
|
|
18
|
+
*/
|
|
19
|
+
import type { ChatModelAdapter } from "@assistant-ui/react";
|
|
20
|
+
import type { AssistantMessage, Chat, CuratorError } from "@darqlabs/curator-sdk";
|
|
21
|
+
export interface CuratorAdapterCallbacks {
|
|
22
|
+
/** Fired once per successfully-returned assistant message. */
|
|
23
|
+
onMessage?: (message: AssistantMessage) => void;
|
|
24
|
+
/** Fired on any send-time error surfaced through the stream. */
|
|
25
|
+
onError?: (error: CuratorError | Error) => void;
|
|
26
|
+
}
|
|
27
|
+
export declare function createCuratorAdapter(chat: Chat, callbacks?: CuratorAdapterCallbacks): ChatModelAdapter;
|
|
28
|
+
//# sourceMappingURL=CuratorAdapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CuratorAdapter.d.ts","sourceRoot":"","sources":["../../src/CuratorAdapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAsB,MAAM,qBAAqB,CAAA;AAC/E,OAAO,KAAK,EACV,gBAAgB,EAChB,IAAI,EACJ,YAAY,EACb,MAAM,uBAAuB,CAAA;AAE9B,MAAM,WAAW,uBAAuB;IACtC,8DAA8D;IAC9D,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,IAAI,CAAA;IAC/C,gEAAgE;IAChE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,GAAG,KAAK,KAAK,IAAI,CAAA;CAChD;AAED,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,IAAI,EACV,SAAS,GAAE,uBAA4B,GACtC,gBAAgB,CA6DlB"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Adapter that plugs the Curator SDK into assistant-ui's `useLocalRuntime`.
|
|
4
|
+
*
|
|
5
|
+
* Each invocation of `run()` is one user-turn. We pull the latest user
|
|
6
|
+
* message text out of assistant-ui's structured `messages[]`, hand it to
|
|
7
|
+
* `chat.stream(...)`, and yield assistant-ui-shaped updates back as the
|
|
8
|
+
* SDK's stream events flow in.
|
|
9
|
+
*
|
|
10
|
+
* stream.delta → accumulate text, yield partial assistant content
|
|
11
|
+
* stream.done → yield final content + status: complete
|
|
12
|
+
* stream.error → yield friendly text + status: incomplete
|
|
13
|
+
* stream.paused_for_ → yield "contact your administrator" text +
|
|
14
|
+
* approval status: incomplete
|
|
15
|
+
*
|
|
16
|
+
* The Chat handle is constructed once per chat session (one per
|
|
17
|
+
* mounted CuratorChat / launcher panel) so multi-turn context stays
|
|
18
|
+
* intact across runs.
|
|
19
|
+
*/
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.createCuratorAdapter = createCuratorAdapter;
|
|
22
|
+
function createCuratorAdapter(chat, callbacks = {}) {
|
|
23
|
+
return {
|
|
24
|
+
async *run({ messages, abortSignal }) {
|
|
25
|
+
const userText = extractLatestUserText(messages);
|
|
26
|
+
if (!userText)
|
|
27
|
+
return;
|
|
28
|
+
let acc = "";
|
|
29
|
+
try {
|
|
30
|
+
for await (const event of chat.stream(userText)) {
|
|
31
|
+
if (abortSignal.aborted)
|
|
32
|
+
return;
|
|
33
|
+
if (event.type === "delta") {
|
|
34
|
+
acc += event.text;
|
|
35
|
+
yield { content: [{ type: "text", text: acc }] };
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (event.type === "done") {
|
|
39
|
+
const finalText = event.message?.content ?? acc;
|
|
40
|
+
yield {
|
|
41
|
+
content: [{ type: "text", text: finalText }],
|
|
42
|
+
status: { type: "complete", reason: "stop" },
|
|
43
|
+
};
|
|
44
|
+
if (event.message)
|
|
45
|
+
callbacks.onMessage?.(event.message);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (event.type === "error") {
|
|
49
|
+
yield {
|
|
50
|
+
content: [{ type: "text", text: event.message }],
|
|
51
|
+
status: { type: "incomplete", reason: "error" },
|
|
52
|
+
};
|
|
53
|
+
callbacks.onError?.(new Error(event.message));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (event.type === "paused_for_approval") {
|
|
57
|
+
const pausedMessage = `This action needs administrator approval. ` +
|
|
58
|
+
`Contact your administrator to review the request for "${event.approval.tool_name}".`;
|
|
59
|
+
yield {
|
|
60
|
+
content: [{ type: "text", text: pausedMessage }],
|
|
61
|
+
status: { type: "incomplete", reason: "error" },
|
|
62
|
+
};
|
|
63
|
+
callbacks.onError?.(new Error(pausedMessage));
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
// tool_call.* and any future event types are silently dropped
|
|
67
|
+
// until a richer UI surface ships for them.
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
const message = err?.message || "Something went wrong sending your message.";
|
|
72
|
+
yield {
|
|
73
|
+
content: [{ type: "text", text: message }],
|
|
74
|
+
status: { type: "incomplete", reason: "error" },
|
|
75
|
+
};
|
|
76
|
+
callbacks.onError?.(err);
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Pull the latest user-turn text out of assistant-ui's structured
|
|
83
|
+
* message array. Text parts are concatenated with newlines; other
|
|
84
|
+
* part types (image, file, etc.) are ignored for now — the SDK's
|
|
85
|
+
* `chat.stream` accepts plain text content only.
|
|
86
|
+
*/
|
|
87
|
+
function extractLatestUserText(messages) {
|
|
88
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
89
|
+
const m = messages[i];
|
|
90
|
+
if (m.role !== "user")
|
|
91
|
+
continue;
|
|
92
|
+
const text = m.content
|
|
93
|
+
.filter((p) => typeof p === "object" && p !== null && p.type === "text")
|
|
94
|
+
.map((p) => p.text)
|
|
95
|
+
.join("\n");
|
|
96
|
+
return text.trim();
|
|
97
|
+
}
|
|
98
|
+
return "";
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=CuratorAdapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CuratorAdapter.js","sourceRoot":"","sources":["../../src/CuratorAdapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <CuratorChat /> — drop-in chat widget backed by a Curator SDK client.
|
|
3
|
+
*
|
|
4
|
+
* <CuratorChat curator={curator} agent="support-bot" />
|
|
5
|
+
*
|
|
6
|
+
* Internals are powered by `@assistant-ui/react` — `useLocalRuntime`
|
|
7
|
+
* wraps our `CuratorAdapter`, which delegates each user turn to
|
|
8
|
+
* `chat.stream(...)` for token-by-token rendering. The outer chrome
|
|
9
|
+
* (header, brand footer, theme tokens, close button) and the bubble
|
|
10
|
+
* layout stay ours so the widget keeps its identity across themes.
|
|
11
|
+
*/
|
|
12
|
+
import { type CSSProperties, type ReactNode } from "react";
|
|
13
|
+
import type { AssistantMessage, Curator, CuratorError, Environment } from "@darqlabs/curator-sdk";
|
|
14
|
+
export interface CuratorChatProps {
|
|
15
|
+
/** SDK instance. Optional when a `<CuratorProvider>` is mounted. */
|
|
16
|
+
curator?: Curator;
|
|
17
|
+
/** Deployment slug to chat with. */
|
|
18
|
+
agent: string;
|
|
19
|
+
/** Override the SDK's default project for this widget. */
|
|
20
|
+
project?: string;
|
|
21
|
+
/** Override the SDK's default environment for this widget. */
|
|
22
|
+
environment?: Environment;
|
|
23
|
+
/** Address a system-scoped deployment. */
|
|
24
|
+
system?: boolean;
|
|
25
|
+
/** Reattach to an existing conversation id instead of starting fresh. */
|
|
26
|
+
conversationId?: string;
|
|
27
|
+
/** Header title. Default: "Chat". */
|
|
28
|
+
title?: string;
|
|
29
|
+
/** Input placeholder. Default: "Type a message…". */
|
|
30
|
+
placeholder?: string;
|
|
31
|
+
/** Shown above the empty message list as a system prompt. */
|
|
32
|
+
welcomeMessage?: string;
|
|
33
|
+
/** Built-in palette. Default: "light". */
|
|
34
|
+
theme?: "light" | "dark";
|
|
35
|
+
/** Class applied to the outer wrapper. */
|
|
36
|
+
className?: string;
|
|
37
|
+
/** Inline styles merged onto the outer wrapper. */
|
|
38
|
+
style?: CSSProperties;
|
|
39
|
+
/** If set, the header shows an X button that calls this. */
|
|
40
|
+
onClose?: () => void;
|
|
41
|
+
/**
|
|
42
|
+
* Indicator rendered inside the assistant bubble while it's waiting
|
|
43
|
+
* for the first token (the gap between Send and the first delta).
|
|
44
|
+
* Default: animated three-dot pulse. Pass any node to swap it out.
|
|
45
|
+
*/
|
|
46
|
+
loadingIndicator?: ReactNode;
|
|
47
|
+
/** Fired once per assistant message that completes successfully. */
|
|
48
|
+
onMessage?: (message: AssistantMessage) => void;
|
|
49
|
+
/** Fired on any terminal stream error or thrown exception. */
|
|
50
|
+
onError?: (error: CuratorError | Error) => void;
|
|
51
|
+
/**
|
|
52
|
+
* Show a retry (↻) button under the latest assistant message. Default:
|
|
53
|
+
* off. Retry re-sends the preceding user message through the SDK — note
|
|
54
|
+
* that this appends a fresh turn to the server-side conversation rather
|
|
55
|
+
* than regenerating the last reply in place, so persisted history will
|
|
56
|
+
* contain the duplicated user message. Fine for casual / demo widgets;
|
|
57
|
+
* enable only if that history shape is acceptable for your deployment.
|
|
58
|
+
*/
|
|
59
|
+
enableRetry?: boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Show a copy button on assistant messages that copies the message text
|
|
62
|
+
* to the clipboard. Default: off. Appears alongside retry (when enabled)
|
|
63
|
+
* in the per-message action bar; a check glyph confirms the copy briefly.
|
|
64
|
+
*/
|
|
65
|
+
enableCopy?: boolean;
|
|
66
|
+
}
|
|
67
|
+
export declare function CuratorChat(props: CuratorChatProps): import("react").JSX.Element;
|
|
68
|
+
declare function AssistantMessage(): import("react").JSX.Element;
|
|
69
|
+
export {};
|
|
70
|
+
//# sourceMappingURL=CuratorChat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CuratorChat.d.ts","sourceRoot":"","sources":["../../src/CuratorChat.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAML,KAAK,aAAa,EAClB,KAAK,SAAS,EACf,MAAM,OAAO,CAAA;AAUd,OAAO,KAAK,EACV,gBAAgB,EAEhB,OAAO,EACP,YAAY,EACZ,WAAW,EACZ,MAAM,uBAAuB,CAAA;AAM9B,MAAM,WAAW,gBAAgB;IAC/B,oEAAoE;IACpE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,oCAAoC;IACpC,KAAK,EAAE,MAAM,CAAA;IACb,0DAA0D;IAC1D,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,8DAA8D;IAC9D,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,0CAA0C;IAC1C,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,CAAA;IAEvB,qCAAqC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,qDAAqD;IACrD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,6DAA6D;IAC7D,cAAc,CAAC,EAAE,MAAM,CAAA;IAEvB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;IACxB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,mDAAmD;IACnD,KAAK,CAAC,EAAE,aAAa,CAAA;IAErB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IAEpB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,SAAS,CAAA;IAC5B,oEAAoE;IACpE,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,IAAI,CAAA;IAC/C,8DAA8D;IAC9D,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,GAAG,KAAK,KAAK,IAAI,CAAA;IAE/C;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,+BAqGlD;AAoDD,iBAAS,gBAAgB,gCAqCxB"}
|