@paymanai/payman-ask-sdk 4.0.25 → 4.0.26

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,3 +1,4 @@
1
+ import * as React from 'react';
1
2
  import { createContext, forwardRef, useCallback, useRef, useState, useMemo, useEffect, useImperativeHandle, useLayoutEffect, useContext } from 'react';
2
3
  import { AnimatePresence, motion } from 'framer-motion';
3
4
  import { clsx } from 'clsx';
@@ -273,6 +274,8 @@ function getEventMessage(event) {
273
274
  }
274
275
  case "RUN_IN_PROGRESS":
275
276
  return event.partialText || "Thinking...";
277
+ case "LLM_CALL_STARTED":
278
+ return event.description || "";
276
279
  case "RUN_COMPLETED":
277
280
  return "Agent run completed";
278
281
  case "RUN_FAILED":
@@ -410,7 +413,8 @@ function createInitialV2State() {
410
413
  finalData: void 0,
411
414
  steps: [],
412
415
  stepCounter: 0,
413
- currentExecutingStepId: void 0
416
+ currentExecutingStepId: void 0,
417
+ trailingActivity: false
414
418
  };
415
419
  }
416
420
  function upsertUserAction(state, req) {
@@ -432,6 +436,7 @@ function processStreamEventV2(rawEvent, state) {
432
436
  if (typeof eventType === "string" && eventType.toUpperCase() === "KEEP_ALIVE") {
433
437
  if (event.executionId) state.executionId = event.executionId;
434
438
  if (event.sessionId) state.sessionId = event.sessionId;
439
+ if (state.finalResponse) state.trailingActivity = true;
435
440
  const description = typeof event.description === "string" ? event.description : "";
436
441
  if (description) {
437
442
  for (let i = state.steps.length - 1; i >= 0; i--) {
@@ -466,7 +471,12 @@ function processStreamEventV2(rawEvent, state) {
466
471
  state.lastEventType = eventType;
467
472
  break;
468
473
  }
474
+ case "LLM_CALL_STARTED":
475
+ if (state.finalResponse) state.trailingActivity = true;
476
+ state.lastEventType = eventType;
477
+ break;
469
478
  case "INTENT_STARTED": {
479
+ if (state.finalResponse) state.trailingActivity = true;
470
480
  const stepId = `step-${state.stepCounter++}`;
471
481
  state.steps.push({
472
482
  id: stepId,
@@ -482,6 +492,7 @@ function processStreamEventV2(rawEvent, state) {
482
492
  break;
483
493
  }
484
494
  case "INTENT_COMPLETED": {
495
+ if (state.finalResponse) state.trailingActivity = true;
485
496
  const intentStep = state.steps.find((s) => s.eventType === "INTENT_STARTED" && s.status === "in_progress");
486
497
  if (intentStep) {
487
498
  intentStep.status = "completed";
@@ -513,6 +524,7 @@ function processStreamEventV2(rawEvent, state) {
513
524
  step2.status = "completed";
514
525
  }
515
526
  });
527
+ state.trailingActivity = false;
516
528
  state.lastEventType = eventType;
517
529
  break;
518
530
  }
@@ -584,6 +596,7 @@ function processStreamEventV2(rawEvent, state) {
584
596
  case "WORKFLOW_ERROR":
585
597
  state.hasError = true;
586
598
  state.errorMessage = event.errorMessage || event.message || "Workflow error";
599
+ state.trailingActivity = false;
587
600
  state.lastEventType = eventType;
588
601
  break;
589
602
  // ---- K2 pipeline stage lifecycle events ----
@@ -872,7 +885,9 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
872
885
  const latestUsefulStep = [...state.steps].reverse().find(
873
886
  (s) => s.message && !isBlandStatus(s.message)
874
887
  );
875
- const currentMessage = useful(activeStep?.message) ?? useful(lastInProgressStep?.message) ?? latestUsefulStep?.message ?? useful(getEventMessage(event)) ?? // Last-resort: every candidate is bland (very first event,
888
+ const eventTypeUpper = typeof event.eventType === "string" ? event.eventType.toUpperCase() : "";
889
+ const liveEventLabel = eventTypeUpper === "KEEP_ALIVE" || eventTypeUpper === "LLM_CALL_STARTED" ? useful(getEventMessage(event)) : void 0;
890
+ const currentMessage = useful(activeStep?.message) ?? useful(lastInProgressStep?.message) ?? liveEventLabel ?? latestUsefulStep?.message ?? useful(getEventMessage(event)) ?? // Last-resort: every candidate is bland (very first event,
876
891
  // nothing useful seen yet). Render the bland label so the
877
892
  // bubble isn't blank.
878
893
  activeStep?.message ?? lastInProgressStep?.message ?? getEventMessage(event);
@@ -897,6 +912,7 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
897
912
  streamingContent: state.finalResponse,
898
913
  content: "",
899
914
  currentMessage,
915
+ hasTrailingActivity: state.trailingActivity,
900
916
  streamProgress: "processing",
901
917
  isError: false,
902
918
  steps: [...state.steps],
@@ -2055,6 +2071,9 @@ function getConflictErrorMessage(errorDetails) {
2055
2071
  }
2056
2072
  function initSentryIfNeeded(dsn) {
2057
2073
  if (!dsn) return;
2074
+ if (typeof window !== "undefined" && (window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1")) {
2075
+ return;
2076
+ }
2058
2077
  if (Sentry.getClient()) return;
2059
2078
  Sentry.init({
2060
2079
  dsn,
@@ -3436,9 +3455,88 @@ function MarkdownImageV2({
3436
3455
  }
3437
3456
  ) });
3438
3457
  }
3439
- function buildComponents(onImageClick, isResolvingRef) {
3458
+ var RAG_SOURCE_CLASS = "payman-v2-rag-source";
3459
+ var RAG_FOLLOW_UP_CLASS = "payman-v2-rag-follow-up";
3460
+ var SOURCE_PATTERN = /^Sources?:\s*\S/i;
3461
+ var MAX_FOLLOW_UP_LENGTH = 320;
3462
+ var HR_PATTERN = /^-{3,}$|^_{3,}$|^\*{3,}$/;
3463
+ function normalizeRagParagraphText(text) {
3464
+ return text.replace(/\s+/g, " ").trim();
3465
+ }
3466
+ function isRagSourceParagraph(text) {
3467
+ return SOURCE_PATTERN.test(normalizeRagParagraphText(text));
3468
+ }
3469
+ function isRagFollowUpCandidate(text) {
3470
+ const normalized = normalizeRagParagraphText(text);
3471
+ return normalized.length > 0 && normalized.length <= MAX_FOLLOW_UP_LENGTH && normalized.endsWith("?");
3472
+ }
3473
+ function extractRagParagraphTexts(content) {
3474
+ const paragraphs = [];
3475
+ const currentParagraph = [];
3476
+ const flushParagraph = () => {
3477
+ const paragraph = normalizeRagParagraphText(currentParagraph.join(" "));
3478
+ currentParagraph.length = 0;
3479
+ if (paragraph) paragraphs.push(paragraph);
3480
+ };
3481
+ content.replace(/\\n/g, "\n").split(/\r?\n/).forEach((line) => {
3482
+ const trimmedLine = line.trim();
3483
+ if (!trimmedLine) {
3484
+ flushParagraph();
3485
+ return;
3486
+ }
3487
+ if (HR_PATTERN.test(trimmedLine)) {
3488
+ flushParagraph();
3489
+ return;
3490
+ }
3491
+ currentParagraph.push(trimmedLine);
3492
+ });
3493
+ flushParagraph();
3494
+ return paragraphs;
3495
+ }
3496
+ function getRagAnswerParagraphRoles(paragraphs) {
3497
+ const normalized = paragraphs.map(normalizeRagParagraphText);
3498
+ const roles = normalized.map(() => null);
3499
+ const sourceIndexes = normalized.map((paragraph, index) => isRagSourceParagraph(paragraph) ? index : -1).filter((index) => index >= 0);
3500
+ for (const sourceIndex of sourceIndexes) {
3501
+ roles[sourceIndex] = "source";
3502
+ for (const candidateIndex of [sourceIndex - 1, sourceIndex + 1]) {
3503
+ if (candidateIndex >= 0 && candidateIndex < normalized.length && roles[candidateIndex] == null && isRagFollowUpCandidate(normalized[candidateIndex] ?? "")) {
3504
+ roles[candidateIndex] = "follow-up";
3505
+ }
3506
+ }
3507
+ }
3508
+ return roles;
3509
+ }
3510
+ function getRagAnswerParagraphRole(paragraph, paragraphs) {
3511
+ const normalizedParagraph = normalizeRagParagraphText(paragraph);
3512
+ if (isRagSourceParagraph(normalizedParagraph)) return "source";
3513
+ const roles = getRagAnswerParagraphRoles(paragraphs);
3514
+ return paragraphs.map(normalizeRagParagraphText).some((candidate, index) => {
3515
+ return candidate === normalizedParagraph && roles[index] === "follow-up";
3516
+ }) ? "follow-up" : null;
3517
+ }
3518
+ function ragAnswerRoleClassName(role) {
3519
+ if (role === "source") return RAG_SOURCE_CLASS;
3520
+ if (role === "follow-up") return RAG_FOLLOW_UP_CLASS;
3521
+ return void 0;
3522
+ }
3523
+ function reactNodeText(node) {
3524
+ if (typeof node === "string" || typeof node === "number") return String(node);
3525
+ if (Array.isArray(node)) return node.map(reactNodeText).join("");
3526
+ if (React.isValidElement(node)) {
3527
+ return reactNodeText(node.props.children);
3528
+ }
3529
+ return "";
3530
+ }
3531
+ function buildComponents(onImageClick, isResolvingRef, ragParagraphsRef) {
3440
3532
  return {
3441
- p: ({ children }) => /* @__PURE__ */ jsx("p", { children }),
3533
+ p: ({ children }) => {
3534
+ const role = getRagAnswerParagraphRole(
3535
+ reactNodeText(children),
3536
+ ragParagraphsRef?.current ?? []
3537
+ );
3538
+ return /* @__PURE__ */ jsx("p", { className: ragAnswerRoleClassName(role), children });
3539
+ },
3442
3540
  code: ({ children }) => /* @__PURE__ */ jsx("code", { children }),
3443
3541
  pre: ({ children }) => /* @__PURE__ */ jsx("div", { className: "payman-v2-markdown-pre", children: /* @__PURE__ */ jsx("pre", { children }) }),
3444
3542
  ul: ({ children }) => /* @__PURE__ */ jsx("ul", { children }),
@@ -3476,8 +3574,13 @@ function MarkdownRendererV2({
3476
3574
  }) {
3477
3575
  const isResolvingRef = useRef(isResolvingImages);
3478
3576
  isResolvingRef.current = isResolvingImages;
3577
+ const ragParagraphsRef = useRef([]);
3578
+ ragParagraphsRef.current = useMemo(
3579
+ () => extractRagParagraphTexts(content),
3580
+ [content]
3581
+ );
3479
3582
  const components = useMemo(
3480
- () => buildComponents(onImageClick, isResolvingRef),
3583
+ () => buildComponents(onImageClick, isResolvingRef, ragParagraphsRef),
3481
3584
  [onImageClick]
3482
3585
  );
3483
3586
  return /* @__PURE__ */ jsx(
@@ -3970,6 +4073,7 @@ function AssistantMessageV2({
3970
4073
  return message.isStreaming ? stripIncompleteImageToken(normalized) : normalized;
3971
4074
  })();
3972
4075
  const isThinkingStreaming = !!message.isStreaming && !rawResponseContent && !message.isError;
4076
+ const showTrailingProgress = !!message.isStreaming && !!rawResponseContent && !message.isError && !message.isCancelled && !!message.hasTrailingActivity;
3973
4077
  const responseTypingEnabled = hasEverStreamed.current && Boolean(rawResponseContent) && !message.isError;
3974
4078
  const { displayedText: displayContent, isTyping: isResponseTyping } = useTypingEffect(
3975
4079
  rawResponseContent,
@@ -4128,7 +4232,7 @@ function AssistantMessageV2({
4128
4232
  {
4129
4233
  isStreaming: isThinkingStreaming,
4130
4234
  stickyLabel,
4131
- currentStepLabel
4235
+ currentStepLabel: currentStepLabel ?? message.currentMessage
4132
4236
  }
4133
4237
  )
4134
4238
  },
@@ -4143,6 +4247,27 @@ function AssistantMessageV2({
4143
4247
  onImageClick
4144
4248
  }
4145
4249
  ) : !isThinkingStreaming ? /* @__PURE__ */ jsx("span", { className: "payman-v2-assistant-msg-placeholder", children: "..." }) : null }),
4250
+ /* @__PURE__ */ jsx(AnimatePresence, { children: showTrailingProgress && /* @__PURE__ */ jsx(
4251
+ motion.div,
4252
+ {
4253
+ initial: { opacity: 0, height: 0 },
4254
+ animate: { opacity: 1, height: "auto" },
4255
+ exit: { opacity: 0, height: 0 },
4256
+ transition: {
4257
+ duration: 0.32,
4258
+ ease: [0.2, 0, 0, 1]
4259
+ },
4260
+ style: { overflow: "hidden" },
4261
+ children: /* @__PURE__ */ jsx(
4262
+ ThinkingBlockV2,
4263
+ {
4264
+ isStreaming: true,
4265
+ currentStepLabel: message.currentMessage ?? currentStepLabel
4266
+ }
4267
+ )
4268
+ },
4269
+ "trailing-progress"
4270
+ ) }),
4146
4271
  isCancelled && message.isStreaming && /* @__PURE__ */ jsxs("div", { className: "payman-v2-assistant-msg-paused", children: [
4147
4272
  /* @__PURE__ */ jsx(
4148
4273
  WifiOff,
@@ -4437,7 +4562,10 @@ function VerificationInline({
4437
4562
  if (busy) return;
4438
4563
  void onCancel(prompt.userActionId);
4439
4564
  }, [busy, onCancel, prompt.userActionId]);
4440
- const description = prompt.message?.trim() || (isNumeric ? `Enter the ${codeLen}-digit code to continue` : "Enter the verification code to continue");
4565
+ const promptMessage = prompt.message?.trim();
4566
+ const description = promptMessage || (isNumeric ? `Enter the ${codeLen}-digit code to continue` : "Enter the verification code to continue");
4567
+ const messageFormat = prompt.metadata?.["payman/messageFormat"];
4568
+ const renderMarkdown = !!promptMessage && messageFormat === "markdown";
4441
4569
  if (hiddenAfterResend) return null;
4442
4570
  return /* @__PURE__ */ jsxs("div", { className: "payman-v2-ua", role: "group", "aria-label": "Verification required", children: [
4443
4571
  /* @__PURE__ */ jsxs("div", { className: "payman-v2-ua-head", children: [
@@ -4445,7 +4573,7 @@ function VerificationInline({
4445
4573
  /* @__PURE__ */ jsx("span", { className: "payman-v2-ua-title", children: "Verification required" }),
4446
4574
  typeof secondsLeft === "number" && !stale && /* @__PURE__ */ jsx("span", { className: "payman-v2-ua-timer", children: expired ? "Expired" : `${secondsLeft}s` })
4447
4575
  ] }),
4448
- /* @__PURE__ */ jsx("p", { className: "payman-v2-ua-desc", children: description }),
4576
+ renderMarkdown ? /* @__PURE__ */ jsx("div", { className: "payman-v2-ua-markdown", children: /* @__PURE__ */ jsx(MarkdownRendererV2, { content: description }) }) : /* @__PURE__ */ jsx("p", { className: "payman-v2-ua-desc", children: description }),
4449
4577
  stale ? /* @__PURE__ */ jsx("p", { className: "payman-v2-ua-stale", children: "This request is no longer available." }) : /* @__PURE__ */ jsxs(Fragment, { children: [
4450
4578
  isNumeric ? /* @__PURE__ */ jsx("div", { className: "payman-v2-ua-field", children: /* @__PURE__ */ jsx(
4451
4579
  OtpInputV2,