@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.native.js
CHANGED
|
@@ -4,7 +4,7 @@ var react = require('react');
|
|
|
4
4
|
var reactNativeMmkv = require('react-native-mmkv');
|
|
5
5
|
var expoSpeechRecognition = require('expo-speech-recognition');
|
|
6
6
|
|
|
7
|
-
// src/hooks/
|
|
7
|
+
// src/hooks/useChatV2.ts
|
|
8
8
|
|
|
9
9
|
// src/utils/generateId.ts
|
|
10
10
|
function generateId() {
|
|
@@ -173,13 +173,13 @@ function getEventMessage(event) {
|
|
|
173
173
|
case "USER_ACTION_REQUIRED":
|
|
174
174
|
return "Waiting for verification...";
|
|
175
175
|
case "USER_ACTION_SUCCESS":
|
|
176
|
-
return "Verification
|
|
176
|
+
return "Verification approved";
|
|
177
177
|
case "USER_ACTION_EXPIRED":
|
|
178
178
|
return "Verification expired";
|
|
179
179
|
case "USER_ACTION_INVALID":
|
|
180
|
-
return "Invalid
|
|
180
|
+
return "Invalid code. Please try again.";
|
|
181
181
|
case "USER_ACTION_REJECTED":
|
|
182
|
-
return "Verification
|
|
182
|
+
return "Verification cancelled";
|
|
183
183
|
case "USER_ACTION_RESENT":
|
|
184
184
|
return "Verification code resent";
|
|
185
185
|
case "USER_ACTION_FAILED":
|
|
@@ -194,6 +194,31 @@ function getEventMessage(event) {
|
|
|
194
194
|
return eventType;
|
|
195
195
|
}
|
|
196
196
|
}
|
|
197
|
+
function isUserActionPrompt(text) {
|
|
198
|
+
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);
|
|
199
|
+
}
|
|
200
|
+
function getUserActionDisplayMessage(eventType, rawMessage) {
|
|
201
|
+
const raw = rawMessage?.trim();
|
|
202
|
+
const safeRaw = raw && !isUserActionPrompt(raw) ? raw : "";
|
|
203
|
+
switch (eventType) {
|
|
204
|
+
case "USER_ACTION_REQUIRED":
|
|
205
|
+
return raw || "Waiting for verification...";
|
|
206
|
+
case "USER_ACTION_SUCCESS":
|
|
207
|
+
return safeRaw || "Verification approved";
|
|
208
|
+
case "USER_ACTION_INVALID":
|
|
209
|
+
return safeRaw || "Invalid code. Please try again.";
|
|
210
|
+
case "USER_ACTION_REJECTED":
|
|
211
|
+
return safeRaw || "Verification cancelled";
|
|
212
|
+
case "USER_ACTION_EXPIRED":
|
|
213
|
+
return safeRaw || "Verification expired";
|
|
214
|
+
case "USER_ACTION_RESENT":
|
|
215
|
+
return safeRaw || "Verification code resent";
|
|
216
|
+
case "USER_ACTION_FAILED":
|
|
217
|
+
return safeRaw || "Verification failed";
|
|
218
|
+
default:
|
|
219
|
+
return safeRaw || raw || eventType;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
197
222
|
function workingPhaseDetailForDisplay(raw) {
|
|
198
223
|
const t = raw.trim();
|
|
199
224
|
if (!t) return "";
|
|
@@ -224,290 +249,8 @@ function extractResponseContent(response) {
|
|
|
224
249
|
}
|
|
225
250
|
return "";
|
|
226
251
|
}
|
|
227
|
-
function completeLastInProgressStep(steps) {
|
|
228
|
-
for (let i = steps.length - 1; i >= 0; i--) {
|
|
229
|
-
if (steps[i].status === "in_progress") {
|
|
230
|
-
steps[i].status = "completed";
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
function processStreamEvent(event, state) {
|
|
236
|
-
const eventType = event.eventType;
|
|
237
|
-
if (typeof eventType === "string" && eventType.toUpperCase() === "KEEP_ALIVE") {
|
|
238
|
-
return state;
|
|
239
|
-
}
|
|
240
|
-
const message = getEventMessage(event);
|
|
241
|
-
if (eventType !== "INTENT_THINKING" && eventType !== "INTENT_THINKING_CONT") {
|
|
242
|
-
if (state.currentThinkingStepId) {
|
|
243
|
-
const thinkingStep = state.steps.find((s) => s.id === state.currentThinkingStepId);
|
|
244
|
-
if (thinkingStep) {
|
|
245
|
-
thinkingStep.isThinking = false;
|
|
246
|
-
}
|
|
247
|
-
state.currentThinkingStepId = void 0;
|
|
248
|
-
}
|
|
249
|
-
state.activeThinkingText = void 0;
|
|
250
|
-
}
|
|
251
|
-
if (eventType === "COMPLETED" || eventType === "WORKFLOW_COMPLETED") {
|
|
252
|
-
let content = extractResponseContent(event.response);
|
|
253
|
-
const trace = event.trace && typeof event.trace === "object" ? event.trace : null;
|
|
254
|
-
if (!content && trace?.workflowMsg && typeof trace.workflowMsg === "string") {
|
|
255
|
-
content = trace.workflowMsg;
|
|
256
|
-
}
|
|
257
|
-
if (!content && trace?.aggregator && typeof trace.aggregator === "object") {
|
|
258
|
-
const agg = trace.aggregator;
|
|
259
|
-
if (typeof agg.response === "string") content = agg.response;
|
|
260
|
-
else content = extractResponseContent(agg.response);
|
|
261
|
-
}
|
|
262
|
-
if (content) {
|
|
263
|
-
state.accumulatedContent = content;
|
|
264
|
-
state.finalData = event.response ?? event.trace;
|
|
265
|
-
state.hasError = false;
|
|
266
|
-
state.errorMessage = "";
|
|
267
|
-
} else {
|
|
268
|
-
state.hasError = true;
|
|
269
|
-
state.errorMessage = "WORKFLOW_FAILED";
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
if (eventType === "STARTED" || eventType === "WORKFLOW_STARTED") ; else if (eventType === "COMPLETED" || eventType === "WORKFLOW_COMPLETED") {
|
|
273
|
-
state.steps.forEach((step) => {
|
|
274
|
-
if (step.status === "in_progress") {
|
|
275
|
-
step.status = "completed";
|
|
276
|
-
}
|
|
277
|
-
});
|
|
278
|
-
} else if (eventType === "INTENT_ERROR") {
|
|
279
|
-
state.errorMessage = message || event.errorMessage || "An error occurred";
|
|
280
|
-
const intentStep = state.steps.find(
|
|
281
|
-
(s) => s.eventType === "INTENT_STARTED" && s.status === "in_progress"
|
|
282
|
-
);
|
|
283
|
-
if (intentStep) {
|
|
284
|
-
intentStep.status = "error";
|
|
285
|
-
}
|
|
286
|
-
} else if (eventType === "ERROR" || eventType === "WORKFLOW_ERROR") {
|
|
287
|
-
state.hasError = true;
|
|
288
|
-
state.errorMessage = message || event.errorMessage || "An error occurred";
|
|
289
|
-
} else if (eventType === "ORCHESTRATOR_COMPLETED") {
|
|
290
|
-
state.inOrchestratorPhase = false;
|
|
291
|
-
const orchestratorStep = state.steps.find(
|
|
292
|
-
(s) => s.eventType === "ORCHESTRATOR_THINKING" && s.status === "in_progress"
|
|
293
|
-
);
|
|
294
|
-
if (orchestratorStep) {
|
|
295
|
-
orchestratorStep.status = "completed";
|
|
296
|
-
if (event.elapsedMs) {
|
|
297
|
-
orchestratorStep.elapsedMs = event.elapsedMs;
|
|
298
|
-
}
|
|
299
|
-
if (orchestratorStep.id === state.currentExecutingStepId) {
|
|
300
|
-
state.currentExecutingStepId = void 0;
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
} else if (eventType === "INTENT_COMPLETED") {
|
|
304
|
-
const intentStep = state.steps.find(
|
|
305
|
-
(s) => s.eventType === "INTENT_STARTED" && s.status === "in_progress"
|
|
306
|
-
);
|
|
307
|
-
if (intentStep) {
|
|
308
|
-
intentStep.status = "completed";
|
|
309
|
-
if (event.elapsedMs) {
|
|
310
|
-
intentStep.elapsedMs = event.elapsedMs;
|
|
311
|
-
}
|
|
312
|
-
if (intentStep.id === state.currentExecutingStepId) {
|
|
313
|
-
state.currentExecutingStepId = void 0;
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
} else if (eventType === "AGGREGATOR_COMPLETED") {
|
|
317
|
-
state.inAggregatorPhase = false;
|
|
318
|
-
const aggregatorStep = state.steps.find(
|
|
319
|
-
(s) => s.eventType === "AGGREGATOR_THINKING" && s.status === "in_progress"
|
|
320
|
-
);
|
|
321
|
-
if (aggregatorStep) {
|
|
322
|
-
aggregatorStep.status = "completed";
|
|
323
|
-
if (event.elapsedMs) {
|
|
324
|
-
aggregatorStep.elapsedMs = event.elapsedMs;
|
|
325
|
-
}
|
|
326
|
-
if (aggregatorStep.id === state.currentExecutingStepId) {
|
|
327
|
-
state.currentExecutingStepId = void 0;
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
} else if (eventType === "ORCHESTRATOR_THINKING" || eventType === "INTENT_STARTED" || eventType === "INTENT_PROGRESS" || eventType === "AGGREGATOR_THINKING") {
|
|
331
|
-
if (eventType === "ORCHESTRATOR_THINKING") {
|
|
332
|
-
state.inOrchestratorPhase = true;
|
|
333
|
-
}
|
|
334
|
-
if (eventType === "AGGREGATOR_THINKING") {
|
|
335
|
-
state.inAggregatorPhase = true;
|
|
336
|
-
}
|
|
337
|
-
if (eventType === "INTENT_PROGRESS") {
|
|
338
|
-
const intentStep = state.steps.find(
|
|
339
|
-
(s) => s.eventType === "INTENT_STARTED" && s.status === "in_progress"
|
|
340
|
-
);
|
|
341
|
-
if (intentStep) {
|
|
342
|
-
intentStep.message = message;
|
|
343
|
-
state.currentExecutingStepId = intentStep.id;
|
|
344
|
-
} else {
|
|
345
|
-
const stepId = `step-${state.stepCounter++}`;
|
|
346
|
-
state.steps.push({
|
|
347
|
-
id: stepId,
|
|
348
|
-
eventType: "INTENT_STARTED",
|
|
349
|
-
message,
|
|
350
|
-
status: "in_progress",
|
|
351
|
-
timestamp: Date.now(),
|
|
352
|
-
elapsedMs: event.elapsedMs
|
|
353
|
-
});
|
|
354
|
-
state.currentExecutingStepId = stepId;
|
|
355
|
-
}
|
|
356
|
-
} else {
|
|
357
|
-
const stepId = `step-${state.stepCounter++}`;
|
|
358
|
-
state.steps.push({
|
|
359
|
-
id: stepId,
|
|
360
|
-
eventType,
|
|
361
|
-
message,
|
|
362
|
-
status: "in_progress",
|
|
363
|
-
timestamp: Date.now(),
|
|
364
|
-
elapsedMs: event.elapsedMs
|
|
365
|
-
});
|
|
366
|
-
state.currentExecutingStepId = stepId;
|
|
367
|
-
}
|
|
368
|
-
} else if (eventType === "USER_ACTION_REQUIRED") {
|
|
369
|
-
completeLastInProgressStep(state.steps);
|
|
370
|
-
if (event.userActionRequest) {
|
|
371
|
-
state.userActionRequest = {
|
|
372
|
-
userActionId: event.userActionRequest.userActionId,
|
|
373
|
-
userActionType: event.userActionRequest.userActionType,
|
|
374
|
-
message: event.userActionRequest.message,
|
|
375
|
-
requestedSchema: event.userActionRequest.requestedSchema,
|
|
376
|
-
metadata: event.userActionRequest.metadata
|
|
377
|
-
};
|
|
378
|
-
}
|
|
379
|
-
state.userActionPending = true;
|
|
380
|
-
const stepId = `step-${state.stepCounter++}`;
|
|
381
|
-
state.steps.push({
|
|
382
|
-
id: stepId,
|
|
383
|
-
eventType,
|
|
384
|
-
message,
|
|
385
|
-
status: "in_progress",
|
|
386
|
-
timestamp: Date.now(),
|
|
387
|
-
elapsedMs: event.elapsedMs
|
|
388
|
-
});
|
|
389
|
-
state.currentExecutingStepId = stepId;
|
|
390
|
-
} else if (eventType === "USER_ACTION_SUCCESS") {
|
|
391
|
-
completeLastInProgressStep(state.steps);
|
|
392
|
-
state.userActionRequest = void 0;
|
|
393
|
-
state.userActionPending = false;
|
|
394
|
-
state.userActionResult = "approved";
|
|
395
|
-
const stepId = `step-${state.stepCounter++}`;
|
|
396
|
-
state.steps.push({
|
|
397
|
-
id: stepId,
|
|
398
|
-
eventType,
|
|
399
|
-
message,
|
|
400
|
-
status: "completed",
|
|
401
|
-
timestamp: Date.now(),
|
|
402
|
-
elapsedMs: event.elapsedMs
|
|
403
|
-
});
|
|
404
|
-
} else if (eventType === "USER_ACTION_INVALID") {
|
|
405
|
-
completeLastInProgressStep(state.steps);
|
|
406
|
-
const errorStepId = `step-${state.stepCounter++}`;
|
|
407
|
-
state.steps.push({
|
|
408
|
-
id: errorStepId,
|
|
409
|
-
eventType,
|
|
410
|
-
message,
|
|
411
|
-
status: "error",
|
|
412
|
-
timestamp: Date.now(),
|
|
413
|
-
elapsedMs: event.elapsedMs
|
|
414
|
-
});
|
|
415
|
-
const retryStepId = `step-${state.stepCounter++}`;
|
|
416
|
-
state.steps.push({
|
|
417
|
-
id: retryStepId,
|
|
418
|
-
eventType: "USER_ACTION_REQUIRED",
|
|
419
|
-
message: "Waiting for verification...",
|
|
420
|
-
status: "in_progress",
|
|
421
|
-
timestamp: Date.now()
|
|
422
|
-
});
|
|
423
|
-
state.currentExecutingStepId = retryStepId;
|
|
424
|
-
} else if (eventType === "USER_ACTION_EXPIRED") {
|
|
425
|
-
completeLastInProgressStep(state.steps);
|
|
426
|
-
state.userActionRequest = void 0;
|
|
427
|
-
state.userActionPending = false;
|
|
428
|
-
const stepId = `step-${state.stepCounter++}`;
|
|
429
|
-
state.steps.push({
|
|
430
|
-
id: stepId,
|
|
431
|
-
eventType,
|
|
432
|
-
message,
|
|
433
|
-
status: "error",
|
|
434
|
-
timestamp: Date.now(),
|
|
435
|
-
elapsedMs: event.elapsedMs
|
|
436
|
-
});
|
|
437
|
-
} else if (eventType === "USER_ACTION_REJECTED") {
|
|
438
|
-
completeLastInProgressStep(state.steps);
|
|
439
|
-
state.userActionRequest = void 0;
|
|
440
|
-
state.userActionPending = false;
|
|
441
|
-
state.userActionResult = "rejected";
|
|
442
|
-
const stepId = `step-${state.stepCounter++}`;
|
|
443
|
-
state.steps.push({
|
|
444
|
-
id: stepId,
|
|
445
|
-
eventType,
|
|
446
|
-
message,
|
|
447
|
-
status: "completed",
|
|
448
|
-
timestamp: Date.now(),
|
|
449
|
-
elapsedMs: event.elapsedMs
|
|
450
|
-
});
|
|
451
|
-
} else if (eventType === "USER_ACTION_RESENT") {
|
|
452
|
-
const stepId = `step-${state.stepCounter++}`;
|
|
453
|
-
state.steps.push({
|
|
454
|
-
id: stepId,
|
|
455
|
-
eventType,
|
|
456
|
-
message,
|
|
457
|
-
status: "completed",
|
|
458
|
-
timestamp: Date.now(),
|
|
459
|
-
elapsedMs: event.elapsedMs
|
|
460
|
-
});
|
|
461
|
-
} else if (eventType === "USER_ACTION_FAILED") {
|
|
462
|
-
completeLastInProgressStep(state.steps);
|
|
463
|
-
state.userActionRequest = void 0;
|
|
464
|
-
state.userActionPending = false;
|
|
465
|
-
const stepId = `step-${state.stepCounter++}`;
|
|
466
|
-
state.steps.push({
|
|
467
|
-
id: stepId,
|
|
468
|
-
eventType,
|
|
469
|
-
message,
|
|
470
|
-
status: "error",
|
|
471
|
-
timestamp: Date.now(),
|
|
472
|
-
elapsedMs: event.elapsedMs
|
|
473
|
-
});
|
|
474
|
-
} else if (eventType === "INTENT_THINKING") {
|
|
475
|
-
if (state.currentThinkingStepId) {
|
|
476
|
-
const prev = state.steps.find((s) => s.id === state.currentThinkingStepId);
|
|
477
|
-
if (prev) prev.isThinking = false;
|
|
478
|
-
}
|
|
479
|
-
const lastInProgress = [...state.steps].reverse().find((s) => s.status === "in_progress");
|
|
480
|
-
if (lastInProgress) {
|
|
481
|
-
lastInProgress.thinkingText = "";
|
|
482
|
-
lastInProgress.isThinking = true;
|
|
483
|
-
state.currentThinkingStepId = lastInProgress.id;
|
|
484
|
-
} else {
|
|
485
|
-
state.currentThinkingStepId = void 0;
|
|
486
|
-
}
|
|
487
|
-
if (state.allThinkingText) state.allThinkingText += "\n\n";
|
|
488
|
-
if (!state.inOrchestratorPhase && !state.inAggregatorPhase) {
|
|
489
|
-
state.activeThinkingText = "";
|
|
490
|
-
}
|
|
491
|
-
} else if (eventType === "INTENT_THINKING_CONT") {
|
|
492
|
-
const delta = event.message || "";
|
|
493
|
-
if (!delta) return state;
|
|
494
|
-
if (state.currentThinkingStepId) {
|
|
495
|
-
const step = state.steps.find((s) => s.id === state.currentThinkingStepId);
|
|
496
|
-
if (step) {
|
|
497
|
-
step.thinkingText = (step.thinkingText || "") + delta;
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
state.allThinkingText += delta;
|
|
501
|
-
if (!state.inOrchestratorPhase && !state.inAggregatorPhase) {
|
|
502
|
-
if (state.activeThinkingText == null) state.activeThinkingText = "";
|
|
503
|
-
state.activeThinkingText += delta;
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
return state;
|
|
507
|
-
}
|
|
508
252
|
|
|
509
253
|
// src/utils/messageStateManager.ts
|
|
510
|
-
var FRIENDLY_ERROR_MESSAGE = "Oops, something went wrong. Please try again.";
|
|
511
254
|
function buildFormattedThinking(steps, allThinkingText) {
|
|
512
255
|
const parts = [];
|
|
513
256
|
const safeSteps = steps ?? [];
|
|
@@ -564,91 +307,32 @@ function buildFormattedThinking(steps, allThinkingText) {
|
|
|
564
307
|
break;
|
|
565
308
|
case "USER_ACTION_REQUIRED":
|
|
566
309
|
parts.push("**Verification Required**");
|
|
567
|
-
if (step.message)
|
|
310
|
+
if (step.message) {
|
|
311
|
+
parts.push(getUserActionDisplayMessage(step.eventType, step.message));
|
|
312
|
+
}
|
|
568
313
|
break;
|
|
569
314
|
case "USER_ACTION_SUCCESS":
|
|
570
|
-
parts.push(`\u2713 ${step.message
|
|
315
|
+
parts.push(`\u2713 ${getUserActionDisplayMessage(step.eventType, step.message)}`);
|
|
571
316
|
break;
|
|
572
317
|
case "USER_ACTION_REJECTED":
|
|
573
|
-
parts.push(
|
|
318
|
+
parts.push(getUserActionDisplayMessage(step.eventType, step.message));
|
|
574
319
|
break;
|
|
575
320
|
case "USER_ACTION_EXPIRED":
|
|
576
|
-
parts.push(`\u2717 ${step.message
|
|
321
|
+
parts.push(`\u2717 ${getUserActionDisplayMessage(step.eventType, step.message)}`);
|
|
322
|
+
break;
|
|
323
|
+
case "USER_ACTION_INVALID":
|
|
324
|
+
parts.push(`\u2717 ${getUserActionDisplayMessage(step.eventType, step.message)}`);
|
|
325
|
+
break;
|
|
326
|
+
case "USER_ACTION_RESENT":
|
|
327
|
+
parts.push(getUserActionDisplayMessage(step.eventType, step.message));
|
|
577
328
|
break;
|
|
578
329
|
case "USER_ACTION_FAILED":
|
|
579
|
-
parts.push(`\u2717 ${step.message
|
|
330
|
+
parts.push(`\u2717 ${getUserActionDisplayMessage(step.eventType, step.message)}`);
|
|
580
331
|
break;
|
|
581
332
|
}
|
|
582
333
|
}
|
|
583
334
|
return parts.length > 0 ? parts.join("\n") : allThinkingText;
|
|
584
335
|
}
|
|
585
|
-
function createStreamingMessageUpdate(state) {
|
|
586
|
-
const hasCompletedContent = state.accumulatedContent && state.finalData !== void 0;
|
|
587
|
-
const steps = state.hasError ? [] : [...state.steps];
|
|
588
|
-
const allThinking = state.hasError ? void 0 : state.allThinkingText;
|
|
589
|
-
return {
|
|
590
|
-
streamingContent: state.hasError ? FRIENDLY_ERROR_MESSAGE : hasCompletedContent ? state.accumulatedContent : "",
|
|
591
|
-
content: state.hasError ? FRIENDLY_ERROR_MESSAGE : "",
|
|
592
|
-
currentMessage: state.hasError ? void 0 : state.currentMessage,
|
|
593
|
-
streamProgress: state.hasError ? "error" : "processing",
|
|
594
|
-
isError: state.hasError,
|
|
595
|
-
errorDetails: state.hasError ? state.errorMessage : void 0,
|
|
596
|
-
executionId: state.executionId,
|
|
597
|
-
sessionId: state.sessionId,
|
|
598
|
-
steps,
|
|
599
|
-
currentExecutingStepId: state.hasError ? void 0 : state.currentExecutingStepId,
|
|
600
|
-
isCancelled: false,
|
|
601
|
-
userActionResult: state.userActionResult,
|
|
602
|
-
activeThinkingText: state.hasError ? void 0 : state.activeThinkingText,
|
|
603
|
-
allThinkingText: allThinking,
|
|
604
|
-
formattedThinkingText: state.hasError ? void 0 : buildFormattedThinking(steps, allThinking || "")
|
|
605
|
-
};
|
|
606
|
-
}
|
|
607
|
-
function createErrorMessageUpdate(error, state) {
|
|
608
|
-
const isAborted = error.name === "AbortError";
|
|
609
|
-
return {
|
|
610
|
-
isStreaming: false,
|
|
611
|
-
streamProgress: isAborted ? "processing" : "error",
|
|
612
|
-
isError: !isAborted,
|
|
613
|
-
isCancelled: isAborted,
|
|
614
|
-
errorDetails: isAborted ? void 0 : error.message,
|
|
615
|
-
content: isAborted ? state.accumulatedContent || "" : state.accumulatedContent || FRIENDLY_ERROR_MESSAGE,
|
|
616
|
-
// Preserve currentMessage when cancelled so UI can show it
|
|
617
|
-
currentMessage: isAborted ? state.currentMessage || "Thinking..." : void 0,
|
|
618
|
-
steps: [...state.steps].map((step) => {
|
|
619
|
-
if (step.status === "in_progress" && isAborted) {
|
|
620
|
-
return { ...step, status: "pending" };
|
|
621
|
-
}
|
|
622
|
-
return step;
|
|
623
|
-
}),
|
|
624
|
-
currentExecutingStepId: void 0
|
|
625
|
-
};
|
|
626
|
-
}
|
|
627
|
-
function createFinalMessage(streamingId, state) {
|
|
628
|
-
const steps = state.hasError ? [] : [...state.steps];
|
|
629
|
-
const allThinking = state.hasError ? void 0 : state.allThinkingText;
|
|
630
|
-
return {
|
|
631
|
-
id: streamingId,
|
|
632
|
-
sessionId: state.sessionId,
|
|
633
|
-
role: "assistant",
|
|
634
|
-
content: state.hasError ? FRIENDLY_ERROR_MESSAGE : state.accumulatedContent || "",
|
|
635
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
636
|
-
isStreaming: false,
|
|
637
|
-
streamProgress: state.hasError ? "error" : "completed",
|
|
638
|
-
isError: state.hasError,
|
|
639
|
-
errorDetails: state.hasError ? state.errorMessage : void 0,
|
|
640
|
-
executionId: state.executionId,
|
|
641
|
-
tracingData: state.finalData,
|
|
642
|
-
steps,
|
|
643
|
-
isCancelled: false,
|
|
644
|
-
currentExecutingStepId: void 0,
|
|
645
|
-
userActionResult: state.userActionResult,
|
|
646
|
-
activeThinkingText: void 0,
|
|
647
|
-
allThinkingText: allThinking,
|
|
648
|
-
formattedThinkingText: state.hasError ? void 0 : buildFormattedThinking(steps, allThinking || ""),
|
|
649
|
-
isResolvingImages: state.hasError ? void 0 : state.isResolvingImages
|
|
650
|
-
};
|
|
651
|
-
}
|
|
652
336
|
function createCancelledMessageUpdate(steps, currentMessage) {
|
|
653
337
|
const updatedSteps = steps.map((step) => {
|
|
654
338
|
if (step.status === "in_progress") {
|
|
@@ -668,35 +352,44 @@ function createCancelledMessageUpdate(steps, currentMessage) {
|
|
|
668
352
|
|
|
669
353
|
// src/utils/requestBuilder.ts
|
|
670
354
|
function buildRequestBody(config, userMessage, sessionId) {
|
|
671
|
-
const
|
|
672
|
-
const sessionAttributes =
|
|
355
|
+
const owner = config.session?.owner;
|
|
356
|
+
const sessionAttributes = owner?.attributes && Object.keys(owner.attributes).length > 0 ? owner.attributes : void 0;
|
|
673
357
|
return {
|
|
674
|
-
workflowName: config.
|
|
358
|
+
workflowName: config.workflow.name,
|
|
675
359
|
userInput: userMessage,
|
|
676
360
|
sessionId,
|
|
677
|
-
sessionOwnerId:
|
|
678
|
-
sessionOwnerLabel:
|
|
361
|
+
sessionOwnerId: owner?.id || "",
|
|
362
|
+
sessionOwnerLabel: owner?.name || "",
|
|
679
363
|
sessionAttributes,
|
|
680
364
|
options: {
|
|
681
365
|
clientTimezone: Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
682
366
|
}
|
|
683
367
|
};
|
|
684
368
|
}
|
|
369
|
+
function getStageParamName(config) {
|
|
370
|
+
return config.api.stageQueryParam ?? "stage";
|
|
371
|
+
}
|
|
372
|
+
function getStage(config) {
|
|
373
|
+
return config.workflow.stage ?? "DEV";
|
|
374
|
+
}
|
|
685
375
|
function buildStreamingUrl(config) {
|
|
686
376
|
const endpoint = config.api.streamEndpoint || "/api/workflows/ask/stream";
|
|
687
|
-
const
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
if (config.
|
|
691
|
-
queryParams.append("workflowVersion", String(config.
|
|
377
|
+
const queryParams = new URLSearchParams({
|
|
378
|
+
[getStageParamName(config)]: getStage(config)
|
|
379
|
+
});
|
|
380
|
+
if (config.workflow.version !== void 0) {
|
|
381
|
+
queryParams.append("workflowVersion", String(config.workflow.version));
|
|
692
382
|
}
|
|
693
383
|
return `${config.api.baseUrl}${endpoint}?${queryParams.toString()}`;
|
|
694
384
|
}
|
|
695
|
-
function
|
|
385
|
+
function deriveBasePath(config) {
|
|
696
386
|
const endpoint = config.api.streamEndpoint || "/api/workflows/ask/stream";
|
|
697
387
|
const [endpointPath] = endpoint.split("?");
|
|
698
|
-
const
|
|
699
|
-
|
|
388
|
+
const normalized = endpointPath.replace(/\/+$/, "");
|
|
389
|
+
return normalized.endsWith("/stream") ? normalized.slice(0, -"/stream".length) : normalized;
|
|
390
|
+
}
|
|
391
|
+
function buildUserActionUrl(config, userActionId, action) {
|
|
392
|
+
const basePath = deriveBasePath(config);
|
|
700
393
|
const encodedUserActionId = encodeURIComponent(userActionId);
|
|
701
394
|
return `${config.api.baseUrl}${basePath}/user-action/${encodedUserActionId}/${action}`;
|
|
702
395
|
}
|
|
@@ -704,21 +397,23 @@ function buildResolveImagesUrl(config) {
|
|
|
704
397
|
if (config.api.resolveImagesEndpoint) {
|
|
705
398
|
return `${config.api.baseUrl}${config.api.resolveImagesEndpoint}`;
|
|
706
399
|
}
|
|
707
|
-
|
|
708
|
-
const [endpointPath] = streamEndpoint.split("?");
|
|
709
|
-
const normalizedEndpointPath = endpointPath.replace(/\/+$/, "");
|
|
710
|
-
const basePath = normalizedEndpointPath.endsWith("/stream") ? normalizedEndpointPath.slice(0, -"/stream".length) : normalizedEndpointPath;
|
|
711
|
-
return `${config.api.baseUrl}${basePath}/resolve-image-urls`;
|
|
400
|
+
return `${config.api.baseUrl}${deriveBasePath(config)}/resolve-image-urls`;
|
|
712
401
|
}
|
|
713
402
|
function buildRequestHeaders(config) {
|
|
714
|
-
const headers = {
|
|
715
|
-
...config.api.headers
|
|
716
|
-
};
|
|
403
|
+
const headers = { ...config.api.headers };
|
|
717
404
|
if (config.api.authToken) {
|
|
718
405
|
headers.Authorization = `Bearer ${config.api.authToken}`;
|
|
719
406
|
}
|
|
720
407
|
return headers;
|
|
721
408
|
}
|
|
409
|
+
function buildScopeKey(config) {
|
|
410
|
+
return [
|
|
411
|
+
config.session?.userId ?? "",
|
|
412
|
+
config.workflow.id ?? "",
|
|
413
|
+
config.workflow.version ?? "",
|
|
414
|
+
config.workflow.stage ?? ""
|
|
415
|
+
].join("|");
|
|
416
|
+
}
|
|
722
417
|
|
|
723
418
|
// src/utils/userActionClient.ts
|
|
724
419
|
async function sendUserActionRequest(config, userActionId, action, data) {
|
|
@@ -737,684 +432,97 @@ async function sendUserActionRequest(config, userActionId, action, data) {
|
|
|
737
432
|
}
|
|
738
433
|
return await response.json();
|
|
739
434
|
}
|
|
740
|
-
async function submitUserAction(config, userActionId, data) {
|
|
741
|
-
return sendUserActionRequest(config, userActionId, "submit", data);
|
|
742
|
-
}
|
|
743
|
-
async function cancelUserAction(config, userActionId) {
|
|
744
|
-
return sendUserActionRequest(config, userActionId, "cancel");
|
|
745
|
-
}
|
|
746
|
-
async function resendUserAction(config, userActionId) {
|
|
747
|
-
return sendUserActionRequest(config, userActionId, "resend");
|
|
748
|
-
}
|
|
749
|
-
var storage = reactNativeMmkv.createMMKV({ id: "payman-chat-store" });
|
|
750
|
-
var chatStore = {
|
|
751
|
-
get(key) {
|
|
752
|
-
const raw = storage.getString(key);
|
|
753
|
-
if (!raw) return [];
|
|
754
|
-
try {
|
|
755
|
-
return JSON.parse(raw);
|
|
756
|
-
} catch {
|
|
757
|
-
return [];
|
|
758
|
-
}
|
|
759
|
-
},
|
|
760
|
-
set(key, messages) {
|
|
761
|
-
storage.set(key, JSON.stringify(messages));
|
|
762
|
-
},
|
|
763
|
-
delete(key) {
|
|
764
|
-
storage.delete(key);
|
|
765
|
-
}
|
|
766
|
-
};
|
|
767
|
-
|
|
768
|
-
// src/utils/activeStreamStore.ts
|
|
769
|
-
var streams = /* @__PURE__ */ new Map();
|
|
770
|
-
var activeStreamStore = {
|
|
771
|
-
has(key) {
|
|
772
|
-
return streams.has(key);
|
|
773
|
-
},
|
|
774
|
-
get(key) {
|
|
775
|
-
const entry = streams.get(key);
|
|
776
|
-
if (!entry) return null;
|
|
777
|
-
return { messages: entry.messages, isWaiting: entry.isWaiting };
|
|
778
|
-
},
|
|
779
|
-
// Called before startStream — registers the controller and initial messages
|
|
780
|
-
start(key, abortController, initialMessages) {
|
|
781
|
-
const existing = streams.get(key);
|
|
782
|
-
streams.set(key, {
|
|
783
|
-
messages: initialMessages,
|
|
784
|
-
isWaiting: true,
|
|
785
|
-
abortController,
|
|
786
|
-
listeners: existing?.listeners ?? /* @__PURE__ */ new Set()
|
|
787
|
-
});
|
|
788
|
-
},
|
|
789
|
-
// Called by the stream on every event — applies the same updater pattern React uses
|
|
790
|
-
applyMessages(key, updater) {
|
|
791
|
-
const entry = streams.get(key);
|
|
792
|
-
if (!entry) return;
|
|
793
|
-
const next = typeof updater === "function" ? updater(entry.messages) : updater;
|
|
794
|
-
entry.messages = next;
|
|
795
|
-
entry.listeners.forEach((l) => l(next, entry.isWaiting));
|
|
796
|
-
},
|
|
797
|
-
setWaiting(key, waiting) {
|
|
798
|
-
const entry = streams.get(key);
|
|
799
|
-
if (!entry) return;
|
|
800
|
-
entry.isWaiting = waiting;
|
|
801
|
-
entry.listeners.forEach((l) => l(entry.messages, waiting));
|
|
802
|
-
},
|
|
803
|
-
// Called when stream completes — persists to chatStore and cleans up
|
|
804
|
-
complete(key) {
|
|
805
|
-
const entry = streams.get(key);
|
|
806
|
-
if (!entry) return;
|
|
807
|
-
entry.isWaiting = false;
|
|
808
|
-
entry.listeners.forEach((l) => l(entry.messages, false));
|
|
809
|
-
const toSave = entry.messages.filter((m) => !m.isStreaming);
|
|
810
|
-
if (toSave.length > 0) chatStore.set(key, toSave);
|
|
811
|
-
streams.delete(key);
|
|
812
|
-
},
|
|
813
|
-
// Subscribe — returns unsubscribe fn. Component calls this on mount, cleanup on unmount.
|
|
814
|
-
subscribe(key, listener) {
|
|
815
|
-
const entry = streams.get(key);
|
|
816
|
-
if (!entry) return () => {
|
|
817
|
-
};
|
|
818
|
-
entry.listeners.add(listener);
|
|
819
|
-
return () => {
|
|
820
|
-
streams.get(key)?.listeners.delete(listener);
|
|
821
|
-
};
|
|
822
|
-
},
|
|
823
|
-
// Explicit user cancel — aborts the controller and removes the entry
|
|
824
|
-
abort(key) {
|
|
825
|
-
const entry = streams.get(key);
|
|
826
|
-
if (!entry) return;
|
|
827
|
-
entry.abortController.abort();
|
|
828
|
-
streams.delete(key);
|
|
829
|
-
}
|
|
830
|
-
};
|
|
831
|
-
|
|
832
|
-
// src/utils/ragImageResolver.ts
|
|
833
|
-
var RAG_IMAGE_REGEX = /\/api\/rag\/chunks\/[^"'\s]+\/image/;
|
|
834
|
-
function hasRagImages(content) {
|
|
835
|
-
return RAG_IMAGE_REGEX.test(content);
|
|
836
|
-
}
|
|
837
|
-
async function waitForNextPaint(signal) {
|
|
838
|
-
if (signal?.aborted) return;
|
|
839
|
-
await new Promise((resolve) => {
|
|
840
|
-
let isSettled = false;
|
|
841
|
-
const finish = () => {
|
|
842
|
-
if (isSettled) return;
|
|
843
|
-
isSettled = true;
|
|
844
|
-
signal?.removeEventListener("abort", finish);
|
|
845
|
-
resolve();
|
|
846
|
-
};
|
|
847
|
-
signal?.addEventListener("abort", finish, { once: true });
|
|
848
|
-
if (typeof requestAnimationFrame === "function") {
|
|
849
|
-
requestAnimationFrame(() => {
|
|
850
|
-
setTimeout(finish, 0);
|
|
851
|
-
});
|
|
852
|
-
return;
|
|
853
|
-
}
|
|
854
|
-
setTimeout(finish, 0);
|
|
855
|
-
});
|
|
856
|
-
}
|
|
857
|
-
async function resolveRagImageUrls(config, content, signal) {
|
|
858
|
-
const url = buildResolveImagesUrl(config);
|
|
859
|
-
const baseHeaders = buildRequestHeaders(config);
|
|
860
|
-
const headers = { "Content-Type": "application/json", ...baseHeaders };
|
|
861
|
-
const response = await fetch(url, {
|
|
862
|
-
method: "POST",
|
|
863
|
-
headers,
|
|
864
|
-
body: JSON.stringify({ input: content }),
|
|
865
|
-
signal
|
|
866
|
-
});
|
|
867
|
-
if (!response.ok) {
|
|
868
|
-
const errorText = await response.text();
|
|
869
|
-
throw new Error(`HTTP ${response.status}: ${errorText}`);
|
|
870
|
-
}
|
|
871
|
-
const text = await response.text();
|
|
872
|
-
try {
|
|
873
|
-
const parsed = JSON.parse(text);
|
|
874
|
-
if (typeof parsed === "string") return parsed;
|
|
875
|
-
if (typeof parsed.output === "string") return parsed.output;
|
|
876
|
-
if (typeof parsed.result === "string") return parsed.result;
|
|
877
|
-
} catch {
|
|
878
|
-
}
|
|
879
|
-
return text;
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
// src/hooks/useStreamManager.ts
|
|
883
|
-
function useStreamManager(config, callbacks, setMessages, setIsWaitingForResponse) {
|
|
884
|
-
const abortControllerRef = react.useRef(null);
|
|
885
|
-
const configRef = react.useRef(config);
|
|
886
|
-
configRef.current = config;
|
|
887
|
-
const callbacksRef = react.useRef(callbacks);
|
|
888
|
-
callbacksRef.current = callbacks;
|
|
889
|
-
const startStream = react.useCallback(
|
|
890
|
-
async (userMessage, streamingId, sessionId, externalAbortController) => {
|
|
891
|
-
abortControllerRef.current?.abort();
|
|
892
|
-
const abortController = externalAbortController ?? new AbortController();
|
|
893
|
-
abortControllerRef.current = abortController;
|
|
894
|
-
const state = {
|
|
895
|
-
accumulatedContent: "",
|
|
896
|
-
executionId: void 0,
|
|
897
|
-
currentSessionId: void 0,
|
|
898
|
-
finalData: void 0,
|
|
899
|
-
steps: [],
|
|
900
|
-
stepCounter: 0,
|
|
901
|
-
currentExecutingStepId: void 0,
|
|
902
|
-
currentThinkingStepId: void 0,
|
|
903
|
-
hasError: false,
|
|
904
|
-
errorMessage: "",
|
|
905
|
-
userActionRequest: void 0,
|
|
906
|
-
userActionPending: false,
|
|
907
|
-
userActionResult: void 0,
|
|
908
|
-
allThinkingText: "",
|
|
909
|
-
inOrchestratorPhase: false,
|
|
910
|
-
inAggregatorPhase: false
|
|
911
|
-
};
|
|
912
|
-
const THROTTLE_MS = 120;
|
|
913
|
-
const CHARS_PER_TICK = 10;
|
|
914
|
-
const displayedLengthRef = { current: 0 };
|
|
915
|
-
let throttleIntervalId = null;
|
|
916
|
-
const getActiveStepMessage = () => state.steps.find((s) => s.id === state.currentExecutingStepId)?.message || [...state.steps].reverse().find((s) => s.status === "in_progress")?.message;
|
|
917
|
-
const advanceDisplayLength = (full) => {
|
|
918
|
-
let newLen = Math.min(displayedLengthRef.current + CHARS_PER_TICK, full.length);
|
|
919
|
-
if (newLen > 0 && newLen < full.length) {
|
|
920
|
-
const code = full.charCodeAt(newLen - 1);
|
|
921
|
-
if (code >= 55296 && code <= 56319) {
|
|
922
|
-
newLen = Math.min(newLen + 1, full.length);
|
|
923
|
-
}
|
|
924
|
-
}
|
|
925
|
-
displayedLengthRef.current = newLen;
|
|
926
|
-
};
|
|
927
|
-
const clearThrottle = () => {
|
|
928
|
-
if (throttleIntervalId != null) {
|
|
929
|
-
clearInterval(throttleIntervalId);
|
|
930
|
-
throttleIntervalId = null;
|
|
931
|
-
}
|
|
932
|
-
};
|
|
933
|
-
abortController.signal.addEventListener("abort", clearThrottle, { once: true });
|
|
934
|
-
const ensureThrottle = () => {
|
|
935
|
-
if (throttleIntervalId != null) return;
|
|
936
|
-
throttleIntervalId = setInterval(() => {
|
|
937
|
-
if (abortController.signal.aborted) {
|
|
938
|
-
clearThrottle();
|
|
939
|
-
return;
|
|
940
|
-
}
|
|
941
|
-
const full = state.activeThinkingText ?? "";
|
|
942
|
-
if (displayedLengthRef.current < full.length) {
|
|
943
|
-
advanceDisplayLength(full);
|
|
944
|
-
const displayText = full.slice(0, displayedLengthRef.current);
|
|
945
|
-
setMessages(
|
|
946
|
-
(prev) => prev.map(
|
|
947
|
-
(msg) => msg.id === streamingId ? {
|
|
948
|
-
...msg,
|
|
949
|
-
...createStreamingMessageUpdate({
|
|
950
|
-
...state,
|
|
951
|
-
activeThinkingText: displayText,
|
|
952
|
-
currentMessage: getActiveStepMessage() || "Thinking..."
|
|
953
|
-
})
|
|
954
|
-
} : msg
|
|
955
|
-
)
|
|
956
|
-
);
|
|
957
|
-
}
|
|
958
|
-
}, THROTTLE_MS);
|
|
959
|
-
};
|
|
960
|
-
const currentConfig = configRef.current;
|
|
961
|
-
const requestBody = buildRequestBody(currentConfig, userMessage, sessionId);
|
|
962
|
-
const url = buildStreamingUrl(currentConfig);
|
|
963
|
-
const headers = buildRequestHeaders(currentConfig);
|
|
964
|
-
try {
|
|
965
|
-
await streamWorkflowEvents(url, requestBody, headers, {
|
|
966
|
-
signal: abortController.signal,
|
|
967
|
-
onEvent: (event) => {
|
|
968
|
-
if (abortController.signal.aborted) {
|
|
969
|
-
return;
|
|
970
|
-
}
|
|
971
|
-
if (typeof event.eventType === "string" && event.eventType.toUpperCase() === "KEEP_ALIVE") {
|
|
972
|
-
if (event.executionId) state.executionId = event.executionId;
|
|
973
|
-
if (event.sessionId) state.currentSessionId = event.sessionId;
|
|
974
|
-
return;
|
|
975
|
-
}
|
|
976
|
-
if (event.executionId) state.executionId = event.executionId;
|
|
977
|
-
if (event.sessionId) state.currentSessionId = event.sessionId;
|
|
978
|
-
const activeThinkingLengthBeforeProcess = state.activeThinkingText?.length ?? 0;
|
|
979
|
-
processStreamEvent(event, state);
|
|
980
|
-
const eventType = event.eventType;
|
|
981
|
-
if (eventType === "INTENT_THINKING") {
|
|
982
|
-
displayedLengthRef.current = 0;
|
|
983
|
-
ensureThrottle();
|
|
984
|
-
} else if (eventType !== "INTENT_THINKING_CONT") {
|
|
985
|
-
displayedLengthRef.current = activeThinkingLengthBeforeProcess;
|
|
986
|
-
clearThrottle();
|
|
987
|
-
}
|
|
988
|
-
if (eventType === "USER_ACTION_REQUIRED" && state.userActionRequest) {
|
|
989
|
-
callbacksRef.current.onUserActionRequired?.(state.userActionRequest);
|
|
990
|
-
} else if (eventType.startsWith("USER_ACTION_") && eventType !== "USER_ACTION_REQUIRED") {
|
|
991
|
-
const msg = event.message?.trim() || event.errorMessage?.trim() || getEventMessage(event);
|
|
992
|
-
callbacksRef.current.onUserActionEvent?.(eventType, msg);
|
|
993
|
-
}
|
|
994
|
-
const isIntentThinkingEvent = eventType === "INTENT_THINKING" || eventType === "INTENT_THINKING_CONT";
|
|
995
|
-
const rawMessage = event.message?.trim() || event.errorMessage?.trim();
|
|
996
|
-
const currentMessage = isIntentThinkingEvent ? getActiveStepMessage() || "Thinking..." : rawMessage || (event.eventType?.startsWith("USER_ACTION_") ? getEventMessage(event) : getActiveStepMessage() || getEventMessage(event));
|
|
997
|
-
const displayThinking = state.activeThinkingText != null ? state.activeThinkingText.slice(0, displayedLengthRef.current) : state.activeThinkingText;
|
|
998
|
-
setMessages(
|
|
999
|
-
(prev) => prev.map(
|
|
1000
|
-
(msg) => msg.id === streamingId ? {
|
|
1001
|
-
...msg,
|
|
1002
|
-
...createStreamingMessageUpdate({
|
|
1003
|
-
...state,
|
|
1004
|
-
activeThinkingText: displayThinking,
|
|
1005
|
-
currentMessage
|
|
1006
|
-
})
|
|
1007
|
-
} : msg
|
|
1008
|
-
)
|
|
1009
|
-
);
|
|
1010
|
-
},
|
|
1011
|
-
onError: (error) => {
|
|
1012
|
-
clearThrottle();
|
|
1013
|
-
setIsWaitingForResponse(false);
|
|
1014
|
-
if (error.name !== "AbortError") {
|
|
1015
|
-
callbacksRef.current.onError?.(error);
|
|
1016
|
-
}
|
|
1017
|
-
if (state.userActionPending) {
|
|
1018
|
-
state.userActionPending = false;
|
|
1019
|
-
state.userActionRequest = void 0;
|
|
1020
|
-
callbacksRef.current.onUserActionEvent?.(
|
|
1021
|
-
"USER_ACTION_FAILED",
|
|
1022
|
-
"Connection lost. Please try again."
|
|
1023
|
-
);
|
|
1024
|
-
}
|
|
1025
|
-
setMessages(
|
|
1026
|
-
(prev) => prev.map(
|
|
1027
|
-
(msg) => msg.id === streamingId ? {
|
|
1028
|
-
...msg,
|
|
1029
|
-
...createErrorMessageUpdate(error, state)
|
|
1030
|
-
} : msg
|
|
1031
|
-
)
|
|
1032
|
-
);
|
|
1033
|
-
},
|
|
1034
|
-
onComplete: () => {
|
|
1035
|
-
clearThrottle();
|
|
1036
|
-
setIsWaitingForResponse(false);
|
|
1037
|
-
if (state.userActionPending) {
|
|
1038
|
-
state.userActionPending = false;
|
|
1039
|
-
state.userActionRequest = void 0;
|
|
1040
|
-
callbacksRef.current.onUserActionEvent?.(
|
|
1041
|
-
"USER_ACTION_FAILED",
|
|
1042
|
-
"Verification could not be completed."
|
|
1043
|
-
);
|
|
1044
|
-
}
|
|
1045
|
-
if (state.currentSessionId && state.currentSessionId !== sessionId) {
|
|
1046
|
-
callbacksRef.current.onSessionIdChange?.(state.currentSessionId);
|
|
1047
|
-
}
|
|
1048
|
-
const needsImageResolve = !state.hasError && !abortController.signal.aborted && hasRagImages(state.accumulatedContent);
|
|
1049
|
-
const finalMessage = createFinalMessage(streamingId, {
|
|
1050
|
-
...state,
|
|
1051
|
-
sessionId: state.currentSessionId || sessionId,
|
|
1052
|
-
isResolvingImages: needsImageResolve
|
|
1053
|
-
});
|
|
1054
|
-
setMessages(
|
|
1055
|
-
(prev) => prev.map(
|
|
1056
|
-
(msg) => msg.id === streamingId ? finalMessage : msg
|
|
1057
|
-
)
|
|
1058
|
-
);
|
|
1059
|
-
callbacksRef.current.onStreamComplete?.(finalMessage);
|
|
1060
|
-
}
|
|
1061
|
-
});
|
|
1062
|
-
clearThrottle();
|
|
1063
|
-
const shouldResolveImages = !abortController.signal.aborted && !state.hasError && hasRagImages(state.accumulatedContent);
|
|
1064
|
-
if (shouldResolveImages) {
|
|
1065
|
-
await waitForNextPaint(abortController.signal);
|
|
1066
|
-
}
|
|
1067
|
-
if (shouldResolveImages && !abortController.signal.aborted) {
|
|
1068
|
-
try {
|
|
1069
|
-
const resolvedContent = await resolveRagImageUrls(
|
|
1070
|
-
currentConfig,
|
|
1071
|
-
state.accumulatedContent,
|
|
1072
|
-
abortController.signal
|
|
1073
|
-
);
|
|
1074
|
-
setMessages(
|
|
1075
|
-
(prev) => prev.map(
|
|
1076
|
-
(msg) => msg.id === streamingId ? { ...msg, content: resolvedContent, isResolvingImages: false } : msg
|
|
1077
|
-
)
|
|
1078
|
-
);
|
|
1079
|
-
} catch {
|
|
1080
|
-
setMessages(
|
|
1081
|
-
(prev) => prev.map(
|
|
1082
|
-
(msg) => msg.id === streamingId ? { ...msg, isResolvingImages: false } : msg
|
|
1083
|
-
)
|
|
1084
|
-
);
|
|
1085
|
-
}
|
|
1086
|
-
}
|
|
1087
|
-
return state.currentSessionId;
|
|
1088
|
-
} catch (error) {
|
|
1089
|
-
clearThrottle();
|
|
1090
|
-
setIsWaitingForResponse(false);
|
|
1091
|
-
if (error.name !== "AbortError") {
|
|
1092
|
-
callbacksRef.current.onError?.(error);
|
|
1093
|
-
}
|
|
1094
|
-
if (state.userActionPending) {
|
|
1095
|
-
state.userActionPending = false;
|
|
1096
|
-
state.userActionRequest = void 0;
|
|
1097
|
-
callbacksRef.current.onUserActionEvent?.(
|
|
1098
|
-
"USER_ACTION_FAILED",
|
|
1099
|
-
"Connection lost. Please try again."
|
|
1100
|
-
);
|
|
1101
|
-
}
|
|
1102
|
-
setMessages(
|
|
1103
|
-
(prev) => prev.map(
|
|
1104
|
-
(msg) => msg.id === streamingId ? {
|
|
1105
|
-
...msg,
|
|
1106
|
-
...createErrorMessageUpdate(error, state)
|
|
1107
|
-
} : msg
|
|
1108
|
-
)
|
|
1109
|
-
);
|
|
1110
|
-
return state.currentSessionId;
|
|
1111
|
-
}
|
|
1112
|
-
},
|
|
1113
|
-
[setMessages, setIsWaitingForResponse]
|
|
1114
|
-
);
|
|
1115
|
-
const cancelStream = react.useCallback(() => {
|
|
1116
|
-
abortControllerRef.current?.abort();
|
|
1117
|
-
}, []);
|
|
1118
|
-
return {
|
|
1119
|
-
startStream,
|
|
1120
|
-
cancelStream,
|
|
1121
|
-
abortControllerRef
|
|
1122
|
-
};
|
|
1123
|
-
}
|
|
1124
|
-
|
|
1125
|
-
// src/hooks/useChat.ts
|
|
1126
|
-
function useChat(config, callbacks = {}) {
|
|
1127
|
-
const [messages, setMessages] = react.useState(() => {
|
|
1128
|
-
if (config.userId) return chatStore.get(config.userId);
|
|
1129
|
-
return config.initialMessages ?? [];
|
|
1130
|
-
});
|
|
1131
|
-
const [isWaitingForResponse, setIsWaitingForResponse] = react.useState(false);
|
|
1132
|
-
const sessionIdRef = react.useRef(
|
|
1133
|
-
config.userId ? chatStore.get(config.userId).find((m) => m.sessionId)?.sessionId ?? config.initialSessionId ?? void 0 : config.initialSessionId ?? void 0
|
|
1134
|
-
);
|
|
1135
|
-
const prevUserIdRef = react.useRef(config.userId);
|
|
1136
|
-
const callbacksRef = react.useRef(callbacks);
|
|
1137
|
-
callbacksRef.current = callbacks;
|
|
1138
|
-
const configRef = react.useRef(config);
|
|
1139
|
-
configRef.current = config;
|
|
1140
|
-
const messagesRef = react.useRef(messages);
|
|
1141
|
-
messagesRef.current = messages;
|
|
1142
|
-
const storeAwareSetMessages = react.useCallback(
|
|
1143
|
-
(updater) => {
|
|
1144
|
-
const { userId } = configRef.current;
|
|
1145
|
-
if (userId && activeStreamStore.has(userId)) {
|
|
1146
|
-
activeStreamStore.applyMessages(userId, updater);
|
|
1147
|
-
}
|
|
1148
|
-
setMessages(updater);
|
|
1149
|
-
},
|
|
1150
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1151
|
-
[]
|
|
1152
|
-
);
|
|
1153
|
-
const storeAwareSetIsWaiting = react.useCallback(
|
|
1154
|
-
(waiting) => {
|
|
1155
|
-
const { userId } = configRef.current;
|
|
1156
|
-
if (userId && activeStreamStore.has(userId)) {
|
|
1157
|
-
activeStreamStore.setWaiting(userId, waiting);
|
|
1158
|
-
}
|
|
1159
|
-
setIsWaitingForResponse(waiting);
|
|
1160
|
-
},
|
|
1161
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1162
|
-
[]
|
|
1163
|
-
);
|
|
1164
|
-
const [userActionState, setUserActionState] = react.useState({
|
|
1165
|
-
request: null,
|
|
1166
|
-
result: null,
|
|
1167
|
-
clearOtpTrigger: 0
|
|
1168
|
-
});
|
|
1169
|
-
const userActionStateRef = react.useRef(userActionState);
|
|
1170
|
-
userActionStateRef.current = userActionState;
|
|
1171
|
-
const wrappedCallbacks = react.useMemo(() => ({
|
|
1172
|
-
...callbacksRef.current,
|
|
1173
|
-
onMessageSent: (message) => callbacksRef.current.onMessageSent?.(message),
|
|
1174
|
-
onStreamStart: () => callbacksRef.current.onStreamStart?.(),
|
|
1175
|
-
onStreamComplete: (message) => callbacksRef.current.onStreamComplete?.(message),
|
|
1176
|
-
onError: (error) => callbacksRef.current.onError?.(error),
|
|
1177
|
-
onExecutionTraceClick: (data) => callbacksRef.current.onExecutionTraceClick?.(data),
|
|
1178
|
-
onSessionIdChange: (sessionId) => callbacksRef.current.onSessionIdChange?.(sessionId),
|
|
1179
|
-
onUserActionRequired: (request) => {
|
|
1180
|
-
setUserActionState((prev) => ({ ...prev, request, result: null }));
|
|
1181
|
-
callbacksRef.current.onUserActionRequired?.(request);
|
|
1182
|
-
},
|
|
1183
|
-
onUserActionEvent: (eventType, message) => {
|
|
1184
|
-
switch (eventType) {
|
|
1185
|
-
case "USER_ACTION_SUCCESS":
|
|
1186
|
-
setUserActionState((prev) => ({ ...prev, request: null, result: "approved" }));
|
|
1187
|
-
break;
|
|
1188
|
-
case "USER_ACTION_REJECTED":
|
|
1189
|
-
setUserActionState((prev) => ({ ...prev, request: null, result: "rejected" }));
|
|
1190
|
-
break;
|
|
1191
|
-
case "USER_ACTION_EXPIRED":
|
|
1192
|
-
case "USER_ACTION_FAILED":
|
|
1193
|
-
setUserActionState((prev) => ({ ...prev, request: null }));
|
|
1194
|
-
break;
|
|
1195
|
-
case "USER_ACTION_INVALID":
|
|
1196
|
-
setUserActionState((prev) => ({ ...prev, clearOtpTrigger: prev.clearOtpTrigger + 1 }));
|
|
1197
|
-
break;
|
|
1198
|
-
}
|
|
1199
|
-
callbacksRef.current.onUserActionEvent?.(eventType, message);
|
|
1200
|
-
}
|
|
1201
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1202
|
-
}), []);
|
|
1203
|
-
const { startStream, cancelStream: cancelStreamManager, abortControllerRef } = useStreamManager(
|
|
1204
|
-
config,
|
|
1205
|
-
wrappedCallbacks,
|
|
1206
|
-
storeAwareSetMessages,
|
|
1207
|
-
storeAwareSetIsWaiting
|
|
1208
|
-
);
|
|
1209
|
-
const sendMessage = react.useCallback(
|
|
1210
|
-
async (userMessage) => {
|
|
1211
|
-
if (!userMessage.trim()) return;
|
|
1212
|
-
if (!sessionIdRef.current && configRef.current.autoGenerateSessionId !== false) {
|
|
1213
|
-
sessionIdRef.current = generateId();
|
|
1214
|
-
callbacksRef.current.onSessionIdChange?.(sessionIdRef.current);
|
|
1215
|
-
}
|
|
1216
|
-
const userMessageId = `user-${Date.now()}`;
|
|
1217
|
-
const userMsg = {
|
|
1218
|
-
id: userMessageId,
|
|
1219
|
-
sessionId: sessionIdRef.current,
|
|
1220
|
-
role: "user",
|
|
1221
|
-
content: userMessage,
|
|
1222
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1223
|
-
};
|
|
1224
|
-
setMessages((prev) => [...prev, userMsg]);
|
|
1225
|
-
callbacksRef.current.onMessageSent?.(userMessage);
|
|
1226
|
-
setIsWaitingForResponse(true);
|
|
1227
|
-
callbacksRef.current.onStreamStart?.();
|
|
1228
|
-
const streamingId = `assistant-${Date.now()}`;
|
|
1229
|
-
const streamingMsg = {
|
|
1230
|
-
id: streamingId,
|
|
1231
|
-
sessionId: sessionIdRef.current,
|
|
1232
|
-
role: "assistant",
|
|
1233
|
-
content: "",
|
|
1234
|
-
streamingContent: "",
|
|
1235
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1236
|
-
isStreaming: true,
|
|
1237
|
-
streamProgress: "started",
|
|
1238
|
-
steps: [],
|
|
1239
|
-
currentExecutingStepId: void 0,
|
|
1240
|
-
isCancelled: false,
|
|
1241
|
-
currentMessage: void 0
|
|
1242
|
-
};
|
|
1243
|
-
setMessages((prev) => [...prev, streamingMsg]);
|
|
1244
|
-
const abortController = new AbortController();
|
|
1245
|
-
const { userId } = configRef.current;
|
|
1246
|
-
if (userId) {
|
|
1247
|
-
const initialMessages = [...messagesRef.current, userMsg, streamingMsg];
|
|
1248
|
-
activeStreamStore.start(userId, abortController, initialMessages);
|
|
1249
|
-
}
|
|
1250
|
-
const newSessionId = await startStream(
|
|
1251
|
-
userMessage,
|
|
1252
|
-
streamingId,
|
|
1253
|
-
sessionIdRef.current,
|
|
1254
|
-
abortController
|
|
1255
|
-
);
|
|
1256
|
-
if (userId) {
|
|
1257
|
-
activeStreamStore.complete(userId);
|
|
1258
|
-
}
|
|
1259
|
-
if (!abortController.signal.aborted && newSessionId && newSessionId !== sessionIdRef.current) {
|
|
1260
|
-
sessionIdRef.current = newSessionId;
|
|
1261
|
-
}
|
|
1262
|
-
},
|
|
1263
|
-
[startStream]
|
|
1264
|
-
);
|
|
1265
|
-
const clearMessages = react.useCallback(() => {
|
|
1266
|
-
if (configRef.current.userId) {
|
|
1267
|
-
chatStore.delete(configRef.current.userId);
|
|
1268
|
-
}
|
|
1269
|
-
setMessages([]);
|
|
1270
|
-
}, []);
|
|
1271
|
-
const prependMessages = react.useCallback((msgs) => {
|
|
1272
|
-
setMessages((prev) => [...msgs, ...prev]);
|
|
1273
|
-
}, []);
|
|
1274
|
-
const cancelStream = react.useCallback(() => {
|
|
1275
|
-
if (configRef.current.userId) {
|
|
1276
|
-
activeStreamStore.abort(configRef.current.userId);
|
|
1277
|
-
}
|
|
1278
|
-
cancelStreamManager();
|
|
1279
|
-
setIsWaitingForResponse(false);
|
|
1280
|
-
setUserActionState((prev) => ({ ...prev, request: null, result: null }));
|
|
1281
|
-
setMessages(
|
|
1282
|
-
(prev) => prev.map((msg) => {
|
|
1283
|
-
if (msg.isStreaming) {
|
|
1284
|
-
return {
|
|
1285
|
-
...msg,
|
|
1286
|
-
...createCancelledMessageUpdate(
|
|
1287
|
-
msg.steps || [],
|
|
1288
|
-
msg.currentMessage
|
|
1289
|
-
)
|
|
1290
|
-
};
|
|
1291
|
-
}
|
|
1292
|
-
return msg;
|
|
1293
|
-
})
|
|
1294
|
-
);
|
|
1295
|
-
}, [cancelStreamManager]);
|
|
1296
|
-
const resetSession = react.useCallback(() => {
|
|
1297
|
-
if (configRef.current.userId) {
|
|
1298
|
-
activeStreamStore.abort(configRef.current.userId);
|
|
1299
|
-
chatStore.delete(configRef.current.userId);
|
|
1300
|
-
}
|
|
1301
|
-
setMessages([]);
|
|
1302
|
-
sessionIdRef.current = void 0;
|
|
1303
|
-
abortControllerRef.current?.abort();
|
|
1304
|
-
setIsWaitingForResponse(false);
|
|
1305
|
-
setUserActionState({ request: null, result: null, clearOtpTrigger: 0 });
|
|
1306
|
-
}, []);
|
|
1307
|
-
const getSessionId = react.useCallback(() => {
|
|
1308
|
-
return sessionIdRef.current;
|
|
1309
|
-
}, []);
|
|
1310
|
-
const getMessages = react.useCallback(() => {
|
|
1311
|
-
return messages;
|
|
1312
|
-
}, [messages]);
|
|
1313
|
-
const approveUserAction = react.useCallback(
|
|
1314
|
-
async (otp) => {
|
|
1315
|
-
const request = userActionStateRef.current.request;
|
|
1316
|
-
if (!request) return;
|
|
1317
|
-
try {
|
|
1318
|
-
await submitUserAction(configRef.current, request.userActionId, { otp });
|
|
1319
|
-
} catch (error) {
|
|
1320
|
-
setUserActionState((prev) => ({
|
|
1321
|
-
...prev,
|
|
1322
|
-
clearOtpTrigger: prev.clearOtpTrigger + 1
|
|
1323
|
-
}));
|
|
1324
|
-
callbacksRef.current.onError?.(error);
|
|
1325
|
-
throw error;
|
|
1326
|
-
}
|
|
1327
|
-
},
|
|
1328
|
-
[]
|
|
1329
|
-
);
|
|
1330
|
-
const rejectUserAction = react.useCallback(async () => {
|
|
1331
|
-
const request = userActionStateRef.current.request;
|
|
1332
|
-
if (!request) return;
|
|
1333
|
-
try {
|
|
1334
|
-
setMessages((prev) => {
|
|
1335
|
-
let lastStreamingIdx = -1;
|
|
1336
|
-
for (let i = prev.length - 1; i >= 0; i--) {
|
|
1337
|
-
if (prev[i].role === "assistant" && prev[i].isStreaming) {
|
|
1338
|
-
lastStreamingIdx = i;
|
|
1339
|
-
break;
|
|
1340
|
-
}
|
|
1341
|
-
}
|
|
1342
|
-
if (lastStreamingIdx === -1) return prev;
|
|
1343
|
-
return prev.map(
|
|
1344
|
-
(msg, i) => i === lastStreamingIdx ? { ...msg, currentMessage: "Rejecting..." } : msg
|
|
1345
|
-
);
|
|
1346
|
-
});
|
|
1347
|
-
await cancelUserAction(configRef.current, request.userActionId);
|
|
1348
|
-
} catch (error) {
|
|
1349
|
-
callbacksRef.current.onError?.(error);
|
|
1350
|
-
throw error;
|
|
1351
|
-
}
|
|
1352
|
-
}, []);
|
|
1353
|
-
const resendOtp = react.useCallback(async () => {
|
|
1354
|
-
const request = userActionStateRef.current.request;
|
|
1355
|
-
if (!request) return;
|
|
1356
|
-
try {
|
|
1357
|
-
await resendUserAction(configRef.current, request.userActionId);
|
|
1358
|
-
} catch (error) {
|
|
1359
|
-
callbacksRef.current.onError?.(error);
|
|
1360
|
-
throw error;
|
|
1361
|
-
}
|
|
1362
|
-
}, []);
|
|
1363
|
-
react.useEffect(() => {
|
|
1364
|
-
const { userId } = config;
|
|
1365
|
-
if (!userId) return;
|
|
1366
|
-
const unsubscribe = activeStreamStore.subscribe(userId, (msgs, isWaiting) => {
|
|
1367
|
-
setMessages(msgs);
|
|
1368
|
-
setIsWaitingForResponse(isWaiting);
|
|
1369
|
-
});
|
|
1370
|
-
const active = activeStreamStore.get(userId);
|
|
1371
|
-
if (active) {
|
|
1372
|
-
setMessages(active.messages);
|
|
1373
|
-
setIsWaitingForResponse(active.isWaiting);
|
|
1374
|
-
}
|
|
1375
|
-
return unsubscribe;
|
|
1376
|
-
}, []);
|
|
1377
|
-
react.useEffect(() => {
|
|
1378
|
-
if (!config.userId) return;
|
|
1379
|
-
const toSave = messages.filter((m) => !m.isStreaming);
|
|
1380
|
-
if (toSave.length > 0) {
|
|
1381
|
-
chatStore.set(config.userId, toSave);
|
|
1382
|
-
}
|
|
1383
|
-
}, [messages, config.userId]);
|
|
1384
|
-
react.useEffect(() => {
|
|
1385
|
-
const prevUserId = prevUserIdRef.current;
|
|
1386
|
-
prevUserIdRef.current = config.userId;
|
|
1387
|
-
if (prevUserId === config.userId) return;
|
|
1388
|
-
if (prevUserId && !config.userId) {
|
|
1389
|
-
chatStore.delete(prevUserId);
|
|
1390
|
-
setMessages([]);
|
|
1391
|
-
sessionIdRef.current = void 0;
|
|
1392
|
-
setIsWaitingForResponse(false);
|
|
1393
|
-
setUserActionState({ request: null, result: null, clearOtpTrigger: 0 });
|
|
1394
|
-
} else if (config.userId) {
|
|
1395
|
-
const stored = chatStore.get(config.userId);
|
|
1396
|
-
setMessages(stored);
|
|
1397
|
-
sessionIdRef.current = stored.find((m) => m.sessionId)?.sessionId;
|
|
1398
|
-
}
|
|
1399
|
-
}, [config.userId]);
|
|
1400
|
-
return {
|
|
1401
|
-
messages,
|
|
1402
|
-
sendMessage,
|
|
1403
|
-
clearMessages,
|
|
1404
|
-
prependMessages,
|
|
1405
|
-
cancelStream,
|
|
1406
|
-
resetSession,
|
|
1407
|
-
getSessionId,
|
|
1408
|
-
getMessages,
|
|
1409
|
-
isWaitingForResponse,
|
|
1410
|
-
sessionId: sessionIdRef.current,
|
|
1411
|
-
// User action (OTP) state and methods
|
|
1412
|
-
userActionState,
|
|
1413
|
-
approveUserAction,
|
|
1414
|
-
rejectUserAction,
|
|
1415
|
-
resendOtp
|
|
1416
|
-
};
|
|
1417
|
-
}
|
|
435
|
+
async function submitUserAction(config, userActionId, data) {
|
|
436
|
+
return sendUserActionRequest(config, userActionId, "submit", data);
|
|
437
|
+
}
|
|
438
|
+
async function cancelUserAction(config, userActionId) {
|
|
439
|
+
return sendUserActionRequest(config, userActionId, "cancel");
|
|
440
|
+
}
|
|
441
|
+
async function resendUserAction(config, userActionId) {
|
|
442
|
+
return sendUserActionRequest(config, userActionId, "resend");
|
|
443
|
+
}
|
|
444
|
+
var storage = reactNativeMmkv.createMMKV({ id: "payman-chat-store" });
|
|
445
|
+
var chatStore = {
|
|
446
|
+
get(key) {
|
|
447
|
+
const raw = storage.getString(key);
|
|
448
|
+
if (!raw) return [];
|
|
449
|
+
try {
|
|
450
|
+
return JSON.parse(raw);
|
|
451
|
+
} catch {
|
|
452
|
+
return [];
|
|
453
|
+
}
|
|
454
|
+
},
|
|
455
|
+
set(key, messages) {
|
|
456
|
+
storage.set(key, JSON.stringify(messages));
|
|
457
|
+
},
|
|
458
|
+
delete(key) {
|
|
459
|
+
storage.delete(key);
|
|
460
|
+
}
|
|
461
|
+
};
|
|
462
|
+
|
|
463
|
+
// src/utils/activeStreamStore.ts
|
|
464
|
+
var streams = /* @__PURE__ */ new Map();
|
|
465
|
+
var activeStreamStore = {
|
|
466
|
+
has(key) {
|
|
467
|
+
return streams.has(key);
|
|
468
|
+
},
|
|
469
|
+
get(key) {
|
|
470
|
+
const entry = streams.get(key);
|
|
471
|
+
if (!entry) return null;
|
|
472
|
+
return { messages: entry.messages, isWaiting: entry.isWaiting };
|
|
473
|
+
},
|
|
474
|
+
// Called before startStream — registers the controller and initial messages
|
|
475
|
+
start(key, abortController, initialMessages) {
|
|
476
|
+
const existing = streams.get(key);
|
|
477
|
+
streams.set(key, {
|
|
478
|
+
messages: initialMessages,
|
|
479
|
+
isWaiting: true,
|
|
480
|
+
abortController,
|
|
481
|
+
listeners: existing?.listeners ?? /* @__PURE__ */ new Set()
|
|
482
|
+
});
|
|
483
|
+
},
|
|
484
|
+
// Called by the stream on every event — applies the same updater pattern React uses
|
|
485
|
+
applyMessages(key, updater) {
|
|
486
|
+
const entry = streams.get(key);
|
|
487
|
+
if (!entry) return;
|
|
488
|
+
const next = typeof updater === "function" ? updater(entry.messages) : updater;
|
|
489
|
+
entry.messages = next;
|
|
490
|
+
entry.listeners.forEach((l) => l(next, entry.isWaiting));
|
|
491
|
+
},
|
|
492
|
+
setWaiting(key, waiting) {
|
|
493
|
+
const entry = streams.get(key);
|
|
494
|
+
if (!entry) return;
|
|
495
|
+
entry.isWaiting = waiting;
|
|
496
|
+
entry.listeners.forEach((l) => l(entry.messages, waiting));
|
|
497
|
+
},
|
|
498
|
+
// Called when stream completes — persists to chatStore and cleans up
|
|
499
|
+
complete(key) {
|
|
500
|
+
const entry = streams.get(key);
|
|
501
|
+
if (!entry) return;
|
|
502
|
+
entry.isWaiting = false;
|
|
503
|
+
entry.listeners.forEach((l) => l(entry.messages, false));
|
|
504
|
+
const toSave = entry.messages.filter((m) => !m.isStreaming);
|
|
505
|
+
if (toSave.length > 0) chatStore.set(key, toSave);
|
|
506
|
+
streams.delete(key);
|
|
507
|
+
},
|
|
508
|
+
// Subscribe — returns unsubscribe fn. Component calls this on mount, cleanup on unmount.
|
|
509
|
+
subscribe(key, listener) {
|
|
510
|
+
const entry = streams.get(key);
|
|
511
|
+
if (!entry) return () => {
|
|
512
|
+
};
|
|
513
|
+
entry.listeners.add(listener);
|
|
514
|
+
return () => {
|
|
515
|
+
streams.get(key)?.listeners.delete(listener);
|
|
516
|
+
};
|
|
517
|
+
},
|
|
518
|
+
// Explicit user cancel — aborts the controller and removes the entry
|
|
519
|
+
abort(key) {
|
|
520
|
+
const entry = streams.get(key);
|
|
521
|
+
if (!entry) return;
|
|
522
|
+
entry.abortController.abort();
|
|
523
|
+
streams.delete(key);
|
|
524
|
+
}
|
|
525
|
+
};
|
|
1418
526
|
|
|
1419
527
|
// src/utils/v2EventProcessor.ts
|
|
1420
528
|
function getEventText(event, field) {
|
|
@@ -1440,7 +548,7 @@ function addThinkingLine(state, header, detail) {
|
|
|
1440
548
|
function appendThinkingText(state, text) {
|
|
1441
549
|
state.formattedThinkingText += text;
|
|
1442
550
|
}
|
|
1443
|
-
function
|
|
551
|
+
function completeLastInProgressStep(steps) {
|
|
1444
552
|
for (let i = steps.length - 1; i >= 0; i--) {
|
|
1445
553
|
if (steps[i].status === "in_progress") {
|
|
1446
554
|
steps[i].status = "completed";
|
|
@@ -1654,7 +762,7 @@ function processStreamEventV2(event, state) {
|
|
|
1654
762
|
break;
|
|
1655
763
|
}
|
|
1656
764
|
case "USER_ACTION_REQUIRED": {
|
|
1657
|
-
|
|
765
|
+
completeLastInProgressStep(state.steps);
|
|
1658
766
|
if (event.userActionRequest) {
|
|
1659
767
|
state.userActionRequest = {
|
|
1660
768
|
userActionId: event.userActionRequest.userActionId,
|
|
@@ -1666,14 +774,18 @@ function processStreamEventV2(event, state) {
|
|
|
1666
774
|
}
|
|
1667
775
|
state.userActionPending = true;
|
|
1668
776
|
const req = event.userActionRequest;
|
|
777
|
+
const displayMessage = getUserActionDisplayMessage(
|
|
778
|
+
eventType,
|
|
779
|
+
req?.message || message
|
|
780
|
+
);
|
|
1669
781
|
if (req) {
|
|
1670
|
-
addThinkingLine(state, "**Verification Required**",
|
|
782
|
+
addThinkingLine(state, "**Verification Required**", displayMessage);
|
|
1671
783
|
}
|
|
1672
784
|
const stepId = `step-${state.stepCounter++}`;
|
|
1673
785
|
state.steps.push({
|
|
1674
786
|
id: stepId,
|
|
1675
787
|
eventType,
|
|
1676
|
-
message,
|
|
788
|
+
message: displayMessage,
|
|
1677
789
|
status: "in_progress",
|
|
1678
790
|
timestamp: Date.now(),
|
|
1679
791
|
elapsedMs: event.elapsedMs
|
|
@@ -1683,8 +795,9 @@ function processStreamEventV2(event, state) {
|
|
|
1683
795
|
break;
|
|
1684
796
|
}
|
|
1685
797
|
case "USER_ACTION_SUCCESS": {
|
|
1686
|
-
|
|
1687
|
-
|
|
798
|
+
const displayMessage = getUserActionDisplayMessage(eventType, event.message);
|
|
799
|
+
appendThinkingText(state, "\n\u2713 " + displayMessage);
|
|
800
|
+
completeLastInProgressStep(state.steps);
|
|
1688
801
|
state.userActionRequest = void 0;
|
|
1689
802
|
state.userActionPending = false;
|
|
1690
803
|
state.userActionResult = "approved";
|
|
@@ -1692,7 +805,7 @@ function processStreamEventV2(event, state) {
|
|
|
1692
805
|
state.steps.push({
|
|
1693
806
|
id: stepId,
|
|
1694
807
|
eventType,
|
|
1695
|
-
message,
|
|
808
|
+
message: displayMessage,
|
|
1696
809
|
status: "completed",
|
|
1697
810
|
timestamp: Date.now(),
|
|
1698
811
|
elapsedMs: event.elapsedMs
|
|
@@ -1701,12 +814,14 @@ function processStreamEventV2(event, state) {
|
|
|
1701
814
|
break;
|
|
1702
815
|
}
|
|
1703
816
|
case "USER_ACTION_INVALID": {
|
|
1704
|
-
|
|
817
|
+
const displayMessage = getUserActionDisplayMessage(eventType, event.message);
|
|
818
|
+
appendThinkingText(state, "\n\u2717 " + displayMessage);
|
|
819
|
+
completeLastInProgressStep(state.steps);
|
|
1705
820
|
const errorStepId = `step-${state.stepCounter++}`;
|
|
1706
821
|
state.steps.push({
|
|
1707
822
|
id: errorStepId,
|
|
1708
823
|
eventType,
|
|
1709
|
-
message,
|
|
824
|
+
message: displayMessage,
|
|
1710
825
|
status: "error",
|
|
1711
826
|
timestamp: Date.now(),
|
|
1712
827
|
elapsedMs: event.elapsedMs
|
|
@@ -1724,8 +839,9 @@ function processStreamEventV2(event, state) {
|
|
|
1724
839
|
break;
|
|
1725
840
|
}
|
|
1726
841
|
case "USER_ACTION_REJECTED": {
|
|
1727
|
-
|
|
1728
|
-
|
|
842
|
+
const displayMessage = getUserActionDisplayMessage(eventType, event.message);
|
|
843
|
+
appendThinkingText(state, "\n" + displayMessage);
|
|
844
|
+
completeLastInProgressStep(state.steps);
|
|
1729
845
|
state.userActionRequest = void 0;
|
|
1730
846
|
state.userActionPending = false;
|
|
1731
847
|
state.userActionResult = "rejected";
|
|
@@ -1733,7 +849,7 @@ function processStreamEventV2(event, state) {
|
|
|
1733
849
|
state.steps.push({
|
|
1734
850
|
id: stepId,
|
|
1735
851
|
eventType,
|
|
1736
|
-
message,
|
|
852
|
+
message: displayMessage,
|
|
1737
853
|
status: "completed",
|
|
1738
854
|
timestamp: Date.now(),
|
|
1739
855
|
elapsedMs: event.elapsedMs
|
|
@@ -1742,15 +858,16 @@ function processStreamEventV2(event, state) {
|
|
|
1742
858
|
break;
|
|
1743
859
|
}
|
|
1744
860
|
case "USER_ACTION_EXPIRED": {
|
|
1745
|
-
|
|
1746
|
-
|
|
861
|
+
const displayMessage = getUserActionDisplayMessage(eventType, event.message);
|
|
862
|
+
appendThinkingText(state, "\n\u2717 " + displayMessage);
|
|
863
|
+
completeLastInProgressStep(state.steps);
|
|
1747
864
|
state.userActionRequest = void 0;
|
|
1748
865
|
state.userActionPending = false;
|
|
1749
866
|
const stepId = `step-${state.stepCounter++}`;
|
|
1750
867
|
state.steps.push({
|
|
1751
868
|
id: stepId,
|
|
1752
869
|
eventType,
|
|
1753
|
-
message,
|
|
870
|
+
message: displayMessage,
|
|
1754
871
|
status: "error",
|
|
1755
872
|
timestamp: Date.now(),
|
|
1756
873
|
elapsedMs: event.elapsedMs
|
|
@@ -1759,11 +876,13 @@ function processStreamEventV2(event, state) {
|
|
|
1759
876
|
break;
|
|
1760
877
|
}
|
|
1761
878
|
case "USER_ACTION_RESENT": {
|
|
879
|
+
const displayMessage = getUserActionDisplayMessage(eventType, event.message);
|
|
880
|
+
appendThinkingText(state, "\n" + displayMessage);
|
|
1762
881
|
const stepId = `step-${state.stepCounter++}`;
|
|
1763
882
|
state.steps.push({
|
|
1764
883
|
id: stepId,
|
|
1765
884
|
eventType,
|
|
1766
|
-
message,
|
|
885
|
+
message: displayMessage,
|
|
1767
886
|
status: "completed",
|
|
1768
887
|
timestamp: Date.now(),
|
|
1769
888
|
elapsedMs: event.elapsedMs
|
|
@@ -1772,15 +891,19 @@ function processStreamEventV2(event, state) {
|
|
|
1772
891
|
break;
|
|
1773
892
|
}
|
|
1774
893
|
case "USER_ACTION_FAILED": {
|
|
1775
|
-
|
|
1776
|
-
|
|
894
|
+
const displayMessage = getUserActionDisplayMessage(
|
|
895
|
+
eventType,
|
|
896
|
+
event.message || event.errorMessage
|
|
897
|
+
);
|
|
898
|
+
appendThinkingText(state, "\n\u2717 " + displayMessage);
|
|
899
|
+
completeLastInProgressStep(state.steps);
|
|
1777
900
|
state.userActionRequest = void 0;
|
|
1778
901
|
state.userActionPending = false;
|
|
1779
902
|
const stepId = `step-${state.stepCounter++}`;
|
|
1780
903
|
state.steps.push({
|
|
1781
904
|
id: stepId,
|
|
1782
905
|
eventType,
|
|
1783
|
-
message,
|
|
906
|
+
message: displayMessage,
|
|
1784
907
|
status: "error",
|
|
1785
908
|
timestamp: Date.now(),
|
|
1786
909
|
elapsedMs: event.elapsedMs
|
|
@@ -1811,8 +934,58 @@ function processStreamEventV2(event, state) {
|
|
|
1811
934
|
return state;
|
|
1812
935
|
}
|
|
1813
936
|
|
|
937
|
+
// src/utils/ragImageResolver.ts
|
|
938
|
+
var RAG_IMAGE_REGEX = /\/api\/rag\/chunks\/[^"'\s]+\/image/;
|
|
939
|
+
function hasRagImages(content) {
|
|
940
|
+
return RAG_IMAGE_REGEX.test(content);
|
|
941
|
+
}
|
|
942
|
+
async function waitForNextPaint(signal) {
|
|
943
|
+
if (signal?.aborted) return;
|
|
944
|
+
await new Promise((resolve) => {
|
|
945
|
+
let isSettled = false;
|
|
946
|
+
const finish = () => {
|
|
947
|
+
if (isSettled) return;
|
|
948
|
+
isSettled = true;
|
|
949
|
+
signal?.removeEventListener("abort", finish);
|
|
950
|
+
resolve();
|
|
951
|
+
};
|
|
952
|
+
signal?.addEventListener("abort", finish, { once: true });
|
|
953
|
+
if (typeof requestAnimationFrame === "function") {
|
|
954
|
+
requestAnimationFrame(() => {
|
|
955
|
+
setTimeout(finish, 0);
|
|
956
|
+
});
|
|
957
|
+
return;
|
|
958
|
+
}
|
|
959
|
+
setTimeout(finish, 0);
|
|
960
|
+
});
|
|
961
|
+
}
|
|
962
|
+
async function resolveRagImageUrls(config, content, signal) {
|
|
963
|
+
const url = buildResolveImagesUrl(config);
|
|
964
|
+
const baseHeaders = buildRequestHeaders(config);
|
|
965
|
+
const headers = { "Content-Type": "application/json", ...baseHeaders };
|
|
966
|
+
const response = await fetch(url, {
|
|
967
|
+
method: "POST",
|
|
968
|
+
headers,
|
|
969
|
+
body: JSON.stringify({ input: content }),
|
|
970
|
+
signal
|
|
971
|
+
});
|
|
972
|
+
if (!response.ok) {
|
|
973
|
+
const errorText = await response.text();
|
|
974
|
+
throw new Error(`HTTP ${response.status}: ${errorText}`);
|
|
975
|
+
}
|
|
976
|
+
const text = await response.text();
|
|
977
|
+
try {
|
|
978
|
+
const parsed = JSON.parse(text);
|
|
979
|
+
if (typeof parsed === "string") return parsed;
|
|
980
|
+
if (typeof parsed.output === "string") return parsed.output;
|
|
981
|
+
if (typeof parsed.result === "string") return parsed.result;
|
|
982
|
+
} catch {
|
|
983
|
+
}
|
|
984
|
+
return text;
|
|
985
|
+
}
|
|
986
|
+
|
|
1814
987
|
// src/hooks/useStreamManagerV2.ts
|
|
1815
|
-
var
|
|
988
|
+
var FRIENDLY_ERROR_MESSAGE = "Oops, something went wrong. Please try again.";
|
|
1816
989
|
function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForResponse) {
|
|
1817
990
|
const abortControllerRef = react.useRef(null);
|
|
1818
991
|
const configRef = react.useRef(config);
|
|
@@ -1852,7 +1025,10 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
|
|
|
1852
1025
|
if (eventType === "USER_ACTION_REQUIRED" && state.userActionRequest) {
|
|
1853
1026
|
callbacksRef.current.onUserActionRequired?.(state.userActionRequest);
|
|
1854
1027
|
} else if (eventType.startsWith("USER_ACTION_") && eventType !== "USER_ACTION_REQUIRED") {
|
|
1855
|
-
const msg =
|
|
1028
|
+
const msg = getUserActionDisplayMessage(
|
|
1029
|
+
eventType,
|
|
1030
|
+
event.message?.trim() || event.errorMessage?.trim() || getEventMessage(event)
|
|
1031
|
+
);
|
|
1856
1032
|
callbacksRef.current.onUserActionEvent?.(eventType, msg);
|
|
1857
1033
|
}
|
|
1858
1034
|
const activeStep = state.steps.find((s) => s.id === state.currentExecutingStepId);
|
|
@@ -1860,8 +1036,8 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
|
|
|
1860
1036
|
const currentMessage = activeStep?.message || lastInProgressStep?.message || getEventMessage(event);
|
|
1861
1037
|
if (state.hasError) {
|
|
1862
1038
|
updateMessage({
|
|
1863
|
-
streamingContent:
|
|
1864
|
-
content:
|
|
1039
|
+
streamingContent: FRIENDLY_ERROR_MESSAGE,
|
|
1040
|
+
content: FRIENDLY_ERROR_MESSAGE,
|
|
1865
1041
|
streamProgress: "error",
|
|
1866
1042
|
isError: true,
|
|
1867
1043
|
errorDetails: state.errorMessage,
|
|
@@ -1911,7 +1087,7 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
|
|
|
1911
1087
|
isError: !isAborted,
|
|
1912
1088
|
isCancelled: isAborted,
|
|
1913
1089
|
errorDetails: isAborted ? void 0 : error.message,
|
|
1914
|
-
content: isAborted ? state.finalResponse || "" : state.finalResponse ||
|
|
1090
|
+
content: isAborted ? state.finalResponse || "" : state.finalResponse || FRIENDLY_ERROR_MESSAGE,
|
|
1915
1091
|
currentMessage: isAborted ? "Thinking..." : void 0,
|
|
1916
1092
|
formattedThinkingText: state.formattedThinkingText || void 0,
|
|
1917
1093
|
steps: [...state.steps].map((step) => {
|
|
@@ -1943,7 +1119,7 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
|
|
|
1943
1119
|
id: streamingId,
|
|
1944
1120
|
sessionId: state.sessionId || sessionId,
|
|
1945
1121
|
role: "assistant",
|
|
1946
|
-
content: state.hasError ?
|
|
1122
|
+
content: state.hasError ? FRIENDLY_ERROR_MESSAGE : state.finalResponse || "",
|
|
1947
1123
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1948
1124
|
isStreaming: false,
|
|
1949
1125
|
streamProgress: state.hasError ? "error" : "completed",
|
|
@@ -2014,7 +1190,7 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
|
|
|
2014
1190
|
isError: !isAborted,
|
|
2015
1191
|
isCancelled: isAborted,
|
|
2016
1192
|
errorDetails: isAborted ? void 0 : error.message,
|
|
2017
|
-
content: isAborted ? state.finalResponse || "" : state.finalResponse ||
|
|
1193
|
+
content: isAborted ? state.finalResponse || "" : state.finalResponse || FRIENDLY_ERROR_MESSAGE,
|
|
2018
1194
|
formattedThinkingText: state.formattedThinkingText || void 0,
|
|
2019
1195
|
steps: [...state.steps].map((step) => {
|
|
2020
1196
|
if (step.status === "in_progress" && isAborted) {
|
|
@@ -2041,45 +1217,199 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
|
|
|
2041
1217
|
};
|
|
2042
1218
|
}
|
|
2043
1219
|
|
|
1220
|
+
// src/utils/workflowUsersClient.ts
|
|
1221
|
+
var DEFAULT_SESSION_PAGE_SIZE = 20;
|
|
1222
|
+
var DEFAULT_CONVERSATION_PAGE_SIZE = 50;
|
|
1223
|
+
function getStageParamName2(config) {
|
|
1224
|
+
return config.api.stageQueryParam ?? "stage";
|
|
1225
|
+
}
|
|
1226
|
+
function requireOwnerId(config) {
|
|
1227
|
+
const ownerId = config.session?.owner?.id;
|
|
1228
|
+
if (!ownerId) {
|
|
1229
|
+
throw new Error(
|
|
1230
|
+
"workflowUsersClient: session.owner.id is required to call this endpoint."
|
|
1231
|
+
);
|
|
1232
|
+
}
|
|
1233
|
+
return ownerId;
|
|
1234
|
+
}
|
|
1235
|
+
function requireWorkflowName(config) {
|
|
1236
|
+
const workflowName = config.workflow.name;
|
|
1237
|
+
if (!workflowName) {
|
|
1238
|
+
throw new Error(
|
|
1239
|
+
"workflowUsersClient: workflow.name is required to call this endpoint."
|
|
1240
|
+
);
|
|
1241
|
+
}
|
|
1242
|
+
return workflowName;
|
|
1243
|
+
}
|
|
1244
|
+
function requireWorkflowId(config) {
|
|
1245
|
+
const workflowId = config.workflow.id;
|
|
1246
|
+
if (!workflowId) {
|
|
1247
|
+
throw new Error(
|
|
1248
|
+
"workflowUsersClient: workflow.id is required to call this endpoint."
|
|
1249
|
+
);
|
|
1250
|
+
}
|
|
1251
|
+
return workflowId;
|
|
1252
|
+
}
|
|
1253
|
+
function isPlaygroundYaakAuth(config) {
|
|
1254
|
+
if (config.api.authToken) return false;
|
|
1255
|
+
const headers = config.api.headers;
|
|
1256
|
+
if (!headers) return false;
|
|
1257
|
+
for (const key of Object.keys(headers)) {
|
|
1258
|
+
const lower = key.toLowerCase();
|
|
1259
|
+
if (lower === "yaak-api-key" || lower === "x-yaak-api-key") return true;
|
|
1260
|
+
}
|
|
1261
|
+
return false;
|
|
1262
|
+
}
|
|
1263
|
+
async function fetchJson(url, headers, signal) {
|
|
1264
|
+
const response = await fetch(url, {
|
|
1265
|
+
method: "GET",
|
|
1266
|
+
headers,
|
|
1267
|
+
signal
|
|
1268
|
+
});
|
|
1269
|
+
if (!response.ok) {
|
|
1270
|
+
const errorText = await response.text();
|
|
1271
|
+
throw new Error(`HTTP ${response.status}: ${errorText}`);
|
|
1272
|
+
}
|
|
1273
|
+
return await response.json();
|
|
1274
|
+
}
|
|
1275
|
+
async function listSessions(config, opts = {}) {
|
|
1276
|
+
const ownerId = requireOwnerId(config);
|
|
1277
|
+
const useYaakEndpoint = isPlaygroundYaakAuth(config);
|
|
1278
|
+
const params = new URLSearchParams({
|
|
1279
|
+
page: String(opts.page ?? 0),
|
|
1280
|
+
size: String(opts.size ?? DEFAULT_SESSION_PAGE_SIZE)
|
|
1281
|
+
});
|
|
1282
|
+
if (useYaakEndpoint) {
|
|
1283
|
+
params.set("workflowUserId", ownerId);
|
|
1284
|
+
params.set("workflowName", requireWorkflowName(config));
|
|
1285
|
+
} else {
|
|
1286
|
+
params.set("workflowId", requireWorkflowId(config));
|
|
1287
|
+
}
|
|
1288
|
+
if (config.workflow.stage) {
|
|
1289
|
+
params.set(getStageParamName2(config), config.workflow.stage);
|
|
1290
|
+
}
|
|
1291
|
+
const url = useYaakEndpoint ? `${config.api.baseUrl}/api/workflows/ask/sessions?${params.toString()}` : `${config.api.baseUrl}/api/workflow-users/${encodeURIComponent(
|
|
1292
|
+
ownerId
|
|
1293
|
+
)}/sessions?${params.toString()}`;
|
|
1294
|
+
return fetchJson(
|
|
1295
|
+
url,
|
|
1296
|
+
buildRequestHeaders(config),
|
|
1297
|
+
opts.signal
|
|
1298
|
+
);
|
|
1299
|
+
}
|
|
1300
|
+
async function listConversations(config, opts) {
|
|
1301
|
+
const ownerId = requireOwnerId(config);
|
|
1302
|
+
const useYaakEndpoint = isPlaygroundYaakAuth(config);
|
|
1303
|
+
const params = new URLSearchParams({
|
|
1304
|
+
sessionId: opts.sessionId,
|
|
1305
|
+
page: String(opts.page ?? 0),
|
|
1306
|
+
size: String(opts.size ?? DEFAULT_CONVERSATION_PAGE_SIZE)
|
|
1307
|
+
});
|
|
1308
|
+
if (useYaakEndpoint) {
|
|
1309
|
+
params.set("workflowUserId", ownerId);
|
|
1310
|
+
params.set("workflowName", requireWorkflowName(config));
|
|
1311
|
+
}
|
|
1312
|
+
if (config.workflow.stage) {
|
|
1313
|
+
params.set(getStageParamName2(config), config.workflow.stage);
|
|
1314
|
+
}
|
|
1315
|
+
const url = useYaakEndpoint ? `${config.api.baseUrl}/api/workflows/ask/conversations?${params.toString()}` : `${config.api.baseUrl}/api/workflow-users/${encodeURIComponent(
|
|
1316
|
+
ownerId
|
|
1317
|
+
)}/conversations?${params.toString()}`;
|
|
1318
|
+
return fetchJson(
|
|
1319
|
+
url,
|
|
1320
|
+
buildRequestHeaders(config),
|
|
1321
|
+
opts.signal
|
|
1322
|
+
);
|
|
1323
|
+
}
|
|
1324
|
+
|
|
2044
1325
|
// src/hooks/useChatV2.ts
|
|
1326
|
+
function conversationEntryToMessages(entry, sessionId) {
|
|
1327
|
+
return [
|
|
1328
|
+
{
|
|
1329
|
+
id: `history-user-${entry.executionId}`,
|
|
1330
|
+
sessionId,
|
|
1331
|
+
role: "user",
|
|
1332
|
+
content: entry.query,
|
|
1333
|
+
timestamp: entry.createdAt,
|
|
1334
|
+
isHistorical: true
|
|
1335
|
+
},
|
|
1336
|
+
{
|
|
1337
|
+
id: `history-assistant-${entry.executionId}`,
|
|
1338
|
+
sessionId,
|
|
1339
|
+
role: "assistant",
|
|
1340
|
+
content: entry.response,
|
|
1341
|
+
timestamp: entry.createdAt,
|
|
1342
|
+
executionId: entry.executionId,
|
|
1343
|
+
isHistorical: true
|
|
1344
|
+
}
|
|
1345
|
+
];
|
|
1346
|
+
}
|
|
1347
|
+
function streamKeyFor(scopeKey, sessionId) {
|
|
1348
|
+
return `${scopeKey}|sid:${sessionId ?? ""}`;
|
|
1349
|
+
}
|
|
2045
1350
|
function useChatV2(config, callbacks = {}) {
|
|
1351
|
+
const scopeKey = react.useMemo(() => buildScopeKey(config), [
|
|
1352
|
+
config.session?.userId,
|
|
1353
|
+
config.workflow.id,
|
|
1354
|
+
config.workflow.version,
|
|
1355
|
+
config.workflow.stage
|
|
1356
|
+
]);
|
|
1357
|
+
const initialSessionId = chatStore.get(scopeKey).find((m) => m.sessionId)?.sessionId ?? config.session?.initialId ?? void 0;
|
|
2046
1358
|
const [messages, setMessages] = react.useState(() => {
|
|
2047
|
-
|
|
2048
|
-
|
|
1359
|
+
const stored = chatStore.get(scopeKey);
|
|
1360
|
+
if (stored.length > 0) return stored;
|
|
1361
|
+
return config.session?.initialMessages ?? [];
|
|
2049
1362
|
});
|
|
2050
1363
|
const [isWaitingForResponse, setIsWaitingForResponse] = react.useState(false);
|
|
2051
|
-
const
|
|
2052
|
-
|
|
2053
|
-
);
|
|
2054
|
-
const
|
|
1364
|
+
const [loadingSessionId, setLoadingSessionId] = react.useState(void 0);
|
|
1365
|
+
const [currentSessionId, setCurrentSessionId] = react.useState(initialSessionId);
|
|
1366
|
+
const sessionIdRef = react.useRef(initialSessionId);
|
|
1367
|
+
const prevScopeKeyRef = react.useRef(scopeKey);
|
|
1368
|
+
const activeStreamSessionRef = react.useRef(void 0);
|
|
2055
1369
|
const callbacksRef = react.useRef(callbacks);
|
|
2056
1370
|
callbacksRef.current = callbacks;
|
|
2057
1371
|
const configRef = react.useRef(config);
|
|
2058
1372
|
configRef.current = config;
|
|
1373
|
+
const scopeKeyRef = react.useRef(scopeKey);
|
|
1374
|
+
scopeKeyRef.current = scopeKey;
|
|
2059
1375
|
const messagesRef = react.useRef(messages);
|
|
2060
1376
|
messagesRef.current = messages;
|
|
2061
1377
|
const storeAwareSetMessages = react.useCallback(
|
|
2062
1378
|
(updater) => {
|
|
2063
|
-
const
|
|
2064
|
-
|
|
2065
|
-
|
|
1379
|
+
const scope = scopeKeyRef.current;
|
|
1380
|
+
const streamSid = activeStreamSessionRef.current;
|
|
1381
|
+
if (streamSid !== void 0) {
|
|
1382
|
+
const streamKey = streamKeyFor(scope, streamSid);
|
|
1383
|
+
if (activeStreamStore.has(streamKey)) {
|
|
1384
|
+
activeStreamStore.applyMessages(
|
|
1385
|
+
streamKey,
|
|
1386
|
+
updater
|
|
1387
|
+
);
|
|
1388
|
+
}
|
|
1389
|
+
if (sessionIdRef.current === streamSid) {
|
|
1390
|
+
setMessages(updater);
|
|
1391
|
+
}
|
|
1392
|
+
return;
|
|
2066
1393
|
}
|
|
2067
1394
|
setMessages(updater);
|
|
2068
1395
|
},
|
|
2069
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2070
1396
|
[]
|
|
2071
1397
|
);
|
|
2072
|
-
const storeAwareSetIsWaiting = react.useCallback(
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
1398
|
+
const storeAwareSetIsWaiting = react.useCallback((waiting) => {
|
|
1399
|
+
const scope = scopeKeyRef.current;
|
|
1400
|
+
const streamSid = activeStreamSessionRef.current;
|
|
1401
|
+
if (streamSid !== void 0) {
|
|
1402
|
+
const streamKey = streamKeyFor(scope, streamSid);
|
|
1403
|
+
if (activeStreamStore.has(streamKey)) {
|
|
1404
|
+
activeStreamStore.setWaiting(streamKey, waiting);
|
|
2077
1405
|
}
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
1406
|
+
if (sessionIdRef.current === streamSid) {
|
|
1407
|
+
setIsWaitingForResponse(waiting);
|
|
1408
|
+
}
|
|
1409
|
+
return;
|
|
1410
|
+
}
|
|
1411
|
+
setIsWaitingForResponse(waiting);
|
|
1412
|
+
}, []);
|
|
2083
1413
|
const [userActionState, setUserActionState] = react.useState({
|
|
2084
1414
|
request: null,
|
|
2085
1415
|
result: null,
|
|
@@ -2087,38 +1417,43 @@ function useChatV2(config, callbacks = {}) {
|
|
|
2087
1417
|
});
|
|
2088
1418
|
const userActionStateRef = react.useRef(userActionState);
|
|
2089
1419
|
userActionStateRef.current = userActionState;
|
|
2090
|
-
const wrappedCallbacks = react.useMemo(
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
1420
|
+
const wrappedCallbacks = react.useMemo(
|
|
1421
|
+
() => ({
|
|
1422
|
+
...callbacksRef.current,
|
|
1423
|
+
onMessageSent: (message) => callbacksRef.current.onMessageSent?.(message),
|
|
1424
|
+
onStreamStart: () => callbacksRef.current.onStreamStart?.(),
|
|
1425
|
+
onStreamComplete: (message) => callbacksRef.current.onStreamComplete?.(message),
|
|
1426
|
+
onError: (error) => callbacksRef.current.onError?.(error),
|
|
1427
|
+
onExecutionTraceClick: (data) => callbacksRef.current.onExecutionTraceClick?.(data),
|
|
1428
|
+
onSessionIdChange: (sessionId) => callbacksRef.current.onSessionIdChange?.(sessionId),
|
|
1429
|
+
onUserActionRequired: (request) => {
|
|
1430
|
+
setUserActionState((prev) => ({ ...prev, request, result: null }));
|
|
1431
|
+
callbacksRef.current.onUserActionRequired?.(request);
|
|
1432
|
+
},
|
|
1433
|
+
onUserActionEvent: (eventType, message) => {
|
|
1434
|
+
switch (eventType) {
|
|
1435
|
+
case "USER_ACTION_SUCCESS":
|
|
1436
|
+
setUserActionState((prev) => ({ ...prev, request: null, result: "approved" }));
|
|
1437
|
+
break;
|
|
1438
|
+
case "USER_ACTION_REJECTED":
|
|
1439
|
+
setUserActionState((prev) => ({ ...prev, request: null, result: "rejected" }));
|
|
1440
|
+
break;
|
|
1441
|
+
case "USER_ACTION_EXPIRED":
|
|
1442
|
+
case "USER_ACTION_FAILED":
|
|
1443
|
+
setUserActionState((prev) => ({ ...prev, request: null }));
|
|
1444
|
+
break;
|
|
1445
|
+
case "USER_ACTION_INVALID":
|
|
1446
|
+
setUserActionState((prev) => ({
|
|
1447
|
+
...prev,
|
|
1448
|
+
clearOtpTrigger: prev.clearOtpTrigger + 1
|
|
1449
|
+
}));
|
|
1450
|
+
break;
|
|
1451
|
+
}
|
|
1452
|
+
callbacksRef.current.onUserActionEvent?.(eventType, message);
|
|
2117
1453
|
}
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
}), []);
|
|
1454
|
+
}),
|
|
1455
|
+
[]
|
|
1456
|
+
);
|
|
2122
1457
|
const { startStream, cancelStream: cancelStreamManager, abortControllerRef } = useStreamManagerV2(
|
|
2123
1458
|
config,
|
|
2124
1459
|
wrappedCallbacks,
|
|
@@ -2128,8 +1463,10 @@ function useChatV2(config, callbacks = {}) {
|
|
|
2128
1463
|
const sendMessage = react.useCallback(
|
|
2129
1464
|
async (userMessage) => {
|
|
2130
1465
|
if (!userMessage.trim()) return;
|
|
2131
|
-
|
|
1466
|
+
const autoGen = configRef.current.session?.autoGenerateId;
|
|
1467
|
+
if (!sessionIdRef.current && autoGen !== false) {
|
|
2132
1468
|
sessionIdRef.current = generateId();
|
|
1469
|
+
setCurrentSessionId(sessionIdRef.current);
|
|
2133
1470
|
callbacksRef.current.onSessionIdChange?.(sessionIdRef.current);
|
|
2134
1471
|
}
|
|
2135
1472
|
const userMessageId = `user-${Date.now()}`;
|
|
@@ -2161,38 +1498,40 @@ function useChatV2(config, callbacks = {}) {
|
|
|
2161
1498
|
};
|
|
2162
1499
|
setMessages((prev) => [...prev, streamingMsg]);
|
|
2163
1500
|
const abortController = new AbortController();
|
|
2164
|
-
const
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
1501
|
+
const scope = scopeKeyRef.current;
|
|
1502
|
+
const streamSessionId = sessionIdRef.current;
|
|
1503
|
+
const streamKey = streamKeyFor(scope, streamSessionId);
|
|
1504
|
+
activeStreamSessionRef.current = streamSessionId;
|
|
1505
|
+
const initialMessages = [...messagesRef.current, userMsg, streamingMsg];
|
|
1506
|
+
activeStreamStore.start(streamKey, abortController, initialMessages);
|
|
2169
1507
|
const newSessionId = await startStream(
|
|
2170
1508
|
userMessage,
|
|
2171
1509
|
streamingId,
|
|
2172
|
-
|
|
1510
|
+
streamSessionId,
|
|
2173
1511
|
abortController
|
|
2174
1512
|
);
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
if (!abortController.signal.aborted && newSessionId && newSessionId !== sessionIdRef.current) {
|
|
1513
|
+
activeStreamStore.complete(streamKey);
|
|
1514
|
+
activeStreamSessionRef.current = void 0;
|
|
1515
|
+
if (!abortController.signal.aborted && newSessionId && newSessionId !== streamSessionId && sessionIdRef.current === streamSessionId) {
|
|
2179
1516
|
sessionIdRef.current = newSessionId;
|
|
1517
|
+
setCurrentSessionId(newSessionId);
|
|
2180
1518
|
}
|
|
2181
1519
|
},
|
|
2182
1520
|
[startStream]
|
|
2183
1521
|
);
|
|
2184
1522
|
const clearMessages = react.useCallback(() => {
|
|
2185
|
-
|
|
2186
|
-
chatStore.delete(configRef.current.userId);
|
|
2187
|
-
}
|
|
1523
|
+
chatStore.delete(scopeKeyRef.current);
|
|
2188
1524
|
setMessages([]);
|
|
2189
1525
|
}, []);
|
|
2190
1526
|
const prependMessages = react.useCallback((msgs) => {
|
|
2191
1527
|
setMessages((prev) => [...msgs, ...prev]);
|
|
2192
1528
|
}, []);
|
|
2193
1529
|
const cancelStream = react.useCallback(() => {
|
|
2194
|
-
|
|
2195
|
-
|
|
1530
|
+
const scope = scopeKeyRef.current;
|
|
1531
|
+
const viewSid = sessionIdRef.current;
|
|
1532
|
+
const viewStreamKey = streamKeyFor(scope, viewSid);
|
|
1533
|
+
if (activeStreamStore.has(viewStreamKey)) {
|
|
1534
|
+
activeStreamStore.abort(viewStreamKey);
|
|
2196
1535
|
}
|
|
2197
1536
|
cancelStreamManager();
|
|
2198
1537
|
setIsWaitingForResponse(false);
|
|
@@ -2202,10 +1541,7 @@ function useChatV2(config, callbacks = {}) {
|
|
|
2202
1541
|
if (msg.isStreaming) {
|
|
2203
1542
|
return {
|
|
2204
1543
|
...msg,
|
|
2205
|
-
...createCancelledMessageUpdate(
|
|
2206
|
-
msg.steps || [],
|
|
2207
|
-
msg.currentMessage
|
|
2208
|
-
)
|
|
1544
|
+
...createCancelledMessageUpdate(msg.steps || [], msg.currentMessage)
|
|
2209
1545
|
};
|
|
2210
1546
|
}
|
|
2211
1547
|
return msg;
|
|
@@ -2213,39 +1549,37 @@ function useChatV2(config, callbacks = {}) {
|
|
|
2213
1549
|
);
|
|
2214
1550
|
}, [cancelStreamManager]);
|
|
2215
1551
|
const resetSession = react.useCallback(() => {
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
1552
|
+
const scope = scopeKeyRef.current;
|
|
1553
|
+
const viewSid = sessionIdRef.current;
|
|
1554
|
+
const viewStreamKey = streamKeyFor(scope, viewSid);
|
|
1555
|
+
if (activeStreamStore.has(viewStreamKey)) {
|
|
1556
|
+
activeStreamStore.abort(viewStreamKey);
|
|
2219
1557
|
}
|
|
1558
|
+
chatStore.delete(scope);
|
|
2220
1559
|
setMessages([]);
|
|
2221
1560
|
sessionIdRef.current = void 0;
|
|
1561
|
+
setCurrentSessionId(void 0);
|
|
1562
|
+
activeStreamSessionRef.current = void 0;
|
|
2222
1563
|
abortControllerRef.current?.abort();
|
|
2223
1564
|
setIsWaitingForResponse(false);
|
|
2224
1565
|
setUserActionState({ request: null, result: null, clearOtpTrigger: 0 });
|
|
2225
1566
|
}, []);
|
|
2226
|
-
const getSessionId = react.useCallback(() =>
|
|
2227
|
-
|
|
1567
|
+
const getSessionId = react.useCallback(() => sessionIdRef.current, []);
|
|
1568
|
+
const getMessages = react.useCallback(() => messages, [messages]);
|
|
1569
|
+
const approveUserAction = react.useCallback(async (otp) => {
|
|
1570
|
+
const request = userActionStateRef.current.request;
|
|
1571
|
+
if (!request) return;
|
|
1572
|
+
try {
|
|
1573
|
+
await submitUserAction(configRef.current, request.userActionId, { otp });
|
|
1574
|
+
} catch (error) {
|
|
1575
|
+
setUserActionState((prev) => ({
|
|
1576
|
+
...prev,
|
|
1577
|
+
clearOtpTrigger: prev.clearOtpTrigger + 1
|
|
1578
|
+
}));
|
|
1579
|
+
callbacksRef.current.onError?.(error);
|
|
1580
|
+
throw error;
|
|
1581
|
+
}
|
|
2228
1582
|
}, []);
|
|
2229
|
-
const getMessages = react.useCallback(() => {
|
|
2230
|
-
return messages;
|
|
2231
|
-
}, [messages]);
|
|
2232
|
-
const approveUserAction = react.useCallback(
|
|
2233
|
-
async (otp) => {
|
|
2234
|
-
const request = userActionStateRef.current.request;
|
|
2235
|
-
if (!request) return;
|
|
2236
|
-
try {
|
|
2237
|
-
await submitUserAction(configRef.current, request.userActionId, { otp });
|
|
2238
|
-
} catch (error) {
|
|
2239
|
-
setUserActionState((prev) => ({
|
|
2240
|
-
...prev,
|
|
2241
|
-
clearOtpTrigger: prev.clearOtpTrigger + 1
|
|
2242
|
-
}));
|
|
2243
|
-
callbacksRef.current.onError?.(error);
|
|
2244
|
-
throw error;
|
|
2245
|
-
}
|
|
2246
|
-
},
|
|
2247
|
-
[]
|
|
2248
|
-
);
|
|
2249
1583
|
const rejectUserAction = react.useCallback(async () => {
|
|
2250
1584
|
const request = userActionStateRef.current.request;
|
|
2251
1585
|
if (!request) return;
|
|
@@ -2279,43 +1613,91 @@ function useChatV2(config, callbacks = {}) {
|
|
|
2279
1613
|
throw error;
|
|
2280
1614
|
}
|
|
2281
1615
|
}, []);
|
|
1616
|
+
const inFlightLoadRef = react.useRef(null);
|
|
1617
|
+
const loadingSessionIdRef = react.useRef(void 0);
|
|
1618
|
+
loadingSessionIdRef.current = loadingSessionId;
|
|
1619
|
+
const loadSession = react.useCallback(async (sessionId) => {
|
|
1620
|
+
const inFlight = inFlightLoadRef.current;
|
|
1621
|
+
if (inFlight && inFlight.sessionId === sessionId) {
|
|
1622
|
+
return inFlight.promise;
|
|
1623
|
+
}
|
|
1624
|
+
if (sessionIdRef.current === sessionId && loadingSessionIdRef.current !== sessionId) {
|
|
1625
|
+
return;
|
|
1626
|
+
}
|
|
1627
|
+
const run = async () => {
|
|
1628
|
+
const scope = scopeKeyRef.current;
|
|
1629
|
+
setUserActionState({ request: null, result: null, clearOtpTrigger: 0 });
|
|
1630
|
+
sessionIdRef.current = sessionId;
|
|
1631
|
+
setCurrentSessionId(sessionId);
|
|
1632
|
+
callbacksRef.current.onSessionIdChange?.(sessionId);
|
|
1633
|
+
const streamKey = streamKeyFor(scope, sessionId);
|
|
1634
|
+
const active = activeStreamStore.get(streamKey);
|
|
1635
|
+
if (active) {
|
|
1636
|
+
setMessages(active.messages);
|
|
1637
|
+
setIsWaitingForResponse(active.isWaiting);
|
|
1638
|
+
setLoadingSessionId(void 0);
|
|
1639
|
+
return;
|
|
1640
|
+
}
|
|
1641
|
+
setIsWaitingForResponse(false);
|
|
1642
|
+
setMessages([]);
|
|
1643
|
+
chatStore.delete(scope);
|
|
1644
|
+
setLoadingSessionId(sessionId);
|
|
1645
|
+
try {
|
|
1646
|
+
const response = await listConversations(configRef.current, { sessionId });
|
|
1647
|
+
const entries = response.data ?? [];
|
|
1648
|
+
const historical = entries.flatMap((entry) => conversationEntryToMessages(entry, sessionId));
|
|
1649
|
+
if (sessionIdRef.current === sessionId) {
|
|
1650
|
+
setMessages(historical);
|
|
1651
|
+
}
|
|
1652
|
+
if (historical.length > 0) {
|
|
1653
|
+
chatStore.set(scope, historical);
|
|
1654
|
+
}
|
|
1655
|
+
} catch (error) {
|
|
1656
|
+
callbacksRef.current.onError?.(error);
|
|
1657
|
+
throw error;
|
|
1658
|
+
} finally {
|
|
1659
|
+
setLoadingSessionId((current) => current === sessionId ? void 0 : current);
|
|
1660
|
+
}
|
|
1661
|
+
};
|
|
1662
|
+
const promise = run().finally(() => {
|
|
1663
|
+
if (inFlightLoadRef.current?.sessionId === sessionId) {
|
|
1664
|
+
inFlightLoadRef.current = null;
|
|
1665
|
+
}
|
|
1666
|
+
});
|
|
1667
|
+
inFlightLoadRef.current = { sessionId, promise };
|
|
1668
|
+
return promise;
|
|
1669
|
+
}, []);
|
|
2282
1670
|
react.useEffect(() => {
|
|
2283
|
-
const
|
|
2284
|
-
|
|
2285
|
-
const unsubscribe = activeStreamStore.subscribe(userId, (msgs, isWaiting) => {
|
|
1671
|
+
const key = streamKeyFor(scopeKey, currentSessionId);
|
|
1672
|
+
const unsubscribe = activeStreamStore.subscribe(key, (msgs, isWaiting) => {
|
|
2286
1673
|
setMessages(msgs);
|
|
2287
1674
|
setIsWaitingForResponse(isWaiting);
|
|
2288
1675
|
});
|
|
2289
|
-
const active = activeStreamStore.get(
|
|
1676
|
+
const active = activeStreamStore.get(key);
|
|
2290
1677
|
if (active) {
|
|
2291
1678
|
setMessages(active.messages);
|
|
2292
1679
|
setIsWaitingForResponse(active.isWaiting);
|
|
2293
1680
|
}
|
|
2294
1681
|
return unsubscribe;
|
|
2295
|
-
}, []);
|
|
1682
|
+
}, [scopeKey, currentSessionId]);
|
|
2296
1683
|
react.useEffect(() => {
|
|
2297
|
-
if (!config.userId) return;
|
|
2298
1684
|
const toSave = messages.filter((m) => !m.isStreaming);
|
|
2299
1685
|
if (toSave.length > 0) {
|
|
2300
|
-
chatStore.set(
|
|
1686
|
+
chatStore.set(scopeKey, toSave);
|
|
2301
1687
|
}
|
|
2302
|
-
}, [messages,
|
|
1688
|
+
}, [messages, scopeKey]);
|
|
2303
1689
|
react.useEffect(() => {
|
|
2304
|
-
const
|
|
2305
|
-
|
|
2306
|
-
if (
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
setMessages(stored);
|
|
2316
|
-
sessionIdRef.current = stored.find((m) => m.sessionId)?.sessionId;
|
|
2317
|
-
}
|
|
2318
|
-
}, [config.userId]);
|
|
1690
|
+
const prevKey = prevScopeKeyRef.current;
|
|
1691
|
+
prevScopeKeyRef.current = scopeKey;
|
|
1692
|
+
if (prevKey === scopeKey) return;
|
|
1693
|
+
const stored = chatStore.get(scopeKey);
|
|
1694
|
+
setMessages(stored);
|
|
1695
|
+
const restoredSessionId = stored.find((m) => m.sessionId)?.sessionId ?? configRef.current.session?.initialId ?? void 0;
|
|
1696
|
+
sessionIdRef.current = restoredSessionId;
|
|
1697
|
+
setCurrentSessionId(restoredSessionId);
|
|
1698
|
+
setIsWaitingForResponse(false);
|
|
1699
|
+
setUserActionState({ request: null, result: null, clearOtpTrigger: 0 });
|
|
1700
|
+
}, [scopeKey]);
|
|
2319
1701
|
return {
|
|
2320
1702
|
messages,
|
|
2321
1703
|
sendMessage,
|
|
@@ -2326,11 +1708,13 @@ function useChatV2(config, callbacks = {}) {
|
|
|
2326
1708
|
getSessionId,
|
|
2327
1709
|
getMessages,
|
|
2328
1710
|
isWaitingForResponse,
|
|
2329
|
-
sessionId:
|
|
1711
|
+
sessionId: currentSessionId,
|
|
2330
1712
|
userActionState,
|
|
2331
1713
|
approveUserAction,
|
|
2332
1714
|
rejectUserAction,
|
|
2333
|
-
resendOtp
|
|
1715
|
+
resendOtp,
|
|
1716
|
+
loadSession,
|
|
1717
|
+
loadingSessionId
|
|
2334
1718
|
};
|
|
2335
1719
|
}
|
|
2336
1720
|
function useVoice() {
|
|
@@ -2450,14 +1834,16 @@ function useVoice() {
|
|
|
2450
1834
|
}
|
|
2451
1835
|
|
|
2452
1836
|
exports.buildFormattedThinking = buildFormattedThinking;
|
|
1837
|
+
exports.buildScopeKey = buildScopeKey;
|
|
2453
1838
|
exports.cancelUserAction = cancelUserAction;
|
|
2454
1839
|
exports.createInitialV2State = createInitialV2State;
|
|
2455
1840
|
exports.generateId = generateId;
|
|
1841
|
+
exports.listConversations = listConversations;
|
|
1842
|
+
exports.listSessions = listSessions;
|
|
2456
1843
|
exports.processStreamEventV2 = processStreamEventV2;
|
|
2457
1844
|
exports.resendUserAction = resendUserAction;
|
|
2458
1845
|
exports.streamWorkflowEvents = streamWorkflowEvents;
|
|
2459
1846
|
exports.submitUserAction = submitUserAction;
|
|
2460
|
-
exports.useChat = useChat;
|
|
2461
1847
|
exports.useChatV2 = useChatV2;
|
|
2462
1848
|
exports.useVoice = useVoice;
|
|
2463
1849
|
exports.workingPhaseDetailForDisplay = workingPhaseDetailForDisplay;
|