@paymanai/payman-ask-sdk 4.0.13 → 4.0.15

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
@@ -3,7 +3,7 @@ import { AnimatePresence, motion } from 'framer-motion';
3
3
  import { clsx } from 'clsx';
4
4
  import { twMerge } from 'tailwind-merge';
5
5
  import * as Sentry from '@sentry/react';
6
- import { ArrowDown, Pencil, X, RotateCcw, Telescope, Zap, Plus, ImagePlus, Paperclip, Mic, ArrowUp, Check, AlertCircle, Copy, WifiOff, ThumbsUp, ThumbsDown, Binoculars, Info, Download, Loader2, ChevronDown, FileText, User, Clock, Sparkles, ImageOff, Eye, ChevronRight, ShieldCheck } from 'lucide-react';
6
+ import { ArrowDown, Pencil, X, RotateCcw, Telescope, Zap, Plus, ImagePlus, Paperclip, Mic, ArrowUp, Check, AlertCircle, Copy, WifiOff, ThumbsUp, ThumbsDown, Binoculars, Info, Download, Loader2, ChevronDown, User, Clock, Sparkles, ImageOff, Eye, ChevronRight, ShieldCheck } from 'lucide-react';
7
7
  import ReactMarkdown from 'react-markdown';
8
8
  import remarkGfm from 'remark-gfm';
9
9
  import { createPortal } from 'react-dom';
@@ -21,9 +21,90 @@ function generateId() {
21
21
  return v.toString(16);
22
22
  });
23
23
  }
