@paymanai/payman-typescript-ask-sdk 2.0.3 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { useMemo, useState, useRef, useCallback, useEffect } from 'react';
1
+ import { useState, useRef, useCallback, useMemo, useEffect } from 'react';
2
2
 
3
3
  // src/hooks/useChatV2.ts
4
4
 
@@ -12,6 +12,13 @@ function generateId() {
12
12
  }
13
13
 
14
14
  // src/utils/streamingClient.ts
15
+ function yieldAfterProgressEvent(event) {
16
+ const t = event.eventType;
17
+ if (t === "RUN_IN_PROGRESS" || t === "INTENT_PROGRESS" || t === "AGGREGATOR_THINKING_CONT" || t === "INTENT_THINKING_CONT" || t === "THINKING_DELTA") {
18
+ return new Promise((resolve) => setTimeout(resolve, 0));
19
+ }
20
+ return Promise.resolve();
21
+ }
15
22
  function parseJSONBuffer(buffer) {
16
23
  const events = [];
17
24
  let braceCount = 0;
@@ -88,6 +95,7 @@ async function streamWorkflowEvents(url, body, headers, options = {}) {
88
95
  const { events: events2 } = parseJSONBuffer(buffer);
89
96
  for (const event of events2) {
90
97
  onEvent?.(event);
98
+ await yieldAfterProgressEvent(event);
91
99
  }
92
100
  }
93
101
  break;
@@ -96,6 +104,7 @@ async function streamWorkflowEvents(url, body, headers, options = {}) {
96
104
  const { events, remaining } = parseJSONBuffer(buffer);
97
105
  for (const event of events) {
98
106
  onEvent?.(event);
107
+ await yieldAfterProgressEvent(event);
99
108
  }
100
109
  buffer = remaining;
101
110
  }
@@ -108,7 +117,38 @@ async function streamWorkflowEvents(url, body, headers, options = {}) {
108
117
  }
109
118
  }
110
119
 
111
- // src/utils/eventProcessor.ts
120
+ // src/utils/stageLabels.ts
121
+ var STAGE_LABELS = {
122
+ sanitizer: "Checking your request",
123
+ analyzer: "Understanding what you're asking",
124
+ prefetcher: "Gathering context",
125
+ planner: "Planning how to handle this",
126
+ execution: "Working on it",
127
+ formatter: "Writing the response"
128
+ };
129
+ function stageLabel(stage) {
130
+ const label = STAGE_LABELS[stage];
131
+ if (label) return label;
132
+ const pretty = stage.replace(/[_-]/g, " ");
133
+ return `Running ${pretty}`;
134
+ }
135
+
136
+ // src/utils/v2EventProcessor.ts
137
+ function isBlandStatus(message) {
138
+ if (!message) return true;
139
+ const normalized = message.trim().toLowerCase().replace(/[…\.]+$/, "").trim();
140
+ return BLAND_STATUS_LABELS.has(normalized);
141
+ }
142
+ var BLAND_STATUS_LABELS = /* @__PURE__ */ new Set([
143
+ "executing",
144
+ "working on it",
145
+ "thinking",
146
+ "processing",
147
+ "reviewing your request",
148
+ "composing response",
149
+ "checking your request",
150
+ "polishing the response"
151
+ ]);
112
152
  function getEventMessage(event) {
113
153
  if (event.message?.trim()) {
114
154
  return event.message.trim();
@@ -118,54 +158,104 @@ function getEventMessage(event) {
118
158
  }
119
159
  const eventType = event.eventType;
120
160
  switch (eventType) {
121
- case "STARTED":
122
- case "WORKFLOW_STARTED":
123
- return "Starting workflow...";
124
- case "ORCHESTRATOR_THINKING":
125
- return "Planning execution strategy...";
126
- case "ORCHESTRATOR_COMPLETED":
127
- return "Planning complete";
128
- case "INTENT_STARTED":
129
- return event.workerName ? `${event.workerName} started` : "Processing intent...";
130
- case "INTENT_PROGRESS":
131
- return event.workerName ? `${event.workerName} in progress` : "Thinking...";
132
- case "INTENT_COMPLETED":
133
- return event.workerName ? `${event.workerName} completed` : "Intent completed";
134
- case "AGGREGATOR_THINKING":
135
- return "Combining results...";
136
- case "AGGREGATOR_COMPLETED":
137
- return "Results combined";
138
- case "COMPLETED":
139
- case "WORKFLOW_COMPLETED":
140
- return "Workflow completed successfully";
141
- case "ERROR":
142
- case "WORKFLOW_ERROR":
143
- case "INTENT_ERROR":
144
- return event.errorMessage || "An error occurred";
145
- case "USER_ACTION_REQUIRED":
146
- return "Waiting for verification...";
147
- case "USER_ACTION_SUCCESS":
148
- return "Verification approved";
149
- case "USER_ACTION_EXPIRED":
150
- return "Verification expired";
151
- case "USER_ACTION_INVALID":
152
- return "Invalid code. Please try again.";
153
- case "USER_ACTION_REJECTED":
154
- return "Verification cancelled";
155
- case "USER_ACTION_RESENT":
156
- return "Verification code resent";
157
- case "USER_ACTION_FAILED":
158
- return "Verification failed";
159
- case "INTENT_THINKING":
160
- return event.workerName ? `${event.workerName} thinking...` : "Thinking...";
161
- case "INTENT_THINKING_CONT":
162
- return event.message || "";
161
+ case "RUN_STARTED":
162
+ return "Starting agent run...";
163
+ case "TOOL_CALL_STARTED": {
164
+ const description = typeof event.description === "string" ? event.description.trim() : "";
165
+ if (description) return description;
166
+ const toolName = typeof event.toolName === "string" ? event.toolName : "";
167
+ return toolName ? `Calling ${toolName}...` : "Calling tool...";
168
+ }
169
+ case "TOOL_CALL_COMPLETED": {
170
+ const description = typeof event.description === "string" ? event.description.trim() : "";
171
+ if (description) return description;
172
+ const toolName = typeof event.toolName === "string" ? event.toolName : "";
173
+ return toolName ? `${toolName} completed` : "Tool call completed";
174
+ }
175
+ case "RUN_IN_PROGRESS":
176
+ return event.partialText || "Thinking...";
177
+ case "RUN_COMPLETED":
178
+ return "Agent run completed";
179
+ case "RUN_FAILED":
180
+ return event.errorMessage || "Agent run failed";
163
181
  case "KEEP_ALIVE":
164
- return "";
182
+ return event.description || "";
183
+ case "THINKING_DELTA":
184
+ return event.text || "";
165
185
  default:
166
186
  return eventType;
167
187
  }
168
188
  }
189
+ function extractResponseContent(response) {
190
+ if (typeof response === "string") {
191
+ return response;
192
+ }
193
+ if (typeof response === "object" && response !== null) {
194
+ const resp = response;
195
+ if ("text" in resp && typeof resp.text === "string") {
196
+ return resp.text;
197
+ }
198
+ if ("content" in resp && typeof resp.content === "string") {
199
+ return resp.content;
200
+ }
201
+ if ("message" in resp && typeof resp.message === "string") {
202
+ return resp.message;
203
+ }
204
+ if ("answer" in resp && typeof resp.answer === "string") {
205
+ return resp.answer;
206
+ }
207
+ return JSON.stringify(response);
208
+ }
209
+ return "";
210
+ }
211
+ function normalizeEvent(event) {
212
+ const type = event.eventType;
213
+ switch (type) {
214
+ case "RUN_STARTED":
215
+ return { ...event, eventType: "WORKFLOW_STARTED" };
216
+ case "TOOL_CALL_STARTED": {
217
+ const toolName = typeof event.toolName === "string" ? event.toolName : void 0;
218
+ const description = typeof event.description === "string" ? event.description.trim() : "";
219
+ return {
220
+ ...event,
221
+ eventType: "INTENT_STARTED",
222
+ workerName: toolName ?? event.workerName,
223
+ message: description || event.message
224
+ };
225
+ }
226
+ case "TOOL_CALL_COMPLETED": {
227
+ const toolName = typeof event.toolName === "string" ? event.toolName : void 0;
228
+ const description = typeof event.description === "string" ? event.description.trim() : "";
229
+ return {
230
+ ...event,
231
+ eventType: "INTENT_COMPLETED",
232
+ workerName: toolName ?? event.workerName,
233
+ message: description || event.message
234
+ };
235
+ }
236
+ case "RUN_IN_PROGRESS":
237
+ return {
238
+ ...event,
239
+ eventType: "INTENT_PROGRESS",
240
+ message: event.partialText ?? event.message
241
+ };
242
+ case "RUN_COMPLETED":
243
+ return {
244
+ ...event,
245
+ eventType: "WORKFLOW_COMPLETED",
246
+ // state machine reads event.response for the final content
247
+ response: event.response ?? event.message
248
+ };
249
+ case "RUN_FAILED":
250
+ return {
251
+ ...event,
252
+ eventType: "WORKFLOW_ERROR",
253
+ errorMessage: event.errorMessage ?? event.message
254
+ };
255
+ default:
256
+ return event;
257
+ }
258
+ }
169
259
  function isUserActionPrompt(text) {
170
260
  return /\benter\b.+\b(code|otp)\b/i.test(text) || /\b(authorization|verification)\s+code\b/i.test(text) || /\bsent\s+to\s+your\b/i.test(text);
171
261
  }
@@ -199,300 +289,6 @@ function workingPhaseDetailForDisplay(raw) {
199
289
  }
200
290
  return t;
201
291
  }
