@personaai/react 0.8.0 → 0.9.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 +38 -10
- package/dist/index.cjs +609 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +227 -3
- package/dist/index.d.ts +227 -3
- package/dist/index.js +604 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -38,7 +38,11 @@ __export(index_exports, {
|
|
|
38
38
|
useMemory: () => useMemory,
|
|
39
39
|
usePersonaContext: () => usePersonaContext,
|
|
40
40
|
useThreads: () => useThreads,
|
|
41
|
-
useVoice: () => useVoice
|
|
41
|
+
useVoice: () => useVoice,
|
|
42
|
+
useWorkflow: () => useWorkflow,
|
|
43
|
+
useWorkflowRuns: () => useWorkflowRuns,
|
|
44
|
+
useWorkflowStream: () => useWorkflowStream,
|
|
45
|
+
useWorkflows: () => useWorkflows
|
|
42
46
|
});
|
|
43
47
|
module.exports = __toCommonJS(index_exports);
|
|
44
48
|
|
|
@@ -177,7 +181,8 @@ function fetchReader(response, controller) {
|
|
|
177
181
|
function xhrStream(opts) {
|
|
178
182
|
return new Promise((resolveStream, rejectStream) => {
|
|
179
183
|
const xhr = new XMLHttpRequest();
|
|
180
|
-
|
|
184
|
+
const method = opts.method ?? "POST";
|
|
185
|
+
xhr.open(method, opts.url);
|
|
181
186
|
for (const [key, val] of Object.entries(opts.headers))
|
|
182
187
|
xhr.setRequestHeader(key, val);
|
|
183
188
|
let consumed = 0;
|
|
@@ -276,7 +281,7 @@ function xhrStream(opts) {
|
|
|
276
281
|
});
|
|
277
282
|
}
|
|
278
283
|
}
|
|
279
|
-
xhr.send(opts.body);
|
|
284
|
+
xhr.send(method === "GET" ? null : opts.body ?? null);
|
|
280
285
|
});
|
|
281
286
|
}
|
|
282
287
|
async function openSSEStream(opts) {
|
|
@@ -288,10 +293,11 @@ async function openSSEStream(opts) {
|
|
|
288
293
|
if (opts.signal.aborted) controller.abort();
|
|
289
294
|
else opts.signal.addEventListener("abort", () => controller.abort());
|
|
290
295
|
}
|
|
296
|
+
const method = opts.method ?? "POST";
|
|
291
297
|
const response = await fetch(opts.url, {
|
|
292
|
-
method
|
|
298
|
+
method,
|
|
293
299
|
headers: opts.headers,
|
|
294
|
-
body: opts.body,
|
|
300
|
+
body: method === "GET" ? void 0 : opts.body,
|
|
295
301
|
signal: controller.signal
|
|
296
302
|
});
|
|
297
303
|
if (!response.ok) {
|
|
@@ -974,6 +980,12 @@ function useChat(options = {}) {
|
|
|
974
980
|
}
|
|
975
981
|
}
|
|
976
982
|
}
|
|
983
|
+
} else if (event.type === "title") {
|
|
984
|
+
const title = event.title;
|
|
985
|
+
if (typeof title === "string" && title.trim()) {
|
|
986
|
+
chatLogger.info("auto title", { title });
|
|
987
|
+
options.onTitle?.(title);
|
|
988
|
+
}
|
|
977
989
|
} else if (event.type === "RUN_ERROR") {
|
|
978
990
|
chatLogger.warn("run error", { message: event.message, code: event.code });
|
|
979
991
|
chatLogger.error("stream run error", { code: event.code, message: event.message });
|
|
@@ -2097,9 +2109,595 @@ function useMcp(options = {}) {
|
|
|
2097
2109
|
};
|
|
2098
2110
|
}
|
|
2099
2111
|
|
|
2112
|
+
// src/hooks/useWorkflows.ts
|
|
2113
|
+
var import_react11 = require("react");
|
|
2114
|
+
function useWorkflows(options) {
|
|
2115
|
+
const opts = typeof options === "boolean" ? { autoFetch: options } : options ?? {};
|
|
2116
|
+
const { autoFetch = true, search, status, page, limit } = opts;
|
|
2117
|
+
const { fetchWithAuth } = usePersonaContext();
|
|
2118
|
+
const [workflows, setWorkflows] = (0, import_react11.useState)([]);
|
|
2119
|
+
const [pagination, setPagination] = (0, import_react11.useState)({
|
|
2120
|
+
page: page ?? 1,
|
|
2121
|
+
limit: limit ?? 20,
|
|
2122
|
+
total: 0,
|
|
2123
|
+
totalPages: 0
|
|
2124
|
+
});
|
|
2125
|
+
const [isLoading, setIsLoading] = (0, import_react11.useState)(false);
|
|
2126
|
+
const [error, setError] = (0, import_react11.useState)(null);
|
|
2127
|
+
const fetchWorkflows = (0, import_react11.useCallback)(async () => {
|
|
2128
|
+
setIsLoading(true);
|
|
2129
|
+
setError(null);
|
|
2130
|
+
try {
|
|
2131
|
+
const params = new URLSearchParams();
|
|
2132
|
+
if (search) params.set("search", search);
|
|
2133
|
+
if (status) params.set("status", status);
|
|
2134
|
+
if (page) params.set("page", String(page));
|
|
2135
|
+
if (limit) params.set("limit", String(limit));
|
|
2136
|
+
const queryStr = params.toString() ? `?${params.toString()}` : "";
|
|
2137
|
+
const res = await fetchWithAuth(`/workflows${queryStr}`);
|
|
2138
|
+
if (!res.ok) {
|
|
2139
|
+
throw new Error(`Failed to list workflows: ${res.statusText}`);
|
|
2140
|
+
}
|
|
2141
|
+
const data = await res.json();
|
|
2142
|
+
const items = Array.isArray(data) ? data : data?.items || data?.workflows || [];
|
|
2143
|
+
setWorkflows(items);
|
|
2144
|
+
if (data?.pagination) {
|
|
2145
|
+
setPagination({
|
|
2146
|
+
page: data.pagination.page ?? 1,
|
|
2147
|
+
limit: data.pagination.limit ?? items.length,
|
|
2148
|
+
total: data.pagination.total ?? items.length,
|
|
2149
|
+
totalPages: data.pagination.totalPages ?? 1
|
|
2150
|
+
});
|
|
2151
|
+
} else {
|
|
2152
|
+
setPagination({
|
|
2153
|
+
page: 1,
|
|
2154
|
+
limit: items.length,
|
|
2155
|
+
total: items.length,
|
|
2156
|
+
totalPages: 1
|
|
2157
|
+
});
|
|
2158
|
+
}
|
|
2159
|
+
return items;
|
|
2160
|
+
} catch (err) {
|
|
2161
|
+
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
2162
|
+
setError(errorObj);
|
|
2163
|
+
return [];
|
|
2164
|
+
} finally {
|
|
2165
|
+
setIsLoading(false);
|
|
2166
|
+
}
|
|
2167
|
+
}, [fetchWithAuth, search, status, page, limit]);
|
|
2168
|
+
const createWorkflow = (0, import_react11.useCallback)(
|
|
2169
|
+
async (input) => {
|
|
2170
|
+
setError(null);
|
|
2171
|
+
try {
|
|
2172
|
+
const res = await fetchWithAuth("/workflows", {
|
|
2173
|
+
method: "POST",
|
|
2174
|
+
headers: { "Content-Type": "application/json" },
|
|
2175
|
+
body: JSON.stringify(input)
|
|
2176
|
+
});
|
|
2177
|
+
if (!res.ok) {
|
|
2178
|
+
const errText = await res.text().catch(() => res.statusText);
|
|
2179
|
+
throw new Error(`Failed to create workflow (${res.status}): ${errText}`);
|
|
2180
|
+
}
|
|
2181
|
+
const created = await res.json();
|
|
2182
|
+
setWorkflows((prev) => [created, ...prev]);
|
|
2183
|
+
return created;
|
|
2184
|
+
} catch (err) {
|
|
2185
|
+
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
2186
|
+
setError(errorObj);
|
|
2187
|
+
throw errorObj;
|
|
2188
|
+
}
|
|
2189
|
+
},
|
|
2190
|
+
[fetchWithAuth]
|
|
2191
|
+
);
|
|
2192
|
+
(0, import_react11.useEffect)(() => {
|
|
2193
|
+
if (autoFetch) {
|
|
2194
|
+
void fetchWorkflows();
|
|
2195
|
+
}
|
|
2196
|
+
}, [autoFetch, fetchWorkflows]);
|
|
2197
|
+
return {
|
|
2198
|
+
workflows,
|
|
2199
|
+
pagination,
|
|
2200
|
+
isLoading,
|
|
2201
|
+
error,
|
|
2202
|
+
refetch: fetchWorkflows,
|
|
2203
|
+
createWorkflow
|
|
2204
|
+
};
|
|
2205
|
+
}
|
|
2206
|
+
|
|
2207
|
+
// src/hooks/useWorkflow.ts
|
|
2208
|
+
var import_react12 = require("react");
|
|
2209
|
+
function useWorkflow(workflowId, options) {
|
|
2210
|
+
const opts = typeof options === "boolean" ? { autoFetch: options } : options ?? {};
|
|
2211
|
+
const { autoFetch = true } = opts;
|
|
2212
|
+
const { fetchWithAuth } = usePersonaContext();
|
|
2213
|
+
const [workflow, setWorkflow] = (0, import_react12.useState)(null);
|
|
2214
|
+
const [versions, setVersions] = (0, import_react12.useState)([]);
|
|
2215
|
+
const [mermaid, setMermaid] = (0, import_react12.useState)(null);
|
|
2216
|
+
const [isLoading, setIsLoading] = (0, import_react12.useState)(false);
|
|
2217
|
+
const [error, setError] = (0, import_react12.useState)(null);
|
|
2218
|
+
const fetchWorkflow = (0, import_react12.useCallback)(async () => {
|
|
2219
|
+
if (!workflowId) return null;
|
|
2220
|
+
setIsLoading(true);
|
|
2221
|
+
setError(null);
|
|
2222
|
+
try {
|
|
2223
|
+
const res = await fetchWithAuth(`/workflows/${workflowId}`);
|
|
2224
|
+
if (!res.ok) {
|
|
2225
|
+
throw new Error(`Failed to fetch workflow (${res.status}): ${res.statusText}`);
|
|
2226
|
+
}
|
|
2227
|
+
const data = await res.json();
|
|
2228
|
+
setWorkflow(data);
|
|
2229
|
+
return data;
|
|
2230
|
+
} catch (err) {
|
|
2231
|
+
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
2232
|
+
setError(errorObj);
|
|
2233
|
+
return null;
|
|
2234
|
+
} finally {
|
|
2235
|
+
setIsLoading(false);
|
|
2236
|
+
}
|
|
2237
|
+
}, [fetchWithAuth, workflowId]);
|
|
2238
|
+
const fetchVersions = (0, import_react12.useCallback)(async () => {
|
|
2239
|
+
if (!workflowId) return [];
|
|
2240
|
+
try {
|
|
2241
|
+
const res = await fetchWithAuth(`/workflows/${workflowId}/versions`);
|
|
2242
|
+
if (!res.ok) return [];
|
|
2243
|
+
const data = await res.json();
|
|
2244
|
+
const items = Array.isArray(data) ? data : data?.items || [];
|
|
2245
|
+
setVersions(items);
|
|
2246
|
+
return items;
|
|
2247
|
+
} catch {
|
|
2248
|
+
return [];
|
|
2249
|
+
}
|
|
2250
|
+
}, [fetchWithAuth, workflowId]);
|
|
2251
|
+
const fetchMermaid = (0, import_react12.useCallback)(async () => {
|
|
2252
|
+
if (!workflowId) return "";
|
|
2253
|
+
try {
|
|
2254
|
+
const res = await fetchWithAuth(`/workflows/${workflowId}/mermaid`);
|
|
2255
|
+
if (!res.ok) return "";
|
|
2256
|
+
const data = await res.json();
|
|
2257
|
+
const code = typeof data?.mermaid === "string" ? data.mermaid : String(data ?? "");
|
|
2258
|
+
setMermaid(code);
|
|
2259
|
+
return code;
|
|
2260
|
+
} catch {
|
|
2261
|
+
return "";
|
|
2262
|
+
}
|
|
2263
|
+
}, [fetchWithAuth, workflowId]);
|
|
2264
|
+
const saveDraft = (0, import_react12.useCallback)(
|
|
2265
|
+
async (draft) => {
|
|
2266
|
+
if (!workflowId) throw new Error("Workflow ID is required");
|
|
2267
|
+
setError(null);
|
|
2268
|
+
const res = await fetchWithAuth(`/workflows/${workflowId}/draft`, {
|
|
2269
|
+
method: "POST",
|
|
2270
|
+
headers: { "Content-Type": "application/json" },
|
|
2271
|
+
body: JSON.stringify({ draft })
|
|
2272
|
+
});
|
|
2273
|
+
if (!res.ok) {
|
|
2274
|
+
const errText = await res.text().catch(() => res.statusText);
|
|
2275
|
+
throw new Error(`Failed to save draft (${res.status}): ${errText}`);
|
|
2276
|
+
}
|
|
2277
|
+
const updated = await res.json();
|
|
2278
|
+
setWorkflow(updated);
|
|
2279
|
+
return updated;
|
|
2280
|
+
},
|
|
2281
|
+
[fetchWithAuth, workflowId]
|
|
2282
|
+
);
|
|
2283
|
+
const publish = (0, import_react12.useCallback)(
|
|
2284
|
+
async (summary) => {
|
|
2285
|
+
if (!workflowId) throw new Error("Workflow ID is required");
|
|
2286
|
+
setError(null);
|
|
2287
|
+
const res = await fetchWithAuth(`/workflows/${workflowId}/publish`, {
|
|
2288
|
+
method: "POST",
|
|
2289
|
+
headers: { "Content-Type": "application/json" },
|
|
2290
|
+
body: JSON.stringify(summary ? { summary } : {})
|
|
2291
|
+
});
|
|
2292
|
+
if (!res.ok) {
|
|
2293
|
+
const errText = await res.text().catch(() => res.statusText);
|
|
2294
|
+
throw new Error(`Failed to publish workflow (${res.status}): ${errText}`);
|
|
2295
|
+
}
|
|
2296
|
+
const versionResult = await res.json();
|
|
2297
|
+
void fetchWorkflow();
|
|
2298
|
+
void fetchVersions();
|
|
2299
|
+
return versionResult;
|
|
2300
|
+
},
|
|
2301
|
+
[fetchWithAuth, workflowId, fetchWorkflow, fetchVersions]
|
|
2302
|
+
);
|
|
2303
|
+
const deleteWorkflow = (0, import_react12.useCallback)(async () => {
|
|
2304
|
+
if (!workflowId) throw new Error("Workflow ID is required");
|
|
2305
|
+
setError(null);
|
|
2306
|
+
const res = await fetchWithAuth(`/workflows/${workflowId}`, {
|
|
2307
|
+
method: "DELETE"
|
|
2308
|
+
});
|
|
2309
|
+
if (!res.ok) {
|
|
2310
|
+
throw new Error(`Failed to delete workflow (${res.status}): ${res.statusText}`);
|
|
2311
|
+
}
|
|
2312
|
+
setWorkflow(null);
|
|
2313
|
+
}, [fetchWithAuth, workflowId]);
|
|
2314
|
+
(0, import_react12.useEffect)(() => {
|
|
2315
|
+
if (autoFetch && workflowId) {
|
|
2316
|
+
void fetchWorkflow();
|
|
2317
|
+
}
|
|
2318
|
+
}, [autoFetch, workflowId, fetchWorkflow]);
|
|
2319
|
+
return {
|
|
2320
|
+
workflow,
|
|
2321
|
+
versions,
|
|
2322
|
+
mermaid,
|
|
2323
|
+
isLoading,
|
|
2324
|
+
error,
|
|
2325
|
+
refetch: fetchWorkflow,
|
|
2326
|
+
fetchVersions,
|
|
2327
|
+
fetchMermaid,
|
|
2328
|
+
saveDraft,
|
|
2329
|
+
publish,
|
|
2330
|
+
deleteWorkflow
|
|
2331
|
+
};
|
|
2332
|
+
}
|
|
2333
|
+
|
|
2334
|
+
// src/hooks/useWorkflowStream.ts
|
|
2335
|
+
var import_react13 = require("react");
|
|
2336
|
+
function useWorkflowStream(workflowId, options) {
|
|
2337
|
+
const { baseUrl, getAuthToken, fetchWithAuth, logger } = usePersonaContext();
|
|
2338
|
+
const [status, setStatus] = (0, import_react13.useState)("idle");
|
|
2339
|
+
const [runId, setRunId] = (0, import_react13.useState)(null);
|
|
2340
|
+
const [activeNodeId, setActiveNodeId] = (0, import_react13.useState)(null);
|
|
2341
|
+
const [nodeRuns, setNodeRuns] = (0, import_react13.useState)(
|
|
2342
|
+
{}
|
|
2343
|
+
);
|
|
2344
|
+
const [text, setText] = (0, import_react13.useState)("");
|
|
2345
|
+
const [output, setOutput] = (0, import_react13.useState)(null);
|
|
2346
|
+
const [error, setError] = (0, import_react13.useState)(null);
|
|
2347
|
+
const [events, setEvents] = (0, import_react13.useState)([]);
|
|
2348
|
+
const abortControllerRef = (0, import_react13.useRef)(null);
|
|
2349
|
+
const currentRunIdRef = (0, import_react13.useRef)(null);
|
|
2350
|
+
currentRunIdRef.current = runId;
|
|
2351
|
+
const optionsRef = (0, import_react13.useRef)(options);
|
|
2352
|
+
optionsRef.current = options;
|
|
2353
|
+
const cancel = (0, import_react13.useCallback)(async () => {
|
|
2354
|
+
if (abortControllerRef.current) {
|
|
2355
|
+
abortControllerRef.current.abort();
|
|
2356
|
+
abortControllerRef.current = null;
|
|
2357
|
+
}
|
|
2358
|
+
const currentRun = currentRunIdRef.current;
|
|
2359
|
+
if (currentRun) {
|
|
2360
|
+
try {
|
|
2361
|
+
await fetchWithAuth(`/workflows/runs/${currentRun}/cancel`, {
|
|
2362
|
+
method: "POST"
|
|
2363
|
+
});
|
|
2364
|
+
} catch (err) {
|
|
2365
|
+
logger.warn("Failed to send cancel request to workflow run", {
|
|
2366
|
+
runId: currentRun,
|
|
2367
|
+
error: String(err)
|
|
2368
|
+
});
|
|
2369
|
+
}
|
|
2370
|
+
}
|
|
2371
|
+
setStatus("cancelled");
|
|
2372
|
+
setActiveNodeId(null);
|
|
2373
|
+
}, [fetchWithAuth, logger]);
|
|
2374
|
+
const reset = (0, import_react13.useCallback)(() => {
|
|
2375
|
+
if (abortControllerRef.current) {
|
|
2376
|
+
abortControllerRef.current.abort();
|
|
2377
|
+
abortControllerRef.current = null;
|
|
2378
|
+
}
|
|
2379
|
+
setStatus("idle");
|
|
2380
|
+
setRunId(null);
|
|
2381
|
+
setActiveNodeId(null);
|
|
2382
|
+
setNodeRuns({});
|
|
2383
|
+
setText("");
|
|
2384
|
+
setOutput(null);
|
|
2385
|
+
setError(null);
|
|
2386
|
+
setEvents([]);
|
|
2387
|
+
}, []);
|
|
2388
|
+
const processStream = (0, import_react13.useCallback)(
|
|
2389
|
+
async (url, method, body, targetRunId) => {
|
|
2390
|
+
if (abortControllerRef.current) {
|
|
2391
|
+
abortControllerRef.current.abort();
|
|
2392
|
+
}
|
|
2393
|
+
const controller = new AbortController();
|
|
2394
|
+
abortControllerRef.current = controller;
|
|
2395
|
+
setStatus("running");
|
|
2396
|
+
setError(null);
|
|
2397
|
+
const token = getAuthToken ? await getAuthToken() : null;
|
|
2398
|
+
const headers = {
|
|
2399
|
+
Accept: "text/event-stream"
|
|
2400
|
+
};
|
|
2401
|
+
if (token) {
|
|
2402
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
2403
|
+
}
|
|
2404
|
+
if (method === "POST") {
|
|
2405
|
+
headers["Content-Type"] = "application/json";
|
|
2406
|
+
}
|
|
2407
|
+
let assignedRunId = targetRunId ?? null;
|
|
2408
|
+
let accumulatedText = "";
|
|
2409
|
+
let finalOutput = null;
|
|
2410
|
+
try {
|
|
2411
|
+
const stream = await openSSEStream({
|
|
2412
|
+
url,
|
|
2413
|
+
method,
|
|
2414
|
+
headers,
|
|
2415
|
+
body,
|
|
2416
|
+
signal: controller.signal
|
|
2417
|
+
});
|
|
2418
|
+
if (!stream.ok) {
|
|
2419
|
+
throw new Error(
|
|
2420
|
+
stream.errorText || `Stream request failed with status ${stream.status}`
|
|
2421
|
+
);
|
|
2422
|
+
}
|
|
2423
|
+
const runIdHeader = stream.getHeader("x-persona-run-id");
|
|
2424
|
+
if (runIdHeader) {
|
|
2425
|
+
assignedRunId = runIdHeader;
|
|
2426
|
+
setRunId(runIdHeader);
|
|
2427
|
+
}
|
|
2428
|
+
let buffer = "";
|
|
2429
|
+
while (true) {
|
|
2430
|
+
const { done, value } = await stream.reader.read();
|
|
2431
|
+
if (done) break;
|
|
2432
|
+
if (!value) continue;
|
|
2433
|
+
buffer += value;
|
|
2434
|
+
const lines = buffer.split("\n");
|
|
2435
|
+
buffer = lines.pop() ?? "";
|
|
2436
|
+
for (const line of lines) {
|
|
2437
|
+
const trimmed = line.trim();
|
|
2438
|
+
if (!trimmed || trimmed.startsWith(":")) continue;
|
|
2439
|
+
if (trimmed.startsWith("data:")) {
|
|
2440
|
+
const rawData = trimmed.slice(5).trim();
|
|
2441
|
+
if (!rawData || rawData === "[DONE]") continue;
|
|
2442
|
+
try {
|
|
2443
|
+
const event = JSON.parse(rawData);
|
|
2444
|
+
setEvents((prev) => [...prev, event]);
|
|
2445
|
+
optionsRef.current?.onEvent?.(event);
|
|
2446
|
+
if ("runId" in event && typeof event.runId === "string" && !assignedRunId) {
|
|
2447
|
+
assignedRunId = event.runId;
|
|
2448
|
+
setRunId(event.runId);
|
|
2449
|
+
}
|
|
2450
|
+
if (event.type === "TEXT_MESSAGE_CHUNK") {
|
|
2451
|
+
accumulatedText += event.delta;
|
|
2452
|
+
setText((prev) => prev + event.delta);
|
|
2453
|
+
} else if (event.type === "CUSTOM") {
|
|
2454
|
+
if (event.name === "workflow_node_started") {
|
|
2455
|
+
const val = event.value;
|
|
2456
|
+
setActiveNodeId(val.nodeId);
|
|
2457
|
+
setNodeRuns((prev) => ({
|
|
2458
|
+
...prev,
|
|
2459
|
+
[val.nodeId]: {
|
|
2460
|
+
nodeId: val.nodeId,
|
|
2461
|
+
nodeType: val.nodeType,
|
|
2462
|
+
nodeLabel: val.nodeLabel,
|
|
2463
|
+
status: "running",
|
|
2464
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2465
|
+
input: val.input
|
|
2466
|
+
}
|
|
2467
|
+
}));
|
|
2468
|
+
optionsRef.current?.onNodeStarted?.(val);
|
|
2469
|
+
} else if (event.name === "workflow_node_completed") {
|
|
2470
|
+
const val = event.value;
|
|
2471
|
+
setNodeRuns((prev) => {
|
|
2472
|
+
const existing = prev[val.nodeId];
|
|
2473
|
+
return {
|
|
2474
|
+
...prev,
|
|
2475
|
+
[val.nodeId]: {
|
|
2476
|
+
nodeId: val.nodeId,
|
|
2477
|
+
nodeType: existing?.nodeType ?? "unknown",
|
|
2478
|
+
nodeLabel: existing?.nodeLabel ?? val.nodeId,
|
|
2479
|
+
status: "completed",
|
|
2480
|
+
startedAt: existing?.startedAt,
|
|
2481
|
+
finishedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2482
|
+
input: existing?.input,
|
|
2483
|
+
output: val.output
|
|
2484
|
+
}
|
|
2485
|
+
};
|
|
2486
|
+
});
|
|
2487
|
+
setActiveNodeId((curr) => curr === val.nodeId ? null : curr);
|
|
2488
|
+
finalOutput = val.output;
|
|
2489
|
+
setOutput(val.output);
|
|
2490
|
+
optionsRef.current?.onNodeCompleted?.(val);
|
|
2491
|
+
} else if (event.name === "workflow_node_failed") {
|
|
2492
|
+
const val = event.value;
|
|
2493
|
+
setNodeRuns((prev) => {
|
|
2494
|
+
const existing = prev[val.nodeId];
|
|
2495
|
+
return {
|
|
2496
|
+
...prev,
|
|
2497
|
+
[val.nodeId]: {
|
|
2498
|
+
nodeId: val.nodeId,
|
|
2499
|
+
nodeType: existing?.nodeType ?? "unknown",
|
|
2500
|
+
nodeLabel: existing?.nodeLabel ?? val.nodeId,
|
|
2501
|
+
status: "failed",
|
|
2502
|
+
startedAt: existing?.startedAt,
|
|
2503
|
+
finishedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2504
|
+
input: existing?.input,
|
|
2505
|
+
error: val.error
|
|
2506
|
+
}
|
|
2507
|
+
};
|
|
2508
|
+
});
|
|
2509
|
+
setActiveNodeId((curr) => curr === val.nodeId ? null : curr);
|
|
2510
|
+
optionsRef.current?.onNodeFailed?.(val);
|
|
2511
|
+
}
|
|
2512
|
+
} else if (event.type === "RUN_FINISHED") {
|
|
2513
|
+
setStatus("completed");
|
|
2514
|
+
setActiveNodeId(null);
|
|
2515
|
+
optionsRef.current?.onFinish?.({
|
|
2516
|
+
runId: assignedRunId || "",
|
|
2517
|
+
output: finalOutput,
|
|
2518
|
+
text: accumulatedText
|
|
2519
|
+
});
|
|
2520
|
+
} else if (event.type === "RUN_ERROR") {
|
|
2521
|
+
const runErr = new Error(event.message || event.code || "Workflow run error");
|
|
2522
|
+
setStatus("failed");
|
|
2523
|
+
setError(runErr);
|
|
2524
|
+
setActiveNodeId(null);
|
|
2525
|
+
optionsRef.current?.onError?.(runErr);
|
|
2526
|
+
}
|
|
2527
|
+
} catch {
|
|
2528
|
+
}
|
|
2529
|
+
}
|
|
2530
|
+
}
|
|
2531
|
+
}
|
|
2532
|
+
setStatus((prev) => prev === "running" ? "completed" : prev);
|
|
2533
|
+
return finalOutput;
|
|
2534
|
+
} catch (err) {
|
|
2535
|
+
if (controller.signal.aborted) {
|
|
2536
|
+
setStatus("cancelled");
|
|
2537
|
+
return null;
|
|
2538
|
+
}
|
|
2539
|
+
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
2540
|
+
setStatus("failed");
|
|
2541
|
+
setError(errorObj);
|
|
2542
|
+
setActiveNodeId(null);
|
|
2543
|
+
optionsRef.current?.onError?.(errorObj);
|
|
2544
|
+
throw errorObj;
|
|
2545
|
+
} finally {
|
|
2546
|
+
if (abortControllerRef.current === controller) {
|
|
2547
|
+
abortControllerRef.current = null;
|
|
2548
|
+
}
|
|
2549
|
+
}
|
|
2550
|
+
},
|
|
2551
|
+
[getAuthToken]
|
|
2552
|
+
);
|
|
2553
|
+
const start = (0, import_react13.useCallback)(
|
|
2554
|
+
async (input, opts) => {
|
|
2555
|
+
const targetWfId = opts?.workflowId || workflowId;
|
|
2556
|
+
if (!targetWfId) {
|
|
2557
|
+
throw new Error("Workflow ID must be provided to start execution");
|
|
2558
|
+
}
|
|
2559
|
+
setNodeRuns({});
|
|
2560
|
+
setText("");
|
|
2561
|
+
setOutput(null);
|
|
2562
|
+
setEvents([]);
|
|
2563
|
+
setActiveNodeId(null);
|
|
2564
|
+
const cleanBase = baseUrl.replace(/\/+$/, "");
|
|
2565
|
+
const url = `${cleanBase}/workflows/${targetWfId}/stream`;
|
|
2566
|
+
const body = JSON.stringify({
|
|
2567
|
+
input: input ?? {},
|
|
2568
|
+
dryRun: opts?.dryRun ?? false
|
|
2569
|
+
});
|
|
2570
|
+
return processStream(url, "POST", body);
|
|
2571
|
+
},
|
|
2572
|
+
[workflowId, baseUrl, processStream]
|
|
2573
|
+
);
|
|
2574
|
+
const resume = (0, import_react13.useCallback)(
|
|
2575
|
+
async (targetRunId, sinceSeq) => {
|
|
2576
|
+
if (!targetRunId) {
|
|
2577
|
+
throw new Error("Run ID is required to resume stream");
|
|
2578
|
+
}
|
|
2579
|
+
setRunId(targetRunId);
|
|
2580
|
+
const cleanBase = baseUrl.replace(/\/+$/, "");
|
|
2581
|
+
const query = sinceSeq !== void 0 ? `?since=${sinceSeq}` : "";
|
|
2582
|
+
const url = `${cleanBase}/workflows/runs/${targetRunId}/resume${query}`;
|
|
2583
|
+
await processStream(url, "GET", void 0, targetRunId);
|
|
2584
|
+
},
|
|
2585
|
+
[baseUrl, processStream]
|
|
2586
|
+
);
|
|
2587
|
+
(0, import_react13.useEffect)(() => {
|
|
2588
|
+
return () => {
|
|
2589
|
+
if (abortControllerRef.current) {
|
|
2590
|
+
abortControllerRef.current.abort();
|
|
2591
|
+
}
|
|
2592
|
+
};
|
|
2593
|
+
}, []);
|
|
2594
|
+
return {
|
|
2595
|
+
runId,
|
|
2596
|
+
status,
|
|
2597
|
+
isRunning: status === "running",
|
|
2598
|
+
activeNodeId,
|
|
2599
|
+
nodeRuns,
|
|
2600
|
+
text,
|
|
2601
|
+
output,
|
|
2602
|
+
error,
|
|
2603
|
+
events,
|
|
2604
|
+
start,
|
|
2605
|
+
cancel,
|
|
2606
|
+
resume,
|
|
2607
|
+
reset
|
|
2608
|
+
};
|
|
2609
|
+
}
|
|
2610
|
+
|
|
2611
|
+
// src/hooks/useWorkflowRuns.ts
|
|
2612
|
+
var import_react14 = require("react");
|
|
2613
|
+
function useWorkflowRuns(workflowId, options) {
|
|
2614
|
+
const opts = typeof options === "boolean" ? { autoFetch: options } : options ?? {};
|
|
2615
|
+
const { autoFetch = true, page = 1, limit = 20 } = opts;
|
|
2616
|
+
const { fetchWithAuth } = usePersonaContext();
|
|
2617
|
+
const [runs, setRuns] = (0, import_react14.useState)([]);
|
|
2618
|
+
const [pagination, setPagination] = (0, import_react14.useState)({
|
|
2619
|
+
page,
|
|
2620
|
+
limit,
|
|
2621
|
+
total: 0,
|
|
2622
|
+
totalPages: 0
|
|
2623
|
+
});
|
|
2624
|
+
const [isLoading, setIsLoading] = (0, import_react14.useState)(false);
|
|
2625
|
+
const [error, setError] = (0, import_react14.useState)(null);
|
|
2626
|
+
const fetchRuns = (0, import_react14.useCallback)(async () => {
|
|
2627
|
+
if (!workflowId) return [];
|
|
2628
|
+
setIsLoading(true);
|
|
2629
|
+
setError(null);
|
|
2630
|
+
try {
|
|
2631
|
+
const query = `?page=${page}&limit=${limit}`;
|
|
2632
|
+
const res = await fetchWithAuth(`/workflows/${workflowId}/runs${query}`);
|
|
2633
|
+
if (!res.ok) {
|
|
2634
|
+
throw new Error(`Failed to list workflow runs: ${res.statusText}`);
|
|
2635
|
+
}
|
|
2636
|
+
const data = await res.json();
|
|
2637
|
+
const items = Array.isArray(data) ? data : data?.items || data?.runs || [];
|
|
2638
|
+
setRuns(items);
|
|
2639
|
+
if (data?.pagination) {
|
|
2640
|
+
setPagination({
|
|
2641
|
+
page: data.pagination.page ?? page,
|
|
2642
|
+
limit: data.pagination.limit ?? limit,
|
|
2643
|
+
total: data.pagination.total ?? items.length,
|
|
2644
|
+
totalPages: data.pagination.totalPages ?? 1
|
|
2645
|
+
});
|
|
2646
|
+
}
|
|
2647
|
+
return items;
|
|
2648
|
+
} catch (err) {
|
|
2649
|
+
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
2650
|
+
setError(errorObj);
|
|
2651
|
+
return [];
|
|
2652
|
+
} finally {
|
|
2653
|
+
setIsLoading(false);
|
|
2654
|
+
}
|
|
2655
|
+
}, [fetchWithAuth, workflowId, page, limit]);
|
|
2656
|
+
const getRun = (0, import_react14.useCallback)(
|
|
2657
|
+
async (runId) => {
|
|
2658
|
+
if (!runId) throw new Error("Run ID is required");
|
|
2659
|
+
const res = await fetchWithAuth(`/workflows/runs/${runId}`);
|
|
2660
|
+
if (!res.ok) {
|
|
2661
|
+
throw new Error(`Failed to fetch workflow run (${res.status}): ${res.statusText}`);
|
|
2662
|
+
}
|
|
2663
|
+
return await res.json();
|
|
2664
|
+
},
|
|
2665
|
+
[fetchWithAuth]
|
|
2666
|
+
);
|
|
2667
|
+
const cancelRun = (0, import_react14.useCallback)(
|
|
2668
|
+
async (runId) => {
|
|
2669
|
+
if (!runId) throw new Error("Run ID is required");
|
|
2670
|
+
const res = await fetchWithAuth(`/workflows/runs/${runId}/cancel`, {
|
|
2671
|
+
method: "POST"
|
|
2672
|
+
});
|
|
2673
|
+
if (!res.ok) {
|
|
2674
|
+
throw new Error(`Failed to cancel workflow run (${res.status}): ${res.statusText}`);
|
|
2675
|
+
}
|
|
2676
|
+
setRuns(
|
|
2677
|
+
(prev) => prev.map((r) => r._id === runId ? { ...r, status: "cancelled" } : r)
|
|
2678
|
+
);
|
|
2679
|
+
},
|
|
2680
|
+
[fetchWithAuth]
|
|
2681
|
+
);
|
|
2682
|
+
(0, import_react14.useEffect)(() => {
|
|
2683
|
+
if (autoFetch && workflowId) {
|
|
2684
|
+
void fetchRuns();
|
|
2685
|
+
}
|
|
2686
|
+
}, [autoFetch, workflowId, fetchRuns]);
|
|
2687
|
+
return {
|
|
2688
|
+
runs,
|
|
2689
|
+
pagination,
|
|
2690
|
+
isLoading,
|
|
2691
|
+
error,
|
|
2692
|
+
refetch: fetchRuns,
|
|
2693
|
+
getRun,
|
|
2694
|
+
cancelRun
|
|
2695
|
+
};
|
|
2696
|
+
}
|
|
2697
|
+
|
|
2100
2698
|
// src/index.ts
|
|
2101
2699
|
var import_logger2 = require("@personaai/logger");
|
|
2102
|
-
var VERSION = "0.
|
|
2700
|
+
var VERSION = "0.9.0";
|
|
2103
2701
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2104
2702
|
0 && (module.exports = {
|
|
2105
2703
|
PersonaProvider,
|
|
@@ -2120,6 +2718,10 @@ var VERSION = "0.8.0";
|
|
|
2120
2718
|
useMemory,
|
|
2121
2719
|
usePersonaContext,
|
|
2122
2720
|
useThreads,
|
|
2123
|
-
useVoice
|
|
2721
|
+
useVoice,
|
|
2722
|
+
useWorkflow,
|
|
2723
|
+
useWorkflowRuns,
|
|
2724
|
+
useWorkflowStream,
|
|
2725
|
+
useWorkflows
|
|
2124
2726
|
});
|
|
2125
2727
|
//# sourceMappingURL=index.cjs.map
|