24
+ var memoryStore = /* @__PURE__ */ new Map();
25
+ var chatStore = {
26
+ get(key) {
27
+ return memoryStore.get(key) ?? [];
28
+ },
29
+ set(key, messages) {
30
+ memoryStore.set(key, messages);
31
+ },
32
+ delete(key) {
33
+ memoryStore.delete(key);
34
+ }
35
+ };
36
+ var streams = /* @__PURE__ */ new Map();
37
+ var activeStreamStore = {
38
+ has(key) {
39
+ return streams.has(key);
40
+ },
41
+ get(key) {
42
+ const entry = streams.get(key);
43
+ if (!entry) return null;
44
+ return { messages: entry.messages, isWaiting: entry.isWaiting };
45
+ },
46
+ // Called before startStream — registers the controller and initial messages
47
+ start(key, abortController, initialMessages) {
48
+ const existing = streams.get(key);
49
+ streams.set(key, {
50
+ messages: initialMessages,
51
+ isWaiting: true,
52
+ abortController,
53
+ listeners: existing?.listeners ?? /* @__PURE__ */ new Set()
54
+ });
55
+ },
56
+ // Called by the stream on every event — applies the same updater pattern React uses
57
+ applyMessages(key, updater) {
58
+ const entry = streams.get(key);
59
+ if (!entry) return;
60
+ const next = typeof updater === "function" ? updater(entry.messages) : updater;
61
+ entry.messages = next;
62
+ entry.listeners.forEach((l) => l(next, entry.isWaiting));
63
+ },
64
+ setWaiting(key, waiting) {
65
+ const entry = streams.get(key);
66
+ if (!entry) return;
67
+ entry.isWaiting = waiting;
68
+ entry.listeners.forEach((l) => l(entry.messages, waiting));
69
+ },
70
+ // Called when stream completes — persists to chatStore and cleans up
71
+ complete(key) {
72
+ const entry = streams.get(key);
73
+ if (!entry) return;
74
+ entry.isWaiting = false;
75
+ entry.listeners.forEach((l) => l(entry.messages, false));
76
+ const toSave = entry.messages.filter((m) => !m.isStreaming);
77
+ if (toSave.length > 0) chatStore.set(key, toSave);
78
+ streams.delete(key);
79
+ },
80
+ // Subscribe — returns unsubscribe fn. Component calls this on mount, cleanup on unmount.
81
+ subscribe(key, listener) {
82
+ const entry = streams.get(key);
83
+ if (!entry) return () => {
84
+ };
85
+ entry.listeners.add(listener);
86
+ return () => {
87
+ streams.get(key)?.listeners.delete(listener);
88
+ };
89
+ },
90
+ // Rename an entry — used when the server assigns a new session ID mid-stream
91
+ rename(oldKey, newKey) {
92
+ const entry = streams.get(oldKey);
93
+ if (!entry) return;
94
+ streams.set(newKey, entry);
95
+ streams.delete(oldKey);
96
+ },
97
+ // Explicit user cancel — aborts the controller and removes the entry
98
+ abort(key) {
99
+ const entry = streams.get(key);
100
+ if (!entry) return;
101
+ entry.abortController.abort();
102
+ streams.delete(key);
103
+ }
104
+ };
24
105
  function yieldAfterProgressEvent(event) {
25
106
  const t = event.eventType;
26
- if (t === "RUN_IN_PROGRESS" || t === "INTENT_PROGRESS" || t === "AGGREGATOR_THINKING_CONT" || t === "INTENT_THINKING_CONT" || t === "THINKING_DELTA") {
107
+ if (t === "RUN_IN_PROGRESS" || t === "INTENT_PROGRESS" || t === "THINKING_DELTA") {
27
108
  return new Promise((resolve) => setTimeout(resolve, 0));
28
109
  }
29
110
  return Promise.resolve();
@@ -279,40 +360,10 @@ function classifyUserActionKind(action, schema) {
279
360
  return isVerificationSchema(schema) ? "verification" : "form";
280
361
  }
281
362
  }
282
- function userActionHeader(kind) {
283
- return kind === "verification" ? "**Verification required**" : "**Action required**";
284
- }
285
- function workingPhaseDetailForDisplay(raw) {
286
- const t = raw.trim();
287
- if (!t) return "";
288
- if (/^Identified\s+\d+\s+tasks?\s+to\s+execute\.?$/i.test(t)) {
289
- return "";
290
- }
291
- return t;
292
- }
293
363
  function getEventText(event, field) {
294
364
  const value = event[field];
295
365
  return typeof value === "string" ? value.trim() : "";
296
366
  }
297
- function shouldShowIntentHeader(event) {
298
- const workerName = getEventText(event, "workerName");
299
- const intentId = getEventText(event, "intentId");
300
- return Boolean(workerName && intentId && workerName === intentId);
301
- }
302
- function addThinkingHeader(state, header) {
303
- state.formattedThinkingText += (state.formattedThinkingText ? "\n" : "") + header;
304
- }
305
- function addThinkingDetail(state, detail) {
306
- const trimmed = detail.trim();
307
- if (!trimmed) return;
308
- state.formattedThinkingText += (state.formattedThinkingText ? "\n" : "") + trimmed;
309
- }
310
- function addThinkingLine(state, header, detail) {
311
- state.formattedThinkingText += (state.formattedThinkingText ? "\n" : "") + header + "\n" + detail;
312
- }
313
- function appendThinkingText(state, text) {
314
- state.formattedThinkingText += text;
315
- }
316
367
  function updateExecutionStageMessage(state, msg) {
317
368
  if (!msg) return;
318
369
  for (let i = state.steps.length - 1; i >= 0; i--) {
@@ -333,9 +384,7 @@ function completeLastInProgressStep(steps) {
333
384
  }
334
385
  function createInitialV2State() {
335
386
  return {
336
- formattedThinkingText: "",
337
387
  finalResponse: "",
338
- currentWorker: "",
339
388
  lastEventType: "",
340
389
  sessionId: void 0,
341
390
  executionId: void 0,
@@ -382,10 +431,6 @@ function processStreamEventV2(rawEvent, state) {
382
431
  return state;
383
432
  }
384
433
  if (typeof eventType === "string" && eventType.toUpperCase() === "THINKING_DELTA") {
385
- const text = typeof event.text === "string" ? event.text : "";
386
- if (text) {
387
- appendThinkingText(state, text);
388
- }
389
434
  if (event.executionId) state.executionId = event.executionId;
390
435
  if (event.sessionId) state.sessionId = event.sessionId;
391
436
  state.lastEventType = "THINKING_DELTA";
@@ -396,7 +441,6 @@ function processStreamEventV2(rawEvent, state) {
396
441
  const message = getEventMessage(event);
397
442
  switch (eventType) {
398
443
  case "WORKFLOW_STARTED":
399
- case "STARTED":
400
444
  state.lastEventType = eventType;
401
445
  break;
402
446
  case "INTENT_PROGRESS": {
@@ -409,97 +453,7 @@ function processStreamEventV2(rawEvent, state) {
409
453
  state.lastEventType = eventType;
410
454
  break;
411
455
  }
412
- case "INTENT_THINKING": {
413
- const worker = getEventText(event, "workerName") || "Worker";
414
- const msg = getEventText(event, "message") || "Thinking...";
415
- const showHeader = shouldShowIntentHeader(event);
416
- if (worker !== state.currentWorker) {
417
- state.currentWorker = worker;
418
- if (showHeader && msg && msg !== worker) {
419
- addThinkingLine(state, `**${worker}**`, msg);
420
- } else if (showHeader) {
421
- addThinkingHeader(state, `**${worker}**`);
422
- } else if (msg !== "Thinking...") {
423
- addThinkingDetail(state, msg);
424
- }
425
- } else if (showHeader || msg !== "Thinking...") {
426
- appendThinkingText(state, "\n" + msg);
427
- }
428
- const lastInProgress = [...state.steps].reverse().find((s) => s.status === "in_progress");
429
- if (lastInProgress) {
430
- lastInProgress.thinkingText = "";
431
- lastInProgress.isThinking = true;
432
- }
433
- state.lastEventType = "INTENT_THINKING";
434
- break;
435
- }
436
- case "INTENT_THINKING_CONT": {
437
- const msg = event.message || "";
438
- if (!msg) break;
439
- if (state.lastEventType === "INTENT_THINKING") {
440
- appendThinkingText(state, "\n" + msg);
441
- } else {
442
- appendThinkingText(state, msg);
443
- }
444
- const thinkingStep = [...state.steps].reverse().find((s) => s.isThinking);
445
- if (thinkingStep) {
446
- thinkingStep.thinkingText = (thinkingStep.thinkingText || "") + msg;
447
- }
448
- state.lastEventType = "INTENT_THINKING_CONT";
449
- break;
450
- }
451
- case "ORCHESTRATOR_THINKING": {
452
- addThinkingLine(state, "**Planning**", event.message || "Understanding your request...");
453
- const stepId = `step-${state.stepCounter++}`;
454
- state.steps.push({
455
- id: stepId,
456
- eventType,
457
- message,
458
- status: "in_progress",
459
- timestamp: Date.now(),
460
- elapsedMs: event.elapsedMs
461
- });
462
- state.currentExecutingStepId = stepId;
463
- state.lastEventType = eventType;
464
- break;
465
- }
466
- case "ORCHESTRATOR_COMPLETED": {
467
- const workingDetail = workingPhaseDetailForDisplay(message);
468
- if (workingDetail) {
469
- addThinkingLine(state, "**Working**", workingDetail);
470
- } else {
471
- addThinkingHeader(state, "**Working**");
472
- }
473
- state.steps.push({
474
- id: `step-${state.stepCounter++}`,
475
- eventType: "WORKING",
476
- message: workingDetail,
477
- status: "completed",
478
- timestamp: Date.now()
479
- });
480
- const step = state.steps.find((s) => s.eventType === "ORCHESTRATOR_THINKING" && s.status === "in_progress");
481
- if (step) {
482
- step.status = "completed";
483
- if (event.elapsedMs) step.elapsedMs = event.elapsedMs;
484
- if (step.id === state.currentExecutingStepId) state.currentExecutingStepId = void 0;
485
- }
486
- state.lastEventType = eventType;
487
- break;
488
- }
489
456
  case "INTENT_STARTED": {
490
- const worker = getEventText(event, "workerName") || "Worker";
491
- const msg = getEventText(event, "message") || "Starting...";
492
- const showHeader = shouldShowIntentHeader(event);
493
- state.currentWorker = worker;
494
- if (showHeader && msg !== worker) {
495
- addThinkingLine(state, `**${worker}**`, msg);
496
- } else if (showHeader) {
497
- addThinkingHeader(state, `**${worker}**`);
498
- } else {
499
- addThinkingDetail(state, msg);
500
- }
501
- const thinkingStep = state.steps.find((s) => s.isThinking);
502
- if (thinkingStep) thinkingStep.isThinking = false;
503
457
  const stepId = `step-${state.stepCounter++}`;
504
458
  state.steps.push({
505
459
  id: stepId,
@@ -518,55 +472,18 @@ function processStreamEventV2(rawEvent, state) {
518
472
  const intentStep = state.steps.find((s) => s.eventType === "INTENT_STARTED" && s.status === "in_progress");
519
473
  if (intentStep) {
520
474
  intentStep.status = "completed";
521
- intentStep.isThinking = false;
522
475
  if (event.elapsedMs) intentStep.elapsedMs = event.elapsedMs;
523
476
  if (intentStep.id === state.currentExecutingStepId) state.currentExecutingStepId = void 0;
524
477
  }
525
478
  state.lastEventType = eventType;
526
479
  break;
527
480
  }
528
- case "AGGREGATOR_THINKING": {
529
- addThinkingLine(state, "**Finalizing**", event.message || "Preparing response...");
530
- const stepId = `step-${state.stepCounter++}`;
531
- state.steps.push({
532
- id: stepId,
533
- eventType,
534
- message,
535
- status: "in_progress",
536
- timestamp: Date.now(),
537
- elapsedMs: event.elapsedMs
538
- });
539
- state.currentExecutingStepId = stepId;
540
- state.lastEventType = eventType;
541
- break;
542
- }
543
- case "AGGREGATOR_COMPLETED": {
544
- appendThinkingText(state, "\n" + (event.message || "Response ready"));
545
- const step = state.steps.find((s) => s.eventType === "AGGREGATOR_THINKING" && s.status === "in_progress");
546
- if (step) {
547
- step.status = "completed";
548
- if (event.elapsedMs) step.elapsedMs = event.elapsedMs;
549
- if (step.id === state.currentExecutingStepId) state.currentExecutingStepId = void 0;
550
- }
551
- state.lastEventType = eventType;
552
- break;
553
- }
554
- case "WORKFLOW_COMPLETED":
555
- case "COMPLETED": {
481
+ case "WORKFLOW_COMPLETED": {
556
482
  const totalTime = Number(event.totalTimeMs);
557
483
  if (Number.isFinite(totalTime) && totalTime > 0) {
558
484
  state.totalElapsedMs = totalTime;
559
485
  }
560
- let content = extractResponseContent(event.response);
561
- const trace = event.trace && typeof event.trace === "object" ? event.trace : null;
562
- if (!content && trace?.workflowMsg && typeof trace.workflowMsg === "string") {
563
- content = trace.workflowMsg;
564
- }
565
- if (!content && trace?.aggregator && typeof trace.aggregator === "object") {
566
- const agg = trace.aggregator;
567
- if (typeof agg.response === "string") content = agg.response;
568
- else content = extractResponseContent(agg.response);
569
- }
486
+ const content = extractResponseContent(event.response);
570
487
  if (content) {
571
488
  state.finalResponse = content;
572
489
  if (event.trace && typeof event.trace === "object") {
@@ -581,7 +498,6 @@ function processStreamEventV2(rawEvent, state) {
581
498
  state.steps.forEach((step) => {
582
499
  if (step.status === "in_progress") {
583
500
  step.status = "completed";
584
- step.isThinking = false;
585
501
  }
586
502
  });
587
503
  state.lastEventType = eventType;
@@ -600,7 +516,6 @@ function processStreamEventV2(rawEvent, state) {
600
516
  };
601
517
  state.notifications.push(notification);
602
518
  state.lastNotification = notification;
603
- if (promptMessage) addThinkingDetail(state, promptMessage);
604
519
  state.lastEventType = eventType;
605
520
  break;
606
521
  }
@@ -626,9 +541,6 @@ function processStreamEventV2(rawEvent, state) {
626
541
  };
627
542
  upsertUserAction(state, request);
628
543
  state.lastUserAction = request;
629
- const header = userActionHeader(kind);
630
- if (promptMessage) addThinkingLine(state, header, promptMessage);
631
- else addThinkingHeader(state, header);
632
544
  const stepId = `step-${state.stepCounter++}`;
633
545
  state.steps.push({
634
546
  id: stepId,
@@ -652,27 +564,15 @@ function processStreamEventV2(rawEvent, state) {
652
564
  };
653
565
  state.notifications.push(notification);
654
566
  state.lastNotification = notification;
655
- if (noteMessage) addThinkingDetail(state, noteMessage);
656
567
  }
657
568
  state.lastEventType = eventType;
658
569
  break;
659
570
  }
660
571
  case "WORKFLOW_ERROR":
661
- case "ERROR":
662
572
  state.hasError = true;
663
573
  state.errorMessage = event.errorMessage || event.message || "Workflow error";
664
574
  state.lastEventType = eventType;
665
575
  break;
666
- case "INTENT_ERROR": {
667
- state.errorMessage = message || event.errorMessage || "An error occurred";
668
- const intentStep = state.steps.find((s) => s.eventType === "INTENT_STARTED" && s.status === "in_progress");
669
- if (intentStep) {
670
- intentStep.status = "error";
671
- intentStep.isThinking = false;
672
- }
673
- state.lastEventType = eventType;
674
- break;
675
- }
676
576
  // ---- K2 pipeline stage lifecycle events ----
677
577
  //
678
578
  // The k2-server playground streaming API emits
@@ -792,22 +692,6 @@ function processStreamEventV2(rawEvent, state) {
792
692
  }
793
693
  return state;
794
694
  }
795
- function createCancelledMessageUpdate(steps, currentMessage) {
796
- const updatedSteps = steps.map((step) => {
797
- if (step.status === "in_progress") {
798
- return { ...step, status: "pending" };
799
- }
800
- return step;
801
- });
802
- return {
803
- isStreaming: false,
804
- isCancelled: true,
805
- steps: updatedSteps,
806
- currentExecutingStepId: void 0,
807
- // Preserve currentMessage so UI can show it with X icon
808
- currentMessage: currentMessage || "Thinking..."
809
- };
810
- }
811
695
  var DEFAULT_STREAM_ENDPOINT = "/api/playground/ask/stream";
812
696
  function buildRequestBody(config, userMessage, sessionId, options) {
813
697
  const sessionOwner = config.sessionParams;
@@ -879,123 +763,6 @@ function buildRequestHeaders(config) {
879
763
  }
880
764
  return headers;
881
765
  }
882
- var UserActionStaleError = class extends Error {
883
- constructor(userActionId, message = "User action is no longer actionable") {
884
- super(message);
885
- __publicField(this, "userActionId");
886
- this.name = "UserActionStaleError";
887
- this.userActionId = userActionId;
888
- }
889
- };
890
- async function sendUserActionRequest(config, userActionId, action, data) {
891
- const url = buildUserActionUrl(config, userActionId, action);
892
- const baseHeaders = buildRequestHeaders(config);
893
- const hasBody = data !== void 0;
894
- const headers = hasBody ? { "Content-Type": "application/json", ...baseHeaders } : baseHeaders;
895
- const response = await fetch(url, {
896
- method: "POST",
897
- headers,
898
- body: hasBody ? JSON.stringify(data) : void 0
899
- });
900
- if (response.status === 404) {
901
- throw new UserActionStaleError(userActionId);
902
- }
903
- if (!response.ok) {
904
- const errorText = await response.text();
905
- throw new Error(`HTTP ${response.status}: ${errorText}`);
906
- }
907
- return await response.json();
908
- }
909
- async function submitUserAction(config, userActionId, content) {
910
- return sendUserActionRequest(config, userActionId, "submit", content ?? {});
911
- }
912
- async function cancelUserAction(config, userActionId) {
913
- return sendUserActionRequest(config, userActionId, "cancel");
914
- }
915
- async function resendUserAction(config, userActionId) {
916
- return sendUserActionRequest(config, userActionId, "resend");
917
- }
918
- var memoryStore = /* @__PURE__ */ new Map();
919
- var chatStore = {
920
- get(key) {
921
- return memoryStore.get(key) ?? [];
922
- },
923
- set(key, messages) {
924
- memoryStore.set(key, messages);
925
- },
926
- delete(key) {
927
- memoryStore.delete(key);
928
- }
929
- };
930
- var streams = /* @__PURE__ */ new Map();
931
- var activeStreamStore = {
932
- has(key) {
933
- return streams.has(key);
934
- },
935
- get(key) {
936
- const entry = streams.get(key);
937
- if (!entry) return null;
938
- return { messages: entry.messages, isWaiting: entry.isWaiting };
939
- },
940
- // Called before startStream — registers the controller and initial messages
941
- start(key, abortController, initialMessages) {
942
- const existing = streams.get(key);
943
- streams.set(key, {
944
- messages: initialMessages,
945
- isWaiting: true,
946
- abortController,
947
- listeners: existing?.listeners ?? /* @__PURE__ */ new Set()
948
- });
949
- },
950
- // Called by the stream on every event — applies the same updater pattern React uses
951
- applyMessages(key, updater) {
952
- const entry = streams.get(key);
953
- if (!entry) return;
954
- const next = typeof updater === "function" ? updater(entry.messages) : updater;
955
- entry.messages = next;
956
- entry.listeners.forEach((l) => l(next, entry.isWaiting));
957
- },
958
- setWaiting(key, waiting) {
959
- const entry = streams.get(key);
960
- if (!entry) return;
961
- entry.isWaiting = waiting;
962
- entry.listeners.forEach((l) => l(entry.messages, waiting));
963
- },
964
- // Called when stream completes — persists to chatStore and cleans up
965
- complete(key) {
966
- const entry = streams.get(key);
967
- if (!entry) return;
968
- entry.isWaiting = false;
969
- entry.listeners.forEach((l) => l(entry.messages, false));
970
- const toSave = entry.messages.filter((m) => !m.isStreaming);
971
- if (toSave.length > 0) chatStore.set(key, toSave);
972
- streams.delete(key);
973
- },
974
- // Subscribe — returns unsubscribe fn. Component calls this on mount, cleanup on unmount.
975
- subscribe(key, listener) {
976
- const entry = streams.get(key);
977
- if (!entry) return () => {
978
- };
979
- entry.listeners.add(listener);
980
- return () => {
981
- streams.get(key)?.listeners.delete(listener);
982
- };
983
- },
984
- // Rename an entry — used when the server assigns a new session ID mid-stream
985
- rename(oldKey, newKey) {
986
- const entry = streams.get(oldKey);
987
- if (!entry) return;
988
- streams.set(newKey, entry);
989
- streams.delete(oldKey);
990
- },
991
- // Explicit user cancel — aborts the controller and removes the entry
992
- abort(key) {
993
- const entry = streams.get(key);
994
- if (!entry) return;
995
- entry.abortController.abort();
996
- streams.delete(key);
997
- }
998
- };
999
766
  var RAG_IMAGE_REGEX = /\/api\/rag\/chunks\/[^"'\s]+\/image/;
1000
767
  function hasRagImages(content) {
1001
768
  return RAG_IMAGE_REGEX.test(content);
@@ -1107,7 +874,6 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
1107
874
  streamProgress: "error",
1108
875
  isError: true,
1109
876
  errorDetails: state.errorMessage,
1110
- formattedThinkingText: state.formattedThinkingText || void 0,
1111
877
  steps: [...state.steps],
1112
878
  currentExecutingStepId: void 0,
1113
879
  executionId: state.executionId,
@@ -1120,7 +886,6 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
1120
886
  currentMessage,
1121
887
  streamProgress: "processing",
1122
888
  isError: false,
1123
- formattedThinkingText: state.formattedThinkingText || void 0,
1124
889
  steps: [...state.steps],
1125
890
  currentExecutingStepId: state.currentExecutingStepId,
1126
891
  executionId: state.executionId,
@@ -1147,7 +912,6 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
1147
912
  errorDetails: isAborted ? void 0 : error.message,
1148
913
  content: isAborted ? state.finalResponse || "" : state.finalResponse || FRIENDLY_ERROR_MESSAGE,
1149
914
  currentMessage: isAborted ? "Thinking..." : void 0,
1150
- formattedThinkingText: state.formattedThinkingText || void 0,
1151
915
  steps: [...state.steps].map((step) => {
1152
916
  if (step.status === "in_progress" && isAborted) {
1153
917
  return { ...step, status: "pending" };
@@ -1186,7 +950,6 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
1186
950
  steps: state.hasError ? [] : [...state.steps],
1187
951
  isCancelled: false,
1188
952
  currentExecutingStepId: void 0,
1189
- formattedThinkingText: state.hasError ? void 0 : state.formattedThinkingText || void 0,
1190
953
  isResolvingImages: needsImageResolve,
1191
954
  totalElapsedMs: state.hasError ? void 0 : state.totalElapsedMs
1192
955
  };
@@ -1239,7 +1002,6 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
1239
1002
  isCancelled: isAborted,
1240
1003
  errorDetails: isAborted ? void 0 : error.message,
1241
1004
  content: isAborted ? state.finalResponse || "" : state.finalResponse || FRIENDLY_ERROR_MESSAGE,
1242
- formattedThinkingText: state.formattedThinkingText || void 0,
1243
1005
  steps: [...state.steps].map((step) => {
1244
1006
  if (step.status === "in_progress" && isAborted) {
1245
1007
  return { ...step, status: "pending" };
@@ -1264,6 +1026,57 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
1264
1026
  abortControllerRef
1265
1027
  };
1266
1028
  }
1029
+ function createCancelledMessageUpdate(steps, currentMessage) {
1030
+ const updatedSteps = steps.map((step) => {
1031
+ if (step.status === "in_progress") {
1032
+ return { ...step, status: "pending" };
1033
+ }
1034
+ return step;
1035
+ });
1036
+ return {
1037
+ isStreaming: false,
1038
+ isCancelled: true,
1039
+ steps: updatedSteps,
1040
+ currentExecutingStepId: void 0,
1041
+ currentMessage: currentMessage || "Thinking..."
1042
+ };
1043
+ }
1044
+ var UserActionStaleError = class extends Error {
1045
+ constructor(userActionId, message = "User action is no longer actionable") {
1046
+ super(message);
1047
+ __publicField(this, "userActionId");
1048
+ this.name = "UserActionStaleError";
1049
+ this.userActionId = userActionId;
1050
+ }
1051
+ };
1052
+ async function sendUserActionRequest(config, userActionId, action, data) {
1053
+ const url = buildUserActionUrl(config, userActionId, action);
1054
+ const baseHeaders = buildRequestHeaders(config);
1055
+ const hasBody = data !== void 0;
1056
+ const headers = hasBody ? { "Content-Type": "application/json", ...baseHeaders } : baseHeaders;
1057
+ const response = await fetch(url, {
1058
+ method: "POST",
1059
+ headers,
1060
+ body: hasBody ? JSON.stringify(data) : void 0
1061
+ });
1062
+ if (response.status === 404) {
1063
+ throw new UserActionStaleError(userActionId);
1064
+ }
1065
+ if (!response.ok) {
1066
+ const errorText = await response.text();
1067
+ throw new Error(`HTTP ${response.status}: ${errorText}`);
1068
+ }
1069
+ return await response.json();
1070
+ }
1071
+ async function submitUserAction(config, userActionId, content) {
1072
+ return sendUserActionRequest(config, userActionId, "submit", content ?? {});
1073
+ }
1074
+ async function cancelUserAction(config, userActionId) {
1075
+ return sendUserActionRequest(config, userActionId, "cancel");
1076
+ }
1077
+ async function resendUserAction(config, userActionId) {
1078
+ return sendUserActionRequest(config, userActionId, "resend");
1079
+ }
1267
1080
  var EMPTY_USER_ACTION_STATE = { prompts: [], notifications: [] };
1268
1081
  function upsertPrompt(prompts, req) {
1269
1082
  const active = { ...req, status: "pending" };
@@ -3548,62 +3361,7 @@ function MarkdownImageV2({
3548
3361
  }
3549
3362
  ) });
3550
3363
  }
3551
- function PdfBlockV2({ title, href, onOpen }) {
3552
- return /* @__PURE__ */ jsxs(
3553
- "button",
3554
- {
3555
- type: "button",
3556
- className: "payman-v2-pdf-block",
3557
- onClick: (e) => {
3558
- e.preventDefault();
3559
- onOpen(href, title);
3560
- },
3561
- "aria-label": `Open PDF: ${title}`,
3562
- children: [
3563
- /* @__PURE__ */ jsx("div", { className: "payman-v2-pdf-block-icon-area", children: /* @__PURE__ */ jsx(FileText, { size: 18, strokeWidth: 1.5 }) }),
3564
- /* @__PURE__ */ jsxs("div", { className: "payman-v2-pdf-block-body", children: [
3565
- /* @__PURE__ */ jsx("span", { className: "payman-v2-pdf-block-name", children: title }),
3566
- /* @__PURE__ */ jsx("span", { className: "payman-v2-pdf-block-sub", children: "PDF \xB7 Click to preview" })
3567
- ] })
3568
- ]
3569
- }
3570
- );
3571
- }
3572
- function isPdfUrl(href) {
3573
- if (!href) return false;
3574
- try {
3575
- const url = new URL(href);
3576
- const filename = url.searchParams.get("filename");
3577
- if (filename?.toLowerCase().endsWith(".pdf")) return true;
3578
- return url.pathname.toLowerCase().endsWith(".pdf");
3579
- } catch {
3580
- return href.toLowerCase().endsWith(".pdf");
3581
- }
3582
- }
3583
- function getPdfTitleFromUrl(href) {
3584
- try {
3585
- const url = new URL(href);
3586
- const filename = url.searchParams.get("filename");
3587
- if (filename) {
3588
- return filename.replace(/\.pdf$/i, "").replace(/[-_]+/g, " ").trim();
3589
- }
3590
- const parts = url.pathname.split("/").filter(Boolean);
3591
- const last = parts[parts.length - 1];
3592
- if (last) return decodeURIComponent(last).replace(/\.pdf$/i, "").replace(/[-_]+/g, " ").trim();
3593
- } catch {
3594
- }
3595
- return "Document";
3596
- }
3597
- function childrenToText(children) {
3598
- if (typeof children === "string") return children;
3599
- if (typeof children === "number") return String(children);
3600
- if (Array.isArray(children)) return children.map(childrenToText).join("");
3601
- if (children && typeof children === "object" && "props" in children) {
3602
- return childrenToText(children.props.children);
3603
- }
3604
- return "";
3605
- }
3606
- function buildComponents(onImageClick, isResolvingRef, onPdfClick) {
3364
+ function buildComponents(onImageClick, isResolvingRef) {
3607
3365
  return {
3608
3366
  p: ({ children }) => /* @__PURE__ */ jsx("p", { children }),
3609
3367
  code: ({ children }) => /* @__PURE__ */ jsx("code", { children }),
@@ -3618,15 +3376,7 @@ function buildComponents(onImageClick, isResolvingRef, onPdfClick) {
3618
3376
  em: ({ children }) => /* @__PURE__ */ jsx("em", { children }),
3619
3377
  blockquote: ({ children }) => /* @__PURE__ */ jsx("blockquote", { children }),
3620
3378
  hr: () => /* @__PURE__ */ jsx("hr", {}),
3621
- a: ({ href, children }) => {
3622
- const url = href ?? "";
3623
- if (onPdfClick && isPdfUrl(url)) {
3624
- const linkText = childrenToText(children).trim();
3625
- const title = linkText || getPdfTitleFromUrl(url);
3626
- return /* @__PURE__ */ jsx(PdfBlockV2, { href: url, title, onOpen: onPdfClick });
3627
- }
3628
- return /* @__PURE__ */ jsx("a", { href, target: "_blank", rel: "noopener noreferrer", children });
3629
- },
3379
+ a: ({ href, children }) => /* @__PURE__ */ jsx("a", { href, target: "_blank", rel: "noopener noreferrer", children }),
3630
3380
  img: ({ src, alt }) => /* @__PURE__ */ jsx(
3631
3381
  MarkdownImageV2,
3632
3382
  {
@@ -3647,14 +3397,13 @@ function MarkdownRendererV2({
3647
3397
  content,
3648
3398
  isStreaming,
3649
3399
  isResolvingImages,
3650
- onImageClick,
3651
- onPdfClick
3400
+ onImageClick
3652
3401
  }) {
3653
3402
  const isResolvingRef = useRef(isResolvingImages);
3654
3403
  isResolvingRef.current = isResolvingImages;
3655
3404
  const components = useMemo(
3656
- () => buildComponents(onImageClick, isResolvingRef, onPdfClick),
3657
- [onImageClick, onPdfClick]
3405
+ () => buildComponents(onImageClick, isResolvingRef),
3406
+ [onImageClick]
3658
3407
  );
3659
3408
  return /* @__PURE__ */ jsx(
3660
3409
  "div",
@@ -3919,199 +3668,6 @@ function FeedbackReasonModal({
3919
3668
  }
3920
3669
  ) : null });
3921
3670
  }
3922
- var MIN_WIDTH = 320;
3923
- var MAX_WIDTH_RATIO = 0.92;
3924
- var DEFAULT_WIDTH = 680;
3925
- function PdfSheetV2({ src, title, onClose }) {
3926
- const [isMounted, setIsMounted] = useState(false);
3927
- const [isLoaded, setIsLoaded] = useState(false);
3928
- const [width, setWidth] = useState(DEFAULT_WIDTH);
3929
- const panelRef = useRef(null);
3930
- const isDragging = useRef(false);
3931
- const dragStartX = useRef(0);
3932
- const dragStartWidth = useRef(0);
3933
- useEffect(() => {
3934
- setIsMounted(true);
3935
- return () => setIsMounted(false);
3936
- }, []);
3937
- useEffect(() => {
3938
- setIsLoaded(false);
3939
- }, [src]);
3940
- useEffect(() => {
3941
- const onResize = () => {
3942
- const max = Math.floor(window.innerWidth * MAX_WIDTH_RATIO);
3943
- setWidth((w) => Math.min(w, max));
3944
- };
3945
- window.addEventListener("resize", onResize);
3946
- return () => window.removeEventListener("resize", onResize);
3947
- }, []);
3948
- const handleKeyDown = useCallback(
3949
- (e) => {
3950
- if (e.key === "Escape") onClose();
3951
- },
3952
- [onClose]
3953
- );
3954
- useEffect(() => {
3955
- if (!src || typeof document === "undefined") return;
3956
- document.addEventListener("keydown", handleKeyDown);
3957
- const previousOverflow = document.body.style.overflow;
3958
- document.body.style.overflow = "hidden";
3959
- return () => {
3960
- document.removeEventListener("keydown", handleKeyDown);
3961
- document.body.style.overflow = previousOverflow;
3962
- };
3963
- }, [src, handleKeyDown]);
3964
- const handleDownload = () => {
3965
- if (!src || typeof document === "undefined") return;
3966
- const a = document.createElement("a");
3967
- a.href = src;
3968
- a.download = title ? `${title}.pdf` : "document.pdf";
3969
- document.body.appendChild(a);
3970
- a.click();
3971
- a.remove();
3972
- };
3973
- const onResizeMouseDown = (e) => {
3974
- e.preventDefault();
3975
- isDragging.current = true;
3976
- dragStartX.current = e.clientX;
3977
- dragStartWidth.current = panelRef.current?.offsetWidth ?? width;
3978
- document.body.style.cursor = "ew-resize";
3979
- document.body.style.userSelect = "none";
3980
- };
3981
- useEffect(() => {
3982
- const onMouseMove = (e) => {
3983
- if (!isDragging.current || !panelRef.current) return;
3984
- const delta = dragStartX.current - e.clientX;
3985
- const maxW = Math.floor(window.innerWidth * MAX_WIDTH_RATIO);
3986
- const newW = Math.max(MIN_WIDTH, Math.min(maxW, dragStartWidth.current + delta));
3987
- panelRef.current.style.width = `${newW}px`;
3988
- };
3989
- const onMouseUp = () => {
3990
- if (!isDragging.current) return;
3991
- isDragging.current = false;
3992
- document.body.style.cursor = "";
3993
- document.body.style.userSelect = "";
3994
- if (panelRef.current) {
3995
- setWidth(panelRef.current.offsetWidth);
3996
- }
3997
- };
3998
- document.addEventListener("mousemove", onMouseMove);
3999
- document.addEventListener("mouseup", onMouseUp);
4000
- return () => {
4001
- document.removeEventListener("mousemove", onMouseMove);
4002
- document.removeEventListener("mouseup", onMouseUp);
4003
- };
4004
- }, []);
4005
- if (!isMounted || typeof document === "undefined") return null;
4006
- return createPortal(
4007
- /* @__PURE__ */ jsx(AnimatePresence, { children: src ? /* @__PURE__ */ jsxs(Fragment, { children: [
4008
- /* @__PURE__ */ jsx(
4009
- motion.div,
4010
- {
4011
- className: "payman-v2-pdf-sheet-overlay",
4012
- initial: { opacity: 0 },
4013
- animate: { opacity: 1 },
4014
- exit: { opacity: 0 },
4015
- transition: { duration: 0.22 },
4016
- onClick: onClose,
4017
- "aria-hidden": "true"
4018
- },
4019
- "pdf-sheet-backdrop"
4020
- ),
4021
- /* @__PURE__ */ jsxs(
4022
- motion.div,
4023
- {
4024
- ref: panelRef,
4025
- className: "payman-v2-pdf-sheet",
4026
- style: { width },
4027
- initial: { x: "100%" },
4028
- animate: { x: 0 },
4029
- exit: { x: "100%" },
4030
- transition: {
4031
- type: "spring",
4032
- stiffness: 340,
4033
- damping: 34,
4034
- mass: 0.85
4035
- },
4036
- role: "dialog",
4037
- "aria-modal": "true",
4038
- "aria-label": title || "PDF Preview",
4039
- children: [
4040
- /* @__PURE__ */ jsx(
4041
- "div",
4042
- {
4043
- className: "payman-v2-pdf-sheet-resize-handle",
4044
- onMouseDown: onResizeMouseDown,
4045
- "aria-hidden": "true",
4046
- children: /* @__PURE__ */ jsx("div", { className: "payman-v2-pdf-sheet-resize-grip" })
4047
- }
4048
- ),
4049
- /* @__PURE__ */ jsxs("div", { className: "payman-v2-pdf-sheet-header", children: [
4050
- /* @__PURE__ */ jsxs("div", { className: "payman-v2-pdf-sheet-header-left", children: [
4051
- /* @__PURE__ */ jsx("div", { className: "payman-v2-pdf-sheet-file-icon", children: /* @__PURE__ */ jsx(FileText, { size: 14, strokeWidth: 1.75 }) }),
4052
- /* @__PURE__ */ jsx("span", { className: "payman-v2-pdf-sheet-title", title, children: title || "Document" })
4053
- ] }),
4054
- /* @__PURE__ */ jsxs("div", { className: "payman-v2-pdf-sheet-header-actions", children: [
4055
- /* @__PURE__ */ jsxs(
4056
- "button",
4057
- {
4058
- type: "button",
4059
- className: "payman-v2-pdf-sheet-download-btn",
4060
- "aria-label": "Download PDF",
4061
- onClick: handleDownload,
4062
- children: [
4063
- /* @__PURE__ */ jsx(Download, { size: 13, strokeWidth: 2 }),
4064
- /* @__PURE__ */ jsx("span", { children: "Download" })
4065
- ]
4066
- }
4067
- ),
4068
- /* @__PURE__ */ jsx(
4069
- "button",
4070
- {
4071
- type: "button",
4072
- className: "payman-v2-pdf-sheet-close-btn",
4073
- "aria-label": "Close preview",
4074
- onClick: onClose,
4075
- children: /* @__PURE__ */ jsx(X, { size: 15, strokeWidth: 2.25 })
4076
- }
4077
- )
4078
- ] })
4079
- ] }),
4080
- /* @__PURE__ */ jsxs("div", { className: "payman-v2-pdf-sheet-body", children: [
4081
- !isLoaded && /* @__PURE__ */ jsxs("div", { className: "payman-v2-pdf-sheet-loading", children: [
4082
- /* @__PURE__ */ jsx(
4083
- Loader2,
4084
- {
4085
- size: 20,
4086
- strokeWidth: 2,
4087
- style: {
4088
- animation: "payman-v2-spin 0.65s linear infinite",
4089
- color: "var(--payman-v2-text-3)"
4090
- }
4091
- }
4092
- ),
4093
- /* @__PURE__ */ jsx("p", { className: "payman-v2-pdf-sheet-loading-text", children: "Loading PDF\u2026" })
4094
- ] }),
4095
- /* @__PURE__ */ jsx(
4096
- "iframe",
4097
- {
4098
- src,
4099
- title: title || "PDF Preview",
4100
- className: "payman-v2-pdf-sheet-iframe",
4101
- style: { opacity: isLoaded ? 1 : 0, transition: "opacity 0.3s ease" },
4102
- onLoad: () => setIsLoaded(true)
4103
- },
4104
- src
4105
- )
4106
- ] })
4107
- ]
4108
- },
4109
- "pdf-sheet-panel"
4110
- )
4111
- ] }) : null }),
4112
- document.body
4113
- );
4114
- }
4115
3671
  var RESPONSE_SPEED = {
4116
3672
  normal: [2, 4],
4117
3673
  fast: 1,
@@ -4239,10 +3795,6 @@ function AssistantMessageV2({
4239
3795
  () => getFeedbackState(message)
4240
3796
  );
4241
3797
  const [reasonModalOpen, setReasonModalOpen] = useState(false);
4242
- const [pdfSheet, setPdfSheet] = useState(null);
4243
- const handlePdfClick = useCallback((href, title) => {
4244
- setPdfSheet({ href, title });
4245
- }, []);
4246
3798
  const canSubmitFeedback = !!onSubmitFeedback && !!message.executionId;
4247
3799
  const [toast, setToast] = useState(null);
4248
3800
  const copyResetTimerRef = useRef(null);
@@ -4440,8 +3992,7 @@ function AssistantMessageV2({
4440
3992
  content: displayContent,
4441
3993
  isStreaming: message.isStreaming && !isCancelled || isResponseTyping,
4442
3994
  isResolvingImages: message.isResolvingImages,
4443
- onImageClick,
4444
- onPdfClick: handlePdfClick
3995
+ onImageClick
4445
3996
  }
4446
3997
  ) : !isThinkingStreaming ? /* @__PURE__ */ jsx("span", { className: "payman-v2-assistant-msg-placeholder", children: "..." }) : null }),
4447
3998
  isCancelled && message.isStreaming && /* @__PURE__ */ jsxs("div", { className: "payman-v2-assistant-msg-paused", children: [
@@ -4539,14 +4090,6 @@ function AssistantMessageV2({
4539
4090
  showToast("Thank you for your feedback", "success");
4540
4091
  }
4541
4092
  }
4542
- ),
4543
- /* @__PURE__ */ jsx(
4544
- PdfSheetV2,
4545
- {
4546
- src: pdfSheet?.href ?? null,
4547
- title: pdfSheet?.title ?? "",
4548
- onClose: () => setPdfSheet(null)
4549
- }
4550
4093
  )
4551
4094
  ] });
4552
4095
  }