202
- function extractResponseContent(response) {
203
- if (typeof response === "string") {
204
- return response;
205
- }
206
- if (typeof response === "object" && response !== null) {
207
- const resp = response;
208
- if ("text" in resp && typeof resp.text === "string") {
209
- return resp.text;
210
- }
211
- if ("content" in resp && typeof resp.content === "string") {
212
- return resp.content;
213
- }
214
- if ("message" in resp && typeof resp.message === "string") {
215
- return resp.message;
216
- }
217
- if ("answer" in resp && typeof resp.answer === "string") {
218
- return resp.answer;
219
- }
220
- return JSON.stringify(response);
221
- }
222
- return "";
223
- }
224
-
225
- // src/utils/messageStateManager.ts
226
- function buildFormattedThinking(steps, allThinkingText) {
227
- const parts = [];
228
- const safeSteps = steps ?? [];
229
- const cleanAll = allThinkingText.replace(/^\s+/, "");
230
- if (cleanAll) {
231
- const firstStepWithThinking = safeSteps.find(
232
- (s) => s.thinkingText && s.thinkingText.trim()
233
- );
234
- if (!firstStepWithThinking) {
235
- parts.push("**Preflight**");
236
- parts.push(cleanAll);
237
- } else {
238
- const stepText = firstStepWithThinking.thinkingText.trim();
239
- const idx = cleanAll.indexOf(stepText);
240
- if (idx > 0) {
241
- const orphaned = cleanAll.substring(0, idx).replace(/\s+$/, "");
242
- if (orphaned) {
243
- parts.push("**Preflight**");
244
- parts.push(orphaned);
245
- }
246
- }
247
- }
248
- }
249
- for (const step of safeSteps) {
250
- switch (step.eventType) {
251
- case "ORCHESTRATOR_THINKING":
252
- parts.push("**Planning**");
253
- if (step.message) parts.push(step.message);
254
- break;
255
- case "WORKING": {
256
- const detail = workingPhaseDetailForDisplay(step.message || "");
257
- parts.push("**Working**");
258
- if (detail) parts.push(detail);
259
- break;
260
- }
261
- case "INTENT_STARTED": {
262
- let label = step.message || "Processing";
263
- const started = label.match(/^(.+?)\s+started$/i);
264
- const progress = label.match(/^(.+?)\s+in progress$/i);
265
- if (started) label = started[1];
266
- else if (progress) label = progress[1];
267
- parts.push(`**${label}**`);
268
- if (step.thinkingText) parts.push(step.thinkingText);
269
- break;
270
- }
271
- case "INTENT_PROGRESS": {
272
- if (step.thinkingText) parts.push(step.thinkingText);
273
- else if (step.message) parts.push(step.message);
274
- break;
275
- }
276
- case "AGGREGATOR_THINKING":
277
- parts.push("**Finalizing**");
278
- if (step.message) parts.push(step.message);
279
- break;
280
- case "USER_ACTION_REQUIRED":
281
- parts.push("**Verification Required**");
282
- if (step.message) {
283
- parts.push(getUserActionDisplayMessage(step.eventType, step.message));
284
- }
285
- break;
286
- case "USER_ACTION_SUCCESS":
287
- parts.push(`\u2713 ${getUserActionDisplayMessage(step.eventType, step.message)}`);
288
- break;
289
- case "USER_ACTION_REJECTED":
290
- parts.push(getUserActionDisplayMessage(step.eventType, step.message));
291
- break;
292
- case "USER_ACTION_EXPIRED":
293
- parts.push(`\u2717 ${getUserActionDisplayMessage(step.eventType, step.message)}`);
294
- break;
295
- case "USER_ACTION_INVALID":
296
- parts.push(`\u2717 ${getUserActionDisplayMessage(step.eventType, step.message)}`);
297
- break;
298
- case "USER_ACTION_RESENT":
299
- parts.push(getUserActionDisplayMessage(step.eventType, step.message));
300
- break;
301
- case "USER_ACTION_FAILED":
302
- parts.push(`\u2717 ${getUserActionDisplayMessage(step.eventType, step.message)}`);
303
- break;
304
- }
305
- }
306
- return parts.length > 0 ? parts.join("\n") : allThinkingText;
307
- }
308
- function createCancelledMessageUpdate(steps, currentMessage) {
309
- const updatedSteps = steps.map((step) => {
310
- if (step.status === "in_progress") {
311
- return { ...step, status: "pending" };
312
- }
313
- return step;
314
- });
315
- return {
316
- isStreaming: false,
317
- isCancelled: true,
318
- steps: updatedSteps,
319
- currentExecutingStepId: void 0,
320
- // Preserve currentMessage so UI can show it with X icon
321
- currentMessage: currentMessage || "Thinking..."
322
- };
323
- }
324
-
325
- // src/utils/requestBuilder.ts
326
- function buildRequestBody(config, userMessage, sessionId) {
327
- const owner = config.session?.owner;
328
- const sessionAttributes = owner?.attributes && Object.keys(owner.attributes).length > 0 ? owner.attributes : void 0;
329
- return {
330
- workflowName: config.workflow.name,
331
- userInput: userMessage,
332
- sessionId,
333
- sessionOwnerId: owner?.id || "",
334
- sessionOwnerLabel: owner?.name || "",
335
- sessionAttributes,
336
- options: {
337
- clientTimezone: Intl.DateTimeFormat().resolvedOptions().timeZone
338
- }
339
- };
340
- }
341
- function getStageParamName(config) {
342
- return config.api.stageQueryParam ?? "stage";
343
- }
344
- function getStage(config) {
345
- return config.workflow.stage ?? "DEV";
346
- }
347
- function buildStreamingUrl(config) {
348
- const endpoint = config.api.streamEndpoint || "/api/workflows/ask/stream";
349
- const queryParams = new URLSearchParams({
350
- [getStageParamName(config)]: getStage(config)
351
- });
352
- if (config.workflow.version !== void 0) {
353
- queryParams.append("workflowVersion", String(config.workflow.version));
354
- }
355
- return `${config.api.baseUrl}${endpoint}?${queryParams.toString()}`;
356
- }
357
- function deriveBasePath(config) {
358
- const endpoint = config.api.streamEndpoint || "/api/workflows/ask/stream";
359
- const [endpointPath] = endpoint.split("?");
360
- const normalized = endpointPath.replace(/\/+$/, "");
361
- return normalized.endsWith("/stream") ? normalized.slice(0, -"/stream".length) : normalized;
362
- }
363
- function buildUserActionUrl(config, userActionId, action) {
364
- const basePath = deriveBasePath(config);
365
- const encodedUserActionId = encodeURIComponent(userActionId);
366
- return `${config.api.baseUrl}${basePath}/user-action/${encodedUserActionId}/${action}`;
367
- }
368
- function buildResolveImagesUrl(config) {
369
- if (config.api.resolveImagesEndpoint) {
370
- return `${config.api.baseUrl}${config.api.resolveImagesEndpoint}`;
371
- }
372
- return `${config.api.baseUrl}${deriveBasePath(config)}/resolve-image-urls`;
373
- }
374
- function buildRequestHeaders(config) {
375
- const headers = { ...config.api.headers };
376
- if (config.api.authToken) {
377
- headers.Authorization = `Bearer ${config.api.authToken}`;
378
- }
379
- return headers;
380
- }
381
- function buildScopeKey(config) {
382
- return [
383
- config.session?.userId ?? "",
384
- config.workflow.id ?? "",
385
- config.workflow.version ?? "",
386
- config.workflow.stage ?? ""
387
- ].join("|");
388
- }
389
-
390
- // src/utils/userActionClient.ts
391
- async function sendUserActionRequest(config, userActionId, action, data) {
392
- const url = buildUserActionUrl(config, userActionId, action);
393
- const baseHeaders = buildRequestHeaders(config);
394
- const hasBody = data !== void 0;
395
- const headers = hasBody ? { "Content-Type": "application/json", ...baseHeaders } : baseHeaders;
396
- const response = await fetch(url, {
397
- method: "POST",
398
- headers,
399
- body: hasBody ? JSON.stringify(data) : void 0
400
- });
401
- if (!response.ok) {
402
- const errorText = await response.text();
403
- throw new Error(`HTTP ${response.status}: ${errorText}`);
404
- }
405
- return await response.json();
406
- }
407
- async function submitUserAction(config, userActionId, data) {
408
- return sendUserActionRequest(config, userActionId, "submit", data);
409
- }
410
- async function cancelUserAction(config, userActionId) {
411
- return sendUserActionRequest(config, userActionId, "cancel");
412
- }
413
- async function resendUserAction(config, userActionId) {
414
- return sendUserActionRequest(config, userActionId, "resend");
415
- }
416
-
417
- // src/utils/chatStore.ts
418
- var memoryStore = /* @__PURE__ */ new Map();
419
- var chatStore = {
420
- get(key) {
421
- return memoryStore.get(key) ?? [];
422
- },
423
- set(key, messages) {
424
- memoryStore.set(key, messages);
425
- },
426
- delete(key) {
427
- memoryStore.delete(key);
428
- }
429
- };
430
-
431
- // src/utils/activeStreamStore.ts
432
- var streams = /* @__PURE__ */ new Map();
433
- var activeStreamStore = {
434
- has(key) {
435
- return streams.has(key);
436
- },
437
- get(key) {
438
- const entry = streams.get(key);
439
- if (!entry) return null;
440
- return { messages: entry.messages, isWaiting: entry.isWaiting };
441
- },
442
- // Called before startStream — registers the controller and initial messages
443
- start(key, abortController, initialMessages) {
444
- const existing = streams.get(key);
445
- streams.set(key, {
446
- messages: initialMessages,
447
- isWaiting: true,
448
- abortController,
449
- listeners: existing?.listeners ?? /* @__PURE__ */ new Set()
450
- });
451
- },
452
- // Called by the stream on every event — applies the same updater pattern React uses
453
- applyMessages(key, updater) {
454
- const entry = streams.get(key);
455
- if (!entry) return;
456
- const next = typeof updater === "function" ? updater(entry.messages) : updater;
457
- entry.messages = next;
458
- entry.listeners.forEach((l) => l(next, entry.isWaiting));
459
- },
460
- setWaiting(key, waiting) {
461
- const entry = streams.get(key);
462
- if (!entry) return;
463
- entry.isWaiting = waiting;
464
- entry.listeners.forEach((l) => l(entry.messages, waiting));
465
- },
466
- // Called when stream completes — persists to chatStore and cleans up
467
- complete(key) {
468
- const entry = streams.get(key);
469
- if (!entry) return;
470
- entry.isWaiting = false;
471
- entry.listeners.forEach((l) => l(entry.messages, false));
472
- const toSave = entry.messages.filter((m) => !m.isStreaming);
473
- if (toSave.length > 0) chatStore.set(key, toSave);
474
- streams.delete(key);
475
- },
476
- // Subscribe — returns unsubscribe fn. Component calls this on mount, cleanup on unmount.
477
- subscribe(key, listener) {
478
- const entry = streams.get(key);
479
- if (!entry) return () => {
480
- };
481
- entry.listeners.add(listener);
482
- return () => {
483
- streams.get(key)?.listeners.delete(listener);
484
- };
485
- },
486
- // Explicit user cancel — aborts the controller and removes the entry
487
- abort(key) {
488
- const entry = streams.get(key);
489
- if (!entry) return;
490
- entry.abortController.abort();
491
- streams.delete(key);
492
- }
493
- };
494
-
495
- // src/utils/v2EventProcessor.ts
496
292
  function getEventText(event, field) {
497
293
  const value = event[field];
498
294
  return typeof value === "string" ? value.trim() : "";
@@ -516,6 +312,16 @@ function addThinkingLine(state, header, detail) {
516
312
  function appendThinkingText(state, text) {
517
313
  state.formattedThinkingText += text;
518
314
  }
315
+ function updateExecutionStageMessage(state, msg) {
316
+ if (!msg) return;
317
+ for (let i = state.steps.length - 1; i >= 0; i--) {
318
+ const s = state.steps[i];
319
+ if (s.eventType === "STAGE_STARTED" && (s.stage === "executor" || s.stage === "execution") && s.status === "in_progress") {
320
+ s.message = msg;
321
+ return;
322
+ }
323
+ }
324
+ }
519
325
  function completeLastInProgressStep(steps) {
520
326
  for (let i = steps.length - 1; i >= 0; i--) {
521
327
  if (steps[i].status === "in_progress") {
@@ -543,11 +349,31 @@ function createInitialV2State() {
543
349
  currentExecutingStepId: void 0
544
350
  };
545
351
  }
546
- function processStreamEventV2(event, state) {
352
+ function processStreamEventV2(rawEvent, state) {
353
+ const event = normalizeEvent(rawEvent);
547
354
  const eventType = event.eventType;
548
355
  if (typeof eventType === "string" && eventType.toUpperCase() === "KEEP_ALIVE") {
549
356
  if (event.executionId) state.executionId = event.executionId;
550
357
  if (event.sessionId) state.sessionId = event.sessionId;
358
+ const description = typeof event.description === "string" ? event.description : "";
359
+ if (description) {
360
+ for (let i = state.steps.length - 1; i >= 0; i--) {
361
+ if (state.steps[i].status === "in_progress") {
362
+ state.steps[i].message = description;
363
+ break;
364
+ }
365
+ }
366
+ }
367
+ return state;
368
+ }
369
+ if (typeof eventType === "string" && eventType.toUpperCase() === "THINKING_DELTA") {
370
+ const text = typeof event.text === "string" ? event.text : "";
371
+ if (text) {
372
+ appendThinkingText(state, text);
373
+ }
374
+ if (event.executionId) state.executionId = event.executionId;
375
+ if (event.sessionId) state.sessionId = event.sessionId;
376
+ state.lastEventType = "THINKING_DELTA";
551
377
  return state;
552
378
  }
553
379
  if (event.executionId) state.executionId = event.executionId;
@@ -558,6 +384,16 @@ function processStreamEventV2(event, state) {
558
384
  case "STARTED":
559
385
  state.lastEventType = eventType;
560
386
  break;
387
+ case "INTENT_PROGRESS": {
388
+ const rawMessage = typeof event.message === "string" ? event.message : "";
389
+ const rawPartial = typeof event.partialText === "string" ? event.partialText : "";
390
+ const delta = rawMessage || rawPartial;
391
+ if (delta.length > 0) {
392
+ state.finalResponse += delta;
393
+ }
394
+ state.lastEventType = eventType;
395
+ break;
396
+ }
561
397
  case "INTENT_THINKING": {
562
398
  const worker = getEventText(event, "workerName") || "Worker";
563
399
  const msg = getEventText(event, "message") || "Thinking...";
@@ -659,6 +495,7 @@ function processStreamEventV2(event, state) {
659
495
  elapsedMs: event.elapsedMs
660
496
  });
661
497
  state.currentExecutingStepId = stepId;
498
+ updateExecutionStageMessage(state, message);
662
499
  state.lastEventType = eventType;
663
500
  break;
664
501
  }
@@ -701,6 +538,10 @@ function processStreamEventV2(event, state) {
701
538
  }
702
539
  case "WORKFLOW_COMPLETED":
703
540
  case "COMPLETED": {
541
+ const totalTime = Number(event.totalTimeMs);
542
+ if (Number.isFinite(totalTime) && totalTime > 0) {
543
+ state.totalElapsedMs = totalTime;
544
+ }
704
545
  let content = extractResponseContent(event.response);
705
546
  const trace = event.trace && typeof event.trace === "object" ? event.trace : null;
706
547
  if (!content && trace?.workflowMsg && typeof trace.workflowMsg === "string") {
@@ -713,7 +554,9 @@ function processStreamEventV2(event, state) {
713
554
  }
714
555
  if (content) {
715
556
  state.finalResponse = content;
716
- state.finalData = event.response ?? event.trace;
557
+ if (event.trace && typeof event.trace === "object") {
558
+ state.finalData = event.trace;
559
+ }
717
560
  state.hasError = false;
718
561
  state.errorMessage = "";
719
562
  } else {
@@ -895,12 +738,369 @@ function processStreamEventV2(event, state) {
895
738
  state.lastEventType = eventType;
896
739
  break;
897
740
  }
898
- default:
899
- state.lastEventType = eventType;
900
- break;
741
+ // ---- K2 pipeline stage lifecycle events ----
742
+ //
743
+ // The k2-server playground streaming API emits
744
+ // STAGE_STARTED / STAGE_COMPLETED / STAGE_FAILED /
745
+ // STAGE_SKIPPED around each pipeline stage so the UI can
746
+ // show real progress (sanitizer → analyzer → planner → …)
747
+ // instead of a static placeholder. Each STAGE_STARTED
748
+ // pushes an in-progress step with a user-facing label; the
749
+ // matching STAGE_COMPLETED/FAILED closes it WITHOUT
750
+ // rewriting the label — a terse "completed" flash between
751
+ // stages was more noise than signal. STAGE_SKIPPED removes
752
+ // the just-opened step entirely (skipping is expected on
753
+ // DIRECT_RESPONSE short-circuits).
754
+ //
755
+ // Finding the matching step uses `stepId` directly rather
756
+ // than comparing labels — the processor remembers which id
757
+ // it minted for the latest open STAGE_STARTED and the
758
+ // closing events look it up from state.currentExecutingStepId.
759
+ case "STAGE_STARTED": {
760
+ const stage = getEventText(event, "stage");
761
+ if (!stage) {
762
+ state.lastEventType = eventType;
763
+ break;
764
+ }
765
+ const serverMessage = getEventText(event, "message");
766
+ let initialMessage = serverMessage || stageLabel(stage);
767
+ if (stage === "executor" || stage === "execution") {
768
+ for (let i = state.steps.length - 1; i >= 0; i--) {
769
+ const s = state.steps[i];
770
+ if (s.eventType === "STAGE_STARTED" && s.stage === "analyzer" && s.status === "completed" && s.message) {
771
+ initialMessage = s.message;
772
+ break;
773
+ }
774
+ }
775
+ }
776
+ const stepId = `stage-${stage}-${state.stepCounter++}`;
777
+ state.steps.push({
778
+ id: stepId,
779
+ eventType,
780
+ message: initialMessage,
781
+ status: "in_progress",
782
+ timestamp: Date.now(),
783
+ stage
784
+ });
785
+ state.currentExecutingStepId = stepId;
786
+ state.lastEventType = eventType;
787
+ break;
788
+ }
789
+ case "STAGE_COMPLETED": {
790
+ const stage = getEventText(event, "stage");
791
+ if (!stage) {
792
+ state.lastEventType = eventType;
793
+ break;
794
+ }
795
+ const serverMessage = getEventText(event, "message");
796
+ for (let i = state.steps.length - 1; i >= 0; i--) {
797
+ const s = state.steps[i];
798
+ if (s.eventType === "STAGE_STARTED" && s.stage === stage && s.status === "in_progress") {
799
+ if (serverMessage) s.message = serverMessage;
800
+ s.status = "completed";
801
+ const durationMs = Number(event.durationMs);
802
+ if (Number.isFinite(durationMs)) s.elapsedMs = durationMs;
803
+ if (s.id === state.currentExecutingStepId) {
804
+ state.currentExecutingStepId = void 0;
805
+ }
806
+ break;
807
+ }
808
+ }
809
+ state.lastEventType = eventType;
810
+ break;
811
+ }
812
+ case "STAGE_FAILED": {
813
+ const stage = getEventText(event, "stage");
814
+ if (!stage) {
815
+ state.lastEventType = eventType;
816
+ break;
817
+ }
818
+ const serverMessage = getEventText(event, "message");
819
+ for (let i = state.steps.length - 1; i >= 0; i--) {
820
+ const s = state.steps[i];
821
+ if (s.eventType === "STAGE_STARTED" && s.stage === stage && s.status === "in_progress") {
822
+ if (serverMessage) s.message = serverMessage;
823
+ s.status = "error";
824
+ const durationMs = Number(event.durationMs);
825
+ if (Number.isFinite(durationMs)) s.elapsedMs = durationMs;
826
+ if (s.id === state.currentExecutingStepId) {
827
+ state.currentExecutingStepId = void 0;
828
+ }
829
+ break;
830
+ }
831
+ }
832
+ state.lastEventType = eventType;
833
+ break;
834
+ }
835
+ case "STAGE_SKIPPED": {
836
+ const stage = getEventText(event, "stage");
837
+ if (!stage) {
838
+ state.lastEventType = eventType;
839
+ break;
840
+ }
841
+ for (let i = state.steps.length - 1; i >= 0; i--) {
842
+ const s = state.steps[i];
843
+ if (s.eventType === "STAGE_STARTED" && s.stage === stage && s.status === "in_progress") {
844
+ if (s.id === state.currentExecutingStepId) {
845
+ state.currentExecutingStepId = void 0;
846
+ }
847
+ s.status = "skipped";
848
+ break;
849
+ }
850
+ }
851
+ state.lastEventType = eventType;
852
+ break;
853
+ }
854
+ default:
855
+ state.lastEventType = eventType;
856
+ break;
857
+ }
858
+ return state;
859
+ }
860
+
861
+ // src/utils/messageStateManager.ts
862
+ function buildFormattedThinking(steps, allThinkingText) {
863
+ const parts = [];
864
+ const safeSteps = steps ?? [];
865
+ const cleanAll = allThinkingText.replace(/^\s+/, "");
866
+ if (cleanAll) {
867
+ const firstStepWithThinking = safeSteps.find(
868
+ (s) => s.thinkingText && s.thinkingText.trim()
869
+ );
870
+ if (!firstStepWithThinking) {
871
+ parts.push("**Preflight**");
872
+ parts.push(cleanAll);
873
+ } else {
874
+ const stepText = firstStepWithThinking.thinkingText.trim();
875
+ const idx = cleanAll.indexOf(stepText);
876
+ if (idx > 0) {
877
+ const orphaned = cleanAll.substring(0, idx).replace(/\s+$/, "");
878
+ if (orphaned) {
879
+ parts.push("**Preflight**");
880
+ parts.push(orphaned);
881
+ }
882
+ }
883
+ }
884
+ }
885
+ for (const step of safeSteps) {
886
+ switch (step.eventType) {
887
+ case "STAGE_STARTED": {
888
+ if (step.message) parts.push(`**${step.message}**`);
889
+ break;
890
+ }
891
+ case "ORCHESTRATOR_THINKING":
892
+ parts.push("**Planning**");
893
+ if (step.message) parts.push(step.message);
894
+ break;
895
+ case "INTENT_STARTED": {
896
+ let label = step.message || "Processing";
897
+ const started = label.match(/^(.+?)\s+started$/i);
898
+ const progress = label.match(/^(.+?)\s+in progress$/i);
899
+ if (started) label = started[1];
900
+ else if (progress) label = progress[1];
901
+ parts.push(`**${label}**`);
902
+ if (step.thinkingText) parts.push(step.thinkingText);
903
+ break;
904
+ }
905
+ case "INTENT_PROGRESS": {
906
+ if (step.thinkingText) parts.push(step.thinkingText);
907
+ else if (step.message) parts.push(step.message);
908
+ break;
909
+ }
910
+ case "AGGREGATOR_THINKING":
911
+ parts.push("**Finalizing**");
912
+ if (step.message) parts.push(step.message);
913
+ break;
914
+ case "USER_ACTION_REQUIRED":
915
+ parts.push("**Verification Required**");
916
+ if (step.message) parts.push(step.message);
917
+ break;
918
+ case "USER_ACTION_SUCCESS":
919
+ parts.push(`\u2713 ${step.message || "Verification successful"}`);
920
+ break;
921
+ case "USER_ACTION_REJECTED":
922
+ parts.push(`\u2717 ${step.message || "Verification rejected"}`);
923
+ break;
924
+ case "USER_ACTION_EXPIRED":
925
+ parts.push(`\u2717 ${step.message || "Verification expired"}`);
926
+ break;
927
+ case "USER_ACTION_FAILED":
928
+ parts.push(`\u2717 ${step.message || "Verification failed"}`);
929
+ break;
930
+ }
931
+ }
932
+ return parts.length > 0 ? parts.join("\n") : allThinkingText;
933
+ }
934
+ function createCancelledMessageUpdate(steps, currentMessage) {
935
+ const updatedSteps = steps.map((step) => {
936
+ if (step.status === "in_progress") {
937
+ return { ...step, status: "pending" };
938
+ }
939
+ return step;
940
+ });
941
+ return {
942
+ isStreaming: false,
943
+ isCancelled: true,
944
+ steps: updatedSteps,
945
+ currentExecutingStepId: void 0,
946
+ // Preserve currentMessage so UI can show it with X icon
947
+ currentMessage: currentMessage || "Thinking..."
948
+ };
949
+ }
950
+
951
+ // src/utils/requestBuilder.ts
952
+ var DEFAULT_STREAM_ENDPOINT = "/api/playground/ask/stream";
953
+ function buildRequestBody(config, userMessage, sessionId, options) {
954
+ const sessionOwner = config.sessionParams;
955
+ const sessionAttributes = sessionOwner?.attributes && Object.keys(sessionOwner.attributes).length > 0 ? sessionOwner.attributes : void 0;
956
+ return {
957
+ agentId: config.agentId,
958
+ userInput: userMessage,
959
+ sessionId,
960
+ sessionOwnerLabel: sessionOwner?.name || void 0,
961
+ sessionAttributes,
962
+ analysisMode: options?.analysisMode
963
+ };
964
+ }
965
+ function buildStreamingUrl(config) {
966
+ const endpoint = config.api.streamEndpoint || DEFAULT_STREAM_ENDPOINT;
967
+ const stage = config.stage || "DEV";
968
+ const stageParamName = config.stageQueryParam ?? "stage";
969
+ const queryParams = new URLSearchParams({ [stageParamName]: stage });
970
+ return `${config.api.baseUrl}${endpoint}?${queryParams.toString()}`;
971
+ }
972
+ function buildUserActionUrl(config, userActionId, action) {
973
+ const endpoint = config.api.streamEndpoint || DEFAULT_STREAM_ENDPOINT;
974
+ const [endpointPath] = endpoint.split("?");
975
+ const normalizedEndpointPath = endpointPath.replace(/\/+$/, "");
976
+ const basePath = normalizedEndpointPath.endsWith("/stream") ? normalizedEndpointPath.slice(0, -"/stream".length) : normalizedEndpointPath;
977
+ const encodedUserActionId = encodeURIComponent(userActionId);
978
+ return `${config.api.baseUrl}${basePath}/user-action/${encodedUserActionId}/${action}`;
979
+ }
980
+ function buildResolveImagesUrl(config) {
981
+ if (config.api.resolveImagesEndpoint) {
982
+ return `${config.api.baseUrl}${config.api.resolveImagesEndpoint}`;
901
983
  }
902
- return state;
984
+ const streamEndpoint = config.api.streamEndpoint || DEFAULT_STREAM_ENDPOINT;
985
+ const [endpointPath] = streamEndpoint.split("?");
986
+ const normalizedEndpointPath = endpointPath.replace(/\/+$/, "");
987
+ const basePath = normalizedEndpointPath.endsWith("/stream") ? normalizedEndpointPath.slice(0, -"/stream".length) : normalizedEndpointPath;
988
+ return `${config.api.baseUrl}${basePath}/resolve-image-urls`;
989
+ }
990
+ function buildRequestHeaders(config) {
991
+ const headers = {
992
+ ...config.api.headers
993
+ };
994
+ if (config.api.authToken) {
995
+ headers.Authorization = `Bearer ${config.api.authToken}`;
996
+ }
997
+ return headers;
998
+ }
999
+
1000
+ // src/utils/userActionClient.ts
1001
+ async function sendUserActionRequest(config, userActionId, action, data) {
1002
+ const url = buildUserActionUrl(config, userActionId, action);
1003
+ const baseHeaders = buildRequestHeaders(config);
1004
+ const hasBody = data !== void 0;
1005
+ const headers = hasBody ? { "Content-Type": "application/json", ...baseHeaders } : baseHeaders;
1006
+ const response = await fetch(url, {
1007
+ method: "POST",
1008
+ headers,
1009
+ body: hasBody ? JSON.stringify(data) : void 0
1010
+ });
1011
+ if (!response.ok) {
1012
+ const errorText = await response.text();
1013
+ throw new Error(`HTTP ${response.status}: ${errorText}`);
1014
+ }
1015
+ return await response.json();
1016
+ }
1017
+ async function submitUserAction(config, userActionId, data) {
1018
+ return sendUserActionRequest(config, userActionId, "submit", data);
1019
+ }
1020
+ async function cancelUserAction(config, userActionId) {
1021
+ return sendUserActionRequest(config, userActionId, "cancel");
903
1022
  }
1023
+ async function resendUserAction(config, userActionId) {
1024
+ return sendUserActionRequest(config, userActionId, "resend");
1025
+ }
1026
+
1027
+ // src/utils/chatStore.ts
1028
+ var memoryStore = /* @__PURE__ */ new Map();
1029
+ var chatStore = {
1030
+ get(key) {
1031
+ return memoryStore.get(key) ?? [];
1032
+ },
1033
+ set(key, messages) {
1034
+ memoryStore.set(key, messages);
1035
+ },
1036
+ delete(key) {
1037
+ memoryStore.delete(key);
1038
+ }
1039
+ };
1040
+
1041
+ // src/utils/activeStreamStore.ts
1042
+ var streams = /* @__PURE__ */ new Map();
1043
+ var activeStreamStore = {
1044
+ has(key) {
1045
+ return streams.has(key);
1046
+ },
1047
+ get(key) {
1048
+ const entry = streams.get(key);
1049
+ if (!entry) return null;
1050
+ return { messages: entry.messages, isWaiting: entry.isWaiting };
1051
+ },
1052
+ // Called before startStream — registers the controller and initial messages
1053
+ start(key, abortController, initialMessages) {
1054
+ const existing = streams.get(key);
1055
+ streams.set(key, {
1056
+ messages: initialMessages,
1057
+ isWaiting: true,
1058
+ abortController,
1059
+ listeners: existing?.listeners ?? /* @__PURE__ */ new Set()
1060
+ });
1061
+ },
1062
+ // Called by the stream on every event — applies the same updater pattern React uses
1063
+ applyMessages(key, updater) {
1064
+ const entry = streams.get(key);
1065
+ if (!entry) return;
1066
+ const next = typeof updater === "function" ? updater(entry.messages) : updater;
1067
+ entry.messages = next;
1068
+ entry.listeners.forEach((l) => l(next, entry.isWaiting));
1069
+ },
1070
+ setWaiting(key, waiting) {
1071
+ const entry = streams.get(key);
1072
+ if (!entry) return;
1073
+ entry.isWaiting = waiting;
1074
+ entry.listeners.forEach((l) => l(entry.messages, waiting));
1075
+ },
1076
+ // Called when stream completes — persists to chatStore and cleans up
1077
+ complete(key) {
1078
+ const entry = streams.get(key);
1079
+ if (!entry) return;
1080
+ entry.isWaiting = false;
1081
+ entry.listeners.forEach((l) => l(entry.messages, false));
1082
+ const toSave = entry.messages.filter((m) => !m.isStreaming);
1083
+ if (toSave.length > 0) chatStore.set(key, toSave);
1084
+ streams.delete(key);
1085
+ },
1086
+ // Subscribe — returns unsubscribe fn. Component calls this on mount, cleanup on unmount.
1087
+ subscribe(key, listener) {
1088
+ const entry = streams.get(key);
1089
+ if (!entry) return () => {
1090
+ };
1091
+ entry.listeners.add(listener);
1092
+ return () => {
1093
+ streams.get(key)?.listeners.delete(listener);
1094
+ };
1095
+ },
1096
+ // Explicit user cancel — aborts the controller and removes the entry
1097
+ abort(key) {
1098
+ const entry = streams.get(key);
1099
+ if (!entry) return;
1100
+ entry.abortController.abort();
1101
+ streams.delete(key);
1102
+ }
1103
+ };
904
1104
 
905
1105
  // src/utils/ragImageResolver.ts
906
1106
  var RAG_IMAGE_REGEX = /\/api\/rag\/chunks\/[^"'\s]+\/image/;
@@ -961,12 +1161,11 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
961
1161
  const callbacksRef = useRef(callbacks);
962
1162
  callbacksRef.current = callbacks;
963
1163
  const startStream = useCallback(
964
- async (userMessage, streamingId, sessionId, externalAbortController) => {
1164
+ async (userMessage, streamingId, sessionId, externalAbortController, options) => {
965
1165
  abortControllerRef.current?.abort();
966
1166
  const abortController = externalAbortController ?? new AbortController();
967
1167
  abortControllerRef.current = abortController;
968
1168
  const state = createInitialV2State();
969
- const streamStartedAt = Date.now();
970
1169
  const updateMessage = (update) => {
971
1170
  if (abortController.signal.aborted) return;
972
1171
  setMessages(
@@ -976,7 +1175,12 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
976
1175
  );
977
1176
  };
978
1177
  const currentConfig = configRef.current;
979
- const requestBody = buildRequestBody(currentConfig, userMessage, sessionId);
1178
+ const requestBody = buildRequestBody(
1179
+ currentConfig,
1180
+ userMessage,
1181
+ sessionId,
1182
+ options
1183
+ );
980
1184
  const url = buildStreamingUrl(currentConfig);
981
1185
  const headers = buildRequestHeaders(currentConfig);
982
1186
  try {
@@ -984,11 +1188,6 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
984
1188
  signal: abortController.signal,
985
1189
  onEvent: (event) => {
986
1190
  if (abortController.signal.aborted) return;
987
- if (typeof event.eventType === "string" && event.eventType.toUpperCase() === "KEEP_ALIVE") {
988
- if (event.executionId) state.executionId = event.executionId;
989
- if (event.sessionId) state.sessionId = event.sessionId;
990
- return;
991
- }
992
1191
  processStreamEventV2(event, state);
993
1192
  const eventType = event.eventType;
994
1193
  if (eventType === "USER_ACTION_REQUIRED" && state.userActionRequest) {
@@ -1002,7 +1201,18 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
1002
1201
  }
1003
1202
  const activeStep = state.steps.find((s) => s.id === state.currentExecutingStepId);
1004
1203
  const lastInProgressStep = [...state.steps].reverse().find((s) => s.status === "in_progress");
1005
- const currentMessage = activeStep?.message || lastInProgressStep?.message || getEventMessage(event);
1204
+ const useful = (m) => m && !isBlandStatus(m) ? m : void 0;
1205
+ const latestUsefulStep = [...state.steps].reverse().find(
1206
+ (s) => s.message && !isBlandStatus(s.message)
1207
+ );
1208
+ const currentMessage = useful(activeStep?.message) ?? useful(lastInProgressStep?.message) ?? latestUsefulStep?.message ?? useful(getEventMessage(event)) ?? // Last-resort: every candidate is bland (very first event,
1209
+ // nothing useful seen yet). Render the bland label so the
1210
+ // bubble isn't blank.
1211
+ activeStep?.message ?? lastInProgressStep?.message ?? getEventMessage(event);
1212
+ if (currentMessage) {
1213
+ callbacksRef.current.onStatusMessage?.(currentMessage);
1214
+ }
1215
+ callbacksRef.current.onStepsUpdate?.([...state.steps]);
1006
1216
  if (state.hasError) {
1007
1217
  updateMessage({
1008
1218
  streamingContent: FRIENDLY_ERROR_MESSAGE,
@@ -1018,7 +1228,7 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
1018
1228
  });
1019
1229
  } else {
1020
1230
  updateMessage({
1021
- streamingContent: "",
1231
+ streamingContent: state.finalResponse,
1022
1232
  content: "",
1023
1233
  currentMessage,
1024
1234
  streamProgress: "processing",
@@ -1035,6 +1245,7 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
1035
1245
  },
1036
1246
  onError: (error) => {
1037
1247
  setIsWaitingForResponse(false);
1248
+ callbacksRef.current.onStatusMessage?.(null);
1038
1249
  if (error.name !== "AbortError") {
1039
1250
  callbacksRef.current.onError?.(error);
1040
1251
  }
@@ -1072,6 +1283,8 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
1072
1283
  },
1073
1284
  onComplete: () => {
1074
1285
  setIsWaitingForResponse(false);
1286
+ callbacksRef.current.onStatusMessage?.(null);
1287
+ callbacksRef.current.onStepsUpdate?.([]);
1075
1288
  if (state.userActionPending) {
1076
1289
  state.userActionPending = false;
1077
1290
  state.userActionRequest = void 0;
@@ -1095,14 +1308,18 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
1095
1308
  isError: state.hasError,
1096
1309
  errorDetails: state.hasError ? state.errorMessage : void 0,
1097
1310
  executionId: state.executionId,
1098
- tracingData: state.finalData,
1311
+ // Defensive: tracingData must be an object (or undefined)
1312
+ // so the JSON viewer doesn't char-iterate a string. The
1313
+ // event processor already drops bare strings; this is
1314
+ // the last stop before the message leaves the SDK.
1315
+ tracingData: state.finalData != null && typeof state.finalData === "object" ? state.finalData : void 0,
1099
1316
  steps: state.hasError ? [] : [...state.steps],
1100
1317
  isCancelled: false,
1101
1318
  currentExecutingStepId: void 0,
1102
1319
  userActionResult: state.userActionResult,
1103
1320
  formattedThinkingText: state.hasError ? void 0 : state.formattedThinkingText || void 0,
1104
1321
  isResolvingImages: needsImageResolve,
1105
- thinkingDurationSec: state.hasError ? void 0 : Math.max(0, Math.round((Date.now() - streamStartedAt) / 1e3))
1322
+ totalElapsedMs: state.hasError ? void 0 : state.totalElapsedMs
1106
1323
  };
1107
1324
  setMessages(
1108
1325
  (prev) => prev.map(
@@ -1187,199 +1404,45 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
1187
1404
  };
1188
1405
  }
1189
1406
 
1190
- // src/utils/workflowUsersClient.ts
1191
- var DEFAULT_SESSION_PAGE_SIZE = 20;
1192
- var DEFAULT_CONVERSATION_PAGE_SIZE = 50;
1193
- function getStageParamName2(config) {
1194
- return config.api.stageQueryParam ?? "stage";
1195
- }
1196
- function requireOwnerId(config) {
1197
- const ownerId = config.session?.owner?.id;
1198
- if (!ownerId) {
1199
- throw new Error(
1200
- "workflowUsersClient: session.owner.id is required to call this endpoint."
1201
- );
1202
- }
1203
- return ownerId;
1204
- }
1205
- function requireWorkflowName(config) {
1206
- const workflowName = config.workflow.name;
1207
- if (!workflowName) {
1208
- throw new Error(
1209
- "workflowUsersClient: workflow.name is required to call this endpoint."
1210
- );
1211
- }
1212
- return workflowName;
1213
- }
1214
- function requireWorkflowId(config) {
1215
- const workflowId = config.workflow.id;
1216
- if (!workflowId) {
1217
- throw new Error(
1218
- "workflowUsersClient: workflow.id is required to call this endpoint."
1219
- );
1220
- }
1221
- return workflowId;
1222
- }
1223
- function isPlaygroundYaakAuth(config) {
1224
- if (config.api.authToken) return false;
1225
- const headers = config.api.headers;
1226
- if (!headers) return false;
1227
- for (const key of Object.keys(headers)) {
1228
- const lower = key.toLowerCase();
1229
- if (lower === "yaak-api-key" || lower === "x-yaak-api-key") return true;
1230
- }
1231
- return false;
1232
- }
1233
- async function fetchJson(url, headers, signal) {
1234
- const response = await fetch(url, {
1235
- method: "GET",
1236
- headers,
1237
- signal
1238
- });
1239
- if (!response.ok) {
1240
- const errorText = await response.text();
1241
- throw new Error(`HTTP ${response.status}: ${errorText}`);
1242
- }
1243
- return await response.json();
1244
- }
1245
- async function listSessions(config, opts = {}) {
1246
- const ownerId = requireOwnerId(config);
1247
- const useYaakEndpoint = isPlaygroundYaakAuth(config);
1248
- const params = new URLSearchParams({
1249
- page: String(opts.page ?? 0),
1250
- size: String(opts.size ?? DEFAULT_SESSION_PAGE_SIZE)
1251
- });
1252
- if (useYaakEndpoint) {
1253
- params.set("workflowUserId", ownerId);
1254
- params.set("workflowName", requireWorkflowName(config));
1255
- } else {
1256
- params.set("workflowId", requireWorkflowId(config));
1257
- }
1258
- if (config.workflow.stage) {
1259
- params.set(getStageParamName2(config), config.workflow.stage);
1260
- }
1261
- const url = useYaakEndpoint ? `${config.api.baseUrl}/api/workflows/ask/sessions?${params.toString()}` : `${config.api.baseUrl}/api/workflow-users/${encodeURIComponent(
1262
- ownerId
1263
- )}/sessions?${params.toString()}`;
1264
- return fetchJson(
1265
- url,
1266
- buildRequestHeaders(config),
1267
- opts.signal
1268
- );
1269
- }
1270
- async function listConversations(config, opts) {
1271
- const ownerId = requireOwnerId(config);
1272
- const useYaakEndpoint = isPlaygroundYaakAuth(config);
1273
- const params = new URLSearchParams({
1274
- sessionId: opts.sessionId,
1275
- page: String(opts.page ?? 0),
1276
- size: String(opts.size ?? DEFAULT_CONVERSATION_PAGE_SIZE)
1277
- });
1278
- if (useYaakEndpoint) {
1279
- params.set("workflowUserId", ownerId);
1280
- params.set("workflowName", requireWorkflowName(config));
1281
- }
1282
- if (config.workflow.stage) {
1283
- params.set(getStageParamName2(config), config.workflow.stage);
1284
- }
1285
- const url = useYaakEndpoint ? `${config.api.baseUrl}/api/workflows/ask/conversations?${params.toString()}` : `${config.api.baseUrl}/api/workflow-users/${encodeURIComponent(
1286
- ownerId
1287
- )}/conversations?${params.toString()}`;
1288
- return fetchJson(
1289
- url,
1290
- buildRequestHeaders(config),
1291
- opts.signal
1292
- );
1293
- }
1294
-
1295
1407
  // src/hooks/useChatV2.ts
1296
- function conversationEntryToMessages(entry, sessionId) {
1297
- return [
1298
- {
1299
- id: `history-user-${entry.executionId}`,
1300
- sessionId,
1301
- role: "user",
1302
- content: entry.query,
1303
- timestamp: entry.createdAt,
1304
- isHistorical: true
1305
- },
1306
- {
1307
- id: `history-assistant-${entry.executionId}`,
1308
- sessionId,
1309
- role: "assistant",
1310
- content: entry.response,
1311
- timestamp: entry.createdAt,
1312
- executionId: entry.executionId,
1313
- isHistorical: true
1314
- }
1315
- ];
1316
- }
1317
- function streamKeyFor(scopeKey, sessionId) {
1318
- return `${scopeKey}|sid:${sessionId ?? ""}`;
1319
- }
1320
1408
  function useChatV2(config, callbacks = {}) {
1321
- const scopeKey = useMemo(() => buildScopeKey(config), [
1322
- config.session?.userId,
1323
- config.workflow?.id,
1324
- config.workflow?.version,
1325
- config.workflow?.stage
1326
- ]);
1327
- const initialSessionId = chatStore.get(scopeKey).find((m) => m.sessionId)?.sessionId ?? config.session?.initialId ?? void 0;
1328
1409
  const [messages, setMessages] = useState(() => {
1329
- const stored = chatStore.get(scopeKey);
1330
- if (stored.length > 0) return stored;
1331
- return config.session?.initialMessages ?? [];
1410
+ if (config.userId) return chatStore.get(config.userId);
1411
+ return config.initialMessages ?? [];
1332
1412
  });
1333
1413
  const [isWaitingForResponse, setIsWaitingForResponse] = useState(false);
1334
- const [loadingSessionId, setLoadingSessionId] = useState(void 0);
1335
- const [currentSessionId, setCurrentSessionId] = useState(initialSessionId);
1336
- const sessionIdRef = useRef(initialSessionId);
1337
- const prevScopeKeyRef = useRef(scopeKey);
1338
- const activeStreamSessionRef = useRef(void 0);
1414
+ const sessionIdRef = useRef(
1415
+ config.userId ? chatStore.get(config.userId).find((m) => m.sessionId)?.sessionId ?? config.initialSessionId ?? void 0 : config.initialSessionId ?? void 0
1416
+ );
1417
+ const prevUserIdRef = useRef(config.userId);
1339
1418
  const callbacksRef = useRef(callbacks);
1340
1419
  callbacksRef.current = callbacks;
1341
1420
  const configRef = useRef(config);
1342
1421
  configRef.current = config;
1343
- const scopeKeyRef = useRef(scopeKey);
1344
- scopeKeyRef.current = scopeKey;
1345
1422
  const messagesRef = useRef(messages);
1346
1423
  messagesRef.current = messages;
1347
1424
  const storeAwareSetMessages = useCallback(
1348
1425
  (updater) => {
1349
- const scope = scopeKeyRef.current;
1350
- const streamSid = activeStreamSessionRef.current;
1351
- if (streamSid !== void 0) {
1352
- const streamKey = streamKeyFor(scope, streamSid);
1353
- if (activeStreamStore.has(streamKey)) {
1354
- activeStreamStore.applyMessages(
1355
- streamKey,
1356
- updater
1357
- );
1358
- }
1359
- if (sessionIdRef.current === streamSid) {
1360
- setMessages(updater);
1361
- }
1362
- return;
1426
+ const { userId } = configRef.current;
1427
+ if (userId && activeStreamStore.has(userId)) {
1428
+ activeStreamStore.applyMessages(userId, updater);
1363
1429
  }
1364
1430
  setMessages(updater);
1365
1431
  },
1432
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1366
1433
  []
1367
1434
  );
1368
- const storeAwareSetIsWaiting = useCallback((waiting) => {
1369
- const scope = scopeKeyRef.current;
1370
- const streamSid = activeStreamSessionRef.current;
1371
- if (streamSid !== void 0) {
1372
- const streamKey = streamKeyFor(scope, streamSid);
1373
- if (activeStreamStore.has(streamKey)) {
1374
- activeStreamStore.setWaiting(streamKey, waiting);
1435
+ const storeAwareSetIsWaiting = useCallback(
1436
+ (waiting) => {
1437
+ const { userId } = configRef.current;
1438
+ if (userId && activeStreamStore.has(userId)) {
1439
+ activeStreamStore.setWaiting(userId, waiting);
1375
1440
  }
1376
- if (sessionIdRef.current === streamSid) {
1377
- setIsWaitingForResponse(waiting);
1378
- }
1379
- return;
1380
- }
1381
- setIsWaitingForResponse(waiting);
1382
- }, []);
1441
+ setIsWaitingForResponse(waiting);
1442
+ },
1443
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1444
+ []
1445
+ );
1383
1446
  const [userActionState, setUserActionState] = useState({
1384
1447
  request: null,
1385
1448
  result: null,
@@ -1387,43 +1450,38 @@ function useChatV2(config, callbacks = {}) {
1387
1450
  });
1388
1451
  const userActionStateRef = useRef(userActionState);
1389
1452
  userActionStateRef.current = userActionState;
1390
- const wrappedCallbacks = useMemo(
1391
- () => ({
1392
- ...callbacksRef.current,
1393
- onMessageSent: (message) => callbacksRef.current.onMessageSent?.(message),
1394
- onStreamStart: () => callbacksRef.current.onStreamStart?.(),
1395
- onStreamComplete: (message) => callbacksRef.current.onStreamComplete?.(message),
1396
- onError: (error) => callbacksRef.current.onError?.(error),
1397
- onExecutionTraceClick: (data) => callbacksRef.current.onExecutionTraceClick?.(data),
1398
- onSessionIdChange: (sessionId) => callbacksRef.current.onSessionIdChange?.(sessionId),
1399
- onUserActionRequired: (request) => {
1400
- setUserActionState((prev) => ({ ...prev, request, result: null }));
1401
- callbacksRef.current.onUserActionRequired?.(request);
1402
- },
1403
- onUserActionEvent: (eventType, message) => {
1404
- switch (eventType) {
1405
- case "USER_ACTION_SUCCESS":
1406
- setUserActionState((prev) => ({ ...prev, request: null, result: "approved" }));
1407
- break;
1408
- case "USER_ACTION_REJECTED":
1409
- setUserActionState((prev) => ({ ...prev, request: null, result: "rejected" }));
1410
- break;
1411
- case "USER_ACTION_EXPIRED":
1412
- case "USER_ACTION_FAILED":
1413
- setUserActionState((prev) => ({ ...prev, request: null }));
1414
- break;
1415
- case "USER_ACTION_INVALID":
1416
- setUserActionState((prev) => ({
1417
- ...prev,
1418
- clearOtpTrigger: prev.clearOtpTrigger + 1
1419
- }));
1420
- break;
1421
- }
1422
- callbacksRef.current.onUserActionEvent?.(eventType, message);
1453
+ const wrappedCallbacks = useMemo(() => ({
1454
+ ...callbacksRef.current,
1455
+ onMessageSent: (message) => callbacksRef.current.onMessageSent?.(message),
1456
+ onStreamStart: () => callbacksRef.current.onStreamStart?.(),
1457
+ onStreamComplete: (message) => callbacksRef.current.onStreamComplete?.(message),
1458
+ onError: (error) => callbacksRef.current.onError?.(error),
1459
+ onExecutionTraceClick: (data) => callbacksRef.current.onExecutionTraceClick?.(data),
1460
+ onSessionIdChange: (sessionId) => callbacksRef.current.onSessionIdChange?.(sessionId),
1461
+ onUserActionRequired: (request) => {
1462
+ setUserActionState((prev) => ({ ...prev, request, result: null }));
1463
+ callbacksRef.current.onUserActionRequired?.(request);
1464
+ },
1465
+ onUserActionEvent: (eventType, message) => {
1466
+ switch (eventType) {
1467
+ case "USER_ACTION_SUCCESS":
1468
+ setUserActionState((prev) => ({ ...prev, request: null, result: "approved" }));
1469
+ break;
1470
+ case "USER_ACTION_REJECTED":
1471
+ setUserActionState((prev) => ({ ...prev, request: null, result: "rejected" }));
1472
+ break;
1473
+ case "USER_ACTION_EXPIRED":
1474
+ case "USER_ACTION_FAILED":
1475
+ setUserActionState((prev) => ({ ...prev, request: null }));
1476
+ break;
1477
+ case "USER_ACTION_INVALID":
1478
+ setUserActionState((prev) => ({ ...prev, clearOtpTrigger: prev.clearOtpTrigger + 1 }));
1479
+ break;
1423
1480
  }
1424
- }),
1425
- []
1426
- );
1481
+ callbacksRef.current.onUserActionEvent?.(eventType, message);
1482
+ }
1483
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1484
+ }), []);
1427
1485
  const { startStream, cancelStream: cancelStreamManager, abortControllerRef } = useStreamManagerV2(
1428
1486
  config,
1429
1487
  wrappedCallbacks,
@@ -1431,12 +1489,10 @@ function useChatV2(config, callbacks = {}) {
1431
1489
  storeAwareSetIsWaiting
1432
1490
  );
1433
1491
  const sendMessage = useCallback(
1434
- async (userMessage) => {
1492
+ async (userMessage, options) => {
1435
1493
  if (!userMessage.trim()) return;
1436
- const autoGen = configRef.current.session?.autoGenerateId;
1437
- if (!sessionIdRef.current && autoGen !== false) {
1494
+ if (!sessionIdRef.current && configRef.current.autoGenerateSessionId !== false) {
1438
1495
  sessionIdRef.current = generateId();
1439
- setCurrentSessionId(sessionIdRef.current);
1440
1496
  callbacksRef.current.onSessionIdChange?.(sessionIdRef.current);
1441
1497
  }
1442
1498
  const userMessageId = `user-${Date.now()}`;
@@ -1468,40 +1524,39 @@ function useChatV2(config, callbacks = {}) {
1468
1524
  };
1469
1525
  setMessages((prev) => [...prev, streamingMsg]);
1470
1526
  const abortController = new AbortController();
1471
- const scope = scopeKeyRef.current;
1472
- const streamSessionId = sessionIdRef.current;
1473
- const streamKey = streamKeyFor(scope, streamSessionId);
1474
- activeStreamSessionRef.current = streamSessionId;
1475
- const initialMessages = [...messagesRef.current, userMsg, streamingMsg];
1476
- activeStreamStore.start(streamKey, abortController, initialMessages);
1527
+ const { userId } = configRef.current;
1528
+ if (userId) {
1529
+ const initialMessages = [...messagesRef.current, userMsg, streamingMsg];
1530
+ activeStreamStore.start(userId, abortController, initialMessages);
1531
+ }
1477
1532
  const newSessionId = await startStream(
1478
1533
  userMessage,
1479
1534
  streamingId,
1480
- streamSessionId,
1481
- abortController
1535
+ sessionIdRef.current,
1536
+ abortController,
1537
+ options
1482
1538
  );
1483
- activeStreamStore.complete(streamKey);
1484
- activeStreamSessionRef.current = void 0;
1485
- if (!abortController.signal.aborted && newSessionId && newSessionId !== streamSessionId && sessionIdRef.current === streamSessionId) {
1539
+ if (userId) {
1540
+ activeStreamStore.complete(userId);
1541
+ }
1542
+ if (!abortController.signal.aborted && newSessionId && newSessionId !== sessionIdRef.current) {
1486
1543
  sessionIdRef.current = newSessionId;
1487
- setCurrentSessionId(newSessionId);
1488
1544
  }
1489
1545
  },
1490
1546
  [startStream]
1491
1547
  );
1492
1548
  const clearMessages = useCallback(() => {
1493
- chatStore.delete(scopeKeyRef.current);
1549
+ if (configRef.current.userId) {
1550
+ chatStore.delete(configRef.current.userId);
1551
+ }
1494
1552
  setMessages([]);
1495
1553
  }, []);
1496
1554
  const prependMessages = useCallback((msgs) => {
1497
1555
  setMessages((prev) => [...msgs, ...prev]);
1498
1556
  }, []);
1499
1557
  const cancelStream = useCallback(() => {
1500
- const scope = scopeKeyRef.current;
1501
- const viewSid = sessionIdRef.current;
1502
- const viewStreamKey = streamKeyFor(scope, viewSid);
1503
- if (activeStreamStore.has(viewStreamKey)) {
1504
- activeStreamStore.abort(viewStreamKey);
1558
+ if (configRef.current.userId) {
1559
+ activeStreamStore.abort(configRef.current.userId);
1505
1560
  }
1506
1561
  cancelStreamManager();
1507
1562
  setIsWaitingForResponse(false);
@@ -1511,7 +1566,10 @@ function useChatV2(config, callbacks = {}) {
1511
1566
  if (msg.isStreaming) {
1512
1567
  return {
1513
1568
  ...msg,
1514
- ...createCancelledMessageUpdate(msg.steps || [], msg.currentMessage)
1569
+ ...createCancelledMessageUpdate(
1570
+ msg.steps || [],
1571
+ msg.currentMessage
1572
+ )
1515
1573
  };
1516
1574
  }
1517
1575
  return msg;
@@ -1519,37 +1577,39 @@ function useChatV2(config, callbacks = {}) {
1519
1577
  );
1520
1578
  }, [cancelStreamManager]);
1521
1579
  const resetSession = useCallback(() => {
1522
- const scope = scopeKeyRef.current;
1523
- const viewSid = sessionIdRef.current;
1524
- const viewStreamKey = streamKeyFor(scope, viewSid);
1525
- if (activeStreamStore.has(viewStreamKey)) {
1526
- activeStreamStore.abort(viewStreamKey);
1580
+ if (configRef.current.userId) {
1581
+ activeStreamStore.abort(configRef.current.userId);
1582
+ chatStore.delete(configRef.current.userId);
1527
1583
  }
1528
- chatStore.delete(scope);
1529
1584
  setMessages([]);
1530
1585
  sessionIdRef.current = void 0;
1531
- setCurrentSessionId(void 0);
1532
- activeStreamSessionRef.current = void 0;
1533
1586
  abortControllerRef.current?.abort();
1534
1587
  setIsWaitingForResponse(false);
1535
1588
  setUserActionState({ request: null, result: null, clearOtpTrigger: 0 });
1536
1589
  }, []);
1537
- const getSessionId = useCallback(() => sessionIdRef.current, []);
1538
- const getMessages = useCallback(() => messages, [messages]);
1539
- const approveUserAction = useCallback(async (otp) => {
1540
- const request = userActionStateRef.current.request;
1541
- if (!request) return;
1542
- try {
1543
- await submitUserAction(configRef.current, request.userActionId, { otp });
1544
- } catch (error) {
1545
- setUserActionState((prev) => ({
1546
- ...prev,
1547
- clearOtpTrigger: prev.clearOtpTrigger + 1
1548
- }));
1549
- callbacksRef.current.onError?.(error);
1550
- throw error;
1551
- }
1590
+ const getSessionId = useCallback(() => {
1591
+ return sessionIdRef.current;
1552
1592
  }, []);
1593
+ const getMessages = useCallback(() => {
1594
+ return messages;
1595
+ }, [messages]);
1596
+ const approveUserAction = useCallback(
1597
+ async (otp) => {
1598
+ const request = userActionStateRef.current.request;
1599
+ if (!request) return;
1600
+ try {
1601
+ await submitUserAction(configRef.current, request.userActionId, { otp });
1602
+ } catch (error) {
1603
+ setUserActionState((prev) => ({
1604
+ ...prev,
1605
+ clearOtpTrigger: prev.clearOtpTrigger + 1
1606
+ }));
1607
+ callbacksRef.current.onError?.(error);
1608
+ throw error;
1609
+ }
1610
+ },
1611
+ []
1612
+ );
1553
1613
  const rejectUserAction = useCallback(async () => {
1554
1614
  const request = userActionStateRef.current.request;
1555
1615
  if (!request) return;
@@ -1583,91 +1643,43 @@ function useChatV2(config, callbacks = {}) {
1583
1643
  throw error;
1584
1644
  }
1585
1645
  }, []);
1586
- const inFlightLoadRef = useRef(null);
1587
- const loadingSessionIdRef = useRef(void 0);
1588
- loadingSessionIdRef.current = loadingSessionId;
1589
- const loadSession = useCallback(async (sessionId) => {
1590
- const inFlight = inFlightLoadRef.current;
1591
- if (inFlight && inFlight.sessionId === sessionId) {
1592
- return inFlight.promise;
1593
- }
1594
- if (sessionIdRef.current === sessionId && loadingSessionIdRef.current !== sessionId) {
1595
- return;
1596
- }
1597
- const run = async () => {
1598
- const scope = scopeKeyRef.current;
1599
- setUserActionState({ request: null, result: null, clearOtpTrigger: 0 });
1600
- sessionIdRef.current = sessionId;
1601
- setCurrentSessionId(sessionId);
1602
- callbacksRef.current.onSessionIdChange?.(sessionId);
1603
- const streamKey = streamKeyFor(scope, sessionId);
1604
- const active = activeStreamStore.get(streamKey);
1605
- if (active) {
1606
- setMessages(active.messages);
1607
- setIsWaitingForResponse(active.isWaiting);
1608
- setLoadingSessionId(void 0);
1609
- return;
1610
- }
1611
- setIsWaitingForResponse(false);
1612
- setMessages([]);
1613
- chatStore.delete(scope);
1614
- setLoadingSessionId(sessionId);
1615
- try {
1616
- const response = await listConversations(configRef.current, { sessionId });
1617
- const entries = response.data ?? [];
1618
- const historical = entries.flatMap((entry) => conversationEntryToMessages(entry, sessionId));
1619
- if (sessionIdRef.current === sessionId) {
1620
- setMessages(historical);
1621
- }
1622
- if (historical.length > 0) {
1623
- chatStore.set(scope, historical);
1624
- }
1625
- } catch (error) {
1626
- callbacksRef.current.onError?.(error);
1627
- throw error;
1628
- } finally {
1629
- setLoadingSessionId((current) => current === sessionId ? void 0 : current);
1630
- }
1631
- };
1632
- const promise = run().finally(() => {
1633
- if (inFlightLoadRef.current?.sessionId === sessionId) {
1634
- inFlightLoadRef.current = null;
1635
- }
1636
- });
1637
- inFlightLoadRef.current = { sessionId, promise };
1638
- return promise;
1639
- }, []);
1640
1646
  useEffect(() => {
1641
- const key = streamKeyFor(scopeKey, currentSessionId);
1642
- const unsubscribe = activeStreamStore.subscribe(key, (msgs, isWaiting) => {
1647
+ const { userId } = config;
1648
+ if (!userId) return;
1649
+ const unsubscribe = activeStreamStore.subscribe(userId, (msgs, isWaiting) => {
1643
1650
  setMessages(msgs);
1644
1651
  setIsWaitingForResponse(isWaiting);
1645
1652
  });
1646
- const active = activeStreamStore.get(key);
1653
+ const active = activeStreamStore.get(userId);
1647
1654
  if (active) {
1648
1655
  setMessages(active.messages);
1649
1656
  setIsWaitingForResponse(active.isWaiting);
1650
1657
  }
1651
1658
  return unsubscribe;
1652
- }, [scopeKey, currentSessionId]);
1659
+ }, []);
1653
1660
  useEffect(() => {
1661
+ if (!config.userId) return;
1654
1662
  const toSave = messages.filter((m) => !m.isStreaming);
1655
1663
  if (toSave.length > 0) {
1656
- chatStore.set(scopeKey, toSave);
1664
+ chatStore.set(config.userId, toSave);
1657
1665
  }
1658
- }, [messages, scopeKey]);
1666
+ }, [messages, config.userId]);
1659
1667
  useEffect(() => {
1660
- const prevKey = prevScopeKeyRef.current;
1661
- prevScopeKeyRef.current = scopeKey;
1662
- if (prevKey === scopeKey) return;
1663
- const stored = chatStore.get(scopeKey);
1664
- setMessages(stored);
1665
- const restoredSessionId = stored.find((m) => m.sessionId)?.sessionId ?? configRef.current.session?.initialId ?? void 0;
1666
- sessionIdRef.current = restoredSessionId;
1667
- setCurrentSessionId(restoredSessionId);
1668
- setIsWaitingForResponse(false);
1669
- setUserActionState({ request: null, result: null, clearOtpTrigger: 0 });
1670
- }, [scopeKey]);
1668
+ const prevUserId = prevUserIdRef.current;
1669
+ prevUserIdRef.current = config.userId;
1670
+ if (prevUserId === config.userId) return;
1671
+ if (prevUserId && !config.userId) {
1672
+ chatStore.delete(prevUserId);
1673
+ setMessages([]);
1674
+ sessionIdRef.current = void 0;
1675
+ setIsWaitingForResponse(false);
1676
+ setUserActionState({ request: null, result: null, clearOtpTrigger: 0 });
1677
+ } else if (config.userId) {
1678
+ const stored = chatStore.get(config.userId);
1679
+ setMessages(stored);
1680
+ sessionIdRef.current = stored.find((m) => m.sessionId)?.sessionId;
1681
+ }
1682
+ }, [config.userId]);
1671
1683
  return {
1672
1684
  messages,
1673
1685
  sendMessage,
@@ -1678,13 +1690,11 @@ function useChatV2(config, callbacks = {}) {
1678
1690
  getSessionId,
1679
1691
  getMessages,
1680
1692
  isWaitingForResponse,
1681
- sessionId: currentSessionId,
1693
+ sessionId: sessionIdRef.current,
1682
1694
  userActionState,
1683
1695
  approveUserAction,
1684
1696
  rejectUserAction,
1685
- resendOtp,
1686
- loadSession,
1687
- loadingSessionId
1697
+ resendOtp
1688
1698
  };
1689
1699
  }
1690
1700
  function getSpeechRecognition() {
@@ -1903,6 +1913,6 @@ function useVoice(config = {}, callbacks = {}) {
1903
1913
  };
1904
1914
  }
1905
1915
 
1906
- export { buildFormattedThinking, buildScopeKey, cancelUserAction, createInitialV2State, generateId, listConversations, listSessions, processStreamEventV2, resendUserAction, streamWorkflowEvents, submitUserAction, useChatV2, useVoice, workingPhaseDetailForDisplay };
1916
+ export { buildFormattedThinking, cancelUserAction, createInitialV2State, generateId, processStreamEventV2, resendUserAction, streamWorkflowEvents, submitUserAction, useChatV2, useVoice };
1907
1917
  //# sourceMappingURL=index.mjs.map
1908
1918
  //# sourceMappingURL=index.mjs.map