@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.js CHANGED
@@ -48,9 +48,90 @@ function generateId() {
48
48
  return v.toString(16);
49
49
  });
50
50
  }
51
+ var memoryStore = /* @__PURE__ */ new Map();
52
+ var chatStore = {
53
+ get(key) {
54
+ return memoryStore.get(key) ?? [];
55
+ },
56
+ set(key, messages) {
57
+ memoryStore.set(key, messages);
58
+ },
59
+ delete(key) {
60
+ memoryStore.delete(key);
61
+ }
62
+ };
63
+ var streams = /* @__PURE__ */ new Map();
64
+ var activeStreamStore = {
65
+ has(key) {
66
+ return streams.has(key);
67
+ },
68
+ get(key) {
69
+ const entry = streams.get(key);
70
+ if (!entry) return null;
71
+ return { messages: entry.messages, isWaiting: entry.isWaiting };
72
+ },
73
+ // Called before startStream — registers the controller and initial messages
74
+ start(key, abortController, initialMessages) {
75
+ const existing = streams.get(key);
76
+ streams.set(key, {
77
+ messages: initialMessages,
78
+ isWaiting: true,
79
+ abortController,
80
+ listeners: existing?.listeners ?? /* @__PURE__ */ new Set()
81
+ });
82
+ },
83
+ // Called by the stream on every event — applies the same updater pattern React uses
84
+ applyMessages(key, updater) {
85
+ const entry = streams.get(key);
86
+ if (!entry) return;
87
+ const next = typeof updater === "function" ? updater(entry.messages) : updater;
88
+ entry.messages = next;
89
+ entry.listeners.forEach((l) => l(next, entry.isWaiting));
90
+ },
91
+ setWaiting(key, waiting) {
92
+ const entry = streams.get(key);
93
+ if (!entry) return;
94
+ entry.isWaiting = waiting;
95
+ entry.listeners.forEach((l) => l(entry.messages, waiting));
96
+ },
97
+ // Called when stream completes — persists to chatStore and cleans up
98
+ complete(key) {
99
+ const entry = streams.get(key);
100
+ if (!entry) return;
101
+ entry.isWaiting = false;
102
+ entry.listeners.forEach((l) => l(entry.messages, false));
103
+ const toSave = entry.messages.filter((m) => !m.isStreaming);
104
+ if (toSave.length > 0) chatStore.set(key, toSave);
105
+ streams.delete(key);
106
+ },
107
+ // Subscribe — returns unsubscribe fn. Component calls this on mount, cleanup on unmount.
108
+ subscribe(key, listener) {
109
+ const entry = streams.get(key);
110
+ if (!entry) return () => {
111
+ };
112
+ entry.listeners.add(listener);
113
+ return () => {
114
+ streams.get(key)?.listeners.delete(listener);
115
+ };
116
+ },
117
+ // Rename an entry — used when the server assigns a new session ID mid-stream
118
+ rename(oldKey, newKey) {
119
+ const entry = streams.get(oldKey);
120
+ if (!entry) return;
121
+ streams.set(newKey, entry);
122
+ streams.delete(oldKey);
123
+ },
124
+ // Explicit user cancel — aborts the controller and removes the entry
125
+ abort(key) {
126
+ const entry = streams.get(key);
127
+ if (!entry) return;
128
+ entry.abortController.abort();
129
+ streams.delete(key);
130
+ }
131
+ };
51
132
  function yieldAfterProgressEvent(event) {
52
133
  const t = event.eventType;
53
- if (t === "RUN_IN_PROGRESS" || t === "INTENT_PROGRESS" || t === "AGGREGATOR_THINKING_CONT" || t === "INTENT_THINKING_CONT" || t === "THINKING_DELTA") {
134
+ if (t === "RUN_IN_PROGRESS" || t === "INTENT_PROGRESS" || t === "THINKING_DELTA") {
54
135
  return new Promise((resolve) => setTimeout(resolve, 0));
55
136
  }
56
137
  return Promise.resolve();
@@ -306,40 +387,10 @@ function classifyUserActionKind(action, schema) {
306
387
  return isVerificationSchema(schema) ? "verification" : "form";
307
388
  }
308
389
  }
309
- function userActionHeader(kind) {
310
- return kind === "verification" ? "**Verification required**" : "**Action required**";
311
- }
312
- function workingPhaseDetailForDisplay(raw) {
313
- const t = raw.trim();
314
- if (!t) return "";
315
- if (/^Identified\s+\d+\s+tasks?\s+to\s+execute\.?$/i.test(t)) {
316
- return "";
317
- }
318
- return t;
319
- }
320
390
  function getEventText(event, field) {
321
391
  const value = event[field];
322
392
  return typeof value === "string" ? value.trim() : "";
323
393
  }
324
- function shouldShowIntentHeader(event) {
325
- const workerName = getEventText(event, "workerName");
326
- const intentId = getEventText(event, "intentId");
327
- return Boolean(workerName && intentId && workerName === intentId);
328
- }
329
- function addThinkingHeader(state, header) {
330
- state.formattedThinkingText += (state.formattedThinkingText ? "\n" : "") + header;
331
- }
332
- function addThinkingDetail(state, detail) {
333
- const trimmed = detail.trim();
334
- if (!trimmed) return;
335
- state.formattedThinkingText += (state.formattedThinkingText ? "\n" : "") + trimmed;
336
- }
337
- function addThinkingLine(state, header, detail) {
338
- state.formattedThinkingText += (state.formattedThinkingText ? "\n" : "") + header + "\n" + detail;
339
- }
340
- function appendThinkingText(state, text) {
341
- state.formattedThinkingText += text;
342
- }
343
394
  function updateExecutionStageMessage(state, msg) {
344
395
  if (!msg) return;
345
396
  for (let i = state.steps.length - 1; i >= 0; i--) {
@@ -360,9 +411,7 @@ function completeLastInProgressStep(steps) {
360
411
  }
361
412
  function createInitialV2State() {
362
413
  return {
363
- formattedThinkingText: "",
364
414
  finalResponse: "",
365
- currentWorker: "",
366
415
  lastEventType: "",
367
416
  sessionId: void 0,
368
417
  executionId: void 0,
@@ -409,10 +458,6 @@ function processStreamEventV2(rawEvent, state) {
409
458
  return state;
410
459
  }
411
460
  if (typeof eventType === "string" && eventType.toUpperCase() === "THINKING_DELTA") {
412
- const text = typeof event.text === "string" ? event.text : "";
413
- if (text) {
414
- appendThinkingText(state, text);
415
- }
416
461
  if (event.executionId) state.executionId = event.executionId;
417
462
  if (event.sessionId) state.sessionId = event.sessionId;
418
463
  state.lastEventType = "THINKING_DELTA";
@@ -423,7 +468,6 @@ function processStreamEventV2(rawEvent, state) {
423
468
  const message = getEventMessage(event);
424
469
  switch (eventType) {
425
470
  case "WORKFLOW_STARTED":
426
- case "STARTED":
427
471
  state.lastEventType = eventType;
428
472
  break;
429
473
  case "INTENT_PROGRESS": {
@@ -436,97 +480,7 @@ function processStreamEventV2(rawEvent, state) {
436
480
  state.lastEventType = eventType;
437
481
  break;
438
482
  }
439
- case "INTENT_THINKING": {
440
- const worker = getEventText(event, "workerName") || "Worker";
441
- const msg = getEventText(event, "message") || "Thinking...";
442
- const showHeader = shouldShowIntentHeader(event);
443
- if (worker !== state.currentWorker) {
444
- state.currentWorker = worker;
445
- if (showHeader && msg && msg !== worker) {
446
- addThinkingLine(state, `**${worker}**`, msg);
447
- } else if (showHeader) {
448
- addThinkingHeader(state, `**${worker}**`);
449
- } else if (msg !== "Thinking...") {
450
- addThinkingDetail(state, msg);
451
- }
452
- } else if (showHeader || msg !== "Thinking...") {
453
- appendThinkingText(state, "\n" + msg);
454
- }
455
- const lastInProgress = [...state.steps].reverse().find((s) => s.status === "in_progress");
456
- if (lastInProgress) {
457
- lastInProgress.thinkingText = "";
458
- lastInProgress.isThinking = true;
459
- }
460
- state.lastEventType = "INTENT_THINKING";
461
- break;
462
- }
463
- case "INTENT_THINKING_CONT": {
464
- const msg = event.message || "";
465
- if (!msg) break;
466
- if (state.lastEventType === "INTENT_THINKING") {
467
- appendThinkingText(state, "\n" + msg);
468
- } else {
469
- appendThinkingText(state, msg);
470
- }
471
- const thinkingStep = [...state.steps].reverse().find((s) => s.isThinking);
472
- if (thinkingStep) {
473
- thinkingStep.thinkingText = (thinkingStep.thinkingText || "") + msg;
474
- }
475
- state.lastEventType = "INTENT_THINKING_CONT";
476
- break;
477
- }
478
- case "ORCHESTRATOR_THINKING": {
479
- addThinkingLine(state, "**Planning**", event.message || "Understanding your request...");
480
- const stepId = `step-${state.stepCounter++}`;
481
- state.steps.push({
482
- id: stepId,
483
- eventType,
484
- message,
485
- status: "in_progress",
486
- timestamp: Date.now(),
487
- elapsedMs: event.elapsedMs
488
- });
489
- state.currentExecutingStepId = stepId;
490
- state.lastEventType = eventType;
491
- break;
492
- }
493
- case "ORCHESTRATOR_COMPLETED": {
494
- const workingDetail = workingPhaseDetailForDisplay(message);
495
- if (workingDetail) {
496
- addThinkingLine(state, "**Working**", workingDetail);
497
- } else {
498
- addThinkingHeader(state, "**Working**");
499
- }
500
- state.steps.push({
501
- id: `step-${state.stepCounter++}`,
502
- eventType: "WORKING",
503
- message: workingDetail,
504
- status: "completed",
505
- timestamp: Date.now()
506
- });
507
- const step = state.steps.find((s) => s.eventType === "ORCHESTRATOR_THINKING" && s.status === "in_progress");
508
- if (step) {
509
- step.status = "completed";
510
- if (event.elapsedMs) step.elapsedMs = event.elapsedMs;
511
- if (step.id === state.currentExecutingStepId) state.currentExecutingStepId = void 0;
512
- }
513
- state.lastEventType = eventType;
514
- break;
515
- }
516
483
  case "INTENT_STARTED": {
517
- const worker = getEventText(event, "workerName") || "Worker";
518
- const msg = getEventText(event, "message") || "Starting...";
519
- const showHeader = shouldShowIntentHeader(event);
520
- state.currentWorker = worker;
521
- if (showHeader && msg !== worker) {
522
- addThinkingLine(state, `**${worker}**`, msg);
523
- } else if (showHeader) {
524
- addThinkingHeader(state, `**${worker}**`);
525
- } else {
526
- addThinkingDetail(state, msg);
527
- }
528
- const thinkingStep = state.steps.find((s) => s.isThinking);
529
- if (thinkingStep) thinkingStep.isThinking = false;
530
484
  const stepId = `step-${state.stepCounter++}`;
531
485
  state.steps.push({
532
486
  id: stepId,
@@ -545,55 +499,18 @@ function processStreamEventV2(rawEvent, state) {
545
499
  const intentStep = state.steps.find((s) => s.eventType === "INTENT_STARTED" && s.status === "in_progress");
546
500
  if (intentStep) {
547
501
  intentStep.status = "completed";
548
- intentStep.isThinking = false;
549
502
  if (event.elapsedMs) intentStep.elapsedMs = event.elapsedMs;
550
503
  if (intentStep.id === state.currentExecutingStepId) state.currentExecutingStepId = void 0;
551
504
  }
552
505
  state.lastEventType = eventType;
553
506
  break;
554
507
  }
555
- case "AGGREGATOR_THINKING": {
556
- addThinkingLine(state, "**Finalizing**", event.message || "Preparing response...");
557
- const stepId = `step-${state.stepCounter++}`;
558
- state.steps.push({
559
- id: stepId,
560
- eventType,
561
- message,
562
- status: "in_progress",
563
- timestamp: Date.now(),
564
- elapsedMs: event.elapsedMs
565
- });
566
- state.currentExecutingStepId = stepId;
567
- state.lastEventType = eventType;
568
- break;
569
- }
570
- case "AGGREGATOR_COMPLETED": {
571
- appendThinkingText(state, "\n" + (event.message || "Response ready"));
572
- const step = state.steps.find((s) => s.eventType === "AGGREGATOR_THINKING" && s.status === "in_progress");
573
- if (step) {
574
- step.status = "completed";
575
- if (event.elapsedMs) step.elapsedMs = event.elapsedMs;
576
- if (step.id === state.currentExecutingStepId) state.currentExecutingStepId = void 0;
577
- }
578
- state.lastEventType = eventType;
579
- break;
580
- }
581
- case "WORKFLOW_COMPLETED":
582
- case "COMPLETED": {
508
+ case "WORKFLOW_COMPLETED": {
583
509
  const totalTime = Number(event.totalTimeMs);
584
510
  if (Number.isFinite(totalTime) && totalTime > 0) {
585
511
  state.totalElapsedMs = totalTime;
586
512
  }
587
- let content = extractResponseContent(event.response);
588
- const trace = event.trace && typeof event.trace === "object" ? event.trace : null;
589
- if (!content && trace?.workflowMsg && typeof trace.workflowMsg === "string") {
590
- content = trace.workflowMsg;
591
- }
592
- if (!content && trace?.aggregator && typeof trace.aggregator === "object") {
593
- const agg = trace.aggregator;
594
- if (typeof agg.response === "string") content = agg.response;
595
- else content = extractResponseContent(agg.response);
596
- }
513
+ const content = extractResponseContent(event.response);
597
514
  if (content) {
598
515
  state.finalResponse = content;
599
516
  if (event.trace && typeof event.trace === "object") {
@@ -608,7 +525,6 @@ function processStreamEventV2(rawEvent, state) {
608
525
  state.steps.forEach((step) => {
609
526
  if (step.status === "in_progress") {
610
527
  step.status = "completed";
611
- step.isThinking = false;
612
528
  }
613
529
  });
614
530
  state.lastEventType = eventType;
@@ -627,7 +543,6 @@ function processStreamEventV2(rawEvent, state) {
627
543
  };
628
544
  state.notifications.push(notification);
629
545
  state.lastNotification = notification;
630
- if (promptMessage) addThinkingDetail(state, promptMessage);
631
546
  state.lastEventType = eventType;
632
547
  break;
633
548
  }
@@ -653,9 +568,6 @@ function processStreamEventV2(rawEvent, state) {
653
568
  };
654
569
  upsertUserAction(state, request);
655
570
  state.lastUserAction = request;
656
- const header = userActionHeader(kind);
657
- if (promptMessage) addThinkingLine(state, header, promptMessage);
658
- else addThinkingHeader(state, header);
659
571
  const stepId = `step-${state.stepCounter++}`;
660
572
  state.steps.push({
661
573
  id: stepId,
@@ -679,27 +591,15 @@ function processStreamEventV2(rawEvent, state) {
679
591
  };
680
592
  state.notifications.push(notification);
681
593
  state.lastNotification = notification;
682
- if (noteMessage) addThinkingDetail(state, noteMessage);
683
594
  }
684
595
  state.lastEventType = eventType;
685
596
  break;
686
597
  }
687
598
  case "WORKFLOW_ERROR":
688
- case "ERROR":
689
599
  state.hasError = true;
690
600
  state.errorMessage = event.errorMessage || event.message || "Workflow error";
691
601
  state.lastEventType = eventType;
692
602
  break;
693
- case "INTENT_ERROR": {
694
- state.errorMessage = message || event.errorMessage || "An error occurred";
695
- const intentStep = state.steps.find((s) => s.eventType === "INTENT_STARTED" && s.status === "in_progress");
696
- if (intentStep) {
697
- intentStep.status = "error";
698
- intentStep.isThinking = false;
699
- }
700
- state.lastEventType = eventType;
701
- break;
702
- }
703
603
  // ---- K2 pipeline stage lifecycle events ----
704
604
  //
705
605
  // The k2-server playground streaming API emits
@@ -819,22 +719,6 @@ function processStreamEventV2(rawEvent, state) {
819
719
  }
820
720
  return state;
821
721
  }
822
- function createCancelledMessageUpdate(steps, currentMessage) {
823
- const updatedSteps = steps.map((step) => {
824
- if (step.status === "in_progress") {
825
- return { ...step, status: "pending" };
826
- }
827
- return step;
828
- });
829
- return {
830
- isStreaming: false,
831
- isCancelled: true,
832
- steps: updatedSteps,
833
- currentExecutingStepId: void 0,
834
- // Preserve currentMessage so UI can show it with X icon
835
- currentMessage: currentMessage || "Thinking..."
836
- };
837
- }
838
722
  var DEFAULT_STREAM_ENDPOINT = "/api/playground/ask/stream";
839
723
  function buildRequestBody(config, userMessage, sessionId, options) {
840
724
  const sessionOwner = config.sessionParams;
@@ -906,123 +790,6 @@ function buildRequestHeaders(config) {
906
790
  }
907
791
  return headers;
908
792
  }
909
- var UserActionStaleError = class extends Error {
910
- constructor(userActionId, message = "User action is no longer actionable") {
911
- super(message);
912
- __publicField(this, "userActionId");
913
- this.name = "UserActionStaleError";
914
- this.userActionId = userActionId;
915
- }
916
- };
917
- async function sendUserActionRequest(config, userActionId, action, data) {
918
- const url = buildUserActionUrl(config, userActionId, action);
919
- const baseHeaders = buildRequestHeaders(config);
920
- const hasBody = data !== void 0;
921
- const headers = hasBody ? { "Content-Type": "application/json", ...baseHeaders } : baseHeaders;
922
- const response = await fetch(url, {
923
- method: "POST",
924
- headers,
925
- body: hasBody ? JSON.stringify(data) : void 0
926
- });
927
- if (response.status === 404) {
928
- throw new UserActionStaleError(userActionId);
929
- }
930
- if (!response.ok) {
931
- const errorText = await response.text();
932
- throw new Error(`HTTP ${response.status}: ${errorText}`);
933
- }
934
- return await response.json();
935
- }
936
- async function submitUserAction(config, userActionId, content) {
937
- return sendUserActionRequest(config, userActionId, "submit", content ?? {});
938
- }
939
- async function cancelUserAction(config, userActionId) {
940
- return sendUserActionRequest(config, userActionId, "cancel");
941
- }
942
- async function resendUserAction(config, userActionId) {
943
- return sendUserActionRequest(config, userActionId, "resend");
944
- }
945
- var memoryStore = /* @__PURE__ */ new Map();
946
- var chatStore = {
947
- get(key) {
948
- return memoryStore.get(key) ?? [];
949
- },
950
- set(key, messages) {
951
- memoryStore.set(key, messages);
952
- },
953
- delete(key) {
954
- memoryStore.delete(key);
955
- }
956
- };
957
- var streams = /* @__PURE__ */ new Map();
958
- var activeStreamStore = {
959
- has(key) {
960
- return streams.has(key);
961
- },
962
- get(key) {
963
- const entry = streams.get(key);
964
- if (!entry) return null;
965
- return { messages: entry.messages, isWaiting: entry.isWaiting };
966
- },
967
- // Called before startStream — registers the controller and initial messages
968
- start(key, abortController, initialMessages) {
969
- const existing = streams.get(key);
970
- streams.set(key, {
971
- messages: initialMessages,
972
- isWaiting: true,
973
- abortController,
974
- listeners: existing?.listeners ?? /* @__PURE__ */ new Set()
975
- });
976
- },
977
- // Called by the stream on every event — applies the same updater pattern React uses
978
- applyMessages(key, updater) {
979
- const entry = streams.get(key);
980
- if (!entry) return;
981
- const next = typeof updater === "function" ? updater(entry.messages) : updater;
982
- entry.messages = next;
983
- entry.listeners.forEach((l) => l(next, entry.isWaiting));
984
- },
985
- setWaiting(key, waiting) {
986
- const entry = streams.get(key);
987
- if (!entry) return;
988
- entry.isWaiting = waiting;
989
- entry.listeners.forEach((l) => l(entry.messages, waiting));
990
- },
991
- // Called when stream completes — persists to chatStore and cleans up
992
- complete(key) {
993
- const entry = streams.get(key);
994
- if (!entry) return;
995
- entry.isWaiting = false;
996
- entry.listeners.forEach((l) => l(entry.messages, false));
997
- const toSave = entry.messages.filter((m) => !m.isStreaming);
998
- if (toSave.length > 0) chatStore.set(key, toSave);
999
- streams.delete(key);
1000
- },
1001
- // Subscribe — returns unsubscribe fn. Component calls this on mount, cleanup on unmount.
1002
- subscribe(key, listener) {
1003
- const entry = streams.get(key);
1004
- if (!entry) return () => {
1005
- };
1006
- entry.listeners.add(listener);
1007
- return () => {
1008
- streams.get(key)?.listeners.delete(listener);
1009
- };
1010
- },
1011
- // Rename an entry — used when the server assigns a new session ID mid-stream
1012
- rename(oldKey, newKey) {
1013
- const entry = streams.get(oldKey);
1014
- if (!entry) return;
1015
- streams.set(newKey, entry);
1016
- streams.delete(oldKey);
1017
- },
1018
- // Explicit user cancel — aborts the controller and removes the entry
1019
- abort(key) {
1020
- const entry = streams.get(key);
1021
- if (!entry) return;
1022
- entry.abortController.abort();
1023
- streams.delete(key);
1024
- }
1025
- };
1026
793
  var RAG_IMAGE_REGEX = /\/api\/rag\/chunks\/[^"'\s]+\/image/;
1027
794
  function hasRagImages(content) {
1028
795
  return RAG_IMAGE_REGEX.test(content);
@@ -1134,7 +901,6 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
1134
901
  streamProgress: "error",
1135
902
  isError: true,
1136
903
  errorDetails: state.errorMessage,
1137
- formattedThinkingText: state.formattedThinkingText || void 0,
1138
904
  steps: [...state.steps],
1139
905
  currentExecutingStepId: void 0,
1140
906
  executionId: state.executionId,
@@ -1147,7 +913,6 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
1147
913
  currentMessage,
1148
914
  streamProgress: "processing",
1149
915
  isError: false,
1150
- formattedThinkingText: state.formattedThinkingText || void 0,
1151
916
  steps: [...state.steps],
1152
917
  currentExecutingStepId: state.currentExecutingStepId,
1153
918
  executionId: state.executionId,
@@ -1174,7 +939,6 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
1174
939
  errorDetails: isAborted ? void 0 : error.message,
1175
940
  content: isAborted ? state.finalResponse || "" : state.finalResponse || FRIENDLY_ERROR_MESSAGE,
1176
941
  currentMessage: isAborted ? "Thinking..." : void 0,
1177
- formattedThinkingText: state.formattedThinkingText || void 0,
1178
942
  steps: [...state.steps].map((step) => {
1179
943
  if (step.status === "in_progress" && isAborted) {
1180
944
  return { ...step, status: "pending" };
@@ -1213,7 +977,6 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
1213
977
  steps: state.hasError ? [] : [...state.steps],
1214
978
  isCancelled: false,
1215
979
  currentExecutingStepId: void 0,
1216
- formattedThinkingText: state.hasError ? void 0 : state.formattedThinkingText || void 0,
1217
980
  isResolvingImages: needsImageResolve,
1218
981
  totalElapsedMs: state.hasError ? void 0 : state.totalElapsedMs
1219
982
  };
@@ -1266,7 +1029,6 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
1266
1029
  isCancelled: isAborted,
1267
1030
  errorDetails: isAborted ? void 0 : error.message,
1268
1031
  content: isAborted ? state.finalResponse || "" : state.finalResponse || FRIENDLY_ERROR_MESSAGE,
1269
- formattedThinkingText: state.formattedThinkingText || void 0,
1270
1032
  steps: [...state.steps].map((step) => {
1271
1033
  if (step.status === "in_progress" && isAborted) {
1272
1034
  return { ...step, status: "pending" };
@@ -1291,6 +1053,57 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
1291
1053
  abortControllerRef
1292
1054
  };
1293
1055
  }
1056
+ function createCancelledMessageUpdate(steps, currentMessage) {
1057
+ const updatedSteps = steps.map((step) => {
1058
+ if (step.status === "in_progress") {
1059
+ return { ...step, status: "pending" };
1060
+ }
1061
+ return step;
1062
+ });
1063
+ return {
1064
+ isStreaming: false,
1065
+ isCancelled: true,
1066
+ steps: updatedSteps,
1067
+ currentExecutingStepId: void 0,
1068
+ currentMessage: currentMessage || "Thinking..."
1069
+ };
1070
+ }
1071
+ var UserActionStaleError = class extends Error {
1072
+ constructor(userActionId, message = "User action is no longer actionable") {
1073
+ super(message);
1074
+ __publicField(this, "userActionId");
1075
+ this.name = "UserActionStaleError";
1076
+ this.userActionId = userActionId;
1077
+ }
1078
+ };
1079
+ async function sendUserActionRequest(config, userActionId, action, data) {
1080
+ const url = buildUserActionUrl(config, userActionId, action);
1081
+ const baseHeaders = buildRequestHeaders(config);
1082
+ const hasBody = data !== void 0;
1083
+ const headers = hasBody ? { "Content-Type": "application/json", ...baseHeaders } : baseHeaders;
1084
+ const response = await fetch(url, {
1085
+ method: "POST",
1086
+ headers,
1087
+ body: hasBody ? JSON.stringify(data) : void 0
1088
+ });
1089
+ if (response.status === 404) {
1090
+ throw new UserActionStaleError(userActionId);
1091
+ }
1092
+ if (!response.ok) {
1093
+ const errorText = await response.text();
1094
+ throw new Error(`HTTP ${response.status}: ${errorText}`);
1095
+ }
1096
+ return await response.json();
1097
+ }
1098
+ async function submitUserAction(config, userActionId, content) {
1099
+ return sendUserActionRequest(config, userActionId, "submit", content ?? {});
1100
+ }
1101
+ async function cancelUserAction(config, userActionId) {
1102
+ return sendUserActionRequest(config, userActionId, "cancel");
1103
+ }
1104
+ async function resendUserAction(config, userActionId) {
1105
+ return sendUserActionRequest(config, userActionId, "resend");
1106
+ }
1294
1107
  var EMPTY_USER_ACTION_STATE = { prompts: [], notifications: [] };
1295
1108
  function upsertPrompt(prompts, req) {
1296
1109
  const active = { ...req, status: "pending" };
@@ -3575,62 +3388,7 @@ function MarkdownImageV2({
3575
3388
  }
3576
3389
  ) });
3577
3390
  }
3578
- function PdfBlockV2({ title, href, onOpen }) {
3579
- return /* @__PURE__ */ jsxRuntime.jsxs(
3580
- "button",
3581
- {
3582
- type: "button",
3583
- className: "payman-v2-pdf-block",
3584
- onClick: (e) => {
3585
- e.preventDefault();
3586
- onOpen(href, title);
3587
- },
3588
- "aria-label": `Open PDF: ${title}`,
3589
- children: [
3590
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "payman-v2-pdf-block-icon-area", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { size: 18, strokeWidth: 1.5 }) }),
3591
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-pdf-block-body", children: [
3592
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "payman-v2-pdf-block-name", children: title }),
3593
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "payman-v2-pdf-block-sub", children: "PDF \xB7 Click to preview" })
3594
- ] })
3595
- ]
3596
- }
3597
- );
3598
- }
3599
- function isPdfUrl(href) {
3600
- if (!href) return false;
3601
- try {
3602
- const url = new URL(href);
3603
- const filename = url.searchParams.get("filename");
3604
- if (filename?.toLowerCase().endsWith(".pdf")) return true;
3605
- return url.pathname.toLowerCase().endsWith(".pdf");
3606
- } catch {
3607
- return href.toLowerCase().endsWith(".pdf");
3608
- }
3609
- }
3610
- function getPdfTitleFromUrl(href) {
3611
- try {
3612
- const url = new URL(href);
3613
- const filename = url.searchParams.get("filename");
3614
- if (filename) {
3615
- return filename.replace(/\.pdf$/i, "").replace(/[-_]+/g, " ").trim();
3616
- }
3617
- const parts = url.pathname.split("/").filter(Boolean);
3618
- const last = parts[parts.length - 1];
3619
- if (last) return decodeURIComponent(last).replace(/\.pdf$/i, "").replace(/[-_]+/g, " ").trim();
3620
- } catch {
3621
- }
3622
- return "Document";
3623
- }
3624
- function childrenToText(children) {
3625
- if (typeof children === "string") return children;
3626
- if (typeof children === "number") return String(children);
3627
- if (Array.isArray(children)) return children.map(childrenToText).join("");
3628
- if (children && typeof children === "object" && "props" in children) {
3629
- return childrenToText(children.props.children);
3630
- }
3631
- return "";
3632
- }
3633
- function buildComponents(onImageClick, isResolvingRef, onPdfClick) {
3391
+ function buildComponents(onImageClick, isResolvingRef) {
3634
3392
  return {
3635
3393
  p: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("p", { children }),
3636
3394
  code: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("code", { children }),
@@ -3645,15 +3403,7 @@ function buildComponents(onImageClick, isResolvingRef, onPdfClick) {
3645
3403
  em: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("em", { children }),
3646
3404
  blockquote: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("blockquote", { children }),
3647
3405
  hr: () => /* @__PURE__ */ jsxRuntime.jsx("hr", {}),
3648
- a: ({ href, children }) => {
3649
- const url = href ?? "";
3650
- if (onPdfClick && isPdfUrl(url)) {
3651
- const linkText = childrenToText(children).trim();
3652
- const title = linkText || getPdfTitleFromUrl(url);
3653
- return /* @__PURE__ */ jsxRuntime.jsx(PdfBlockV2, { href: url, title, onOpen: onPdfClick });
3654
- }
3655
- return /* @__PURE__ */ jsxRuntime.jsx("a", { href, target: "_blank", rel: "noopener noreferrer", children });
3656
- },
3406
+ a: ({ href, children }) => /* @__PURE__ */ jsxRuntime.jsx("a", { href, target: "_blank", rel: "noopener noreferrer", children }),
3657
3407
  img: ({ src, alt }) => /* @__PURE__ */ jsxRuntime.jsx(
3658
3408
  MarkdownImageV2,
3659
3409
  {
@@ -3674,14 +3424,13 @@ function MarkdownRendererV2({
3674
3424
  content,
3675
3425
  isStreaming,
3676
3426
  isResolvingImages,
3677
- onImageClick,
3678
- onPdfClick
3427
+ onImageClick
3679
3428
  }) {
3680
3429
  const isResolvingRef = react.useRef(isResolvingImages);
3681
3430
  isResolvingRef.current = isResolvingImages;
3682
3431
  const components = react.useMemo(
3683
- () => buildComponents(onImageClick, isResolvingRef, onPdfClick),
3684
- [onImageClick, onPdfClick]
3432
+ () => buildComponents(onImageClick, isResolvingRef),
3433
+ [onImageClick]
3685
3434
  );
3686
3435
  return /* @__PURE__ */ jsxRuntime.jsx(
3687
3436
  "div",
@@ -3946,199 +3695,6 @@ function FeedbackReasonModal({
3946
3695
  }
3947
3696
  ) : null });
3948
3697
  }
3949
- var MIN_WIDTH = 320;
3950
- var MAX_WIDTH_RATIO = 0.92;
3951
- var DEFAULT_WIDTH = 680;
3952
- function PdfSheetV2({ src, title, onClose }) {
3953
- const [isMounted, setIsMounted] = react.useState(false);
3954
- const [isLoaded, setIsLoaded] = react.useState(false);
3955
- const [width, setWidth] = react.useState(DEFAULT_WIDTH);
3956
- const panelRef = react.useRef(null);
3957
- const isDragging = react.useRef(false);
3958
- const dragStartX = react.useRef(0);
3959
- const dragStartWidth = react.useRef(0);
3960
- react.useEffect(() => {
3961
- setIsMounted(true);
3962
- return () => setIsMounted(false);
3963
- }, []);
3964
- react.useEffect(() => {
3965
- setIsLoaded(false);
3966
- }, [src]);
3967
- react.useEffect(() => {
3968
- const onResize = () => {
3969
- const max = Math.floor(window.innerWidth * MAX_WIDTH_RATIO);
3970
- setWidth((w) => Math.min(w, max));
3971
- };
3972
- window.addEventListener("resize", onResize);
3973
- return () => window.removeEventListener("resize", onResize);
3974
- }, []);
3975
- const handleKeyDown = react.useCallback(
3976
- (e) => {
3977
- if (e.key === "Escape") onClose();
3978
- },
3979
- [onClose]
3980
- );
3981
- react.useEffect(() => {
3982
- if (!src || typeof document === "undefined") return;
3983
- document.addEventListener("keydown", handleKeyDown);
3984
- const previousOverflow = document.body.style.overflow;
3985
- document.body.style.overflow = "hidden";
3986
- return () => {
3987
- document.removeEventListener("keydown", handleKeyDown);
3988
- document.body.style.overflow = previousOverflow;
3989
- };
3990
- }, [src, handleKeyDown]);
3991
- const handleDownload = () => {
3992
- if (!src || typeof document === "undefined") return;
3993
- const a = document.createElement("a");
3994
- a.href = src;
3995
- a.download = title ? `${title}.pdf` : "document.pdf";
3996
- document.body.appendChild(a);
3997
- a.click();
3998
- a.remove();
3999
- };
4000
- const onResizeMouseDown = (e) => {
4001
- e.preventDefault();
4002
- isDragging.current = true;
4003
- dragStartX.current = e.clientX;
4004
- dragStartWidth.current = panelRef.current?.offsetWidth ?? width;
4005
- document.body.style.cursor = "ew-resize";
4006
- document.body.style.userSelect = "none";
4007
- };
4008
- react.useEffect(() => {
4009
- const onMouseMove = (e) => {
4010
- if (!isDragging.current || !panelRef.current) return;
4011
- const delta = dragStartX.current - e.clientX;
4012
- const maxW = Math.floor(window.innerWidth * MAX_WIDTH_RATIO);
4013
- const newW = Math.max(MIN_WIDTH, Math.min(maxW, dragStartWidth.current + delta));
4014
- panelRef.current.style.width = `${newW}px`;
4015
- };
4016
- const onMouseUp = () => {
4017
- if (!isDragging.current) return;
4018
- isDragging.current = false;
4019
- document.body.style.cursor = "";
4020
- document.body.style.userSelect = "";
4021
- if (panelRef.current) {
4022
- setWidth(panelRef.current.offsetWidth);
4023
- }
4024
- };
4025
- document.addEventListener("mousemove", onMouseMove);
4026
- document.addEventListener("mouseup", onMouseUp);
4027
- return () => {
4028
- document.removeEventListener("mousemove", onMouseMove);
4029
- document.removeEventListener("mouseup", onMouseUp);
4030
- };
4031
- }, []);
4032
- if (!isMounted || typeof document === "undefined") return null;
4033
- return reactDom.createPortal(
4034
- /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: src ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4035
- /* @__PURE__ */ jsxRuntime.jsx(
4036
- framerMotion.motion.div,
4037
- {
4038
- className: "payman-v2-pdf-sheet-overlay",
4039
- initial: { opacity: 0 },
4040
- animate: { opacity: 1 },
4041
- exit: { opacity: 0 },
4042
- transition: { duration: 0.22 },
4043
- onClick: onClose,
4044
- "aria-hidden": "true"
4045
- },
4046
- "pdf-sheet-backdrop"
4047
- ),
4048
- /* @__PURE__ */ jsxRuntime.jsxs(
4049
- framerMotion.motion.div,
4050
- {
4051
- ref: panelRef,
4052
- className: "payman-v2-pdf-sheet",
4053
- style: { width },
4054
- initial: { x: "100%" },
4055
- animate: { x: 0 },
4056
- exit: { x: "100%" },
4057
- transition: {
4058
- type: "spring",
4059
- stiffness: 340,
4060
- damping: 34,
4061
- mass: 0.85
4062
- },
4063
- role: "dialog",
4064
- "aria-modal": "true",
4065
- "aria-label": title || "PDF Preview",
4066
- children: [
4067
- /* @__PURE__ */ jsxRuntime.jsx(
4068
- "div",
4069
- {
4070
- className: "payman-v2-pdf-sheet-resize-handle",
4071
- onMouseDown: onResizeMouseDown,
4072
- "aria-hidden": "true",
4073
- children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "payman-v2-pdf-sheet-resize-grip" })
4074
- }
4075
- ),
4076
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-pdf-sheet-header", children: [
4077
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-pdf-sheet-header-left", children: [
4078
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "payman-v2-pdf-sheet-file-icon", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { size: 14, strokeWidth: 1.75 }) }),
4079
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "payman-v2-pdf-sheet-title", title, children: title || "Document" })
4080
- ] }),
4081
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-pdf-sheet-header-actions", children: [
4082
- /* @__PURE__ */ jsxRuntime.jsxs(
4083
- "button",
4084
- {
4085
- type: "button",
4086
- className: "payman-v2-pdf-sheet-download-btn",
4087
- "aria-label": "Download PDF",
4088
- onClick: handleDownload,
4089
- children: [
4090
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Download, { size: 13, strokeWidth: 2 }),
4091
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Download" })
4092
- ]
4093
- }
4094
- ),
4095
- /* @__PURE__ */ jsxRuntime.jsx(
4096
- "button",
4097
- {
4098
- type: "button",
4099
- className: "payman-v2-pdf-sheet-close-btn",
4100
- "aria-label": "Close preview",
4101
- onClick: onClose,
4102
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: 15, strokeWidth: 2.25 })
4103
- }
4104
- )
4105
- ] })
4106
- ] }),
4107
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-pdf-sheet-body", children: [
4108
- !isLoaded && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-pdf-sheet-loading", children: [
4109
- /* @__PURE__ */ jsxRuntime.jsx(
4110
- lucideReact.Loader2,
4111
- {
4112
- size: 20,
4113
- strokeWidth: 2,
4114
- style: {
4115
- animation: "payman-v2-spin 0.65s linear infinite",
4116
- color: "var(--payman-v2-text-3)"
4117
- }
4118
- }
4119
- ),
4120
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "payman-v2-pdf-sheet-loading-text", children: "Loading PDF\u2026" })
4121
- ] }),
4122
- /* @__PURE__ */ jsxRuntime.jsx(
4123
- "iframe",
4124
- {
4125
- src,
4126
- title: title || "PDF Preview",
4127
- className: "payman-v2-pdf-sheet-iframe",
4128
- style: { opacity: isLoaded ? 1 : 0, transition: "opacity 0.3s ease" },
4129
- onLoad: () => setIsLoaded(true)
4130
- },
4131
- src
4132
- )
4133
- ] })
4134
- ]
4135
- },
4136
- "pdf-sheet-panel"
4137
- )
4138
- ] }) : null }),
4139
- document.body
4140
- );
4141
- }
4142
3698
  var RESPONSE_SPEED = {
4143
3699
  normal: [2, 4],
4144
3700
  fast: 1,
@@ -4266,10 +3822,6 @@ function AssistantMessageV2({
4266
3822
  () => getFeedbackState(message)
4267
3823
  );
4268
3824
  const [reasonModalOpen, setReasonModalOpen] = react.useState(false);
4269
- const [pdfSheet, setPdfSheet] = react.useState(null);
4270
- const handlePdfClick = react.useCallback((href, title) => {
4271
- setPdfSheet({ href, title });
4272
- }, []);
4273
3825
  const canSubmitFeedback = !!onSubmitFeedback && !!message.executionId;
4274
3826
  const [toast, setToast] = react.useState(null);
4275
3827
  const copyResetTimerRef = react.useRef(null);
@@ -4467,8 +4019,7 @@ function AssistantMessageV2({
4467
4019
  content: displayContent,
4468
4020
  isStreaming: message.isStreaming && !isCancelled || isResponseTyping,
4469
4021
  isResolvingImages: message.isResolvingImages,
4470
- onImageClick,
4471
- onPdfClick: handlePdfClick
4022
+ onImageClick
4472
4023
  }
4473
4024
  ) : !isThinkingStreaming ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "payman-v2-assistant-msg-placeholder", children: "..." }) : null }),
4474
4025
  isCancelled && message.isStreaming && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-assistant-msg-paused", children: [
@@ -4566,14 +4117,6 @@ function AssistantMessageV2({
4566
4117
  showToast("Thank you for your feedback", "success");
4567
4118
  }
4568
4119
  }
4569
- ),
4570
- /* @__PURE__ */ jsxRuntime.jsx(
4571
- PdfSheetV2,
4572
- {
4573
- src: pdfSheet?.href ?? null,
4574
- title: pdfSheet?.title ?? "",
4575
- onClose: () => setPdfSheet(null)
4576
- }
4577
4120
  )
4578
4121
  ] });
4579
4122
  }