@personaai/react 0.3.4 → 0.4.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/dist/index.cjs +210 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +58 -2
- package/dist/index.d.ts +58 -2
- package/dist/index.js +208 -16
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -415,6 +415,62 @@ declare function useMcpConnections(options?: UseMcpConnectionsOptions): {
|
|
|
415
415
|
refetch: () => Promise<PersonaMcpConnection[]>;
|
|
416
416
|
};
|
|
417
417
|
|
|
418
|
-
|
|
418
|
+
/**
|
|
419
|
+
* SSE transport for chat streams, with a React Native fallback.
|
|
420
|
+
*
|
|
421
|
+
* On the web, `fetch` gives a streaming `response.body` and we read it with a
|
|
422
|
+
* ReadableStream reader. React Native's `fetch` is the whatwg-fetch polyfill
|
|
423
|
+
* over XMLHttpRequest: `response.body` is `undefined`, and the promise only
|
|
424
|
+
* settles once the entire response has arrived. That means the check cannot be
|
|
425
|
+
* "call fetch, then see whether body exists" - by that point the whole stream
|
|
426
|
+
* has already been buffered and the chance to stream is gone. The transport has
|
|
427
|
+
* to be chosen *before* the request is made.
|
|
428
|
+
*
|
|
429
|
+
* XMLHttpRequest itself does stream everywhere React Native runs: it appends to
|
|
430
|
+
* `responseText` and fires `readyState === 3` (LOADING) on every chunk, which is
|
|
431
|
+
* all an SSE consumer needs. So the RN path issues the request over raw XHR and
|
|
432
|
+
* hands back the same reader interface the fetch path does, leaving callers
|
|
433
|
+
* unaware of which one they got.
|
|
434
|
+
*/
|
|
435
|
+
/** Minimal reader interface, mirroring the shape of a ReadableStream reader. */
|
|
436
|
+
interface SSEReader {
|
|
437
|
+
/** Resolves with the next decoded chunk, or `{ done: true }` at end of stream. */
|
|
438
|
+
read(): Promise<{
|
|
439
|
+
done: boolean;
|
|
440
|
+
value?: string;
|
|
441
|
+
}>;
|
|
442
|
+
/** Aborts the underlying request. */
|
|
443
|
+
cancel(): void;
|
|
444
|
+
}
|
|
445
|
+
interface SSEStream {
|
|
446
|
+
status: number;
|
|
447
|
+
ok: boolean;
|
|
448
|
+
getHeader(name: string): string | null;
|
|
449
|
+
/** Present only when `ok` is false, so callers can surface the server's message. */
|
|
450
|
+
errorText?: string;
|
|
451
|
+
reader: SSEReader;
|
|
452
|
+
}
|
|
453
|
+
interface OpenSSEOptions {
|
|
454
|
+
url: string;
|
|
455
|
+
headers: Record<string, string>;
|
|
456
|
+
body: string;
|
|
457
|
+
signal?: AbortSignal;
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Whether `fetch` on this platform yields a streaming body.
|
|
461
|
+
*
|
|
462
|
+
* `navigator.product === 'ReactNative'` is the long-standing marker React
|
|
463
|
+
* Native sets, and is checked rather than feature-detecting `ReadableStream`:
|
|
464
|
+
* newer RN versions do expose a global `ReadableStream` while still leaving
|
|
465
|
+
* `response.body` undefined, so the presence of the type says nothing about
|
|
466
|
+
* whether fetch will populate it.
|
|
467
|
+
*/
|
|
468
|
+
declare function supportsStreamingFetch(): boolean;
|
|
469
|
+
/**
|
|
470
|
+
* Opens an SSE stream, using whichever transport this platform can stream over.
|
|
471
|
+
*/
|
|
472
|
+
declare function openSSEStream(opts: OpenSSEOptions): Promise<SSEStream>;
|
|
473
|
+
|
|
474
|
+
declare const VERSION = "0.4.0";
|
|
419
475
|
|
|
420
|
-
export { type PersonaAgentSummary, type PersonaClarificationQuestion, type PersonaFileItem, type PersonaHealthInfo, type PersonaHitlActionRequest, type PersonaInterrupt, type PersonaMcpConnection, type PersonaMemoryAgentGroup, type PersonaMemoryFile, type PersonaMemoryList, type PersonaMessage, type PersonaPresentedFile, PersonaProvider, type PersonaProviderProps, type PersonaResumeValue, type PersonaRole, type PersonaStreamingEvent, type PersonaSubagentActivityEntry, type PersonaThread, type PersonaTodo, type PersonaToolCall, type PersonaWorkspaceFile, type SendMessageOverride, type UseChatOptions, type UseMcpConnectionsOptions, VERSION, useAgents, useChat, useConnection, useFiles, useMcpConnections, useMemory, usePersonaContext, useThreads };
|
|
476
|
+
export { type OpenSSEOptions, type PersonaAgentSummary, type PersonaClarificationQuestion, type PersonaFileItem, type PersonaHealthInfo, type PersonaHitlActionRequest, type PersonaInterrupt, type PersonaMcpConnection, type PersonaMemoryAgentGroup, type PersonaMemoryFile, type PersonaMemoryList, type PersonaMessage, type PersonaPresentedFile, PersonaProvider, type PersonaProviderProps, type PersonaResumeValue, type PersonaRole, type PersonaStreamingEvent, type PersonaSubagentActivityEntry, type PersonaThread, type PersonaTodo, type PersonaToolCall, type PersonaWorkspaceFile, type SSEReader, type SSEStream, type SendMessageOverride, type UseChatOptions, type UseMcpConnectionsOptions, VERSION, openSSEStream, supportsStreamingFetch, useAgents, useChat, useConnection, useFiles, useMcpConnections, useMemory, usePersonaContext, useThreads };
|
package/dist/index.d.ts
CHANGED
|
@@ -415,6 +415,62 @@ declare function useMcpConnections(options?: UseMcpConnectionsOptions): {
|
|
|
415
415
|
refetch: () => Promise<PersonaMcpConnection[]>;
|
|
416
416
|
};
|
|
417
417
|
|
|
418
|
-
|
|
418
|
+
/**
|
|
419
|
+
* SSE transport for chat streams, with a React Native fallback.
|
|
420
|
+
*
|
|
421
|
+
* On the web, `fetch` gives a streaming `response.body` and we read it with a
|
|
422
|
+
* ReadableStream reader. React Native's `fetch` is the whatwg-fetch polyfill
|
|
423
|
+
* over XMLHttpRequest: `response.body` is `undefined`, and the promise only
|
|
424
|
+
* settles once the entire response has arrived. That means the check cannot be
|
|
425
|
+
* "call fetch, then see whether body exists" - by that point the whole stream
|
|
426
|
+
* has already been buffered and the chance to stream is gone. The transport has
|
|
427
|
+
* to be chosen *before* the request is made.
|
|
428
|
+
*
|
|
429
|
+
* XMLHttpRequest itself does stream everywhere React Native runs: it appends to
|
|
430
|
+
* `responseText` and fires `readyState === 3` (LOADING) on every chunk, which is
|
|
431
|
+
* all an SSE consumer needs. So the RN path issues the request over raw XHR and
|
|
432
|
+
* hands back the same reader interface the fetch path does, leaving callers
|
|
433
|
+
* unaware of which one they got.
|
|
434
|
+
*/
|
|
435
|
+
/** Minimal reader interface, mirroring the shape of a ReadableStream reader. */
|
|
436
|
+
interface SSEReader {
|
|
437
|
+
/** Resolves with the next decoded chunk, or `{ done: true }` at end of stream. */
|
|
438
|
+
read(): Promise<{
|
|
439
|
+
done: boolean;
|
|
440
|
+
value?: string;
|
|
441
|
+
}>;
|
|
442
|
+
/** Aborts the underlying request. */
|
|
443
|
+
cancel(): void;
|
|
444
|
+
}
|
|
445
|
+
interface SSEStream {
|
|
446
|
+
status: number;
|
|
447
|
+
ok: boolean;
|
|
448
|
+
getHeader(name: string): string | null;
|
|
449
|
+
/** Present only when `ok` is false, so callers can surface the server's message. */
|
|
450
|
+
errorText?: string;
|
|
451
|
+
reader: SSEReader;
|
|
452
|
+
}
|
|
453
|
+
interface OpenSSEOptions {
|
|
454
|
+
url: string;
|
|
455
|
+
headers: Record<string, string>;
|
|
456
|
+
body: string;
|
|
457
|
+
signal?: AbortSignal;
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Whether `fetch` on this platform yields a streaming body.
|
|
461
|
+
*
|
|
462
|
+
* `navigator.product === 'ReactNative'` is the long-standing marker React
|
|
463
|
+
* Native sets, and is checked rather than feature-detecting `ReadableStream`:
|
|
464
|
+
* newer RN versions do expose a global `ReadableStream` while still leaving
|
|
465
|
+
* `response.body` undefined, so the presence of the type says nothing about
|
|
466
|
+
* whether fetch will populate it.
|
|
467
|
+
*/
|
|
468
|
+
declare function supportsStreamingFetch(): boolean;
|
|
469
|
+
/**
|
|
470
|
+
* Opens an SSE stream, using whichever transport this platform can stream over.
|
|
471
|
+
*/
|
|
472
|
+
declare function openSSEStream(opts: OpenSSEOptions): Promise<SSEStream>;
|
|
473
|
+
|
|
474
|
+
declare const VERSION = "0.4.0";
|
|
419
475
|
|
|
420
|
-
export { type PersonaAgentSummary, type PersonaClarificationQuestion, type PersonaFileItem, type PersonaHealthInfo, type PersonaHitlActionRequest, type PersonaInterrupt, type PersonaMcpConnection, type PersonaMemoryAgentGroup, type PersonaMemoryFile, type PersonaMemoryList, type PersonaMessage, type PersonaPresentedFile, PersonaProvider, type PersonaProviderProps, type PersonaResumeValue, type PersonaRole, type PersonaStreamingEvent, type PersonaSubagentActivityEntry, type PersonaThread, type PersonaTodo, type PersonaToolCall, type PersonaWorkspaceFile, type SendMessageOverride, type UseChatOptions, type UseMcpConnectionsOptions, VERSION, useAgents, useChat, useConnection, useFiles, useMcpConnections, useMemory, usePersonaContext, useThreads };
|
|
476
|
+
export { type OpenSSEOptions, type PersonaAgentSummary, type PersonaClarificationQuestion, type PersonaFileItem, type PersonaHealthInfo, type PersonaHitlActionRequest, type PersonaInterrupt, type PersonaMcpConnection, type PersonaMemoryAgentGroup, type PersonaMemoryFile, type PersonaMemoryList, type PersonaMessage, type PersonaPresentedFile, PersonaProvider, type PersonaProviderProps, type PersonaResumeValue, type PersonaRole, type PersonaStreamingEvent, type PersonaSubagentActivityEntry, type PersonaThread, type PersonaTodo, type PersonaToolCall, type PersonaWorkspaceFile, type SSEReader, type SSEStream, type SendMessageOverride, type UseChatOptions, type UseMcpConnectionsOptions, VERSION, openSSEStream, supportsStreamingFetch, useAgents, useChat, useConnection, useFiles, useMcpConnections, useMemory, usePersonaContext, useThreads };
|
package/dist/index.js
CHANGED
|
@@ -42,6 +42,181 @@ function usePersonaContext() {
|
|
|
42
42
|
|
|
43
43
|
// src/hooks/useChat.ts
|
|
44
44
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
45
|
+
|
|
46
|
+
// src/streaming.ts
|
|
47
|
+
function supportsStreamingFetch() {
|
|
48
|
+
if (typeof navigator !== "undefined" && navigator.product === "ReactNative") {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
return typeof fetch !== "undefined" && typeof ReadableStream !== "undefined";
|
|
52
|
+
}
|
|
53
|
+
function fetchReader(response, controller) {
|
|
54
|
+
const reader = response.body.getReader();
|
|
55
|
+
const decoder = new TextDecoder("utf-8");
|
|
56
|
+
return {
|
|
57
|
+
async read() {
|
|
58
|
+
const { done, value } = await reader.read();
|
|
59
|
+
if (done) return { done: true };
|
|
60
|
+
return { done: false, value: decoder.decode(value, { stream: true }) };
|
|
61
|
+
},
|
|
62
|
+
cancel() {
|
|
63
|
+
controller.abort();
|
|
64
|
+
void reader.cancel().catch(() => {
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function xhrStream(opts) {
|
|
70
|
+
return new Promise((resolveStream, rejectStream) => {
|
|
71
|
+
const xhr = new XMLHttpRequest();
|
|
72
|
+
xhr.open("POST", opts.url);
|
|
73
|
+
for (const [key, val] of Object.entries(opts.headers)) xhr.setRequestHeader(key, val);
|
|
74
|
+
let consumed = 0;
|
|
75
|
+
let finished = false;
|
|
76
|
+
let failure = null;
|
|
77
|
+
const queue = [];
|
|
78
|
+
let waiting = null;
|
|
79
|
+
let waitingReject = null;
|
|
80
|
+
let headersResolved = false;
|
|
81
|
+
const pump = () => {
|
|
82
|
+
const text = xhr.responseText;
|
|
83
|
+
if (text.length <= consumed) return;
|
|
84
|
+
const chunk = text.slice(consumed);
|
|
85
|
+
consumed = text.length;
|
|
86
|
+
if (waiting) {
|
|
87
|
+
const resolve = waiting;
|
|
88
|
+
waiting = null;
|
|
89
|
+
waitingReject = null;
|
|
90
|
+
resolve({ done: false, value: chunk });
|
|
91
|
+
} else {
|
|
92
|
+
queue.push(chunk);
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
const finish = (err) => {
|
|
96
|
+
if (finished) return;
|
|
97
|
+
finished = true;
|
|
98
|
+
failure = err ?? null;
|
|
99
|
+
if (waiting) {
|
|
100
|
+
const resolve = waiting;
|
|
101
|
+
const reject = waitingReject;
|
|
102
|
+
waiting = null;
|
|
103
|
+
waitingReject = null;
|
|
104
|
+
if (err && reject) reject(err);
|
|
105
|
+
else resolve({ done: true });
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
const reader = {
|
|
109
|
+
read() {
|
|
110
|
+
if (queue.length > 0) {
|
|
111
|
+
return Promise.resolve({ done: false, value: queue.shift() });
|
|
112
|
+
}
|
|
113
|
+
if (finished) {
|
|
114
|
+
return failure ? Promise.reject(failure) : Promise.resolve({ done: true });
|
|
115
|
+
}
|
|
116
|
+
return new Promise((resolve, reject) => {
|
|
117
|
+
waiting = resolve;
|
|
118
|
+
waitingReject = reject;
|
|
119
|
+
});
|
|
120
|
+
},
|
|
121
|
+
cancel() {
|
|
122
|
+
finish();
|
|
123
|
+
xhr.abort();
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
const resolveHeaders = () => {
|
|
127
|
+
if (headersResolved) return;
|
|
128
|
+
headersResolved = true;
|
|
129
|
+
const ok = xhr.status >= 200 && xhr.status < 300;
|
|
130
|
+
resolveStream({
|
|
131
|
+
status: xhr.status,
|
|
132
|
+
ok,
|
|
133
|
+
getHeader: (name) => xhr.getResponseHeader(name),
|
|
134
|
+
reader
|
|
135
|
+
});
|
|
136
|
+
};
|
|
137
|
+
xhr.onreadystatechange = () => {
|
|
138
|
+
if (xhr.readyState === 2) {
|
|
139
|
+
resolveHeaders();
|
|
140
|
+
} else if (xhr.readyState === 3) {
|
|
141
|
+
resolveHeaders();
|
|
142
|
+
pump();
|
|
143
|
+
} else if (xhr.readyState === 4) {
|
|
144
|
+
resolveHeaders();
|
|
145
|
+
pump();
|
|
146
|
+
finish();
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
xhr.onerror = () => {
|
|
150
|
+
const err = new Error("Network request failed");
|
|
151
|
+
if (!headersResolved) rejectStream(err);
|
|
152
|
+
finish(err);
|
|
153
|
+
};
|
|
154
|
+
xhr.ontimeout = () => {
|
|
155
|
+
const err = new Error("Network request timed out");
|
|
156
|
+
if (!headersResolved) rejectStream(err);
|
|
157
|
+
finish(err);
|
|
158
|
+
};
|
|
159
|
+
if (opts.signal) {
|
|
160
|
+
if (opts.signal.aborted) {
|
|
161
|
+
xhr.abort();
|
|
162
|
+
finish();
|
|
163
|
+
} else {
|
|
164
|
+
opts.signal.addEventListener("abort", () => {
|
|
165
|
+
finish();
|
|
166
|
+
xhr.abort();
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
xhr.send(opts.body);
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
async function openSSEStream(opts) {
|
|
174
|
+
if (!supportsStreamingFetch()) {
|
|
175
|
+
return xhrStream(opts);
|
|
176
|
+
}
|
|
177
|
+
const controller = new AbortController();
|
|
178
|
+
if (opts.signal) {
|
|
179
|
+
if (opts.signal.aborted) controller.abort();
|
|
180
|
+
else opts.signal.addEventListener("abort", () => controller.abort());
|
|
181
|
+
}
|
|
182
|
+
const response = await fetch(opts.url, {
|
|
183
|
+
method: "POST",
|
|
184
|
+
headers: opts.headers,
|
|
185
|
+
body: opts.body,
|
|
186
|
+
signal: controller.signal
|
|
187
|
+
});
|
|
188
|
+
if (!response.ok) {
|
|
189
|
+
const errorText = await response.text().catch(() => "Stream failed");
|
|
190
|
+
return {
|
|
191
|
+
status: response.status,
|
|
192
|
+
ok: false,
|
|
193
|
+
errorText,
|
|
194
|
+
getHeader: (name) => response.headers.get(name),
|
|
195
|
+
reader: { read: async () => ({ done: true }), cancel: () => controller.abort() }
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
if (!response.body) {
|
|
199
|
+
const text = await response.text();
|
|
200
|
+
let handed = false;
|
|
201
|
+
return {
|
|
202
|
+
status: response.status,
|
|
203
|
+
ok: true,
|
|
204
|
+
getHeader: (name) => response.headers.get(name),
|
|
205
|
+
reader: {
|
|
206
|
+
read: async () => handed ? { done: true } : (handed = true, { done: false, value: text }),
|
|
207
|
+
cancel: () => controller.abort()
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
return {
|
|
212
|
+
status: response.status,
|
|
213
|
+
ok: true,
|
|
214
|
+
getHeader: (name) => response.headers.get(name),
|
|
215
|
+
reader: fetchReader(response, controller)
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// src/hooks/useChat.ts
|
|
45
220
|
function isErrorToolContent(content) {
|
|
46
221
|
if (typeof content !== "string" || !content.trim().startsWith("{")) return false;
|
|
47
222
|
try {
|
|
@@ -50,6 +225,20 @@ function isErrorToolContent(content) {
|
|
|
50
225
|
return false;
|
|
51
226
|
}
|
|
52
227
|
}
|
|
228
|
+
function persistedTraceToActivityEntries(items) {
|
|
229
|
+
const entries = [];
|
|
230
|
+
for (const item of items) {
|
|
231
|
+
if (item.type === "text") {
|
|
232
|
+
if (item.text) entries.push({ kind: "text", delta: item.text });
|
|
233
|
+
} else {
|
|
234
|
+
entries.push({ kind: "tool_start", toolName: item.name, args: item.argsText });
|
|
235
|
+
if (item.status === "completed") {
|
|
236
|
+
entries.push({ kind: "tool_result", toolName: item.name, result: item.resultText });
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return entries;
|
|
241
|
+
}
|
|
53
242
|
function parsePresentedFile(content) {
|
|
54
243
|
try {
|
|
55
244
|
const parsed = JSON.parse(content);
|
|
@@ -94,7 +283,7 @@ function normalizePendingInterrupt(pending) {
|
|
|
94
283
|
return null;
|
|
95
284
|
}
|
|
96
285
|
function useChat(options = {}) {
|
|
97
|
-
const { defaultAgentId, fetchWithAuth } = usePersonaContext();
|
|
286
|
+
const { defaultAgentId, fetchWithAuth, baseUrl, getAuthToken } = usePersonaContext();
|
|
98
287
|
const agentId = options.agentId || defaultAgentId;
|
|
99
288
|
const threadId = options.threadId;
|
|
100
289
|
const [messages, setMessages] = useState(options.initialMessages || []);
|
|
@@ -134,12 +323,16 @@ function useChat(options = {}) {
|
|
|
134
323
|
const body = await res.json();
|
|
135
324
|
const data = body?.data ?? body;
|
|
136
325
|
const raw = data?.messages ?? [];
|
|
326
|
+
const subagentTraces = data?.subagentTraces ?? {};
|
|
137
327
|
const loaded = raw.map((m, i) => ({
|
|
138
328
|
id: m.id || `history-${id}-${i}`,
|
|
139
329
|
role: m.role,
|
|
140
330
|
content: m.content,
|
|
141
331
|
createdAt: /* @__PURE__ */ new Date(),
|
|
142
|
-
toolCalls: m.toolCalls
|
|
332
|
+
toolCalls: m.toolCalls?.map((tc) => {
|
|
333
|
+
const trace = subagentTraces[tc.toolCallId];
|
|
334
|
+
return Array.isArray(trace) && trace.length > 0 ? { ...tc, subagentActivity: persistedTraceToActivityEntries(trace) } : tc;
|
|
335
|
+
})
|
|
143
336
|
}));
|
|
144
337
|
setMessages(loaded);
|
|
145
338
|
setInterrupt(normalizePendingInterrupt(data?.pendingInterrupt));
|
|
@@ -203,10 +396,12 @@ function useChat(options = {}) {
|
|
|
203
396
|
content: m.content
|
|
204
397
|
}));
|
|
205
398
|
const resolvedThreadId = await (overrideOptions?.threadId ?? options.threadId);
|
|
206
|
-
const
|
|
207
|
-
|
|
399
|
+
const token = getAuthToken ? await getAuthToken() : null;
|
|
400
|
+
const stream = await openSSEStream({
|
|
401
|
+
url: `${baseUrl}/chat`,
|
|
208
402
|
headers: {
|
|
209
|
-
"Content-Type": "application/json"
|
|
403
|
+
"Content-Type": "application/json",
|
|
404
|
+
...token ? { Authorization: `Bearer ${token}` } : {}
|
|
210
405
|
},
|
|
211
406
|
body: JSON.stringify({
|
|
212
407
|
agentId: targetAgentId,
|
|
@@ -216,15 +411,10 @@ function useChat(options = {}) {
|
|
|
216
411
|
}),
|
|
217
412
|
signal: controller.signal
|
|
218
413
|
});
|
|
219
|
-
if (!
|
|
220
|
-
|
|
221
|
-
throw new Error(`Chat error (${response.status}): ${errText}`);
|
|
222
|
-
}
|
|
223
|
-
if (!response.body) {
|
|
224
|
-
throw new Error("No response body received for streaming.");
|
|
414
|
+
if (!stream.ok) {
|
|
415
|
+
throw new Error(`Chat error (${stream.status}): ${stream.errorText ?? "Stream failed"}`);
|
|
225
416
|
}
|
|
226
|
-
const reader =
|
|
227
|
-
const decoder = new TextDecoder("utf-8");
|
|
417
|
+
const reader = stream.reader;
|
|
228
418
|
let buffer = "";
|
|
229
419
|
let accumulatedText = "";
|
|
230
420
|
let accumulatedReasoning = "";
|
|
@@ -239,7 +429,7 @@ function useChat(options = {}) {
|
|
|
239
429
|
while (true) {
|
|
240
430
|
const { done, value } = await reader.read();
|
|
241
431
|
if (done) break;
|
|
242
|
-
buffer +=
|
|
432
|
+
buffer += value ?? "";
|
|
243
433
|
const lines = buffer.split("\n");
|
|
244
434
|
buffer = lines.pop() ?? "";
|
|
245
435
|
for (const line of lines) {
|
|
@@ -352,7 +542,7 @@ function useChat(options = {}) {
|
|
|
352
542
|
abortControllerRef.current = null;
|
|
353
543
|
}
|
|
354
544
|
},
|
|
355
|
-
[agentId,
|
|
545
|
+
[agentId, baseUrl, getAuthToken, input, isStreaming, messages, options]
|
|
356
546
|
);
|
|
357
547
|
const handleInputChange = useCallback((e) => {
|
|
358
548
|
setInput(e.target.value);
|
|
@@ -838,10 +1028,12 @@ function useMcpConnections(options = {}) {
|
|
|
838
1028
|
}
|
|
839
1029
|
|
|
840
1030
|
// src/index.ts
|
|
841
|
-
var VERSION = "0.
|
|
1031
|
+
var VERSION = "0.4.0";
|
|
842
1032
|
export {
|
|
843
1033
|
PersonaProvider,
|
|
844
1034
|
VERSION,
|
|
1035
|
+
openSSEStream,
|
|
1036
|
+
supportsStreamingFetch,
|
|
845
1037
|
useAgents,
|
|
846
1038
|
useChat,
|
|
847
1039
|
useConnection,
|