@paymanai/payman-typescript-ask-sdk 1.2.11 → 2.0.1
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.d.mts +136 -108
- package/dist/index.d.ts +136 -108
- package/dist/index.js +589 -1203
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +588 -1204
- package/dist/index.mjs.map +1 -1
- package/dist/index.native.js +591 -1205
- package/dist/index.native.js.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { useState, useRef, useCallback,
|
|
1
|
+
import { useMemo, useState, useRef, useCallback, useEffect } from 'react';
|
|
2
2
|
|
|
3
|
-
// src/hooks/
|
|
3
|
+
// src/hooks/useChatV2.ts
|
|
4
4
|
|
|
5
5
|
// src/utils/generateId.ts
|
|
6
6
|
function generateId() {
|
|
@@ -145,13 +145,13 @@ function getEventMessage(event) {
|
|
|
145
145
|
case "USER_ACTION_REQUIRED":
|
|
146
146
|
return "Waiting for verification...";
|
|
147
147
|
case "USER_ACTION_SUCCESS":
|
|
148
|
-
return "Verification
|
|
148
|
+
return "Verification approved";
|
|
149
149
|
case "USER_ACTION_EXPIRED":
|
|
150
150
|
return "Verification expired";
|
|
151
151
|
case "USER_ACTION_INVALID":
|
|
152
|
-
return "Invalid
|
|
152
|
+
return "Invalid code. Please try again.";
|
|
153
153
|
case "USER_ACTION_REJECTED":
|
|
154
|
-
return "Verification
|
|
154
|
+
return "Verification cancelled";
|
|
155
155
|
case "USER_ACTION_RESENT":
|
|
156
156
|
return "Verification code resent";
|
|
157
157
|
case "USER_ACTION_FAILED":
|
|
@@ -166,6 +166,31 @@ function getEventMessage(event) {
|
|
|
166
166
|
return eventType;
|
|
167
167
|
}
|
|
168
168
|
}
|
|
169
|
+
function isUserActionPrompt(text) {
|
|
170
|
+
return /\benter\b.+\b(code|otp)\b/i.test(text) || /\b(authorization|verification)\s+code\b/i.test(text) || /\bsent\s+to\s+your\b/i.test(text);
|
|
171
|
+
}
|
|
172
|
+
function getUserActionDisplayMessage(eventType, rawMessage) {
|
|
173
|
+
const raw = rawMessage?.trim();
|
|
174
|
+
const safeRaw = raw && !isUserActionPrompt(raw) ? raw : "";
|
|
175
|
+
switch (eventType) {
|
|
176
|
+
case "USER_ACTION_REQUIRED":
|
|
177
|
+
return raw || "Waiting for verification...";
|
|
178
|
+
case "USER_ACTION_SUCCESS":
|
|
179
|
+
return safeRaw || "Verification approved";
|
|
180
|
+
case "USER_ACTION_INVALID":
|
|
181
|
+
return safeRaw || "Invalid code. Please try again.";
|
|
182
|
+
case "USER_ACTION_REJECTED":
|
|
183
|
+
return safeRaw || "Verification cancelled";
|
|
184
|
+
case "USER_ACTION_EXPIRED":
|
|
185
|
+
return safeRaw || "Verification expired";
|
|
186
|
+
case "USER_ACTION_RESENT":
|
|
187
|
+
return safeRaw || "Verification code resent";
|
|
188
|
+
case "USER_ACTION_FAILED":
|
|
189
|
+
return safeRaw || "Verification failed";
|
|
190
|
+
default:
|
|
191
|
+
return safeRaw || raw || eventType;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
169
194
|
function workingPhaseDetailForDisplay(raw) {
|
|
170
195
|
const t = raw.trim();
|
|
171
196
|
if (!t) return "";
|
|
@@ -196,290 +221,8 @@ function extractResponseContent(response) {
|
|
|
196
221
|
}
|
|
197
222
|
return "";
|
|
198
223
|
}
|
|
199
|
-
function completeLastInProgressStep(steps) {
|
|
200
|
-
for (let i = steps.length - 1; i >= 0; i--) {
|
|
201
|
-
if (steps[i].status === "in_progress") {
|
|
202
|
-
steps[i].status = "completed";
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
function processStreamEvent(event, state) {
|
|
208
|
-
const eventType = event.eventType;
|
|
209
|
-
if (typeof eventType === "string" && eventType.toUpperCase() === "KEEP_ALIVE") {
|
|
210
|
-
return state;
|
|
211
|
-
}
|
|
212
|
-
const message = getEventMessage(event);
|
|
213
|
-
if (eventType !== "INTENT_THINKING" && eventType !== "INTENT_THINKING_CONT") {
|
|
214
|
-
if (state.currentThinkingStepId) {
|
|
215
|
-
const thinkingStep = state.steps.find((s) => s.id === state.currentThinkingStepId);
|
|
216
|
-
if (thinkingStep) {
|
|
217
|
-
thinkingStep.isThinking = false;
|
|
218
|
-
}
|
|
219
|
-
state.currentThinkingStepId = void 0;
|
|
220
|
-
}
|
|
221
|
-
state.activeThinkingText = void 0;
|
|
222
|
-
}
|
|
223
|
-
if (eventType === "COMPLETED" || eventType === "WORKFLOW_COMPLETED") {
|
|
224
|
-
let content = extractResponseContent(event.response);
|
|
225
|
-
const trace = event.trace && typeof event.trace === "object" ? event.trace : null;
|
|
226
|
-
if (!content && trace?.workflowMsg && typeof trace.workflowMsg === "string") {
|
|
227
|
-
content = trace.workflowMsg;
|
|
228
|
-
}
|
|
229
|
-
if (!content && trace?.aggregator && typeof trace.aggregator === "object") {
|
|
230
|
-
const agg = trace.aggregator;
|
|
231
|
-
if (typeof agg.response === "string") content = agg.response;
|
|
232
|
-
else content = extractResponseContent(agg.response);
|
|
233
|
-
}
|
|
234
|
-
if (content) {
|
|
235
|
-
state.accumulatedContent = content;
|
|
236
|
-
state.finalData = event.response ?? event.trace;
|
|
237
|
-
state.hasError = false;
|
|
238
|
-
state.errorMessage = "";
|
|
239
|
-
} else {
|
|
240
|
-
state.hasError = true;
|
|
241
|
-
state.errorMessage = "WORKFLOW_FAILED";
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
if (eventType === "STARTED" || eventType === "WORKFLOW_STARTED") ; else if (eventType === "COMPLETED" || eventType === "WORKFLOW_COMPLETED") {
|
|
245
|
-
state.steps.forEach((step) => {
|
|
246
|
-
if (step.status === "in_progress") {
|
|
247
|
-
step.status = "completed";
|
|
248
|
-
}
|
|
249
|
-
});
|
|
250
|
-
} else if (eventType === "INTENT_ERROR") {
|
|
251
|
-
state.errorMessage = message || event.errorMessage || "An error occurred";
|
|
252
|
-
const intentStep = state.steps.find(
|
|
253
|
-
(s) => s.eventType === "INTENT_STARTED" && s.status === "in_progress"
|
|
254
|
-
);
|
|
255
|
-
if (intentStep) {
|
|
256
|
-
intentStep.status = "error";
|
|
257
|
-
}
|
|
258
|
-
} else if (eventType === "ERROR" || eventType === "WORKFLOW_ERROR") {
|
|
259
|
-
state.hasError = true;
|
|
260
|
-
state.errorMessage = message || event.errorMessage || "An error occurred";
|
|
261
|
-
} else if (eventType === "ORCHESTRATOR_COMPLETED") {
|
|
262
|
-
state.inOrchestratorPhase = false;
|
|
263
|
-
const orchestratorStep = state.steps.find(
|
|
264
|
-
(s) => s.eventType === "ORCHESTRATOR_THINKING" && s.status === "in_progress"
|
|
265
|
-
);
|
|
266
|
-
if (orchestratorStep) {
|
|
267
|
-
orchestratorStep.status = "completed";
|
|
268
|
-
if (event.elapsedMs) {
|
|
269
|
-
orchestratorStep.elapsedMs = event.elapsedMs;
|
|
270
|
-
}
|
|
271
|
-
if (orchestratorStep.id === state.currentExecutingStepId) {
|
|
272
|
-
state.currentExecutingStepId = void 0;
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
} else if (eventType === "INTENT_COMPLETED") {
|
|
276
|
-
const intentStep = state.steps.find(
|
|
277
|
-
(s) => s.eventType === "INTENT_STARTED" && s.status === "in_progress"
|
|
278
|
-
);
|
|
279
|
-
if (intentStep) {
|
|
280
|
-
intentStep.status = "completed";
|
|
281
|
-
if (event.elapsedMs) {
|
|
282
|
-
intentStep.elapsedMs = event.elapsedMs;
|
|
283
|
-
}
|
|
284
|
-
if (intentStep.id === state.currentExecutingStepId) {
|
|
285
|
-
state.currentExecutingStepId = void 0;
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
} else if (eventType === "AGGREGATOR_COMPLETED") {
|
|
289
|
-
state.inAggregatorPhase = false;
|
|
290
|
-
const aggregatorStep = state.steps.find(
|
|
291
|
-
(s) => s.eventType === "AGGREGATOR_THINKING" && s.status === "in_progress"
|
|
292
|
-
);
|
|
293
|
-
if (aggregatorStep) {
|
|
294
|
-
aggregatorStep.status = "completed";
|
|
295
|
-
if (event.elapsedMs) {
|
|
296
|
-
aggregatorStep.elapsedMs = event.elapsedMs;
|
|
297
|
-
}
|
|
298
|
-
if (aggregatorStep.id === state.currentExecutingStepId) {
|
|
299
|
-
state.currentExecutingStepId = void 0;
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
} else if (eventType === "ORCHESTRATOR_THINKING" || eventType === "INTENT_STARTED" || eventType === "INTENT_PROGRESS" || eventType === "AGGREGATOR_THINKING") {
|
|
303
|
-
if (eventType === "ORCHESTRATOR_THINKING") {
|
|
304
|
-
state.inOrchestratorPhase = true;
|
|
305
|
-
}
|
|
306
|
-
if (eventType === "AGGREGATOR_THINKING") {
|
|
307
|
-
state.inAggregatorPhase = true;
|
|
308
|
-
}
|
|
309
|
-
if (eventType === "INTENT_PROGRESS") {
|
|
310
|
-
const intentStep = state.steps.find(
|
|
311
|
-
(s) => s.eventType === "INTENT_STARTED" && s.status === "in_progress"
|
|
312
|
-
);
|
|
313
|
-
if (intentStep) {
|
|
314
|
-
intentStep.message = message;
|
|
315
|
-
state.currentExecutingStepId = intentStep.id;
|
|
316
|
-
} else {
|
|
317
|
-
const stepId = `step-${state.stepCounter++}`;
|
|
318
|
-
state.steps.push({
|
|
319
|
-
id: stepId,
|
|
320
|
-
eventType: "INTENT_STARTED",
|
|
321
|
-
message,
|
|
322
|
-
status: "in_progress",
|
|
323
|
-
timestamp: Date.now(),
|
|
324
|
-
elapsedMs: event.elapsedMs
|
|
325
|
-
});
|
|
326
|
-
state.currentExecutingStepId = stepId;
|
|
327
|
-
}
|
|
328
|
-
} else {
|
|
329
|
-
const stepId = `step-${state.stepCounter++}`;
|
|
330
|
-
state.steps.push({
|
|
331
|
-
id: stepId,
|
|
332
|
-
eventType,
|
|
333
|
-
message,
|
|
334
|
-
status: "in_progress",
|
|
335
|
-
timestamp: Date.now(),
|
|
336
|
-
elapsedMs: event.elapsedMs
|
|
337
|
-
});
|
|
338
|
-
state.currentExecutingStepId = stepId;
|
|
339
|
-
}
|
|
340
|
-
} else if (eventType === "USER_ACTION_REQUIRED") {
|
|
341
|
-
completeLastInProgressStep(state.steps);
|
|
342
|
-
if (event.userActionRequest) {
|
|
343
|
-
state.userActionRequest = {
|
|
344
|
-
userActionId: event.userActionRequest.userActionId,
|
|
345
|
-
userActionType: event.userActionRequest.userActionType,
|
|
346
|
-
message: event.userActionRequest.message,
|
|
347
|
-
requestedSchema: event.userActionRequest.requestedSchema,
|
|
348
|
-
metadata: event.userActionRequest.metadata
|
|
349
|
-
};
|
|
350
|
-
}
|
|
351
|
-
state.userActionPending = true;
|
|
352
|
-
const stepId = `step-${state.stepCounter++}`;
|
|
353
|
-
state.steps.push({
|
|
354
|
-
id: stepId,
|
|
355
|
-
eventType,
|
|
356
|
-
message,
|
|
357
|
-
status: "in_progress",
|
|
358
|
-
timestamp: Date.now(),
|
|
359
|
-
elapsedMs: event.elapsedMs
|
|
360
|
-
});
|
|
361
|
-
state.currentExecutingStepId = stepId;
|
|
362
|
-
} else if (eventType === "USER_ACTION_SUCCESS") {
|
|
363
|
-
completeLastInProgressStep(state.steps);
|
|
364
|
-
state.userActionRequest = void 0;
|
|
365
|
-
state.userActionPending = false;
|
|
366
|
-
state.userActionResult = "approved";
|
|
367
|
-
const stepId = `step-${state.stepCounter++}`;
|
|
368
|
-
state.steps.push({
|
|
369
|
-
id: stepId,
|
|
370
|
-
eventType,
|
|
371
|
-
message,
|
|
372
|
-
status: "completed",
|
|
373
|
-
timestamp: Date.now(),
|
|
374
|
-
elapsedMs: event.elapsedMs
|
|
375
|
-
});
|
|
376
|
-
} else if (eventType === "USER_ACTION_INVALID") {
|
|
377
|
-
completeLastInProgressStep(state.steps);
|
|
378
|
-
const errorStepId = `step-${state.stepCounter++}`;
|
|
379
|
-
state.steps.push({
|
|
380
|
-
id: errorStepId,
|
|
381
|
-
eventType,
|
|
382
|
-
message,
|
|
383
|
-
status: "error",
|
|
384
|
-
timestamp: Date.now(),
|
|
385
|
-
elapsedMs: event.elapsedMs
|
|
386
|
-
});
|
|
387
|
-
const retryStepId = `step-${state.stepCounter++}`;
|
|
388
|
-
state.steps.push({
|
|
389
|
-
id: retryStepId,
|
|
390
|
-
eventType: "USER_ACTION_REQUIRED",
|
|
391
|
-
message: "Waiting for verification...",
|
|
392
|
-
status: "in_progress",
|
|
393
|
-
timestamp: Date.now()
|
|
394
|
-
});
|
|
395
|
-
state.currentExecutingStepId = retryStepId;
|
|
396
|
-
} else if (eventType === "USER_ACTION_EXPIRED") {
|
|
397
|
-
completeLastInProgressStep(state.steps);
|
|
398
|
-
state.userActionRequest = void 0;
|
|
399
|
-
state.userActionPending = false;
|
|
400
|
-
const stepId = `step-${state.stepCounter++}`;
|
|
401
|
-
state.steps.push({
|
|
402
|
-
id: stepId,
|
|
403
|
-
eventType,
|
|
404
|
-
message,
|
|
405
|
-
status: "error",
|
|
406
|
-
timestamp: Date.now(),
|
|
407
|
-
elapsedMs: event.elapsedMs
|
|
408
|
-
});
|
|
409
|
-
} else if (eventType === "USER_ACTION_REJECTED") {
|
|
410
|
-
completeLastInProgressStep(state.steps);
|
|
411
|
-
state.userActionRequest = void 0;
|
|
412
|
-
state.userActionPending = false;
|
|
413
|
-
state.userActionResult = "rejected";
|
|
414
|
-
const stepId = `step-${state.stepCounter++}`;
|
|
415
|
-
state.steps.push({
|
|
416
|
-
id: stepId,
|
|
417
|
-
eventType,
|
|
418
|
-
message,
|
|
419
|
-
status: "completed",
|
|
420
|
-
timestamp: Date.now(),
|
|
421
|
-
elapsedMs: event.elapsedMs
|
|
422
|
-
});
|
|
423
|
-
} else if (eventType === "USER_ACTION_RESENT") {
|
|
424
|
-
const stepId = `step-${state.stepCounter++}`;
|
|
425
|
-
state.steps.push({
|
|
426
|
-
id: stepId,
|
|
427
|
-
eventType,
|
|
428
|
-
message,
|
|
429
|
-
status: "completed",
|
|
430
|
-
timestamp: Date.now(),
|
|
431
|
-
elapsedMs: event.elapsedMs
|
|
432
|
-
});
|
|
433
|
-
} else if (eventType === "USER_ACTION_FAILED") {
|
|
434
|
-
completeLastInProgressStep(state.steps);
|
|
435
|
-
state.userActionRequest = void 0;
|
|
436
|
-
state.userActionPending = false;
|
|
437
|
-
const stepId = `step-${state.stepCounter++}`;
|
|
438
|
-
state.steps.push({
|
|
439
|
-
id: stepId,
|
|
440
|
-
eventType,
|
|
441
|
-
message,
|
|
442
|
-
status: "error",
|
|
443
|
-
timestamp: Date.now(),
|
|
444
|
-
elapsedMs: event.elapsedMs
|
|
445
|
-
});
|
|
446
|
-
} else if (eventType === "INTENT_THINKING") {
|
|
447
|
-
if (state.currentThinkingStepId) {
|
|
448
|
-
const prev = state.steps.find((s) => s.id === state.currentThinkingStepId);
|
|
449
|
-
if (prev) prev.isThinking = false;
|
|
450
|
-
}
|
|
451
|
-
const lastInProgress = [...state.steps].reverse().find((s) => s.status === "in_progress");
|
|
452
|
-
if (lastInProgress) {
|
|
453
|
-
lastInProgress.thinkingText = "";
|
|
454
|
-
lastInProgress.isThinking = true;
|
|
455
|
-
state.currentThinkingStepId = lastInProgress.id;
|
|
456
|
-
} else {
|
|
457
|
-
state.currentThinkingStepId = void 0;
|
|
458
|
-
}
|
|
459
|
-
if (state.allThinkingText) state.allThinkingText += "\n\n";
|
|
460
|
-
if (!state.inOrchestratorPhase && !state.inAggregatorPhase) {
|
|
461
|
-
state.activeThinkingText = "";
|
|
462
|
-
}
|
|
463
|
-
} else if (eventType === "INTENT_THINKING_CONT") {
|
|
464
|
-
const delta = event.message || "";
|
|
465
|
-
if (!delta) return state;
|
|
466
|
-
if (state.currentThinkingStepId) {
|
|
467
|
-
const step = state.steps.find((s) => s.id === state.currentThinkingStepId);
|
|
468
|
-
if (step) {
|
|
469
|
-
step.thinkingText = (step.thinkingText || "") + delta;
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
state.allThinkingText += delta;
|
|
473
|
-
if (!state.inOrchestratorPhase && !state.inAggregatorPhase) {
|
|
474
|
-
if (state.activeThinkingText == null) state.activeThinkingText = "";
|
|
475
|
-
state.activeThinkingText += delta;
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
return state;
|
|
479
|
-
}
|
|
480
224
|
|
|
481
225
|
// src/utils/messageStateManager.ts
|
|
482
|
-
var FRIENDLY_ERROR_MESSAGE = "Oops, something went wrong. Please try again.";
|
|
483
226
|
function buildFormattedThinking(steps, allThinkingText) {
|
|
484
227
|
const parts = [];
|
|
485
228
|
const safeSteps = steps ?? [];
|
|
@@ -536,91 +279,32 @@ function buildFormattedThinking(steps, allThinkingText) {
|
|
|
536
279
|
break;
|
|
537
280
|
case "USER_ACTION_REQUIRED":
|
|
538
281
|
parts.push("**Verification Required**");
|
|
539
|
-
if (step.message)
|
|
282
|
+
if (step.message) {
|
|
283
|
+
parts.push(getUserActionDisplayMessage(step.eventType, step.message));
|
|
284
|
+
}
|
|
540
285
|
break;
|
|
541
286
|
case "USER_ACTION_SUCCESS":
|
|
542
|
-
parts.push(`\u2713 ${step.message
|
|
287
|
+
parts.push(`\u2713 ${getUserActionDisplayMessage(step.eventType, step.message)}`);
|
|
543
288
|
break;
|
|
544
289
|
case "USER_ACTION_REJECTED":
|
|
545
|
-
parts.push(
|
|
290
|
+
parts.push(getUserActionDisplayMessage(step.eventType, step.message));
|
|
546
291
|
break;
|
|
547
292
|
case "USER_ACTION_EXPIRED":
|
|
548
|
-
parts.push(`\u2717 ${step.message
|
|
293
|
+
parts.push(`\u2717 ${getUserActionDisplayMessage(step.eventType, step.message)}`);
|
|
294
|
+
break;
|
|
295
|
+
case "USER_ACTION_INVALID":
|
|
296
|
+
parts.push(`\u2717 ${getUserActionDisplayMessage(step.eventType, step.message)}`);
|
|
297
|
+
break;
|
|
298
|
+
case "USER_ACTION_RESENT":
|
|
299
|
+
parts.push(getUserActionDisplayMessage(step.eventType, step.message));
|
|
549
300
|
break;
|
|
550
301
|
case "USER_ACTION_FAILED":
|
|
551
|
-
parts.push(`\u2717 ${step.message
|
|
302
|
+
parts.push(`\u2717 ${getUserActionDisplayMessage(step.eventType, step.message)}`);
|
|
552
303
|
break;
|
|
553
304
|
}
|
|
554
305
|
}
|
|
555
306
|
return parts.length > 0 ? parts.join("\n") : allThinkingText;
|
|
556
307
|
}
|
|
557
|
-
function createStreamingMessageUpdate(state) {
|
|
558
|
-
const hasCompletedContent = state.accumulatedContent && state.finalData !== void 0;
|
|
559
|
-
const steps = state.hasError ? [] : [...state.steps];
|
|
560
|
-
const allThinking = state.hasError ? void 0 : state.allThinkingText;
|
|
561
|
-
return {
|
|
562
|
-
streamingContent: state.hasError ? FRIENDLY_ERROR_MESSAGE : hasCompletedContent ? state.accumulatedContent : "",
|
|
563
|
-
content: state.hasError ? FRIENDLY_ERROR_MESSAGE : "",
|
|
564
|
-
currentMessage: state.hasError ? void 0 : state.currentMessage,
|
|
565
|
-
streamProgress: state.hasError ? "error" : "processing",
|
|
566
|
-
isError: state.hasError,
|
|
567
|
-
errorDetails: state.hasError ? state.errorMessage : void 0,
|
|
568
|
-
executionId: state.executionId,
|
|
569
|
-
sessionId: state.sessionId,
|
|
570
|
-
steps,
|
|
571
|
-
currentExecutingStepId: state.hasError ? void 0 : state.currentExecutingStepId,
|
|
572
|
-
isCancelled: false,
|
|
573
|
-
userActionResult: state.userActionResult,
|
|
574
|
-
activeThinkingText: state.hasError ? void 0 : state.activeThinkingText,
|
|
575
|
-
allThinkingText: allThinking,
|
|
576
|
-
formattedThinkingText: state.hasError ? void 0 : buildFormattedThinking(steps, allThinking || "")
|
|
577
|
-
};
|
|
578
|
-
}
|
|
579
|
-
function createErrorMessageUpdate(error, state) {
|
|
580
|
-
const isAborted = error.name === "AbortError";
|
|
581
|
-
return {
|
|
582
|
-
isStreaming: false,
|
|
583
|
-
streamProgress: isAborted ? "processing" : "error",
|
|
584
|
-
isError: !isAborted,
|
|
585
|
-
isCancelled: isAborted,
|
|
586
|
-
errorDetails: isAborted ? void 0 : error.message,
|
|
587
|
-
content: isAborted ? state.accumulatedContent || "" : state.accumulatedContent || FRIENDLY_ERROR_MESSAGE,
|
|
588
|
-
// Preserve currentMessage when cancelled so UI can show it
|
|
589
|
-
currentMessage: isAborted ? state.currentMessage || "Thinking..." : void 0,
|
|
590
|
-
steps: [...state.steps].map((step) => {
|
|
591
|
-
if (step.status === "in_progress" && isAborted) {
|
|
592
|
-
return { ...step, status: "pending" };
|
|
593
|
-
}
|
|
594
|
-
return step;
|
|
595
|
-
}),
|
|
596
|
-
currentExecutingStepId: void 0
|
|
597
|
-
};
|
|
598
|
-
}
|
|
599
|
-
function createFinalMessage(streamingId, state) {
|
|
600
|
-
const steps = state.hasError ? [] : [...state.steps];
|
|
601
|
-
const allThinking = state.hasError ? void 0 : state.allThinkingText;
|
|
602
|
-
return {
|
|
603
|
-
id: streamingId,
|
|
604
|
-
sessionId: state.sessionId,
|
|
605
|
-
role: "assistant",
|
|
606
|
-
content: state.hasError ? FRIENDLY_ERROR_MESSAGE : state.accumulatedContent || "",
|
|
607
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
608
|
-
isStreaming: false,
|
|
609
|
-
streamProgress: state.hasError ? "error" : "completed",
|
|
610
|
-
isError: state.hasError,
|
|
611
|
-
errorDetails: state.hasError ? state.errorMessage : void 0,
|
|
612
|
-
executionId: state.executionId,
|
|
613
|
-
tracingData: state.finalData,
|
|
614
|
-
steps,
|
|
615
|
-
isCancelled: false,
|
|
616
|
-
currentExecutingStepId: void 0,
|
|
617
|
-
userActionResult: state.userActionResult,
|
|
618
|
-
activeThinkingText: void 0,
|
|
619
|
-
allThinkingText: allThinking,
|
|
620
|
-
formattedThinkingText: state.hasError ? void 0 : buildFormattedThinking(steps, allThinking || ""),
|
|
621
|
-
isResolvingImages: state.hasError ? void 0 : state.isResolvingImages
|
|
622
|
-
};
|
|
623
|
-
}
|
|
624
308
|
function createCancelledMessageUpdate(steps, currentMessage) {
|
|
625
309
|
const updatedSteps = steps.map((step) => {
|
|
626
310
|
if (step.status === "in_progress") {
|
|
@@ -640,35 +324,44 @@ function createCancelledMessageUpdate(steps, currentMessage) {
|
|
|
640
324
|
|
|
641
325
|
// src/utils/requestBuilder.ts
|
|
642
326
|
function buildRequestBody(config, userMessage, sessionId) {
|
|
643
|
-
const
|
|
644
|
-
const sessionAttributes =
|
|
327
|
+
const owner = config.session?.owner;
|
|
328
|
+
const sessionAttributes = owner?.attributes && Object.keys(owner.attributes).length > 0 ? owner.attributes : void 0;
|
|
645
329
|
return {
|
|
646
|
-
workflowName: config.
|
|
330
|
+
workflowName: config.workflow.name,
|
|
647
331
|
userInput: userMessage,
|
|
648
332
|
sessionId,
|
|
649
|
-
sessionOwnerId:
|
|
650
|
-
sessionOwnerLabel:
|
|
333
|
+
sessionOwnerId: owner?.id || "",
|
|
334
|
+
sessionOwnerLabel: owner?.name || "",
|
|
651
335
|
sessionAttributes,
|
|
652
336
|
options: {
|
|
653
337
|
clientTimezone: Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
654
338
|
}
|
|
655
339
|
};
|
|
656
340
|
}
|
|
341
|
+
function getStageParamName(config) {
|
|
342
|
+
return config.api.stageQueryParam ?? "stage";
|
|
343
|
+
}
|
|
344
|
+
function getStage(config) {
|
|
345
|
+
return config.workflow.stage ?? "DEV";
|
|
346
|
+
}
|
|
657
347
|
function buildStreamingUrl(config) {
|
|
658
348
|
const endpoint = config.api.streamEndpoint || "/api/workflows/ask/stream";
|
|
659
|
-
const
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
if (config.
|
|
663
|
-
queryParams.append("workflowVersion", String(config.
|
|
349
|
+
const queryParams = new URLSearchParams({
|
|
350
|
+
[getStageParamName(config)]: getStage(config)
|
|
351
|
+
});
|
|
352
|
+
if (config.workflow.version !== void 0) {
|
|
353
|
+
queryParams.append("workflowVersion", String(config.workflow.version));
|
|
664
354
|
}
|
|
665
355
|
return `${config.api.baseUrl}${endpoint}?${queryParams.toString()}`;
|
|
666
356
|
}
|
|
667
|
-
function
|
|
357
|
+
function deriveBasePath(config) {
|
|
668
358
|
const endpoint = config.api.streamEndpoint || "/api/workflows/ask/stream";
|
|
669
359
|
const [endpointPath] = endpoint.split("?");
|
|
670
|
-
const
|
|
671
|
-
|
|
360
|
+
const normalized = endpointPath.replace(/\/+$/, "");
|
|
361
|
+
return normalized.endsWith("/stream") ? normalized.slice(0, -"/stream".length) : normalized;
|
|
362
|
+
}
|
|
363
|
+
function buildUserActionUrl(config, userActionId, action) {
|
|
364
|
+
const basePath = deriveBasePath(config);
|
|
672
365
|
const encodedUserActionId = encodeURIComponent(userActionId);
|
|
673
366
|
return `${config.api.baseUrl}${basePath}/user-action/${encodedUserActionId}/${action}`;
|
|
674
367
|
}
|
|
@@ -676,21 +369,23 @@ function buildResolveImagesUrl(config) {
|
|
|
676
369
|
if (config.api.resolveImagesEndpoint) {
|
|
677
370
|
return `${config.api.baseUrl}${config.api.resolveImagesEndpoint}`;
|
|
678
371
|
}
|
|
679
|
-
|
|
680
|
-
const [endpointPath] = streamEndpoint.split("?");
|
|
681
|
-
const normalizedEndpointPath = endpointPath.replace(/\/+$/, "");
|
|
682
|
-
const basePath = normalizedEndpointPath.endsWith("/stream") ? normalizedEndpointPath.slice(0, -"/stream".length) : normalizedEndpointPath;
|
|
683
|
-
return `${config.api.baseUrl}${basePath}/resolve-image-urls`;
|
|
372
|
+
return `${config.api.baseUrl}${deriveBasePath(config)}/resolve-image-urls`;
|
|
684
373
|
}
|
|
685
374
|
function buildRequestHeaders(config) {
|
|
686
|
-
const headers = {
|
|
687
|
-
...config.api.headers
|
|
688
|
-
};
|
|
375
|
+
const headers = { ...config.api.headers };
|
|
689
376
|
if (config.api.authToken) {
|
|
690
377
|
headers.Authorization = `Bearer ${config.api.authToken}`;
|
|
691
378
|
}
|
|
692
379
|
return headers;
|
|
693
380
|
}
|
|
381
|
+
function buildScopeKey(config) {
|
|
382
|
+
return [
|
|
383
|
+
config.session?.userId ?? "",
|
|
384
|
+
config.workflow.id ?? "",
|
|
385
|
+
config.workflow.version ?? "",
|
|
386
|
+
config.workflow.stage ?? ""
|
|
387
|
+
].join("|");
|
|
388
|
+
}
|
|
694
389
|
|
|
695
390
|
// src/utils/userActionClient.ts
|
|
696
391
|
async function sendUserActionRequest(config, userActionId, action, data) {
|
|
@@ -706,683 +401,96 @@ async function sendUserActionRequest(config, userActionId, action, data) {
|
|
|
706
401
|
if (!response.ok) {
|
|
707
402
|
const errorText = await response.text();
|
|
708
403
|
throw new Error(`HTTP ${response.status}: ${errorText}`);
|
|
709
|
-
}
|
|
710
|
-
return await response.json();
|
|
711
|
-
}
|
|
712
|
-
async function submitUserAction(config, userActionId, data) {
|
|
713
|
-
return sendUserActionRequest(config, userActionId, "submit", data);
|
|
714
|
-
}
|
|
715
|
-
async function cancelUserAction(config, userActionId) {
|
|
716
|
-
return sendUserActionRequest(config, userActionId, "cancel");
|
|
717
|
-
}
|
|
718
|
-
async function resendUserAction(config, userActionId) {
|
|
719
|
-
return sendUserActionRequest(config, userActionId, "resend");
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
// src/utils/chatStore.ts
|
|
723
|
-
var memoryStore = /* @__PURE__ */ new Map();
|
|
724
|
-
var chatStore = {
|
|
725
|
-
get(key) {
|
|
726
|
-
return memoryStore.get(key) ?? [];
|
|
727
|
-
},
|
|
728
|
-
set(key, messages) {
|
|
729
|
-
memoryStore.set(key, messages);
|
|
730
|
-
},
|
|
731
|
-
delete(key) {
|
|
732
|
-
memoryStore.delete(key);
|
|
733
|
-
}
|
|
734
|
-
};
|
|
735
|
-
|
|
736
|
-
// src/utils/activeStreamStore.ts
|
|
737
|
-
var streams = /* @__PURE__ */ new Map();
|
|
738
|
-
var activeStreamStore = {
|
|
739
|
-
has(key) {
|
|
740
|
-
return streams.has(key);
|
|
741
|
-
},
|
|
742
|
-
get(key) {
|
|
743
|
-
const entry = streams.get(key);
|
|
744
|
-
if (!entry) return null;
|
|
745
|
-
return { messages: entry.messages, isWaiting: entry.isWaiting };
|
|
746
|
-
},
|
|
747
|
-
// Called before startStream — registers the controller and initial messages
|
|
748
|
-
start(key, abortController, initialMessages) {
|
|
749
|
-
const existing = streams.get(key);
|
|
750
|
-
streams.set(key, {
|
|
751
|
-
messages: initialMessages,
|
|
752
|
-
isWaiting: true,
|
|
753
|
-
abortController,
|
|
754
|
-
listeners: existing?.listeners ?? /* @__PURE__ */ new Set()
|
|
755
|
-
});
|
|
756
|
-
},
|
|
757
|
-
// Called by the stream on every event — applies the same updater pattern React uses
|
|
758
|
-
applyMessages(key, updater) {
|
|
759
|
-
const entry = streams.get(key);
|
|
760
|
-
if (!entry) return;
|
|
761
|
-
const next = typeof updater === "function" ? updater(entry.messages) : updater;
|
|
762
|
-
entry.messages = next;
|
|
763
|
-
entry.listeners.forEach((l) => l(next, entry.isWaiting));
|
|
764
|
-
},
|
|
765
|
-
setWaiting(key, waiting) {
|
|
766
|
-
const entry = streams.get(key);
|
|
767
|
-
if (!entry) return;
|
|
768
|
-
entry.isWaiting = waiting;
|
|
769
|
-
entry.listeners.forEach((l) => l(entry.messages, waiting));
|
|
770
|
-
},
|
|
771
|
-
// Called when stream completes — persists to chatStore and cleans up
|
|
772
|
-
complete(key) {
|
|
773
|
-
const entry = streams.get(key);
|
|
774
|
-
if (!entry) return;
|
|
775
|
-
entry.isWaiting = false;
|
|
776
|
-
entry.listeners.forEach((l) => l(entry.messages, false));
|
|
777
|
-
const toSave = entry.messages.filter((m) => !m.isStreaming);
|
|
778
|
-
if (toSave.length > 0) chatStore.set(key, toSave);
|
|
779
|
-
streams.delete(key);
|
|
780
|
-
},
|
|
781
|
-
// Subscribe — returns unsubscribe fn. Component calls this on mount, cleanup on unmount.
|
|
782
|
-
subscribe(key, listener) {
|
|
783
|
-
const entry = streams.get(key);
|
|
784
|
-
if (!entry) return () => {
|
|
785
|
-
};
|
|
786
|
-
entry.listeners.add(listener);
|
|
787
|
-
return () => {
|
|
788
|
-
streams.get(key)?.listeners.delete(listener);
|
|
789
|
-
};
|
|
790
|
-
},
|
|
791
|
-
// Explicit user cancel — aborts the controller and removes the entry
|
|
792
|
-
abort(key) {
|
|
793
|
-
const entry = streams.get(key);
|
|
794
|
-
if (!entry) return;
|
|
795
|
-
entry.abortController.abort();
|
|
796
|
-
streams.delete(key);
|
|
797
|
-
}
|
|
798
|
-
};
|
|
799
|
-
|
|
800
|
-
// src/utils/ragImageResolver.ts
|
|
801
|
-
var RAG_IMAGE_REGEX = /\/api\/rag\/chunks\/[^"'\s]+\/image/;
|
|
802
|
-
function hasRagImages(content) {
|
|
803
|
-
return RAG_IMAGE_REGEX.test(content);
|
|
804
|
-
}
|
|
805
|
-
async function waitForNextPaint(signal) {
|
|
806
|
-
if (signal?.aborted) return;
|
|
807
|
-
await new Promise((resolve) => {
|
|
808
|
-
let isSettled = false;
|
|
809
|
-
const finish = () => {
|
|
810
|
-
if (isSettled) return;
|
|
811
|
-
isSettled = true;
|
|
812
|
-
signal?.removeEventListener("abort", finish);
|
|
813
|
-
resolve();
|
|
814
|
-
};
|
|
815
|
-
signal?.addEventListener("abort", finish, { once: true });
|
|
816
|
-
if (typeof requestAnimationFrame === "function") {
|
|
817
|
-
requestAnimationFrame(() => {
|
|
818
|
-
setTimeout(finish, 0);
|
|
819
|
-
});
|
|
820
|
-
return;
|
|
821
|
-
}
|
|
822
|
-
setTimeout(finish, 0);
|
|
823
|
-
});
|
|
824
|
-
}
|
|
825
|
-
async function resolveRagImageUrls(config, content, signal) {
|
|
826
|
-
const url = buildResolveImagesUrl(config);
|
|
827
|
-
const baseHeaders = buildRequestHeaders(config);
|
|
828
|
-
const headers = { "Content-Type": "application/json", ...baseHeaders };
|
|
829
|
-
const response = await fetch(url, {
|
|
830
|
-
method: "POST",
|
|
831
|
-
headers,
|
|
832
|
-
body: JSON.stringify({ input: content }),
|
|
833
|
-
signal
|
|
834
|
-
});
|
|
835
|
-
if (!response.ok) {
|
|
836
|
-
const errorText = await response.text();
|
|
837
|
-
throw new Error(`HTTP ${response.status}: ${errorText}`);
|
|
838
|
-
}
|
|
839
|
-
const text = await response.text();
|
|
840
|
-
try {
|
|
841
|
-
const parsed = JSON.parse(text);
|
|
842
|
-
if (typeof parsed === "string") return parsed;
|
|
843
|
-
if (typeof parsed.output === "string") return parsed.output;
|
|
844
|
-
if (typeof parsed.result === "string") return parsed.result;
|
|
845
|
-
} catch {
|
|
846
|
-
}
|
|
847
|
-
return text;
|
|
848
|
-
}
|
|
849
|
-
|
|
850
|
-
// src/hooks/useStreamManager.ts
|
|
851
|
-
function useStreamManager(config, callbacks, setMessages, setIsWaitingForResponse) {
|
|
852
|
-
const abortControllerRef = useRef(null);
|
|
853
|
-
const configRef = useRef(config);
|
|
854
|
-
configRef.current = config;
|
|
855
|
-
const callbacksRef = useRef(callbacks);
|
|
856
|
-
callbacksRef.current = callbacks;
|
|
857
|
-
const startStream = useCallback(
|
|
858
|
-
async (userMessage, streamingId, sessionId, externalAbortController) => {
|
|
859
|
-
abortControllerRef.current?.abort();
|
|
860
|
-
const abortController = externalAbortController ?? new AbortController();
|
|
861
|
-
abortControllerRef.current = abortController;
|
|
862
|
-
const state = {
|
|
863
|
-
accumulatedContent: "",
|
|
864
|
-
executionId: void 0,
|
|
865
|
-
currentSessionId: void 0,
|
|
866
|
-
finalData: void 0,
|
|
867
|
-
steps: [],
|
|
868
|
-
stepCounter: 0,
|
|
869
|
-
currentExecutingStepId: void 0,
|
|
870
|
-
currentThinkingStepId: void 0,
|
|
871
|
-
hasError: false,
|
|
872
|
-
errorMessage: "",
|
|
873
|
-
userActionRequest: void 0,
|
|
874
|
-
userActionPending: false,
|
|
875
|
-
userActionResult: void 0,
|
|
876
|
-
allThinkingText: "",
|
|
877
|
-
inOrchestratorPhase: false,
|
|
878
|
-
inAggregatorPhase: false
|
|
879
|
-
};
|
|
880
|
-
const THROTTLE_MS = 120;
|
|
881
|
-
const CHARS_PER_TICK = 10;
|
|
882
|
-
const displayedLengthRef = { current: 0 };
|
|
883
|
-
let throttleIntervalId = null;
|
|
884
|
-
const getActiveStepMessage = () => state.steps.find((s) => s.id === state.currentExecutingStepId)?.message || [...state.steps].reverse().find((s) => s.status === "in_progress")?.message;
|
|
885
|
-
const advanceDisplayLength = (full) => {
|
|
886
|
-
let newLen = Math.min(displayedLengthRef.current + CHARS_PER_TICK, full.length);
|
|
887
|
-
if (newLen > 0 && newLen < full.length) {
|
|
888
|
-
const code = full.charCodeAt(newLen - 1);
|
|
889
|
-
if (code >= 55296 && code <= 56319) {
|
|
890
|
-
newLen = Math.min(newLen + 1, full.length);
|
|
891
|
-
}
|
|
892
|
-
}
|
|
893
|
-
displayedLengthRef.current = newLen;
|
|
894
|
-
};
|
|
895
|
-
const clearThrottle = () => {
|
|
896
|
-
if (throttleIntervalId != null) {
|
|
897
|
-
clearInterval(throttleIntervalId);
|
|
898
|
-
throttleIntervalId = null;
|
|
899
|
-
}
|
|
900
|
-
};
|
|
901
|
-
abortController.signal.addEventListener("abort", clearThrottle, { once: true });
|
|
902
|
-
const ensureThrottle = () => {
|
|
903
|
-
if (throttleIntervalId != null) return;
|
|
904
|
-
throttleIntervalId = setInterval(() => {
|
|
905
|
-
if (abortController.signal.aborted) {
|
|
906
|
-
clearThrottle();
|
|
907
|
-
return;
|
|
908
|
-
}
|
|
909
|
-
const full = state.activeThinkingText ?? "";
|
|
910
|
-
if (displayedLengthRef.current < full.length) {
|
|
911
|
-
advanceDisplayLength(full);
|
|
912
|
-
const displayText = full.slice(0, displayedLengthRef.current);
|
|
913
|
-
setMessages(
|
|
914
|
-
(prev) => prev.map(
|
|
915
|
-
(msg) => msg.id === streamingId ? {
|
|
916
|
-
...msg,
|
|
917
|
-
...createStreamingMessageUpdate({
|
|
918
|
-
...state,
|
|
919
|
-
activeThinkingText: displayText,
|
|
920
|
-
currentMessage: getActiveStepMessage() || "Thinking..."
|
|
921
|
-
})
|
|
922
|
-
} : msg
|
|
923
|
-
)
|
|
924
|
-
);
|
|
925
|
-
}
|
|
926
|
-
}, THROTTLE_MS);
|
|
927
|
-
};
|
|
928
|
-
const currentConfig = configRef.current;
|
|
929
|
-
const requestBody = buildRequestBody(currentConfig, userMessage, sessionId);
|
|
930
|
-
const url = buildStreamingUrl(currentConfig);
|
|
931
|
-
const headers = buildRequestHeaders(currentConfig);
|
|
932
|
-
try {
|
|
933
|
-
await streamWorkflowEvents(url, requestBody, headers, {
|
|
934
|
-
signal: abortController.signal,
|
|
935
|
-
onEvent: (event) => {
|
|
936
|
-
if (abortController.signal.aborted) {
|
|
937
|
-
return;
|
|
938
|
-
}
|
|
939
|
-
if (typeof event.eventType === "string" && event.eventType.toUpperCase() === "KEEP_ALIVE") {
|
|
940
|
-
if (event.executionId) state.executionId = event.executionId;
|
|
941
|
-
if (event.sessionId) state.currentSessionId = event.sessionId;
|
|
942
|
-
return;
|
|
943
|
-
}
|
|
944
|
-
if (event.executionId) state.executionId = event.executionId;
|
|
945
|
-
if (event.sessionId) state.currentSessionId = event.sessionId;
|
|
946
|
-
const activeThinkingLengthBeforeProcess = state.activeThinkingText?.length ?? 0;
|
|
947
|
-
processStreamEvent(event, state);
|
|
948
|
-
const eventType = event.eventType;
|
|
949
|
-
if (eventType === "INTENT_THINKING") {
|
|
950
|
-
displayedLengthRef.current = 0;
|
|
951
|
-
ensureThrottle();
|
|
952
|
-
} else if (eventType !== "INTENT_THINKING_CONT") {
|
|
953
|
-
displayedLengthRef.current = activeThinkingLengthBeforeProcess;
|
|
954
|
-
clearThrottle();
|
|
955
|
-
}
|
|
956
|
-
if (eventType === "USER_ACTION_REQUIRED" && state.userActionRequest) {
|
|
957
|
-
callbacksRef.current.onUserActionRequired?.(state.userActionRequest);
|
|
958
|
-
} else if (eventType.startsWith("USER_ACTION_") && eventType !== "USER_ACTION_REQUIRED") {
|
|
959
|
-
const msg = event.message?.trim() || event.errorMessage?.trim() || getEventMessage(event);
|
|
960
|
-
callbacksRef.current.onUserActionEvent?.(eventType, msg);
|
|
961
|
-
}
|
|
962
|
-
const isIntentThinkingEvent = eventType === "INTENT_THINKING" || eventType === "INTENT_THINKING_CONT";
|
|
963
|
-
const rawMessage = event.message?.trim() || event.errorMessage?.trim();
|
|
964
|
-
const currentMessage = isIntentThinkingEvent ? getActiveStepMessage() || "Thinking..." : rawMessage || (event.eventType?.startsWith("USER_ACTION_") ? getEventMessage(event) : getActiveStepMessage() || getEventMessage(event));
|
|
965
|
-
const displayThinking = state.activeThinkingText != null ? state.activeThinkingText.slice(0, displayedLengthRef.current) : state.activeThinkingText;
|
|
966
|
-
setMessages(
|
|
967
|
-
(prev) => prev.map(
|
|
968
|
-
(msg) => msg.id === streamingId ? {
|
|
969
|
-
...msg,
|
|
970
|
-
...createStreamingMessageUpdate({
|
|
971
|
-
...state,
|
|
972
|
-
activeThinkingText: displayThinking,
|
|
973
|
-
currentMessage
|
|
974
|
-
})
|
|
975
|
-
} : msg
|
|
976
|
-
)
|
|
977
|
-
);
|
|
978
|
-
},
|
|
979
|
-
onError: (error) => {
|
|
980
|
-
clearThrottle();
|
|
981
|
-
setIsWaitingForResponse(false);
|
|
982
|
-
if (error.name !== "AbortError") {
|
|
983
|
-
callbacksRef.current.onError?.(error);
|
|
984
|
-
}
|
|
985
|
-
if (state.userActionPending) {
|
|
986
|
-
state.userActionPending = false;
|
|
987
|
-
state.userActionRequest = void 0;
|
|
988
|
-
callbacksRef.current.onUserActionEvent?.(
|
|
989
|
-
"USER_ACTION_FAILED",
|
|
990
|
-
"Connection lost. Please try again."
|
|
991
|
-
);
|
|
992
|
-
}
|
|
993
|
-
setMessages(
|
|
994
|
-
(prev) => prev.map(
|
|
995
|
-
(msg) => msg.id === streamingId ? {
|
|
996
|
-
...msg,
|
|
997
|
-
...createErrorMessageUpdate(error, state)
|
|
998
|
-
} : msg
|
|
999
|
-
)
|
|
1000
|
-
);
|
|
1001
|
-
},
|
|
1002
|
-
onComplete: () => {
|
|
1003
|
-
clearThrottle();
|
|
1004
|
-
setIsWaitingForResponse(false);
|
|
1005
|
-
if (state.userActionPending) {
|
|
1006
|
-
state.userActionPending = false;
|
|
1007
|
-
state.userActionRequest = void 0;
|
|
1008
|
-
callbacksRef.current.onUserActionEvent?.(
|
|
1009
|
-
"USER_ACTION_FAILED",
|
|
1010
|
-
"Verification could not be completed."
|
|
1011
|
-
);
|
|
1012
|
-
}
|
|
1013
|
-
if (state.currentSessionId && state.currentSessionId !== sessionId) {
|
|
1014
|
-
callbacksRef.current.onSessionIdChange?.(state.currentSessionId);
|
|
1015
|
-
}
|
|
1016
|
-
const needsImageResolve = !state.hasError && !abortController.signal.aborted && hasRagImages(state.accumulatedContent);
|
|
1017
|
-
const finalMessage = createFinalMessage(streamingId, {
|
|
1018
|
-
...state,
|
|
1019
|
-
sessionId: state.currentSessionId || sessionId,
|
|
1020
|
-
isResolvingImages: needsImageResolve
|
|
1021
|
-
});
|
|
1022
|
-
setMessages(
|
|
1023
|
-
(prev) => prev.map(
|
|
1024
|
-
(msg) => msg.id === streamingId ? finalMessage : msg
|
|
1025
|
-
)
|
|
1026
|
-
);
|
|
1027
|
-
callbacksRef.current.onStreamComplete?.(finalMessage);
|
|
1028
|
-
}
|
|
1029
|
-
});
|
|
1030
|
-
clearThrottle();
|
|
1031
|
-
const shouldResolveImages = !abortController.signal.aborted && !state.hasError && hasRagImages(state.accumulatedContent);
|
|
1032
|
-
if (shouldResolveImages) {
|
|
1033
|
-
await waitForNextPaint(abortController.signal);
|
|
1034
|
-
}
|
|
1035
|
-
if (shouldResolveImages && !abortController.signal.aborted) {
|
|
1036
|
-
try {
|
|
1037
|
-
const resolvedContent = await resolveRagImageUrls(
|
|
1038
|
-
currentConfig,
|
|
1039
|
-
state.accumulatedContent,
|
|
1040
|
-
abortController.signal
|
|
1041
|
-
);
|
|
1042
|
-
setMessages(
|
|
1043
|
-
(prev) => prev.map(
|
|
1044
|
-
(msg) => msg.id === streamingId ? { ...msg, content: resolvedContent, isResolvingImages: false } : msg
|
|
1045
|
-
)
|
|
1046
|
-
);
|
|
1047
|
-
} catch {
|
|
1048
|
-
setMessages(
|
|
1049
|
-
(prev) => prev.map(
|
|
1050
|
-
(msg) => msg.id === streamingId ? { ...msg, isResolvingImages: false } : msg
|
|
1051
|
-
)
|
|
1052
|
-
);
|
|
1053
|
-
}
|
|
1054
|
-
}
|
|
1055
|
-
return state.currentSessionId;
|
|
1056
|
-
} catch (error) {
|
|
1057
|
-
clearThrottle();
|
|
1058
|
-
setIsWaitingForResponse(false);
|
|
1059
|
-
if (error.name !== "AbortError") {
|
|
1060
|
-
callbacksRef.current.onError?.(error);
|
|
1061
|
-
}
|
|
1062
|
-
if (state.userActionPending) {
|
|
1063
|
-
state.userActionPending = false;
|
|
1064
|
-
state.userActionRequest = void 0;
|
|
1065
|
-
callbacksRef.current.onUserActionEvent?.(
|
|
1066
|
-
"USER_ACTION_FAILED",
|
|
1067
|
-
"Connection lost. Please try again."
|
|
1068
|
-
);
|
|
1069
|
-
}
|
|
1070
|
-
setMessages(
|
|
1071
|
-
(prev) => prev.map(
|
|
1072
|
-
(msg) => msg.id === streamingId ? {
|
|
1073
|
-
...msg,
|
|
1074
|
-
...createErrorMessageUpdate(error, state)
|
|
1075
|
-
} : msg
|
|
1076
|
-
)
|
|
1077
|
-
);
|
|
1078
|
-
return state.currentSessionId;
|
|
1079
|
-
}
|
|
1080
|
-
},
|
|
1081
|
-
[setMessages, setIsWaitingForResponse]
|
|
1082
|
-
);
|
|
1083
|
-
const cancelStream = useCallback(() => {
|
|
1084
|
-
abortControllerRef.current?.abort();
|
|
1085
|
-
}, []);
|
|
1086
|
-
return {
|
|
1087
|
-
startStream,
|
|
1088
|
-
cancelStream,
|
|
1089
|
-
abortControllerRef
|
|
1090
|
-
};
|
|
1091
|
-
}
|
|
1092
|
-
|
|
1093
|
-
// src/hooks/useChat.ts
|
|
1094
|
-
function useChat(config, callbacks = {}) {
|
|
1095
|
-
const [messages, setMessages] = useState(() => {
|
|
1096
|
-
if (config.userId) return chatStore.get(config.userId);
|
|
1097
|
-
return config.initialMessages ?? [];
|
|
1098
|
-
});
|
|
1099
|
-
const [isWaitingForResponse, setIsWaitingForResponse] = useState(false);
|
|
1100
|
-
const sessionIdRef = useRef(
|
|
1101
|
-
config.userId ? chatStore.get(config.userId).find((m) => m.sessionId)?.sessionId ?? config.initialSessionId ?? void 0 : config.initialSessionId ?? void 0
|
|
1102
|
-
);
|
|
1103
|
-
const prevUserIdRef = useRef(config.userId);
|
|
1104
|
-
const callbacksRef = useRef(callbacks);
|
|
1105
|
-
callbacksRef.current = callbacks;
|
|
1106
|
-
const configRef = useRef(config);
|
|
1107
|
-
configRef.current = config;
|
|
1108
|
-
const messagesRef = useRef(messages);
|
|
1109
|
-
messagesRef.current = messages;
|
|
1110
|
-
const storeAwareSetMessages = useCallback(
|
|
1111
|
-
(updater) => {
|
|
1112
|
-
const { userId } = configRef.current;
|
|
1113
|
-
if (userId && activeStreamStore.has(userId)) {
|
|
1114
|
-
activeStreamStore.applyMessages(userId, updater);
|
|
1115
|
-
}
|
|
1116
|
-
setMessages(updater);
|
|
1117
|
-
},
|
|
1118
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1119
|
-
[]
|
|
1120
|
-
);
|
|
1121
|
-
const storeAwareSetIsWaiting = useCallback(
|
|
1122
|
-
(waiting) => {
|
|
1123
|
-
const { userId } = configRef.current;
|
|
1124
|
-
if (userId && activeStreamStore.has(userId)) {
|
|
1125
|
-
activeStreamStore.setWaiting(userId, waiting);
|
|
1126
|
-
}
|
|
1127
|
-
setIsWaitingForResponse(waiting);
|
|
1128
|
-
},
|
|
1129
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1130
|
-
[]
|
|
1131
|
-
);
|
|
1132
|
-
const [userActionState, setUserActionState] = useState({
|
|
1133
|
-
request: null,
|
|
1134
|
-
result: null,
|
|
1135
|
-
clearOtpTrigger: 0
|
|
1136
|
-
});
|
|
1137
|
-
const userActionStateRef = useRef(userActionState);
|
|
1138
|
-
userActionStateRef.current = userActionState;
|
|
1139
|
-
const wrappedCallbacks = useMemo(() => ({
|
|
1140
|
-
...callbacksRef.current,
|
|
1141
|
-
onMessageSent: (message) => callbacksRef.current.onMessageSent?.(message),
|
|
1142
|
-
onStreamStart: () => callbacksRef.current.onStreamStart?.(),
|
|
1143
|
-
onStreamComplete: (message) => callbacksRef.current.onStreamComplete?.(message),
|
|
1144
|
-
onError: (error) => callbacksRef.current.onError?.(error),
|
|
1145
|
-
onExecutionTraceClick: (data) => callbacksRef.current.onExecutionTraceClick?.(data),
|
|
1146
|
-
onSessionIdChange: (sessionId) => callbacksRef.current.onSessionIdChange?.(sessionId),
|
|
1147
|
-
onUserActionRequired: (request) => {
|
|
1148
|
-
setUserActionState((prev) => ({ ...prev, request, result: null }));
|
|
1149
|
-
callbacksRef.current.onUserActionRequired?.(request);
|
|
1150
|
-
},
|
|
1151
|
-
onUserActionEvent: (eventType, message) => {
|
|
1152
|
-
switch (eventType) {
|
|
1153
|
-
case "USER_ACTION_SUCCESS":
|
|
1154
|
-
setUserActionState((prev) => ({ ...prev, request: null, result: "approved" }));
|
|
1155
|
-
break;
|
|
1156
|
-
case "USER_ACTION_REJECTED":
|
|
1157
|
-
setUserActionState((prev) => ({ ...prev, request: null, result: "rejected" }));
|
|
1158
|
-
break;
|
|
1159
|
-
case "USER_ACTION_EXPIRED":
|
|
1160
|
-
case "USER_ACTION_FAILED":
|
|
1161
|
-
setUserActionState((prev) => ({ ...prev, request: null }));
|
|
1162
|
-
break;
|
|
1163
|
-
case "USER_ACTION_INVALID":
|
|
1164
|
-
setUserActionState((prev) => ({ ...prev, clearOtpTrigger: prev.clearOtpTrigger + 1 }));
|
|
1165
|
-
break;
|
|
1166
|
-
}
|
|
1167
|
-
callbacksRef.current.onUserActionEvent?.(eventType, message);
|
|
1168
|
-
}
|
|
1169
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1170
|
-
}), []);
|
|
1171
|
-
const { startStream, cancelStream: cancelStreamManager, abortControllerRef } = useStreamManager(
|
|
1172
|
-
config,
|
|
1173
|
-
wrappedCallbacks,
|
|
1174
|
-
storeAwareSetMessages,
|
|
1175
|
-
storeAwareSetIsWaiting
|
|
1176
|
-
);
|
|
1177
|
-
const sendMessage = useCallback(
|
|
1178
|
-
async (userMessage) => {
|
|
1179
|
-
if (!userMessage.trim()) return;
|
|
1180
|
-
if (!sessionIdRef.current && configRef.current.autoGenerateSessionId !== false) {
|
|
1181
|
-
sessionIdRef.current = generateId();
|
|
1182
|
-
callbacksRef.current.onSessionIdChange?.(sessionIdRef.current);
|
|
1183
|
-
}
|
|
1184
|
-
const userMessageId = `user-${Date.now()}`;
|
|
1185
|
-
const userMsg = {
|
|
1186
|
-
id: userMessageId,
|
|
1187
|
-
sessionId: sessionIdRef.current,
|
|
1188
|
-
role: "user",
|
|
1189
|
-
content: userMessage,
|
|
1190
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1191
|
-
};
|
|
1192
|
-
setMessages((prev) => [...prev, userMsg]);
|
|
1193
|
-
callbacksRef.current.onMessageSent?.(userMessage);
|
|
1194
|
-
setIsWaitingForResponse(true);
|
|
1195
|
-
callbacksRef.current.onStreamStart?.();
|
|
1196
|
-
const streamingId = `assistant-${Date.now()}`;
|
|
1197
|
-
const streamingMsg = {
|
|
1198
|
-
id: streamingId,
|
|
1199
|
-
sessionId: sessionIdRef.current,
|
|
1200
|
-
role: "assistant",
|
|
1201
|
-
content: "",
|
|
1202
|
-
streamingContent: "",
|
|
1203
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1204
|
-
isStreaming: true,
|
|
1205
|
-
streamProgress: "started",
|
|
1206
|
-
steps: [],
|
|
1207
|
-
currentExecutingStepId: void 0,
|
|
1208
|
-
isCancelled: false,
|
|
1209
|
-
currentMessage: void 0
|
|
1210
|
-
};
|
|
1211
|
-
setMessages((prev) => [...prev, streamingMsg]);
|
|
1212
|
-
const abortController = new AbortController();
|
|
1213
|
-
const { userId } = configRef.current;
|
|
1214
|
-
if (userId) {
|
|
1215
|
-
const initialMessages = [...messagesRef.current, userMsg, streamingMsg];
|
|
1216
|
-
activeStreamStore.start(userId, abortController, initialMessages);
|
|
1217
|
-
}
|
|
1218
|
-
const newSessionId = await startStream(
|
|
1219
|
-
userMessage,
|
|
1220
|
-
streamingId,
|
|
1221
|
-
sessionIdRef.current,
|
|
1222
|
-
abortController
|
|
1223
|
-
);
|
|
1224
|
-
if (userId) {
|
|
1225
|
-
activeStreamStore.complete(userId);
|
|
1226
|
-
}
|
|
1227
|
-
if (!abortController.signal.aborted && newSessionId && newSessionId !== sessionIdRef.current) {
|
|
1228
|
-
sessionIdRef.current = newSessionId;
|
|
1229
|
-
}
|
|
1230
|
-
},
|
|
1231
|
-
[startStream]
|
|
1232
|
-
);
|
|
1233
|
-
const clearMessages = useCallback(() => {
|
|
1234
|
-
if (configRef.current.userId) {
|
|
1235
|
-
chatStore.delete(configRef.current.userId);
|
|
1236
|
-
}
|
|
1237
|
-
setMessages([]);
|
|
1238
|
-
}, []);
|
|
1239
|
-
const prependMessages = useCallback((msgs) => {
|
|
1240
|
-
setMessages((prev) => [...msgs, ...prev]);
|
|
1241
|
-
}, []);
|
|
1242
|
-
const cancelStream = useCallback(() => {
|
|
1243
|
-
if (configRef.current.userId) {
|
|
1244
|
-
activeStreamStore.abort(configRef.current.userId);
|
|
1245
|
-
}
|
|
1246
|
-
cancelStreamManager();
|
|
1247
|
-
setIsWaitingForResponse(false);
|
|
1248
|
-
setUserActionState((prev) => ({ ...prev, request: null, result: null }));
|
|
1249
|
-
setMessages(
|
|
1250
|
-
(prev) => prev.map((msg) => {
|
|
1251
|
-
if (msg.isStreaming) {
|
|
1252
|
-
return {
|
|
1253
|
-
...msg,
|
|
1254
|
-
...createCancelledMessageUpdate(
|
|
1255
|
-
msg.steps || [],
|
|
1256
|
-
msg.currentMessage
|
|
1257
|
-
)
|
|
1258
|
-
};
|
|
1259
|
-
}
|
|
1260
|
-
return msg;
|
|
1261
|
-
})
|
|
1262
|
-
);
|
|
1263
|
-
}, [cancelStreamManager]);
|
|
1264
|
-
const resetSession = useCallback(() => {
|
|
1265
|
-
if (configRef.current.userId) {
|
|
1266
|
-
activeStreamStore.abort(configRef.current.userId);
|
|
1267
|
-
chatStore.delete(configRef.current.userId);
|
|
1268
|
-
}
|
|
1269
|
-
setMessages([]);
|
|
1270
|
-
sessionIdRef.current = void 0;
|
|
1271
|
-
abortControllerRef.current?.abort();
|
|
1272
|
-
setIsWaitingForResponse(false);
|
|
1273
|
-
setUserActionState({ request: null, result: null, clearOtpTrigger: 0 });
|
|
1274
|
-
}, []);
|
|
1275
|
-
const getSessionId = useCallback(() => {
|
|
1276
|
-
return sessionIdRef.current;
|
|
1277
|
-
}, []);
|
|
1278
|
-
const getMessages = useCallback(() => {
|
|
1279
|
-
return messages;
|
|
1280
|
-
}, [messages]);
|
|
1281
|
-
const approveUserAction = useCallback(
|
|
1282
|
-
async (otp) => {
|
|
1283
|
-
const request = userActionStateRef.current.request;
|
|
1284
|
-
if (!request) return;
|
|
1285
|
-
try {
|
|
1286
|
-
await submitUserAction(configRef.current, request.userActionId, { otp });
|
|
1287
|
-
} catch (error) {
|
|
1288
|
-
setUserActionState((prev) => ({
|
|
1289
|
-
...prev,
|
|
1290
|
-
clearOtpTrigger: prev.clearOtpTrigger + 1
|
|
1291
|
-
}));
|
|
1292
|
-
callbacksRef.current.onError?.(error);
|
|
1293
|
-
throw error;
|
|
1294
|
-
}
|
|
1295
|
-
},
|
|
1296
|
-
[]
|
|
1297
|
-
);
|
|
1298
|
-
const rejectUserAction = useCallback(async () => {
|
|
1299
|
-
const request = userActionStateRef.current.request;
|
|
1300
|
-
if (!request) return;
|
|
1301
|
-
try {
|
|
1302
|
-
setMessages((prev) => {
|
|
1303
|
-
let lastStreamingIdx = -1;
|
|
1304
|
-
for (let i = prev.length - 1; i >= 0; i--) {
|
|
1305
|
-
if (prev[i].role === "assistant" && prev[i].isStreaming) {
|
|
1306
|
-
lastStreamingIdx = i;
|
|
1307
|
-
break;
|
|
1308
|
-
}
|
|
1309
|
-
}
|
|
1310
|
-
if (lastStreamingIdx === -1) return prev;
|
|
1311
|
-
return prev.map(
|
|
1312
|
-
(msg, i) => i === lastStreamingIdx ? { ...msg, currentMessage: "Rejecting..." } : msg
|
|
1313
|
-
);
|
|
1314
|
-
});
|
|
1315
|
-
await cancelUserAction(configRef.current, request.userActionId);
|
|
1316
|
-
} catch (error) {
|
|
1317
|
-
callbacksRef.current.onError?.(error);
|
|
1318
|
-
throw error;
|
|
1319
|
-
}
|
|
1320
|
-
}, []);
|
|
1321
|
-
const resendOtp = useCallback(async () => {
|
|
1322
|
-
const request = userActionStateRef.current.request;
|
|
1323
|
-
if (!request) return;
|
|
1324
|
-
try {
|
|
1325
|
-
await resendUserAction(configRef.current, request.userActionId);
|
|
1326
|
-
} catch (error) {
|
|
1327
|
-
callbacksRef.current.onError?.(error);
|
|
1328
|
-
throw error;
|
|
1329
|
-
}
|
|
1330
|
-
}, []);
|
|
1331
|
-
useEffect(() => {
|
|
1332
|
-
const { userId } = config;
|
|
1333
|
-
if (!userId) return;
|
|
1334
|
-
const unsubscribe = activeStreamStore.subscribe(userId, (msgs, isWaiting) => {
|
|
1335
|
-
setMessages(msgs);
|
|
1336
|
-
setIsWaitingForResponse(isWaiting);
|
|
1337
|
-
});
|
|
1338
|
-
const active = activeStreamStore.get(userId);
|
|
1339
|
-
if (active) {
|
|
1340
|
-
setMessages(active.messages);
|
|
1341
|
-
setIsWaitingForResponse(active.isWaiting);
|
|
1342
|
-
}
|
|
1343
|
-
return unsubscribe;
|
|
1344
|
-
}, []);
|
|
1345
|
-
useEffect(() => {
|
|
1346
|
-
if (!config.userId) return;
|
|
1347
|
-
const toSave = messages.filter((m) => !m.isStreaming);
|
|
1348
|
-
if (toSave.length > 0) {
|
|
1349
|
-
chatStore.set(config.userId, toSave);
|
|
1350
|
-
}
|
|
1351
|
-
}, [messages, config.userId]);
|
|
1352
|
-
useEffect(() => {
|
|
1353
|
-
const prevUserId = prevUserIdRef.current;
|
|
1354
|
-
prevUserIdRef.current = config.userId;
|
|
1355
|
-
if (prevUserId === config.userId) return;
|
|
1356
|
-
if (prevUserId && !config.userId) {
|
|
1357
|
-
chatStore.delete(prevUserId);
|
|
1358
|
-
setMessages([]);
|
|
1359
|
-
sessionIdRef.current = void 0;
|
|
1360
|
-
setIsWaitingForResponse(false);
|
|
1361
|
-
setUserActionState({ request: null, result: null, clearOtpTrigger: 0 });
|
|
1362
|
-
} else if (config.userId) {
|
|
1363
|
-
const stored = chatStore.get(config.userId);
|
|
1364
|
-
setMessages(stored);
|
|
1365
|
-
sessionIdRef.current = stored.find((m) => m.sessionId)?.sessionId;
|
|
1366
|
-
}
|
|
1367
|
-
}, [config.userId]);
|
|
1368
|
-
return {
|
|
1369
|
-
messages,
|
|
1370
|
-
sendMessage,
|
|
1371
|
-
clearMessages,
|
|
1372
|
-
prependMessages,
|
|
1373
|
-
cancelStream,
|
|
1374
|
-
resetSession,
|
|
1375
|
-
getSessionId,
|
|
1376
|
-
getMessages,
|
|
1377
|
-
isWaitingForResponse,
|
|
1378
|
-
sessionId: sessionIdRef.current,
|
|
1379
|
-
// User action (OTP) state and methods
|
|
1380
|
-
userActionState,
|
|
1381
|
-
approveUserAction,
|
|
1382
|
-
rejectUserAction,
|
|
1383
|
-
resendOtp
|
|
1384
|
-
};
|
|
404
|
+
}
|
|
405
|
+
return await response.json();
|
|
406
|
+
}
|
|
407
|
+
async function submitUserAction(config, userActionId, data) {
|
|
408
|
+
return sendUserActionRequest(config, userActionId, "submit", data);
|
|
409
|
+
}
|
|
410
|
+
async function cancelUserAction(config, userActionId) {
|
|
411
|
+
return sendUserActionRequest(config, userActionId, "cancel");
|
|
1385
412
|
}
|
|
413
|
+
async function resendUserAction(config, userActionId) {
|
|
414
|
+
return sendUserActionRequest(config, userActionId, "resend");
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// src/utils/chatStore.ts
|
|
418
|
+
var memoryStore = /* @__PURE__ */ new Map();
|
|
419
|
+
var chatStore = {
|
|
420
|
+
get(key) {
|
|
421
|
+
return memoryStore.get(key) ?? [];
|
|
422
|
+
},
|
|
423
|
+
set(key, messages) {
|
|
424
|
+
memoryStore.set(key, messages);
|
|
425
|
+
},
|
|
426
|
+
delete(key) {
|
|
427
|
+
memoryStore.delete(key);
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
|
|
431
|
+
// src/utils/activeStreamStore.ts
|
|
432
|
+
var streams = /* @__PURE__ */ new Map();
|
|
433
|
+
var activeStreamStore = {
|
|
434
|
+
has(key) {
|
|
435
|
+
return streams.has(key);
|
|
436
|
+
},
|
|
437
|
+
get(key) {
|
|
438
|
+
const entry = streams.get(key);
|
|
439
|
+
if (!entry) return null;
|
|
440
|
+
return { messages: entry.messages, isWaiting: entry.isWaiting };
|
|
441
|
+
},
|
|
442
|
+
// Called before startStream — registers the controller and initial messages
|
|
443
|
+
start(key, abortController, initialMessages) {
|
|
444
|
+
const existing = streams.get(key);
|
|
445
|
+
streams.set(key, {
|
|
446
|
+
messages: initialMessages,
|
|
447
|
+
isWaiting: true,
|
|
448
|
+
abortController,
|
|
449
|
+
listeners: existing?.listeners ?? /* @__PURE__ */ new Set()
|
|
450
|
+
});
|
|
451
|
+
},
|
|
452
|
+
// Called by the stream on every event — applies the same updater pattern React uses
|
|
453
|
+
applyMessages(key, updater) {
|
|
454
|
+
const entry = streams.get(key);
|
|
455
|
+
if (!entry) return;
|
|
456
|
+
const next = typeof updater === "function" ? updater(entry.messages) : updater;
|
|
457
|
+
entry.messages = next;
|
|
458
|
+
entry.listeners.forEach((l) => l(next, entry.isWaiting));
|
|
459
|
+
},
|
|
460
|
+
setWaiting(key, waiting) {
|
|
461
|
+
const entry = streams.get(key);
|
|
462
|
+
if (!entry) return;
|
|
463
|
+
entry.isWaiting = waiting;
|
|
464
|
+
entry.listeners.forEach((l) => l(entry.messages, waiting));
|
|
465
|
+
},
|
|
466
|
+
// Called when stream completes — persists to chatStore and cleans up
|
|
467
|
+
complete(key) {
|
|
468
|
+
const entry = streams.get(key);
|
|
469
|
+
if (!entry) return;
|
|
470
|
+
entry.isWaiting = false;
|
|
471
|
+
entry.listeners.forEach((l) => l(entry.messages, false));
|
|
472
|
+
const toSave = entry.messages.filter((m) => !m.isStreaming);
|
|
473
|
+
if (toSave.length > 0) chatStore.set(key, toSave);
|
|
474
|
+
streams.delete(key);
|
|
475
|
+
},
|
|
476
|
+
// Subscribe — returns unsubscribe fn. Component calls this on mount, cleanup on unmount.
|
|
477
|
+
subscribe(key, listener) {
|
|
478
|
+
const entry = streams.get(key);
|
|
479
|
+
if (!entry) return () => {
|
|
480
|
+
};
|
|
481
|
+
entry.listeners.add(listener);
|
|
482
|
+
return () => {
|
|
483
|
+
streams.get(key)?.listeners.delete(listener);
|
|
484
|
+
};
|
|
485
|
+
},
|
|
486
|
+
// Explicit user cancel — aborts the controller and removes the entry
|
|
487
|
+
abort(key) {
|
|
488
|
+
const entry = streams.get(key);
|
|
489
|
+
if (!entry) return;
|
|
490
|
+
entry.abortController.abort();
|
|
491
|
+
streams.delete(key);
|
|
492
|
+
}
|
|
493
|
+
};
|
|
1386
494
|
|
|
1387
495
|
// src/utils/v2EventProcessor.ts
|
|
1388
496
|
function getEventText(event, field) {
|
|
@@ -1408,7 +516,7 @@ function addThinkingLine(state, header, detail) {
|
|
|
1408
516
|
function appendThinkingText(state, text) {
|
|
1409
517
|
state.formattedThinkingText += text;
|
|
1410
518
|
}
|
|
1411
|
-
function
|
|
519
|
+
function completeLastInProgressStep(steps) {
|
|
1412
520
|
for (let i = steps.length - 1; i >= 0; i--) {
|
|
1413
521
|
if (steps[i].status === "in_progress") {
|
|
1414
522
|
steps[i].status = "completed";
|
|
@@ -1622,7 +730,7 @@ function processStreamEventV2(event, state) {
|
|
|
1622
730
|
break;
|
|
1623
731
|
}
|
|
1624
732
|
case "USER_ACTION_REQUIRED": {
|
|
1625
|
-
|
|
733
|
+
completeLastInProgressStep(state.steps);
|
|
1626
734
|
if (event.userActionRequest) {
|
|
1627
735
|
state.userActionRequest = {
|
|
1628
736
|
userActionId: event.userActionRequest.userActionId,
|
|
@@ -1634,14 +742,18 @@ function processStreamEventV2(event, state) {
|
|
|
1634
742
|
}
|
|
1635
743
|
state.userActionPending = true;
|
|
1636
744
|
const req = event.userActionRequest;
|
|
745
|
+
const displayMessage = getUserActionDisplayMessage(
|
|
746
|
+
eventType,
|
|
747
|
+
req?.message || message
|
|
748
|
+
);
|
|
1637
749
|
if (req) {
|
|
1638
|
-
addThinkingLine(state, "**Verification Required**",
|
|
750
|
+
addThinkingLine(state, "**Verification Required**", displayMessage);
|
|
1639
751
|
}
|
|
1640
752
|
const stepId = `step-${state.stepCounter++}`;
|
|
1641
753
|
state.steps.push({
|
|
1642
754
|
id: stepId,
|
|
1643
755
|
eventType,
|
|
1644
|
-
message,
|
|
756
|
+
message: displayMessage,
|
|
1645
757
|
status: "in_progress",
|
|
1646
758
|
timestamp: Date.now(),
|
|
1647
759
|
elapsedMs: event.elapsedMs
|
|
@@ -1651,8 +763,9 @@ function processStreamEventV2(event, state) {
|
|
|
1651
763
|
break;
|
|
1652
764
|
}
|
|
1653
765
|
case "USER_ACTION_SUCCESS": {
|
|
1654
|
-
|
|
1655
|
-
|
|
766
|
+
const displayMessage = getUserActionDisplayMessage(eventType, event.message);
|
|
767
|
+
appendThinkingText(state, "\n\u2713 " + displayMessage);
|
|
768
|
+
completeLastInProgressStep(state.steps);
|
|
1656
769
|
state.userActionRequest = void 0;
|
|
1657
770
|
state.userActionPending = false;
|
|
1658
771
|
state.userActionResult = "approved";
|
|
@@ -1660,7 +773,7 @@ function processStreamEventV2(event, state) {
|
|
|
1660
773
|
state.steps.push({
|
|
1661
774
|
id: stepId,
|
|
1662
775
|
eventType,
|
|
1663
|
-
message,
|
|
776
|
+
message: displayMessage,
|
|
1664
777
|
status: "completed",
|
|
1665
778
|
timestamp: Date.now(),
|
|
1666
779
|
elapsedMs: event.elapsedMs
|
|
@@ -1669,12 +782,14 @@ function processStreamEventV2(event, state) {
|
|
|
1669
782
|
break;
|
|
1670
783
|
}
|
|
1671
784
|
case "USER_ACTION_INVALID": {
|
|
1672
|
-
|
|
785
|
+
const displayMessage = getUserActionDisplayMessage(eventType, event.message);
|
|
786
|
+
appendThinkingText(state, "\n\u2717 " + displayMessage);
|
|
787
|
+
completeLastInProgressStep(state.steps);
|
|
1673
788
|
const errorStepId = `step-${state.stepCounter++}`;
|
|
1674
789
|
state.steps.push({
|
|
1675
790
|
id: errorStepId,
|
|
1676
791
|
eventType,
|
|
1677
|
-
message,
|
|
792
|
+
message: displayMessage,
|
|
1678
793
|
status: "error",
|
|
1679
794
|
timestamp: Date.now(),
|
|
1680
795
|
elapsedMs: event.elapsedMs
|
|
@@ -1692,8 +807,9 @@ function processStreamEventV2(event, state) {
|
|
|
1692
807
|
break;
|
|
1693
808
|
}
|
|
1694
809
|
case "USER_ACTION_REJECTED": {
|
|
1695
|
-
|
|
1696
|
-
|
|
810
|
+
const displayMessage = getUserActionDisplayMessage(eventType, event.message);
|
|
811
|
+
appendThinkingText(state, "\n" + displayMessage);
|
|
812
|
+
completeLastInProgressStep(state.steps);
|
|
1697
813
|
state.userActionRequest = void 0;
|
|
1698
814
|
state.userActionPending = false;
|
|
1699
815
|
state.userActionResult = "rejected";
|
|
@@ -1701,7 +817,7 @@ function processStreamEventV2(event, state) {
|
|
|
1701
817
|
state.steps.push({
|
|
1702
818
|
id: stepId,
|
|
1703
819
|
eventType,
|
|
1704
|
-
message,
|
|
820
|
+
message: displayMessage,
|
|
1705
821
|
status: "completed",
|
|
1706
822
|
timestamp: Date.now(),
|
|
1707
823
|
elapsedMs: event.elapsedMs
|
|
@@ -1710,15 +826,16 @@ function processStreamEventV2(event, state) {
|
|
|
1710
826
|
break;
|
|
1711
827
|
}
|
|
1712
828
|
case "USER_ACTION_EXPIRED": {
|
|
1713
|
-
|
|
1714
|
-
|
|
829
|
+
const displayMessage = getUserActionDisplayMessage(eventType, event.message);
|
|
830
|
+
appendThinkingText(state, "\n\u2717 " + displayMessage);
|
|
831
|
+
completeLastInProgressStep(state.steps);
|
|
1715
832
|
state.userActionRequest = void 0;
|
|
1716
833
|
state.userActionPending = false;
|
|
1717
834
|
const stepId = `step-${state.stepCounter++}`;
|
|
1718
835
|
state.steps.push({
|
|
1719
836
|
id: stepId,
|
|
1720
837
|
eventType,
|
|
1721
|
-
message,
|
|
838
|
+
message: displayMessage,
|
|
1722
839
|
status: "error",
|
|
1723
840
|
timestamp: Date.now(),
|
|
1724
841
|
elapsedMs: event.elapsedMs
|
|
@@ -1727,11 +844,13 @@ function processStreamEventV2(event, state) {
|
|
|
1727
844
|
break;
|
|
1728
845
|
}
|
|
1729
846
|
case "USER_ACTION_RESENT": {
|
|
847
|
+
const displayMessage = getUserActionDisplayMessage(eventType, event.message);
|
|
848
|
+
appendThinkingText(state, "\n" + displayMessage);
|
|
1730
849
|
const stepId = `step-${state.stepCounter++}`;
|
|
1731
850
|
state.steps.push({
|
|
1732
851
|
id: stepId,
|
|
1733
852
|
eventType,
|
|
1734
|
-
message,
|
|
853
|
+
message: displayMessage,
|
|
1735
854
|
status: "completed",
|
|
1736
855
|
timestamp: Date.now(),
|
|
1737
856
|
elapsedMs: event.elapsedMs
|
|
@@ -1740,15 +859,19 @@ function processStreamEventV2(event, state) {
|
|
|
1740
859
|
break;
|
|
1741
860
|
}
|
|
1742
861
|
case "USER_ACTION_FAILED": {
|
|
1743
|
-
|
|
1744
|
-
|
|
862
|
+
const displayMessage = getUserActionDisplayMessage(
|
|
863
|
+
eventType,
|
|
864
|
+
event.message || event.errorMessage
|
|
865
|
+
);
|
|
866
|
+
appendThinkingText(state, "\n\u2717 " + displayMessage);
|
|
867
|
+
completeLastInProgressStep(state.steps);
|
|
1745
868
|
state.userActionRequest = void 0;
|
|
1746
869
|
state.userActionPending = false;
|
|
1747
870
|
const stepId = `step-${state.stepCounter++}`;
|
|
1748
871
|
state.steps.push({
|
|
1749
872
|
id: stepId,
|
|
1750
873
|
eventType,
|
|
1751
|
-
message,
|
|
874
|
+
message: displayMessage,
|
|
1752
875
|
status: "error",
|
|
1753
876
|
timestamp: Date.now(),
|
|
1754
877
|
elapsedMs: event.elapsedMs
|
|
@@ -1779,8 +902,58 @@ function processStreamEventV2(event, state) {
|
|
|
1779
902
|
return state;
|
|
1780
903
|
}
|
|
1781
904
|
|
|
905
|
+
// src/utils/ragImageResolver.ts
|
|
906
|
+
var RAG_IMAGE_REGEX = /\/api\/rag\/chunks\/[^"'\s]+\/image/;
|
|
907
|
+
function hasRagImages(content) {
|
|
908
|
+
return RAG_IMAGE_REGEX.test(content);
|
|
909
|
+
}
|
|
910
|
+
async function waitForNextPaint(signal) {
|
|
911
|
+
if (signal?.aborted) return;
|
|
912
|
+
await new Promise((resolve) => {
|
|
913
|
+
let isSettled = false;
|
|
914
|
+
const finish = () => {
|
|
915
|
+
if (isSettled) return;
|
|
916
|
+
isSettled = true;
|
|
917
|
+
signal?.removeEventListener("abort", finish);
|
|
918
|
+
resolve();
|
|
919
|
+
};
|
|
920
|
+
signal?.addEventListener("abort", finish, { once: true });
|
|
921
|
+
if (typeof requestAnimationFrame === "function") {
|
|
922
|
+
requestAnimationFrame(() => {
|
|
923
|
+
setTimeout(finish, 0);
|
|
924
|
+
});
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
setTimeout(finish, 0);
|
|
928
|
+
});
|
|
929
|
+
}
|
|
930
|
+
async function resolveRagImageUrls(config, content, signal) {
|
|
931
|
+
const url = buildResolveImagesUrl(config);
|
|
932
|
+
const baseHeaders = buildRequestHeaders(config);
|
|
933
|
+
const headers = { "Content-Type": "application/json", ...baseHeaders };
|
|
934
|
+
const response = await fetch(url, {
|
|
935
|
+
method: "POST",
|
|
936
|
+
headers,
|
|
937
|
+
body: JSON.stringify({ input: content }),
|
|
938
|
+
signal
|
|
939
|
+
});
|
|
940
|
+
if (!response.ok) {
|
|
941
|
+
const errorText = await response.text();
|
|
942
|
+
throw new Error(`HTTP ${response.status}: ${errorText}`);
|
|
943
|
+
}
|
|
944
|
+
const text = await response.text();
|
|
945
|
+
try {
|
|
946
|
+
const parsed = JSON.parse(text);
|
|
947
|
+
if (typeof parsed === "string") return parsed;
|
|
948
|
+
if (typeof parsed.output === "string") return parsed.output;
|
|
949
|
+
if (typeof parsed.result === "string") return parsed.result;
|
|
950
|
+
} catch {
|
|
951
|
+
}
|
|
952
|
+
return text;
|
|
953
|
+
}
|
|
954
|
+
|
|
1782
955
|
// src/hooks/useStreamManagerV2.ts
|
|
1783
|
-
var
|
|
956
|
+
var FRIENDLY_ERROR_MESSAGE = "Oops, something went wrong. Please try again.";
|
|
1784
957
|
function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForResponse) {
|
|
1785
958
|
const abortControllerRef = useRef(null);
|
|
1786
959
|
const configRef = useRef(config);
|
|
@@ -1820,7 +993,10 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
|
|
|
1820
993
|
if (eventType === "USER_ACTION_REQUIRED" && state.userActionRequest) {
|
|
1821
994
|
callbacksRef.current.onUserActionRequired?.(state.userActionRequest);
|
|
1822
995
|
} else if (eventType.startsWith("USER_ACTION_") && eventType !== "USER_ACTION_REQUIRED") {
|
|
1823
|
-
const msg =
|
|
996
|
+
const msg = getUserActionDisplayMessage(
|
|
997
|
+
eventType,
|
|
998
|
+
event.message?.trim() || event.errorMessage?.trim() || getEventMessage(event)
|
|
999
|
+
);
|
|
1824
1000
|
callbacksRef.current.onUserActionEvent?.(eventType, msg);
|
|
1825
1001
|
}
|
|
1826
1002
|
const activeStep = state.steps.find((s) => s.id === state.currentExecutingStepId);
|
|
@@ -1828,8 +1004,8 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
|
|
|
1828
1004
|
const currentMessage = activeStep?.message || lastInProgressStep?.message || getEventMessage(event);
|
|
1829
1005
|
if (state.hasError) {
|
|
1830
1006
|
updateMessage({
|
|
1831
|
-
streamingContent:
|
|
1832
|
-
content:
|
|
1007
|
+
streamingContent: FRIENDLY_ERROR_MESSAGE,
|
|
1008
|
+
content: FRIENDLY_ERROR_MESSAGE,
|
|
1833
1009
|
streamProgress: "error",
|
|
1834
1010
|
isError: true,
|
|
1835
1011
|
errorDetails: state.errorMessage,
|
|
@@ -1879,7 +1055,7 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
|
|
|
1879
1055
|
isError: !isAborted,
|
|
1880
1056
|
isCancelled: isAborted,
|
|
1881
1057
|
errorDetails: isAborted ? void 0 : error.message,
|
|
1882
|
-
content: isAborted ? state.finalResponse || "" : state.finalResponse ||
|
|
1058
|
+
content: isAborted ? state.finalResponse || "" : state.finalResponse || FRIENDLY_ERROR_MESSAGE,
|
|
1883
1059
|
currentMessage: isAborted ? "Thinking..." : void 0,
|
|
1884
1060
|
formattedThinkingText: state.formattedThinkingText || void 0,
|
|
1885
1061
|
steps: [...state.steps].map((step) => {
|
|
@@ -1911,7 +1087,7 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
|
|
|
1911
1087
|
id: streamingId,
|
|
1912
1088
|
sessionId: state.sessionId || sessionId,
|
|
1913
1089
|
role: "assistant",
|
|
1914
|
-
content: state.hasError ?
|
|
1090
|
+
content: state.hasError ? FRIENDLY_ERROR_MESSAGE : state.finalResponse || "",
|
|
1915
1091
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1916
1092
|
isStreaming: false,
|
|
1917
1093
|
streamProgress: state.hasError ? "error" : "completed",
|
|
@@ -1982,7 +1158,7 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
|
|
|
1982
1158
|
isError: !isAborted,
|
|
1983
1159
|
isCancelled: isAborted,
|
|
1984
1160
|
errorDetails: isAborted ? void 0 : error.message,
|
|
1985
|
-
content: isAborted ? state.finalResponse || "" : state.finalResponse ||
|
|
1161
|
+
content: isAborted ? state.finalResponse || "" : state.finalResponse || FRIENDLY_ERROR_MESSAGE,
|
|
1986
1162
|
formattedThinkingText: state.formattedThinkingText || void 0,
|
|
1987
1163
|
steps: [...state.steps].map((step) => {
|
|
1988
1164
|
if (step.status === "in_progress" && isAborted) {
|
|
@@ -2009,45 +1185,199 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
|
|
|
2009
1185
|
};
|
|
2010
1186
|
}
|
|
2011
1187
|
|
|
1188
|
+
// src/utils/workflowUsersClient.ts
|
|
1189
|
+
var DEFAULT_SESSION_PAGE_SIZE = 20;
|
|
1190
|
+
var DEFAULT_CONVERSATION_PAGE_SIZE = 50;
|
|
1191
|
+
function getStageParamName2(config) {
|
|
1192
|
+
return config.api.stageQueryParam ?? "stage";
|
|
1193
|
+
}
|
|
1194
|
+
function requireOwnerId(config) {
|
|
1195
|
+
const ownerId = config.session?.owner?.id;
|
|
1196
|
+
if (!ownerId) {
|
|
1197
|
+
throw new Error(
|
|
1198
|
+
"workflowUsersClient: session.owner.id is required to call this endpoint."
|
|
1199
|
+
);
|
|
1200
|
+
}
|
|
1201
|
+
return ownerId;
|
|
1202
|
+
}
|
|
1203
|
+
function requireWorkflowName(config) {
|
|
1204
|
+
const workflowName = config.workflow.name;
|
|
1205
|
+
if (!workflowName) {
|
|
1206
|
+
throw new Error(
|
|
1207
|
+
"workflowUsersClient: workflow.name is required to call this endpoint."
|
|
1208
|
+
);
|
|
1209
|
+
}
|
|
1210
|
+
return workflowName;
|
|
1211
|
+
}
|
|
1212
|
+
function requireWorkflowId(config) {
|
|
1213
|
+
const workflowId = config.workflow.id;
|
|
1214
|
+
if (!workflowId) {
|
|
1215
|
+
throw new Error(
|
|
1216
|
+
"workflowUsersClient: workflow.id is required to call this endpoint."
|
|
1217
|
+
);
|
|
1218
|
+
}
|
|
1219
|
+
return workflowId;
|
|
1220
|
+
}
|
|
1221
|
+
function isPlaygroundYaakAuth(config) {
|
|
1222
|
+
if (config.api.authToken) return false;
|
|
1223
|
+
const headers = config.api.headers;
|
|
1224
|
+
if (!headers) return false;
|
|
1225
|
+
for (const key of Object.keys(headers)) {
|
|
1226
|
+
const lower = key.toLowerCase();
|
|
1227
|
+
if (lower === "yaak-api-key" || lower === "x-yaak-api-key") return true;
|
|
1228
|
+
}
|
|
1229
|
+
return false;
|
|
1230
|
+
}
|
|
1231
|
+
async function fetchJson(url, headers, signal) {
|
|
1232
|
+
const response = await fetch(url, {
|
|
1233
|
+
method: "GET",
|
|
1234
|
+
headers,
|
|
1235
|
+
signal
|
|
1236
|
+
});
|
|
1237
|
+
if (!response.ok) {
|
|
1238
|
+
const errorText = await response.text();
|
|
1239
|
+
throw new Error(`HTTP ${response.status}: ${errorText}`);
|
|
1240
|
+
}
|
|
1241
|
+
return await response.json();
|
|
1242
|
+
}
|
|
1243
|
+
async function listSessions(config, opts = {}) {
|
|
1244
|
+
const ownerId = requireOwnerId(config);
|
|
1245
|
+
const useYaakEndpoint = isPlaygroundYaakAuth(config);
|
|
1246
|
+
const params = new URLSearchParams({
|
|
1247
|
+
page: String(opts.page ?? 0),
|
|
1248
|
+
size: String(opts.size ?? DEFAULT_SESSION_PAGE_SIZE)
|
|
1249
|
+
});
|
|
1250
|
+
if (useYaakEndpoint) {
|
|
1251
|
+
params.set("workflowUserId", ownerId);
|
|
1252
|
+
params.set("workflowName", requireWorkflowName(config));
|
|
1253
|
+
} else {
|
|
1254
|
+
params.set("workflowId", requireWorkflowId(config));
|
|
1255
|
+
}
|
|
1256
|
+
if (config.workflow.stage) {
|
|
1257
|
+
params.set(getStageParamName2(config), config.workflow.stage);
|
|
1258
|
+
}
|
|
1259
|
+
const url = useYaakEndpoint ? `${config.api.baseUrl}/api/workflows/ask/sessions?${params.toString()}` : `${config.api.baseUrl}/api/workflow-users/${encodeURIComponent(
|
|
1260
|
+
ownerId
|
|
1261
|
+
)}/sessions?${params.toString()}`;
|
|
1262
|
+
return fetchJson(
|
|
1263
|
+
url,
|
|
1264
|
+
buildRequestHeaders(config),
|
|
1265
|
+
opts.signal
|
|
1266
|
+
);
|
|
1267
|
+
}
|
|
1268
|
+
async function listConversations(config, opts) {
|
|
1269
|
+
const ownerId = requireOwnerId(config);
|
|
1270
|
+
const useYaakEndpoint = isPlaygroundYaakAuth(config);
|
|
1271
|
+
const params = new URLSearchParams({
|
|
1272
|
+
sessionId: opts.sessionId,
|
|
1273
|
+
page: String(opts.page ?? 0),
|
|
1274
|
+
size: String(opts.size ?? DEFAULT_CONVERSATION_PAGE_SIZE)
|
|
1275
|
+
});
|
|
1276
|
+
if (useYaakEndpoint) {
|
|
1277
|
+
params.set("workflowUserId", ownerId);
|
|
1278
|
+
params.set("workflowName", requireWorkflowName(config));
|
|
1279
|
+
}
|
|
1280
|
+
if (config.workflow.stage) {
|
|
1281
|
+
params.set(getStageParamName2(config), config.workflow.stage);
|
|
1282
|
+
}
|
|
1283
|
+
const url = useYaakEndpoint ? `${config.api.baseUrl}/api/workflows/ask/conversations?${params.toString()}` : `${config.api.baseUrl}/api/workflow-users/${encodeURIComponent(
|
|
1284
|
+
ownerId
|
|
1285
|
+
)}/conversations?${params.toString()}`;
|
|
1286
|
+
return fetchJson(
|
|
1287
|
+
url,
|
|
1288
|
+
buildRequestHeaders(config),
|
|
1289
|
+
opts.signal
|
|
1290
|
+
);
|
|
1291
|
+
}
|
|
1292
|
+
|
|
2012
1293
|
// src/hooks/useChatV2.ts
|
|
1294
|
+
function conversationEntryToMessages(entry, sessionId) {
|
|
1295
|
+
return [
|
|
1296
|
+
{
|
|
1297
|
+
id: `history-user-${entry.executionId}`,
|
|
1298
|
+
sessionId,
|
|
1299
|
+
role: "user",
|
|
1300
|
+
content: entry.query,
|
|
1301
|
+
timestamp: entry.createdAt,
|
|
1302
|
+
isHistorical: true
|
|
1303
|
+
},
|
|
1304
|
+
{
|
|
1305
|
+
id: `history-assistant-${entry.executionId}`,
|
|
1306
|
+
sessionId,
|
|
1307
|
+
role: "assistant",
|
|
1308
|
+
content: entry.response,
|
|
1309
|
+
timestamp: entry.createdAt,
|
|
1310
|
+
executionId: entry.executionId,
|
|
1311
|
+
isHistorical: true
|
|
1312
|
+
}
|
|
1313
|
+
];
|
|
1314
|
+
}
|
|
1315
|
+
function streamKeyFor(scopeKey, sessionId) {
|
|
1316
|
+
return `${scopeKey}|sid:${sessionId ?? ""}`;
|
|
1317
|
+
}
|
|
2013
1318
|
function useChatV2(config, callbacks = {}) {
|
|
1319
|
+
const scopeKey = useMemo(() => buildScopeKey(config), [
|
|
1320
|
+
config.session?.userId,
|
|
1321
|
+
config.workflow.id,
|
|
1322
|
+
config.workflow.version,
|
|
1323
|
+
config.workflow.stage
|
|
1324
|
+
]);
|
|
1325
|
+
const initialSessionId = chatStore.get(scopeKey).find((m) => m.sessionId)?.sessionId ?? config.session?.initialId ?? void 0;
|
|
2014
1326
|
const [messages, setMessages] = useState(() => {
|
|
2015
|
-
|
|
2016
|
-
|
|
1327
|
+
const stored = chatStore.get(scopeKey);
|
|
1328
|
+
if (stored.length > 0) return stored;
|
|
1329
|
+
return config.session?.initialMessages ?? [];
|
|
2017
1330
|
});
|
|
2018
1331
|
const [isWaitingForResponse, setIsWaitingForResponse] = useState(false);
|
|
2019
|
-
const
|
|
2020
|
-
|
|
2021
|
-
);
|
|
2022
|
-
const
|
|
1332
|
+
const [loadingSessionId, setLoadingSessionId] = useState(void 0);
|
|
1333
|
+
const [currentSessionId, setCurrentSessionId] = useState(initialSessionId);
|
|
1334
|
+
const sessionIdRef = useRef(initialSessionId);
|
|
1335
|
+
const prevScopeKeyRef = useRef(scopeKey);
|
|
1336
|
+
const activeStreamSessionRef = useRef(void 0);
|
|
2023
1337
|
const callbacksRef = useRef(callbacks);
|
|
2024
1338
|
callbacksRef.current = callbacks;
|
|
2025
1339
|
const configRef = useRef(config);
|
|
2026
1340
|
configRef.current = config;
|
|
1341
|
+
const scopeKeyRef = useRef(scopeKey);
|
|
1342
|
+
scopeKeyRef.current = scopeKey;
|
|
2027
1343
|
const messagesRef = useRef(messages);
|
|
2028
1344
|
messagesRef.current = messages;
|
|
2029
1345
|
const storeAwareSetMessages = useCallback(
|
|
2030
1346
|
(updater) => {
|
|
2031
|
-
const
|
|
2032
|
-
|
|
2033
|
-
|
|
1347
|
+
const scope = scopeKeyRef.current;
|
|
1348
|
+
const streamSid = activeStreamSessionRef.current;
|
|
1349
|
+
if (streamSid !== void 0) {
|
|
1350
|
+
const streamKey = streamKeyFor(scope, streamSid);
|
|
1351
|
+
if (activeStreamStore.has(streamKey)) {
|
|
1352
|
+
activeStreamStore.applyMessages(
|
|
1353
|
+
streamKey,
|
|
1354
|
+
updater
|
|
1355
|
+
);
|
|
1356
|
+
}
|
|
1357
|
+
if (sessionIdRef.current === streamSid) {
|
|
1358
|
+
setMessages(updater);
|
|
1359
|
+
}
|
|
1360
|
+
return;
|
|
2034
1361
|
}
|
|
2035
1362
|
setMessages(updater);
|
|
2036
1363
|
},
|
|
2037
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2038
1364
|
[]
|
|
2039
1365
|
);
|
|
2040
|
-
const storeAwareSetIsWaiting = useCallback(
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
1366
|
+
const storeAwareSetIsWaiting = useCallback((waiting) => {
|
|
1367
|
+
const scope = scopeKeyRef.current;
|
|
1368
|
+
const streamSid = activeStreamSessionRef.current;
|
|
1369
|
+
if (streamSid !== void 0) {
|
|
1370
|
+
const streamKey = streamKeyFor(scope, streamSid);
|
|
1371
|
+
if (activeStreamStore.has(streamKey)) {
|
|
1372
|
+
activeStreamStore.setWaiting(streamKey, waiting);
|
|
2045
1373
|
}
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
1374
|
+
if (sessionIdRef.current === streamSid) {
|
|
1375
|
+
setIsWaitingForResponse(waiting);
|
|
1376
|
+
}
|
|
1377
|
+
return;
|
|
1378
|
+
}
|
|
1379
|
+
setIsWaitingForResponse(waiting);
|
|
1380
|
+
}, []);
|
|
2051
1381
|
const [userActionState, setUserActionState] = useState({
|
|
2052
1382
|
request: null,
|
|
2053
1383
|
result: null,
|
|
@@ -2055,38 +1385,43 @@ function useChatV2(config, callbacks = {}) {
|
|
|
2055
1385
|
});
|
|
2056
1386
|
const userActionStateRef = useRef(userActionState);
|
|
2057
1387
|
userActionStateRef.current = userActionState;
|
|
2058
|
-
const wrappedCallbacks = useMemo(
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
1388
|
+
const wrappedCallbacks = useMemo(
|
|
1389
|
+
() => ({
|
|
1390
|
+
...callbacksRef.current,
|
|
1391
|
+
onMessageSent: (message) => callbacksRef.current.onMessageSent?.(message),
|
|
1392
|
+
onStreamStart: () => callbacksRef.current.onStreamStart?.(),
|
|
1393
|
+
onStreamComplete: (message) => callbacksRef.current.onStreamComplete?.(message),
|
|
1394
|
+
onError: (error) => callbacksRef.current.onError?.(error),
|
|
1395
|
+
onExecutionTraceClick: (data) => callbacksRef.current.onExecutionTraceClick?.(data),
|
|
1396
|
+
onSessionIdChange: (sessionId) => callbacksRef.current.onSessionIdChange?.(sessionId),
|
|
1397
|
+
onUserActionRequired: (request) => {
|
|
1398
|
+
setUserActionState((prev) => ({ ...prev, request, result: null }));
|
|
1399
|
+
callbacksRef.current.onUserActionRequired?.(request);
|
|
1400
|
+
},
|
|
1401
|
+
onUserActionEvent: (eventType, message) => {
|
|
1402
|
+
switch (eventType) {
|
|
1403
|
+
case "USER_ACTION_SUCCESS":
|
|
1404
|
+
setUserActionState((prev) => ({ ...prev, request: null, result: "approved" }));
|
|
1405
|
+
break;
|
|
1406
|
+
case "USER_ACTION_REJECTED":
|
|
1407
|
+
setUserActionState((prev) => ({ ...prev, request: null, result: "rejected" }));
|
|
1408
|
+
break;
|
|
1409
|
+
case "USER_ACTION_EXPIRED":
|
|
1410
|
+
case "USER_ACTION_FAILED":
|
|
1411
|
+
setUserActionState((prev) => ({ ...prev, request: null }));
|
|
1412
|
+
break;
|
|
1413
|
+
case "USER_ACTION_INVALID":
|
|
1414
|
+
setUserActionState((prev) => ({
|
|
1415
|
+
...prev,
|
|
1416
|
+
clearOtpTrigger: prev.clearOtpTrigger + 1
|
|
1417
|
+
}));
|
|
1418
|
+
break;
|
|
1419
|
+
}
|
|
1420
|
+
callbacksRef.current.onUserActionEvent?.(eventType, message);
|
|
2085
1421
|
}
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
}), []);
|
|
1422
|
+
}),
|
|
1423
|
+
[]
|
|
1424
|
+
);
|
|
2090
1425
|
const { startStream, cancelStream: cancelStreamManager, abortControllerRef } = useStreamManagerV2(
|
|
2091
1426
|
config,
|
|
2092
1427
|
wrappedCallbacks,
|
|
@@ -2096,8 +1431,10 @@ function useChatV2(config, callbacks = {}) {
|
|
|
2096
1431
|
const sendMessage = useCallback(
|
|
2097
1432
|
async (userMessage) => {
|
|
2098
1433
|
if (!userMessage.trim()) return;
|
|
2099
|
-
|
|
1434
|
+
const autoGen = configRef.current.session?.autoGenerateId;
|
|
1435
|
+
if (!sessionIdRef.current && autoGen !== false) {
|
|
2100
1436
|
sessionIdRef.current = generateId();
|
|
1437
|
+
setCurrentSessionId(sessionIdRef.current);
|
|
2101
1438
|
callbacksRef.current.onSessionIdChange?.(sessionIdRef.current);
|
|
2102
1439
|
}
|
|
2103
1440
|
const userMessageId = `user-${Date.now()}`;
|
|
@@ -2129,38 +1466,40 @@ function useChatV2(config, callbacks = {}) {
|
|
|
2129
1466
|
};
|
|
2130
1467
|
setMessages((prev) => [...prev, streamingMsg]);
|
|
2131
1468
|
const abortController = new AbortController();
|
|
2132
|
-
const
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
1469
|
+
const scope = scopeKeyRef.current;
|
|
1470
|
+
const streamSessionId = sessionIdRef.current;
|
|
1471
|
+
const streamKey = streamKeyFor(scope, streamSessionId);
|
|
1472
|
+
activeStreamSessionRef.current = streamSessionId;
|
|
1473
|
+
const initialMessages = [...messagesRef.current, userMsg, streamingMsg];
|
|
1474
|
+
activeStreamStore.start(streamKey, abortController, initialMessages);
|
|
2137
1475
|
const newSessionId = await startStream(
|
|
2138
1476
|
userMessage,
|
|
2139
1477
|
streamingId,
|
|
2140
|
-
|
|
1478
|
+
streamSessionId,
|
|
2141
1479
|
abortController
|
|
2142
1480
|
);
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
if (!abortController.signal.aborted && newSessionId && newSessionId !== sessionIdRef.current) {
|
|
1481
|
+
activeStreamStore.complete(streamKey);
|
|
1482
|
+
activeStreamSessionRef.current = void 0;
|
|
1483
|
+
if (!abortController.signal.aborted && newSessionId && newSessionId !== streamSessionId && sessionIdRef.current === streamSessionId) {
|
|
2147
1484
|
sessionIdRef.current = newSessionId;
|
|
1485
|
+
setCurrentSessionId(newSessionId);
|
|
2148
1486
|
}
|
|
2149
1487
|
},
|
|
2150
1488
|
[startStream]
|
|
2151
1489
|
);
|
|
2152
1490
|
const clearMessages = useCallback(() => {
|
|
2153
|
-
|
|
2154
|
-
chatStore.delete(configRef.current.userId);
|
|
2155
|
-
}
|
|
1491
|
+
chatStore.delete(scopeKeyRef.current);
|
|
2156
1492
|
setMessages([]);
|
|
2157
1493
|
}, []);
|
|
2158
1494
|
const prependMessages = useCallback((msgs) => {
|
|
2159
1495
|
setMessages((prev) => [...msgs, ...prev]);
|
|
2160
1496
|
}, []);
|
|
2161
1497
|
const cancelStream = useCallback(() => {
|
|
2162
|
-
|
|
2163
|
-
|
|
1498
|
+
const scope = scopeKeyRef.current;
|
|
1499
|
+
const viewSid = sessionIdRef.current;
|
|
1500
|
+
const viewStreamKey = streamKeyFor(scope, viewSid);
|
|
1501
|
+
if (activeStreamStore.has(viewStreamKey)) {
|
|
1502
|
+
activeStreamStore.abort(viewStreamKey);
|
|
2164
1503
|
}
|
|
2165
1504
|
cancelStreamManager();
|
|
2166
1505
|
setIsWaitingForResponse(false);
|
|
@@ -2170,10 +1509,7 @@ function useChatV2(config, callbacks = {}) {
|
|
|
2170
1509
|
if (msg.isStreaming) {
|
|
2171
1510
|
return {
|
|
2172
1511
|
...msg,
|
|
2173
|
-
...createCancelledMessageUpdate(
|
|
2174
|
-
msg.steps || [],
|
|
2175
|
-
msg.currentMessage
|
|
2176
|
-
)
|
|
1512
|
+
...createCancelledMessageUpdate(msg.steps || [], msg.currentMessage)
|
|
2177
1513
|
};
|
|
2178
1514
|
}
|
|
2179
1515
|
return msg;
|
|
@@ -2181,39 +1517,37 @@ function useChatV2(config, callbacks = {}) {
|
|
|
2181
1517
|
);
|
|
2182
1518
|
}, [cancelStreamManager]);
|
|
2183
1519
|
const resetSession = useCallback(() => {
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
1520
|
+
const scope = scopeKeyRef.current;
|
|
1521
|
+
const viewSid = sessionIdRef.current;
|
|
1522
|
+
const viewStreamKey = streamKeyFor(scope, viewSid);
|
|
1523
|
+
if (activeStreamStore.has(viewStreamKey)) {
|
|
1524
|
+
activeStreamStore.abort(viewStreamKey);
|
|
2187
1525
|
}
|
|
1526
|
+
chatStore.delete(scope);
|
|
2188
1527
|
setMessages([]);
|
|
2189
1528
|
sessionIdRef.current = void 0;
|
|
1529
|
+
setCurrentSessionId(void 0);
|
|
1530
|
+
activeStreamSessionRef.current = void 0;
|
|
2190
1531
|
abortControllerRef.current?.abort();
|
|
2191
1532
|
setIsWaitingForResponse(false);
|
|
2192
1533
|
setUserActionState({ request: null, result: null, clearOtpTrigger: 0 });
|
|
2193
1534
|
}, []);
|
|
2194
|
-
const getSessionId = useCallback(() =>
|
|
2195
|
-
|
|
1535
|
+
const getSessionId = useCallback(() => sessionIdRef.current, []);
|
|
1536
|
+
const getMessages = useCallback(() => messages, [messages]);
|
|
1537
|
+
const approveUserAction = useCallback(async (otp) => {
|
|
1538
|
+
const request = userActionStateRef.current.request;
|
|
1539
|
+
if (!request) return;
|
|
1540
|
+
try {
|
|
1541
|
+
await submitUserAction(configRef.current, request.userActionId, { otp });
|
|
1542
|
+
} catch (error) {
|
|
1543
|
+
setUserActionState((prev) => ({
|
|
1544
|
+
...prev,
|
|
1545
|
+
clearOtpTrigger: prev.clearOtpTrigger + 1
|
|
1546
|
+
}));
|
|
1547
|
+
callbacksRef.current.onError?.(error);
|
|
1548
|
+
throw error;
|
|
1549
|
+
}
|
|
2196
1550
|
}, []);
|
|
2197
|
-
const getMessages = useCallback(() => {
|
|
2198
|
-
return messages;
|
|
2199
|
-
}, [messages]);
|
|
2200
|
-
const approveUserAction = useCallback(
|
|
2201
|
-
async (otp) => {
|
|
2202
|
-
const request = userActionStateRef.current.request;
|
|
2203
|
-
if (!request) return;
|
|
2204
|
-
try {
|
|
2205
|
-
await submitUserAction(configRef.current, request.userActionId, { otp });
|
|
2206
|
-
} catch (error) {
|
|
2207
|
-
setUserActionState((prev) => ({
|
|
2208
|
-
...prev,
|
|
2209
|
-
clearOtpTrigger: prev.clearOtpTrigger + 1
|
|
2210
|
-
}));
|
|
2211
|
-
callbacksRef.current.onError?.(error);
|
|
2212
|
-
throw error;
|
|
2213
|
-
}
|
|
2214
|
-
},
|
|
2215
|
-
[]
|
|
2216
|
-
);
|
|
2217
1551
|
const rejectUserAction = useCallback(async () => {
|
|
2218
1552
|
const request = userActionStateRef.current.request;
|
|
2219
1553
|
if (!request) return;
|
|
@@ -2247,43 +1581,91 @@ function useChatV2(config, callbacks = {}) {
|
|
|
2247
1581
|
throw error;
|
|
2248
1582
|
}
|
|
2249
1583
|
}, []);
|
|
1584
|
+
const inFlightLoadRef = useRef(null);
|
|
1585
|
+
const loadingSessionIdRef = useRef(void 0);
|
|
1586
|
+
loadingSessionIdRef.current = loadingSessionId;
|
|
1587
|
+
const loadSession = useCallback(async (sessionId) => {
|
|
1588
|
+
const inFlight = inFlightLoadRef.current;
|
|
1589
|
+
if (inFlight && inFlight.sessionId === sessionId) {
|
|
1590
|
+
return inFlight.promise;
|
|
1591
|
+
}
|
|
1592
|
+
if (sessionIdRef.current === sessionId && loadingSessionIdRef.current !== sessionId) {
|
|
1593
|
+
return;
|
|
1594
|
+
}
|
|
1595
|
+
const run = async () => {
|
|
1596
|
+
const scope = scopeKeyRef.current;
|
|
1597
|
+
setUserActionState({ request: null, result: null, clearOtpTrigger: 0 });
|
|
1598
|
+
sessionIdRef.current = sessionId;
|
|
1599
|
+
setCurrentSessionId(sessionId);
|
|
1600
|
+
callbacksRef.current.onSessionIdChange?.(sessionId);
|
|
1601
|
+
const streamKey = streamKeyFor(scope, sessionId);
|
|
1602
|
+
const active = activeStreamStore.get(streamKey);
|
|
1603
|
+
if (active) {
|
|
1604
|
+
setMessages(active.messages);
|
|
1605
|
+
setIsWaitingForResponse(active.isWaiting);
|
|
1606
|
+
setLoadingSessionId(void 0);
|
|
1607
|
+
return;
|
|
1608
|
+
}
|
|
1609
|
+
setIsWaitingForResponse(false);
|
|
1610
|
+
setMessages([]);
|
|
1611
|
+
chatStore.delete(scope);
|
|
1612
|
+
setLoadingSessionId(sessionId);
|
|
1613
|
+
try {
|
|
1614
|
+
const response = await listConversations(configRef.current, { sessionId });
|
|
1615
|
+
const entries = response.data ?? [];
|
|
1616
|
+
const historical = entries.flatMap((entry) => conversationEntryToMessages(entry, sessionId));
|
|
1617
|
+
if (sessionIdRef.current === sessionId) {
|
|
1618
|
+
setMessages(historical);
|
|
1619
|
+
}
|
|
1620
|
+
if (historical.length > 0) {
|
|
1621
|
+
chatStore.set(scope, historical);
|
|
1622
|
+
}
|
|
1623
|
+
} catch (error) {
|
|
1624
|
+
callbacksRef.current.onError?.(error);
|
|
1625
|
+
throw error;
|
|
1626
|
+
} finally {
|
|
1627
|
+
setLoadingSessionId((current) => current === sessionId ? void 0 : current);
|
|
1628
|
+
}
|
|
1629
|
+
};
|
|
1630
|
+
const promise = run().finally(() => {
|
|
1631
|
+
if (inFlightLoadRef.current?.sessionId === sessionId) {
|
|
1632
|
+
inFlightLoadRef.current = null;
|
|
1633
|
+
}
|
|
1634
|
+
});
|
|
1635
|
+
inFlightLoadRef.current = { sessionId, promise };
|
|
1636
|
+
return promise;
|
|
1637
|
+
}, []);
|
|
2250
1638
|
useEffect(() => {
|
|
2251
|
-
const
|
|
2252
|
-
|
|
2253
|
-
const unsubscribe = activeStreamStore.subscribe(userId, (msgs, isWaiting) => {
|
|
1639
|
+
const key = streamKeyFor(scopeKey, currentSessionId);
|
|
1640
|
+
const unsubscribe = activeStreamStore.subscribe(key, (msgs, isWaiting) => {
|
|
2254
1641
|
setMessages(msgs);
|
|
2255
1642
|
setIsWaitingForResponse(isWaiting);
|
|
2256
1643
|
});
|
|
2257
|
-
const active = activeStreamStore.get(
|
|
1644
|
+
const active = activeStreamStore.get(key);
|
|
2258
1645
|
if (active) {
|
|
2259
1646
|
setMessages(active.messages);
|
|
2260
1647
|
setIsWaitingForResponse(active.isWaiting);
|
|
2261
1648
|
}
|
|
2262
1649
|
return unsubscribe;
|
|
2263
|
-
}, []);
|
|
1650
|
+
}, [scopeKey, currentSessionId]);
|
|
2264
1651
|
useEffect(() => {
|
|
2265
|
-
if (!config.userId) return;
|
|
2266
1652
|
const toSave = messages.filter((m) => !m.isStreaming);
|
|
2267
1653
|
if (toSave.length > 0) {
|
|
2268
|
-
chatStore.set(
|
|
1654
|
+
chatStore.set(scopeKey, toSave);
|
|
2269
1655
|
}
|
|
2270
|
-
}, [messages,
|
|
1656
|
+
}, [messages, scopeKey]);
|
|
2271
1657
|
useEffect(() => {
|
|
2272
|
-
const
|
|
2273
|
-
|
|
2274
|
-
if (
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
setMessages(stored);
|
|
2284
|
-
sessionIdRef.current = stored.find((m) => m.sessionId)?.sessionId;
|
|
2285
|
-
}
|
|
2286
|
-
}, [config.userId]);
|
|
1658
|
+
const prevKey = prevScopeKeyRef.current;
|
|
1659
|
+
prevScopeKeyRef.current = scopeKey;
|
|
1660
|
+
if (prevKey === scopeKey) return;
|
|
1661
|
+
const stored = chatStore.get(scopeKey);
|
|
1662
|
+
setMessages(stored);
|
|
1663
|
+
const restoredSessionId = stored.find((m) => m.sessionId)?.sessionId ?? configRef.current.session?.initialId ?? void 0;
|
|
1664
|
+
sessionIdRef.current = restoredSessionId;
|
|
1665
|
+
setCurrentSessionId(restoredSessionId);
|
|
1666
|
+
setIsWaitingForResponse(false);
|
|
1667
|
+
setUserActionState({ request: null, result: null, clearOtpTrigger: 0 });
|
|
1668
|
+
}, [scopeKey]);
|
|
2287
1669
|
return {
|
|
2288
1670
|
messages,
|
|
2289
1671
|
sendMessage,
|
|
@@ -2294,11 +1676,13 @@ function useChatV2(config, callbacks = {}) {
|
|
|
2294
1676
|
getSessionId,
|
|
2295
1677
|
getMessages,
|
|
2296
1678
|
isWaitingForResponse,
|
|
2297
|
-
sessionId:
|
|
1679
|
+
sessionId: currentSessionId,
|
|
2298
1680
|
userActionState,
|
|
2299
1681
|
approveUserAction,
|
|
2300
1682
|
rejectUserAction,
|
|
2301
|
-
resendOtp
|
|
1683
|
+
resendOtp,
|
|
1684
|
+
loadSession,
|
|
1685
|
+
loadingSessionId
|
|
2302
1686
|
};
|
|
2303
1687
|
}
|
|
2304
1688
|
function getSpeechRecognition() {
|
|
@@ -2517,6 +1901,6 @@ function useVoice(config = {}, callbacks = {}) {
|
|
|
2517
1901
|
};
|
|
2518
1902
|
}
|
|
2519
1903
|
|
|
2520
|
-
export { buildFormattedThinking, cancelUserAction, createInitialV2State, generateId, processStreamEventV2, resendUserAction, streamWorkflowEvents, submitUserAction,
|
|
1904
|
+
export { buildFormattedThinking, buildScopeKey, cancelUserAction, createInitialV2State, generateId, listConversations, listSessions, processStreamEventV2, resendUserAction, streamWorkflowEvents, submitUserAction, useChatV2, useVoice, workingPhaseDetailForDisplay };
|
|
2521
1905
|
//# sourceMappingURL=index.mjs.map
|
|
2522
1906
|
//# sourceMappingURL=index.mjs.map
|