@windmill-labs/chat-sdk 1.846.1 → 1.848.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/README.md +46 -3
- package/dist/assistant-ui.d.ts +4 -4
- package/dist/{chat-u1tspn7Q.cjs → chat-C0iOSX6H.cjs} +71 -10
- package/dist/{chat-DgINfcUU.js → chat-DjonfE4j.js} +72 -11
- package/dist/chat.d.ts +2 -2
- package/dist/config.d.ts +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/react.cjs +9 -4
- package/dist/react.d.ts +4 -4
- package/dist/react.js +9 -4
- package/dist/runnable.d.ts +9 -0
- package/dist/types.d.ts +37 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -148,6 +148,45 @@ const chat = useWindmillChat({ flowPath: 'f/support/assistant' })
|
|
|
148
148
|
- **`wmill app dev`**: there is no viewer session on the dev server, so pass
|
|
149
149
|
`baseUrl`, `workspace` and `token` explicitly during development.
|
|
150
150
|
|
|
151
|
+
### A saved agent, through an agent runnable
|
|
152
|
+
|
|
153
|
+
To chat with a saved AI agent (an `ai_agent` resource), give the app an **agent
|
|
154
|
+
runnable**: a path runnable of type `agent` naming the agent, picked under "AI agents"
|
|
155
|
+
in the editor, or in `raw_app.yaml`:
|
|
156
|
+
|
|
157
|
+
```yaml
|
|
158
|
+
runnables:
|
|
159
|
+
chat:
|
|
160
|
+
type: agent
|
|
161
|
+
path: f/support/agent
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Each call runs one turn of the agent's chat as the app, so a sandboxed app declares no
|
|
165
|
+
frontend SDK scope, viewers get no consent prompt and need no access to the agent.
|
|
166
|
+
Name the runnable and pass the app's generated `wmill.ts`, which the chat goes through:
|
|
167
|
+
|
|
168
|
+
```tsx
|
|
169
|
+
import { useWindmillChat } from '@windmill-labs/chat-sdk/react'
|
|
170
|
+
import * as wmill from './wmill'
|
|
171
|
+
|
|
172
|
+
const chat = useWindmillChat({ wmill, runnable: 'chat' })
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
`runnable` is checked against the runnables `wmill.ts` declares, and names the local
|
|
176
|
+
history, so two agent runnables in one app keep separate conversations. Going through
|
|
177
|
+
`wmill.ts` is what makes the same code work in a deployed app and under `wmill app dev`.
|
|
178
|
+
|
|
179
|
+
`createChat` and the assistant-ui runtime take the same options; the AI SDK transport
|
|
180
|
+
does not. The runnable takes `user_message` and `memory_id`, the conversation id, which
|
|
181
|
+
the agent's memory is keyed by, so it remembers earlier turns (called from `wmill.ts`
|
|
182
|
+
without `memory_id`, it is a single run with no conversation). The agent needs managed
|
|
183
|
+
memory: one whose memory is off takes `previous_messages` instead, the history you keep. A signed-in viewer's turns
|
|
184
|
+
are filed under them, so nobody else can continue their conversations; an anonymous
|
|
185
|
+
visitor's are kept apart per app. The chat makes no request of its own: history is
|
|
186
|
+
`'local'` (the app's own storage), `stop()` stops following without cancelling the turn,
|
|
187
|
+
a message sent while it still runs is refused with `TurnRunningError`, and attachments
|
|
188
|
+
are refused.
|
|
189
|
+
|
|
151
190
|
## Any framework
|
|
152
191
|
|
|
153
192
|
`createChat` returns a store: `subscribe` calls the listener immediately and on every
|
|
@@ -178,7 +217,7 @@ await chat.sendMessage('Hello')
|
|
|
178
217
|
|
|
179
218
|
| Option | |
|
|
180
219
|
|---|---|
|
|
181
|
-
| `flowPath` | Path of the deployed flow, e.g. `f/support/assistant`. Required. |
|
|
220
|
+
| `flowPath` | Path of the deployed flow, e.g. `f/support/assistant`. Required unless `follow` is set. |
|
|
182
221
|
| `baseUrl` | The Windmill origin. Detected inside a raw app. |
|
|
183
222
|
| `workspace` | Detected inside a raw app. |
|
|
184
223
|
| `token` | A token, or a function returning one (called before every request, so it can fetch a short-lived token from your backend). Omit it inside a raw app. |
|
|
@@ -190,6 +229,8 @@ await chat.sendMessage('Hello')
|
|
|
190
229
|
| `pollDelayMs` | How often, in ms, the server polls a running turn for the stream (Enterprise; 50 at the fastest, other servers ignore it). Unset, the server relaxes from 100 ms to 3 s over a long turn; set it when tokens must keep flowing at that pace. |
|
|
191
230
|
| `onFinish`, `onError` | Called when a turn has its answer, or could not run at all. |
|
|
192
231
|
| `run` | Runs the flow for a turn yourself and returns the job id, instead of the deployed flow at `flowPath` (Windmill's editor chats with an undeployed flow through a preview run this way). Pass `memory_id` = the conversation id. |
|
|
232
|
+
| `follow` | With `run`: follows the job through your own client, calling `onStream` with each chunk of its result stream and resolving with its result. The chat then makes no request of its own; `runnable` sets both for a raw app's agent runnable, see [A saved agent](#a-saved-agent-through-an-agent-runnable). |
|
|
233
|
+
| `runnable`, `wmill` | In a raw app, chat through the agent runnable of that name, going through the app's generated module (`import * as wmill from './wmill'`). Replaces `flowPath`, `run` and `follow`. |
|
|
193
234
|
|
|
194
235
|
## State
|
|
195
236
|
|
|
@@ -294,7 +335,8 @@ That store is keyed by the **Windmill user**, so it fits a viewer session or a t
|
|
|
294
335
|
issued per user. With one token shared by every visitor of a site, all visitors would
|
|
295
336
|
see each other's conversations. For that setup use `history: 'local'` (the default
|
|
296
337
|
with an explicit `token`): the conversation list and messages stay in the browser's
|
|
297
|
-
`localStorage`, per Windmill instance, workspace and flow
|
|
338
|
+
`localStorage`, per Windmill instance, workspace and flow, and the chat starts with that
|
|
339
|
+
list in `state.conversations`, without a `loadConversations()` call. `'none'` keeps nothing
|
|
298
340
|
beyond the page.
|
|
299
341
|
|
|
300
342
|
When the default `'server'` mode turns out unreadable (a token or sandboxed app
|
|
@@ -333,7 +375,8 @@ custom integrations.
|
|
|
333
375
|
When asked to add a chat over a Windmill flow: the flow must be deployed with chat mode
|
|
334
376
|
on. Pick the entry point from the table at the top (`useChat` → `@windmill-labs/chat-sdk/ai-sdk`,
|
|
335
377
|
assistant-ui → `@windmill-labs/chat-sdk/assistant-ui`, otherwise `@windmill-labs/chat-sdk/react`). Inside a
|
|
336
|
-
Windmill raw app pass only `flowPath
|
|
378
|
+
Windmill raw app pass only `flowPath`; for a saved agent, use an `agent` runnable and pass
|
|
379
|
+
`{ wmill, runnable }`. Elsewhere pass `baseUrl`, `workspace` and a
|
|
337
380
|
`token`; for a public page use a token scoped to `jobs:run:flows:<flowPath>` and leave
|
|
338
381
|
`history` at its default. Render `role`, `content`, `pending`, `success` and
|
|
339
382
|
`tool.status`; never build the SSE handling yourself.
|
package/dist/assistant-ui.d.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import { type AssistantRuntime, type ThreadMessageLike } from '@assistant-ui/react';
|
|
2
|
-
import type { ChatMessage,
|
|
2
|
+
import type { ChatMessage, RawAppWmill, TypedChatOptions } from './types';
|
|
3
3
|
/** One assistant turn: the assistant and tool rows between two user messages. */
|
|
4
4
|
export interface WindmillTurn {
|
|
5
5
|
id: string;
|
|
6
6
|
role: 'user' | 'assistant' | 'system';
|
|
7
7
|
messages: ChatMessage[];
|
|
8
8
|
}
|
|
9
|
-
export
|
|
9
|
+
export type WindmillRuntimeOptions<W extends RawAppWmill = RawAppWmill> = TypedChatOptions<W> & {
|
|
10
10
|
/** Load the conversation list on mount so `ThreadListPrimitive` has something to show. Default true. */
|
|
11
11
|
threadList?: boolean;
|
|
12
|
-
}
|
|
12
|
+
};
|
|
13
13
|
/**
|
|
14
14
|
* An assistant-ui runtime over a chat-mode flow, for `AssistantRuntimeProvider`.
|
|
15
15
|
* Conversations become threads, so the thread list primitives switch, create and
|
|
16
16
|
* delete Windmill conversations.
|
|
17
17
|
*/
|
|
18
|
-
export declare function useWindmillRuntime(options: WindmillRuntimeOptions): AssistantRuntime;
|
|
18
|
+
export declare function useWindmillRuntime<W extends RawAppWmill>(options: WindmillRuntimeOptions<W>): AssistantRuntime;
|
|
19
19
|
/** Folds the role-per-row message list into turns: one entry per user message, one per answer. */
|
|
20
20
|
export declare function groupTurns(messages: ChatMessage[]): WindmillTurn[];
|
|
21
21
|
/** A turn as assistant-ui content parts; the status reflects streaming and a failed flow. */
|
|
@@ -1,4 +1,29 @@
|
|
|
1
1
|
const require_follow = require("./follow-Dug-Afeu.cjs");
|
|
2
|
+
//#region src/runnable.ts
|
|
3
|
+
/**
|
|
4
|
+
* `run` and `follow` over a raw app's agent runnable (a path runnable of type `agent`, naming
|
|
5
|
+
* a saved AI agent), behind the `runnable` option. `memory_id` is the conversation id, the
|
|
6
|
+
* agent's memory key.
|
|
7
|
+
*/
|
|
8
|
+
function rawAppRunnable(start, streamJob) {
|
|
9
|
+
return {
|
|
10
|
+
run: async (args, { conversationId }) => {
|
|
11
|
+
try {
|
|
12
|
+
return String(await start({
|
|
13
|
+
...args,
|
|
14
|
+
memory_id: conversationId
|
|
15
|
+
}));
|
|
16
|
+
} catch (e) {
|
|
17
|
+
const text = e instanceof Error ? e.message : String(e);
|
|
18
|
+
throw require_follow.turnRunningError(text.slice(text.indexOf("{"), text.lastIndexOf("}") + 1)) ?? e;
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
follow: (jobId, onStream) => streamJob(jobId, (update) => {
|
|
22
|
+
if (update.new_result_stream) onStream(update.new_result_stream);
|
|
23
|
+
})
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
2
27
|
//#region src/config.ts
|
|
3
28
|
/**
|
|
4
29
|
* The Windmill a raw app bundle runs in. A sandboxed app gets `window.process.env`
|
|
@@ -22,19 +47,32 @@ function detectRawApp() {
|
|
|
22
47
|
};
|
|
23
48
|
}
|
|
24
49
|
function resolveConfig(options) {
|
|
25
|
-
if (
|
|
50
|
+
if (options.runnable !== void 0) {
|
|
51
|
+
if (!options.wmill) throw new Error("windmill-chat: `runnable` needs `wmill`, the app's generated module");
|
|
52
|
+
if (options.flowPath || options.run || options.follow) throw new Error("windmill-chat: `runnable` replaces `flowPath`, `run` and `follow`");
|
|
53
|
+
const app = globalThis.ctx?.path;
|
|
54
|
+
options = {
|
|
55
|
+
...options,
|
|
56
|
+
...rawAppRunnable(options.wmill.backendAsync[options.runnable], options.wmill.streamJob),
|
|
57
|
+
flowPath: `runnable:${typeof app === "string" ? `${app}:` : ""}${options.runnable}`
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const follow = options.follow;
|
|
61
|
+
if (follow && !options.run) throw new Error("windmill-chat: `follow` needs `run`, which starts the job it follows");
|
|
62
|
+
if (follow && options.history === "server") throw new Error("windmill-chat: server history is read with the SDK's own requests, which `follow` replaces");
|
|
63
|
+
if (!options.flowPath && !follow) throw new Error("windmill-chat: flowPath is required");
|
|
26
64
|
const explicitToken = options.token !== void 0;
|
|
27
65
|
const detected = options.baseUrl && options.workspace && explicitToken ? void 0 : detectRawApp();
|
|
28
66
|
const baseUrl = options.baseUrl ?? detected?.baseUrl;
|
|
29
67
|
const workspace = options.workspace ?? detected?.workspace;
|
|
30
|
-
if (!baseUrl || !workspace) throw new Error("windmill-chat: pass baseUrl and workspace. They are only detected inside a raw app: an unsandboxed one on the Windmill origin, or a sandboxed one whose policy declares frontend SDK scopes.");
|
|
68
|
+
if ((!baseUrl || !workspace) && !follow) throw new Error("windmill-chat: pass baseUrl and workspace. They are only detected inside a raw app: an unsandboxed one on the Windmill origin, or a sandboxed one whose policy declares frontend SDK scopes.");
|
|
31
69
|
const token = options.token ?? (options.baseUrl === void 0 || options.baseUrl === detected?.baseUrl ? detected?.token : void 0);
|
|
32
70
|
return {
|
|
33
|
-
flowPath: options.flowPath,
|
|
34
|
-
baseUrl,
|
|
35
|
-
workspace,
|
|
71
|
+
flowPath: options.flowPath ?? "",
|
|
72
|
+
baseUrl: baseUrl ?? "",
|
|
73
|
+
workspace: workspace ?? "",
|
|
36
74
|
token,
|
|
37
|
-
history: options.history ?? (explicitToken ? "local" : "server"),
|
|
75
|
+
history: options.history ?? (explicitToken || follow ? "local" : "server"),
|
|
38
76
|
historyExplicit: options.history !== void 0,
|
|
39
77
|
inputs: options.inputs ?? {},
|
|
40
78
|
fetch: options.fetch,
|
|
@@ -43,6 +81,7 @@ function resolveConfig(options) {
|
|
|
43
81
|
pageSize: options.pageSize ?? 50,
|
|
44
82
|
pollDelayMs: options.pollDelayMs,
|
|
45
83
|
run: options.run,
|
|
84
|
+
follow,
|
|
46
85
|
onFinish: options.onFinish,
|
|
47
86
|
onError: options.onError
|
|
48
87
|
};
|
|
@@ -188,7 +227,8 @@ async function uploadAttachments(api, attachments, turnId, signal) {
|
|
|
188
227
|
const results = await Promise.allSettled(attachments.map(async (attachment, index) => {
|
|
189
228
|
try {
|
|
190
229
|
const blob = attachmentBlob(attachment);
|
|
191
|
-
const
|
|
230
|
+
const name = attachment.name?.split(/[\\/]/).pop()?.replace(/^\.+$/, "");
|
|
231
|
+
const filename = storedAttachmentName(name || `attachment-${index + 1}`, blob.type);
|
|
192
232
|
const { file_key } = await api.uploadFile(`${prefix}/${index}/${filename}`, blob, {
|
|
193
233
|
contentType: blob.type,
|
|
194
234
|
signal: batch.signal
|
|
@@ -267,6 +307,7 @@ var ChatImpl = class {
|
|
|
267
307
|
const attachments = options.attachments ?? [];
|
|
268
308
|
const attachmentsInput = options.attachmentsInput;
|
|
269
309
|
if (attachments.length > 0 && !attachmentsInput) throw new Error("windmill-chat: attachments need `attachmentsInput`, the flow input that takes them");
|
|
310
|
+
if (attachments.length > 0 && require_follow._classPrivateFieldGet2(_config, this).follow) throw new Error("windmill-chat: attachments upload with the SDK's own requests, which `follow` replaces");
|
|
270
311
|
if (attachmentsInput && !attachmentsInput.multiple && attachments.length > 1) throw new Error(`windmill-chat: \`${attachmentsInput.name}\` holds one file; got ${attachments.length}`);
|
|
271
312
|
const isNew = require_follow._classPrivateFieldGet2(_state, this).conversationId === void 0;
|
|
272
313
|
const conversationId = require_follow._classPrivateFieldGet2(_state, this).conversationId ?? require_follow.randomId();
|
|
@@ -429,7 +470,7 @@ var ChatImpl = class {
|
|
|
429
470
|
});
|
|
430
471
|
require_follow._assertClassBrand(_ChatImpl_brand, this, _persistLocal).call(this);
|
|
431
472
|
}
|
|
432
|
-
if (turn.jobId) await require_follow._classPrivateFieldGet2(_api, this).cancelJob(turn.jobId).catch(() => {});
|
|
473
|
+
if (turn.jobId && !require_follow._classPrivateFieldGet2(_config, this).follow) await require_follow._classPrivateFieldGet2(_api, this).cancelJob(turn.jobId).catch(() => {});
|
|
433
474
|
if (require_follow._classPrivateFieldGet2(_state, this).history !== "server") return;
|
|
434
475
|
await require_follow.sleep(RECONCILE_DELAY_MS).catch(() => {});
|
|
435
476
|
if (require_follow._classPrivateFieldGet2(_turn, this) || require_follow._classPrivateFieldGet2(_state, this).conversationId !== turn.conversationId) return;
|
|
@@ -560,7 +601,7 @@ var ChatImpl = class {
|
|
|
560
601
|
messages: [],
|
|
561
602
|
status: "idle",
|
|
562
603
|
error: void 0,
|
|
563
|
-
conversations: [],
|
|
604
|
+
conversations: require_follow._classPrivateFieldGet2(_config, this).history === "local" ? require_follow._classPrivateFieldGet2(_local, this).listConversations() : [],
|
|
564
605
|
history: require_follow._classPrivateFieldGet2(_config, this).history,
|
|
565
606
|
loadingMessages: false,
|
|
566
607
|
hasMoreMessages: false
|
|
@@ -635,6 +676,26 @@ async function _select(conversationId) {
|
|
|
635
676
|
}
|
|
636
677
|
async function _follow(turn, onStreamStart) {
|
|
637
678
|
let started = false;
|
|
679
|
+
const { follow } = require_follow._classPrivateFieldGet2(_config, this);
|
|
680
|
+
if (follow) {
|
|
681
|
+
const { signal } = turn.controller;
|
|
682
|
+
const parser = require_follow.createStreamEventParser();
|
|
683
|
+
const onStream = (chunk) => {
|
|
684
|
+
if (signal.aborted) return;
|
|
685
|
+
if (!started) {
|
|
686
|
+
started = true;
|
|
687
|
+
onStreamStart();
|
|
688
|
+
}
|
|
689
|
+
require_follow._assertClassBrand(_ChatImpl_brand, this, _applyEvents).call(this, turn, parser.push(chunk));
|
|
690
|
+
};
|
|
691
|
+
const aborted = new Promise((_, reject) => {
|
|
692
|
+
if (signal.aborted) reject(require_follow.abortError());
|
|
693
|
+
signal.addEventListener("abort", () => reject(require_follow.abortError()), { once: true });
|
|
694
|
+
});
|
|
695
|
+
const result = await Promise.race([follow(turn.jobId, onStream, { signal }), aborted]);
|
|
696
|
+
require_follow._assertClassBrand(_ChatImpl_brand, this, _applyEvents).call(this, turn, parser.flush());
|
|
697
|
+
return result;
|
|
698
|
+
}
|
|
638
699
|
for await (const event of require_follow.followJob(require_follow._classPrivateFieldGet2(_api, this), turn.jobId, { signal: turn.controller.signal })) {
|
|
639
700
|
if (event.type === "completed") {
|
|
640
701
|
if (event.streamLost) require_follow._assertClassBrand(_ChatImpl_brand, this, _dropCutRound).call(this, turn);
|
|
@@ -772,7 +833,7 @@ async function _finishTurn(turn, result, isNew) {
|
|
|
772
833
|
let messages = require_follow._classPrivateFieldGet2(_state, this).messages;
|
|
773
834
|
let failed = false;
|
|
774
835
|
if (require_follow.isErrorResult(result)) {
|
|
775
|
-
failed = await require_follow._classPrivateFieldGet2(_api, this).getCompletedResult(turn.jobId, turn.controller.signal).then((r) => r.success === false).catch(() => true);
|
|
836
|
+
failed = require_follow._classPrivateFieldGet2(_config, this).follow ? true : await require_follow._classPrivateFieldGet2(_api, this).getCompletedResult(turn.jobId, turn.controller.signal).then((r) => r.success === false).catch(() => true);
|
|
776
837
|
if (!require_follow._assertClassBrand(_ChatImpl_brand, this, _turnActive).call(this, turn)) return;
|
|
777
838
|
if (failed) messages = [...messages, assistantMessage(require_follow.errorResultMessage(result), false, turn.jobId)];
|
|
778
839
|
}
|
|
@@ -1,4 +1,29 @@
|
|
|
1
|
-
import { C as _assertClassBrand, S as _classPrivateFieldSet2, T as _classPrivateMethodInitSpec, _ as WindmillApiError, a as errorResultMessage, c as isErrorResult, d as randomId, f as sleep, g as TurnRunningError, i as conversationTitle, l as now, n as abortError, o as extractChatAnswer, p as truncateTitle, s as isAbortError, t as followJob, v as WindmillChatApi, w as _classPrivateFieldInitSpec, x as _classPrivateFieldGet2 } from "./follow-DXfmfPfr.js";
|
|
1
|
+
import { C as _assertClassBrand, S as _classPrivateFieldSet2, T as _classPrivateMethodInitSpec, _ as WindmillApiError, a as errorResultMessage, b as turnRunningError, c as isErrorResult, d as randomId, f as sleep, g as TurnRunningError, i as conversationTitle, l as now, m as createStreamEventParser, n as abortError, o as extractChatAnswer, p as truncateTitle, s as isAbortError, t as followJob, v as WindmillChatApi, w as _classPrivateFieldInitSpec, x as _classPrivateFieldGet2 } from "./follow-DXfmfPfr.js";
|
|
2
|
+
//#region src/runnable.ts
|
|
3
|
+
/**
|
|
4
|
+
* `run` and `follow` over a raw app's agent runnable (a path runnable of type `agent`, naming
|
|
5
|
+
* a saved AI agent), behind the `runnable` option. `memory_id` is the conversation id, the
|
|
6
|
+
* agent's memory key.
|
|
7
|
+
*/
|
|
8
|
+
function rawAppRunnable(start, streamJob) {
|
|
9
|
+
return {
|
|
10
|
+
run: async (args, { conversationId }) => {
|
|
11
|
+
try {
|
|
12
|
+
return String(await start({
|
|
13
|
+
...args,
|
|
14
|
+
memory_id: conversationId
|
|
15
|
+
}));
|
|
16
|
+
} catch (e) {
|
|
17
|
+
const text = e instanceof Error ? e.message : String(e);
|
|
18
|
+
throw turnRunningError(text.slice(text.indexOf("{"), text.lastIndexOf("}") + 1)) ?? e;
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
follow: (jobId, onStream) => streamJob(jobId, (update) => {
|
|
22
|
+
if (update.new_result_stream) onStream(update.new_result_stream);
|
|
23
|
+
})
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
2
27
|
//#region src/config.ts
|
|
3
28
|
/**
|
|
4
29
|
* The Windmill a raw app bundle runs in. A sandboxed app gets `window.process.env`
|
|
@@ -22,19 +47,32 @@ function detectRawApp() {
|
|
|
22
47
|
};
|
|
23
48
|
}
|
|
24
49
|
function resolveConfig(options) {
|
|
25
|
-
if (
|
|
50
|
+
if (options.runnable !== void 0) {
|
|
51
|
+
if (!options.wmill) throw new Error("windmill-chat: `runnable` needs `wmill`, the app's generated module");
|
|
52
|
+
if (options.flowPath || options.run || options.follow) throw new Error("windmill-chat: `runnable` replaces `flowPath`, `run` and `follow`");
|
|
53
|
+
const app = globalThis.ctx?.path;
|
|
54
|
+
options = {
|
|
55
|
+
...options,
|
|
56
|
+
...rawAppRunnable(options.wmill.backendAsync[options.runnable], options.wmill.streamJob),
|
|
57
|
+
flowPath: `runnable:${typeof app === "string" ? `${app}:` : ""}${options.runnable}`
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const follow = options.follow;
|
|
61
|
+
if (follow && !options.run) throw new Error("windmill-chat: `follow` needs `run`, which starts the job it follows");
|
|
62
|
+
if (follow && options.history === "server") throw new Error("windmill-chat: server history is read with the SDK's own requests, which `follow` replaces");
|
|
63
|
+
if (!options.flowPath && !follow) throw new Error("windmill-chat: flowPath is required");
|
|
26
64
|
const explicitToken = options.token !== void 0;
|
|
27
65
|
const detected = options.baseUrl && options.workspace && explicitToken ? void 0 : detectRawApp();
|
|
28
66
|
const baseUrl = options.baseUrl ?? detected?.baseUrl;
|
|
29
67
|
const workspace = options.workspace ?? detected?.workspace;
|
|
30
|
-
if (!baseUrl || !workspace) throw new Error("windmill-chat: pass baseUrl and workspace. They are only detected inside a raw app: an unsandboxed one on the Windmill origin, or a sandboxed one whose policy declares frontend SDK scopes.");
|
|
68
|
+
if ((!baseUrl || !workspace) && !follow) throw new Error("windmill-chat: pass baseUrl and workspace. They are only detected inside a raw app: an unsandboxed one on the Windmill origin, or a sandboxed one whose policy declares frontend SDK scopes.");
|
|
31
69
|
const token = options.token ?? (options.baseUrl === void 0 || options.baseUrl === detected?.baseUrl ? detected?.token : void 0);
|
|
32
70
|
return {
|
|
33
|
-
flowPath: options.flowPath,
|
|
34
|
-
baseUrl,
|
|
35
|
-
workspace,
|
|
71
|
+
flowPath: options.flowPath ?? "",
|
|
72
|
+
baseUrl: baseUrl ?? "",
|
|
73
|
+
workspace: workspace ?? "",
|
|
36
74
|
token,
|
|
37
|
-
history: options.history ?? (explicitToken ? "local" : "server"),
|
|
75
|
+
history: options.history ?? (explicitToken || follow ? "local" : "server"),
|
|
38
76
|
historyExplicit: options.history !== void 0,
|
|
39
77
|
inputs: options.inputs ?? {},
|
|
40
78
|
fetch: options.fetch,
|
|
@@ -43,6 +81,7 @@ function resolveConfig(options) {
|
|
|
43
81
|
pageSize: options.pageSize ?? 50,
|
|
44
82
|
pollDelayMs: options.pollDelayMs,
|
|
45
83
|
run: options.run,
|
|
84
|
+
follow,
|
|
46
85
|
onFinish: options.onFinish,
|
|
47
86
|
onError: options.onError
|
|
48
87
|
};
|
|
@@ -188,7 +227,8 @@ async function uploadAttachments(api, attachments, turnId, signal) {
|
|
|
188
227
|
const results = await Promise.allSettled(attachments.map(async (attachment, index) => {
|
|
189
228
|
try {
|
|
190
229
|
const blob = attachmentBlob(attachment);
|
|
191
|
-
const
|
|
230
|
+
const name = attachment.name?.split(/[\\/]/).pop()?.replace(/^\.+$/, "");
|
|
231
|
+
const filename = storedAttachmentName(name || `attachment-${index + 1}`, blob.type);
|
|
192
232
|
const { file_key } = await api.uploadFile(`${prefix}/${index}/${filename}`, blob, {
|
|
193
233
|
contentType: blob.type,
|
|
194
234
|
signal: batch.signal
|
|
@@ -267,6 +307,7 @@ var ChatImpl = class {
|
|
|
267
307
|
const attachments = options.attachments ?? [];
|
|
268
308
|
const attachmentsInput = options.attachmentsInput;
|
|
269
309
|
if (attachments.length > 0 && !attachmentsInput) throw new Error("windmill-chat: attachments need `attachmentsInput`, the flow input that takes them");
|
|
310
|
+
if (attachments.length > 0 && _classPrivateFieldGet2(_config, this).follow) throw new Error("windmill-chat: attachments upload with the SDK's own requests, which `follow` replaces");
|
|
270
311
|
if (attachmentsInput && !attachmentsInput.multiple && attachments.length > 1) throw new Error(`windmill-chat: \`${attachmentsInput.name}\` holds one file; got ${attachments.length}`);
|
|
271
312
|
const isNew = _classPrivateFieldGet2(_state, this).conversationId === void 0;
|
|
272
313
|
const conversationId = _classPrivateFieldGet2(_state, this).conversationId ?? randomId();
|
|
@@ -429,7 +470,7 @@ var ChatImpl = class {
|
|
|
429
470
|
});
|
|
430
471
|
_assertClassBrand(_ChatImpl_brand, this, _persistLocal).call(this);
|
|
431
472
|
}
|
|
432
|
-
if (turn.jobId) await _classPrivateFieldGet2(_api, this).cancelJob(turn.jobId).catch(() => {});
|
|
473
|
+
if (turn.jobId && !_classPrivateFieldGet2(_config, this).follow) await _classPrivateFieldGet2(_api, this).cancelJob(turn.jobId).catch(() => {});
|
|
433
474
|
if (_classPrivateFieldGet2(_state, this).history !== "server") return;
|
|
434
475
|
await sleep(RECONCILE_DELAY_MS).catch(() => {});
|
|
435
476
|
if (_classPrivateFieldGet2(_turn, this) || _classPrivateFieldGet2(_state, this).conversationId !== turn.conversationId) return;
|
|
@@ -560,7 +601,7 @@ var ChatImpl = class {
|
|
|
560
601
|
messages: [],
|
|
561
602
|
status: "idle",
|
|
562
603
|
error: void 0,
|
|
563
|
-
conversations: [],
|
|
604
|
+
conversations: _classPrivateFieldGet2(_config, this).history === "local" ? _classPrivateFieldGet2(_local, this).listConversations() : [],
|
|
564
605
|
history: _classPrivateFieldGet2(_config, this).history,
|
|
565
606
|
loadingMessages: false,
|
|
566
607
|
hasMoreMessages: false
|
|
@@ -635,6 +676,26 @@ async function _select(conversationId) {
|
|
|
635
676
|
}
|
|
636
677
|
async function _follow(turn, onStreamStart) {
|
|
637
678
|
let started = false;
|
|
679
|
+
const { follow } = _classPrivateFieldGet2(_config, this);
|
|
680
|
+
if (follow) {
|
|
681
|
+
const { signal } = turn.controller;
|
|
682
|
+
const parser = createStreamEventParser();
|
|
683
|
+
const onStream = (chunk) => {
|
|
684
|
+
if (signal.aborted) return;
|
|
685
|
+
if (!started) {
|
|
686
|
+
started = true;
|
|
687
|
+
onStreamStart();
|
|
688
|
+
}
|
|
689
|
+
_assertClassBrand(_ChatImpl_brand, this, _applyEvents).call(this, turn, parser.push(chunk));
|
|
690
|
+
};
|
|
691
|
+
const aborted = new Promise((_, reject) => {
|
|
692
|
+
if (signal.aborted) reject(abortError());
|
|
693
|
+
signal.addEventListener("abort", () => reject(abortError()), { once: true });
|
|
694
|
+
});
|
|
695
|
+
const result = await Promise.race([follow(turn.jobId, onStream, { signal }), aborted]);
|
|
696
|
+
_assertClassBrand(_ChatImpl_brand, this, _applyEvents).call(this, turn, parser.flush());
|
|
697
|
+
return result;
|
|
698
|
+
}
|
|
638
699
|
for await (const event of followJob(_classPrivateFieldGet2(_api, this), turn.jobId, { signal: turn.controller.signal })) {
|
|
639
700
|
if (event.type === "completed") {
|
|
640
701
|
if (event.streamLost) _assertClassBrand(_ChatImpl_brand, this, _dropCutRound).call(this, turn);
|
|
@@ -772,7 +833,7 @@ async function _finishTurn(turn, result, isNew) {
|
|
|
772
833
|
let messages = _classPrivateFieldGet2(_state, this).messages;
|
|
773
834
|
let failed = false;
|
|
774
835
|
if (isErrorResult(result)) {
|
|
775
|
-
failed = await _classPrivateFieldGet2(_api, this).getCompletedResult(turn.jobId, turn.controller.signal).then((r) => r.success === false).catch(() => true);
|
|
836
|
+
failed = _classPrivateFieldGet2(_config, this).follow ? true : await _classPrivateFieldGet2(_api, this).getCompletedResult(turn.jobId, turn.controller.signal).then((r) => r.success === false).catch(() => true);
|
|
776
837
|
if (!_assertClassBrand(_ChatImpl_brand, this, _turnActive).call(this, turn)) return;
|
|
777
838
|
if (failed) messages = [...messages, assistantMessage(errorResultMessage(result), false, turn.jobId)];
|
|
778
839
|
}
|
package/dist/chat.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { Chat,
|
|
2
|
-
export declare function createChat(options:
|
|
1
|
+
import type { Chat, RawAppWmill, TypedChatOptions } from './types';
|
|
2
|
+
export declare function createChat<W extends RawAppWmill>(options: TypedChatOptions<W>): Chat;
|
package/dist/config.d.ts
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_follow = require("./follow-Dug-Afeu.cjs");
|
|
3
|
-
const require_chat = require("./chat-
|
|
3
|
+
const require_chat = require("./chat-C0iOSX6H.cjs");
|
|
4
4
|
exports.CHAT_UPLOADS_PREFIX = require_chat.CHAT_UPLOADS_PREFIX;
|
|
5
5
|
exports.TurnRunningError = require_follow.TurnRunningError;
|
|
6
6
|
exports.WindmillApiError = require_follow.WindmillApiError;
|
package/dist/index.d.ts
CHANGED
|
@@ -5,4 +5,4 @@ export { parseStreamEvents, createStreamEventParser, type AgentStreamEvent } fro
|
|
|
5
5
|
export { followJob, type FollowEvent } from './follow';
|
|
6
6
|
export { extractChatAnswer, conversationIdFor } from './utils';
|
|
7
7
|
export { storedAttachmentName, uploadAttachments, CHAT_UPLOADS_PREFIX, type UploadedAttachment } from './attachments';
|
|
8
|
-
export type { AttachmentsInput, AttachmentUpload, Chat, ChatAttachment, ChatMessage, ChatOptions, ChatRole, ChatState, ChatStatus, Conversation, FetchLike, HistoryMode, SendMessageOptions, StorageLike, TokenSource, ToolInvocation } from './types';
|
|
8
|
+
export type { AttachmentsInput, AttachmentUpload, Chat, ChatAttachment, ChatMessage, ChatOptions, ChatRole, ChatState, ChatStatus, Conversation, FetchLike, HistoryMode, RawAppWmill, TypedChatOptions, SendMessageOptions, StorageLike, TokenSource, ToolInvocation } from './types';
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { _ as WindmillApiError, b as turnRunningError, g as TurnRunningError, h as parseStreamEvents, m as createStreamEventParser, o as extractChatAnswer, r as conversationIdFor, t as followJob, v as WindmillChatApi, y as readServerSentEvents } from "./follow-DXfmfPfr.js";
|
|
2
|
-
import { a as detectRawApp, i as uploadAttachments, n as CHAT_UPLOADS_PREFIX, r as storedAttachmentName, t as createChat } from "./chat-
|
|
2
|
+
import { a as detectRawApp, i as uploadAttachments, n as CHAT_UPLOADS_PREFIX, r as storedAttachmentName, t as createChat } from "./chat-DjonfE4j.js";
|
|
3
3
|
export { CHAT_UPLOADS_PREFIX, TurnRunningError, WindmillApiError, WindmillChatApi, conversationIdFor, createChat, createStreamEventParser, detectRawApp, extractChatAnswer, followJob, parseStreamEvents, readServerSentEvents, storedAttachmentName, turnRunningError, uploadAttachments };
|
package/dist/react.cjs
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_chat = require("./chat-
|
|
2
|
+
const require_chat = require("./chat-C0iOSX6H.cjs");
|
|
3
3
|
let react = require("react");
|
|
4
4
|
//#region src/react.ts
|
|
5
5
|
/**
|
|
6
6
|
* A chat on a chat-mode flow. The chat is created once per `flowPath`, `baseUrl`,
|
|
7
|
-
* `workspace`, `history`, `storageKey`, credential and presence of `run`, and
|
|
7
|
+
* `workspace`, `history`, `storageKey`, credential and presence of `run` and `follow`, and
|
|
8
8
|
* destroyed on unmount. A credential change is a new user, whose chat must not
|
|
9
9
|
* carry the previous one's state: a different token string, or a switch between no
|
|
10
10
|
* token, a token string and a token function, all recreate it. A token function is
|
|
11
11
|
* read through a ref on every call, so a new closure per render changes what the
|
|
12
12
|
* next call runs and nothing else; pass a `storageKey` per user when local history
|
|
13
|
-
* must not be shared. `run`, the callbacks and `inputs` are read the same way: the
|
|
13
|
+
* must not be shared. `run`, `follow`, the callbacks and `inputs` are read the same way: the
|
|
14
14
|
* latest render's values go with the next message.
|
|
15
15
|
*/
|
|
16
16
|
function useWindmillChat(options) {
|
|
@@ -18,6 +18,7 @@ function useWindmillChat(options) {
|
|
|
18
18
|
latest.current = options;
|
|
19
19
|
const credential = typeof options.token === "function" ? "fn" : typeof options.token === "string" ? `str:${options.token}` : "none";
|
|
20
20
|
const customRun = options.run !== void 0;
|
|
21
|
+
const customFollow = options.follow !== void 0;
|
|
21
22
|
const chat = (0, react.useMemo)(() => require_chat.createChat({
|
|
22
23
|
...options,
|
|
23
24
|
inputs: void 0,
|
|
@@ -26,16 +27,20 @@ function useWindmillChat(options) {
|
|
|
26
27
|
return typeof token === "function" ? token() : token ?? "";
|
|
27
28
|
} : options.token,
|
|
28
29
|
run: customRun ? (args, turn) => (latest.current.run ?? options.run)(args, turn) : void 0,
|
|
30
|
+
follow: customFollow ? (jobId, onStream, turn) => (latest.current.follow ?? options.follow)(jobId, onStream, turn) : void 0,
|
|
29
31
|
onFinish: (turn) => latest.current.onFinish?.(turn),
|
|
30
32
|
onError: (error, turn) => latest.current.onError?.(error, turn)
|
|
31
33
|
}), [
|
|
32
34
|
options.flowPath,
|
|
35
|
+
options.runnable,
|
|
36
|
+
options.wmill,
|
|
33
37
|
options.baseUrl,
|
|
34
38
|
options.workspace,
|
|
35
39
|
options.history,
|
|
36
40
|
options.storageKey,
|
|
37
41
|
credential,
|
|
38
|
-
customRun
|
|
42
|
+
customRun,
|
|
43
|
+
customFollow
|
|
39
44
|
]);
|
|
40
45
|
(0, react.useEffect)(() => () => chat.destroy(), [chat]);
|
|
41
46
|
const state = (0, react.useSyncExternalStore)(chat.subscribe, chat.getState, chat.getState);
|
package/dist/react.d.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import type { Chat,
|
|
1
|
+
import type { Chat, ChatState, RawAppWmill, TypedChatOptions } from './types';
|
|
2
2
|
export type UseWindmillChat = ChatState & Pick<Chat, 'sendMessage' | 'resumeTurn' | 'stop' | 'newConversation' | 'selectConversation' | 'loadConversations' | 'deleteConversation' | 'renameConversation' | 'loadOlderMessages' | 'refreshMessages'> & {
|
|
3
3
|
chat: Chat;
|
|
4
4
|
};
|
|
5
5
|
/**
|
|
6
6
|
* A chat on a chat-mode flow. The chat is created once per `flowPath`, `baseUrl`,
|
|
7
|
-
* `workspace`, `history`, `storageKey`, credential and presence of `run`, and
|
|
7
|
+
* `workspace`, `history`, `storageKey`, credential and presence of `run` and `follow`, and
|
|
8
8
|
* destroyed on unmount. A credential change is a new user, whose chat must not
|
|
9
9
|
* carry the previous one's state: a different token string, or a switch between no
|
|
10
10
|
* token, a token string and a token function, all recreate it. A token function is
|
|
11
11
|
* read through a ref on every call, so a new closure per render changes what the
|
|
12
12
|
* next call runs and nothing else; pass a `storageKey` per user when local history
|
|
13
|
-
* must not be shared. `run`, the callbacks and `inputs` are read the same way: the
|
|
13
|
+
* must not be shared. `run`, `follow`, the callbacks and `inputs` are read the same way: the
|
|
14
14
|
* latest render's values go with the next message.
|
|
15
15
|
*/
|
|
16
|
-
export declare function useWindmillChat(options:
|
|
16
|
+
export declare function useWindmillChat<W extends RawAppWmill>(options: TypedChatOptions<W>): UseWindmillChat;
|
package/dist/react.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { t as createChat } from "./chat-
|
|
1
|
+
import { t as createChat } from "./chat-DjonfE4j.js";
|
|
2
2
|
import { useEffect, useMemo, useRef, useSyncExternalStore } from "react";
|
|
3
3
|
//#region src/react.ts
|
|
4
4
|
/**
|
|
5
5
|
* A chat on a chat-mode flow. The chat is created once per `flowPath`, `baseUrl`,
|
|
6
|
-
* `workspace`, `history`, `storageKey`, credential and presence of `run`, and
|
|
6
|
+
* `workspace`, `history`, `storageKey`, credential and presence of `run` and `follow`, and
|
|
7
7
|
* destroyed on unmount. A credential change is a new user, whose chat must not
|
|
8
8
|
* carry the previous one's state: a different token string, or a switch between no
|
|
9
9
|
* token, a token string and a token function, all recreate it. A token function is
|
|
10
10
|
* read through a ref on every call, so a new closure per render changes what the
|
|
11
11
|
* next call runs and nothing else; pass a `storageKey` per user when local history
|
|
12
|
-
* must not be shared. `run`, the callbacks and `inputs` are read the same way: the
|
|
12
|
+
* must not be shared. `run`, `follow`, the callbacks and `inputs` are read the same way: the
|
|
13
13
|
* latest render's values go with the next message.
|
|
14
14
|
*/
|
|
15
15
|
function useWindmillChat(options) {
|
|
@@ -17,6 +17,7 @@ function useWindmillChat(options) {
|
|
|
17
17
|
latest.current = options;
|
|
18
18
|
const credential = typeof options.token === "function" ? "fn" : typeof options.token === "string" ? `str:${options.token}` : "none";
|
|
19
19
|
const customRun = options.run !== void 0;
|
|
20
|
+
const customFollow = options.follow !== void 0;
|
|
20
21
|
const chat = useMemo(() => createChat({
|
|
21
22
|
...options,
|
|
22
23
|
inputs: void 0,
|
|
@@ -25,16 +26,20 @@ function useWindmillChat(options) {
|
|
|
25
26
|
return typeof token === "function" ? token() : token ?? "";
|
|
26
27
|
} : options.token,
|
|
27
28
|
run: customRun ? (args, turn) => (latest.current.run ?? options.run)(args, turn) : void 0,
|
|
29
|
+
follow: customFollow ? (jobId, onStream, turn) => (latest.current.follow ?? options.follow)(jobId, onStream, turn) : void 0,
|
|
28
30
|
onFinish: (turn) => latest.current.onFinish?.(turn),
|
|
29
31
|
onError: (error, turn) => latest.current.onError?.(error, turn)
|
|
30
32
|
}), [
|
|
31
33
|
options.flowPath,
|
|
34
|
+
options.runnable,
|
|
35
|
+
options.wmill,
|
|
32
36
|
options.baseUrl,
|
|
33
37
|
options.workspace,
|
|
34
38
|
options.history,
|
|
35
39
|
options.storageKey,
|
|
36
40
|
credential,
|
|
37
|
-
customRun
|
|
41
|
+
customRun,
|
|
42
|
+
customFollow
|
|
38
43
|
]);
|
|
39
44
|
useEffect(() => () => chat.destroy(), [chat]);
|
|
40
45
|
const state = useSyncExternalStore(chat.subscribe, chat.getState, chat.getState);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ChatOptions } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* `run` and `follow` over a raw app's agent runnable (a path runnable of type `agent`, naming
|
|
4
|
+
* a saved AI agent), behind the `runnable` option. `memory_id` is the conversation id, the
|
|
5
|
+
* agent's memory key.
|
|
6
|
+
*/
|
|
7
|
+
export declare function rawAppRunnable(start: (args: any) => Promise<string>, streamJob: (jobId: string, onUpdate?: (update: {
|
|
8
|
+
new_result_stream?: string;
|
|
9
|
+
}) => void) => Promise<unknown>): Required<Pick<ChatOptions, 'run' | 'follow'>>;
|
package/dist/types.d.ts
CHANGED
|
@@ -81,9 +81,33 @@ export interface ChatState {
|
|
|
81
81
|
export type TokenSource = string | (() => string | Promise<string>);
|
|
82
82
|
export type StorageLike = Pick<Storage, 'getItem' | 'setItem' | 'removeItem'>;
|
|
83
83
|
export type FetchLike = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
|
|
84
|
+
/** A raw app's generated `wmill.ts`, as far as a chat uses it. */
|
|
85
|
+
export interface RawAppWmill {
|
|
86
|
+
backendAsync: Record<string, (args: any) => Promise<string>>;
|
|
87
|
+
streamJob: (jobId: string, onUpdate?: (update: {
|
|
88
|
+
new_result_stream?: string;
|
|
89
|
+
}) => void) => Promise<unknown>;
|
|
90
|
+
}
|
|
91
|
+
/** `ChatOptions` whose `runnable` must name one of `wmill`'s runnables. */
|
|
92
|
+
export type TypedChatOptions<W extends RawAppWmill> = ChatOptions & {
|
|
93
|
+
wmill?: W;
|
|
94
|
+
runnable?: keyof W['backendAsync'] & string;
|
|
95
|
+
};
|
|
84
96
|
export interface ChatOptions {
|
|
85
|
-
/**
|
|
86
|
-
|
|
97
|
+
/**
|
|
98
|
+
* Path of a deployed flow with chat mode enabled, e.g. `f/support/assistant`. Required
|
|
99
|
+
* unless `runnable` or `follow` is set, where it only names the local history.
|
|
100
|
+
*/
|
|
101
|
+
flowPath?: string;
|
|
102
|
+
/**
|
|
103
|
+
* In a raw app, chat through its agent runnable of this name instead of a flow:
|
|
104
|
+
* `{ wmill, runnable: 'chat' }`. Each turn runs as the app, so a sandboxed app needs no
|
|
105
|
+
* frontend SDK scope and its viewers no access to the agent; the chat follows it as
|
|
106
|
+
* with `follow`. It also names the local history, so each runnable keeps its own.
|
|
107
|
+
*/
|
|
108
|
+
runnable?: string;
|
|
109
|
+
/** The app's generated module, `import * as wmill from './wmill'`, which `runnable` goes through. */
|
|
110
|
+
wmill?: RawAppWmill;
|
|
87
111
|
/** Windmill origin, e.g. `https://app.windmill.dev`. Detected inside a raw app. */
|
|
88
112
|
baseUrl?: string;
|
|
89
113
|
/** Detected inside a raw app. */
|
|
@@ -124,6 +148,17 @@ export interface ChatOptions {
|
|
|
124
148
|
conversationId: string;
|
|
125
149
|
signal: AbortSignal;
|
|
126
150
|
}) => Promise<string>;
|
|
151
|
+
/**
|
|
152
|
+
* Follows the job `run` returned through your own client instead of the SDK's requests:
|
|
153
|
+
* call `onStream` with each chunk of the job's result stream and resolve with its result.
|
|
154
|
+
* With it the chat makes no request of its own, so it needs no credential, `baseUrl` or
|
|
155
|
+
* `workspace`, and in exchange history is `local` (or `none`), `stop()` stops following
|
|
156
|
+
* without cancelling the job, and attachments are refused. `runnable` sets both for a raw
|
|
157
|
+
* app's agent runnable.
|
|
158
|
+
*/
|
|
159
|
+
follow?: (jobId: string, onStream: (chunk: string) => void, turn: {
|
|
160
|
+
signal: AbortSignal;
|
|
161
|
+
}) => Promise<unknown>;
|
|
127
162
|
/** Called once a turn has its answer (a failed flow included: its error is the answer). */
|
|
128
163
|
onFinish?: (turn: {
|
|
129
164
|
conversationId: string;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@windmill-labs/chat-sdk",
|
|
3
3
|
"description": "Build chat interfaces on Windmill flows deployed in chat mode, from any frontend or raw app",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.848.0",
|
|
5
5
|
"author": "Ruben Fiszel",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"homepage": "https://github.com/windmill-labs/windmill/tree/main/chat-sdk#readme",
|