@paymanai/payman-ask-sdk 4.0.15 → 4.0.16

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
@@ -4236,6 +4236,7 @@ function VerificationInline({
4236
4236
  const [code, setCode] = react.useState("");
4237
4237
  const [errored, setErrored] = react.useState(false);
4238
4238
  const [resendSec, setResendSec] = react.useState(0);
4239
+ const [hiddenAfterResend, setHiddenAfterResend] = react.useState(false);
4239
4240
  const lastSubmittedRef = react.useRef(null);
4240
4241
  const resendTimerRef = react.useRef(void 0);
4241
4242
  const status = prompt.status;
@@ -4249,6 +4250,9 @@ function VerificationInline({
4249
4250
  lastSubmittedRef.current = null;
4250
4251
  }
4251
4252
  }, [prompt.subAction, prompt.userActionId]);
4253
+ react.useEffect(() => {
4254
+ setHiddenAfterResend(false);
4255
+ }, [prompt.expirySeconds, prompt.message, prompt.subAction, prompt.userActionId]);
4252
4256
  react.useEffect(() => {
4253
4257
  if (code.length < codeLen) lastSubmittedRef.current = null;
4254
4258
  }, [code, codeLen]);
@@ -4299,11 +4303,13 @@ function VerificationInline({
4299
4303
  if (locked || resendSec > 0) return;
4300
4304
  setErrored(false);
4301
4305
  setCode("");
4306
+ setHiddenAfterResend(true);
4302
4307
  lastSubmittedRef.current = null;
4303
4308
  try {
4304
4309
  await onResend(prompt.userActionId);
4305
4310
  startResendCooldown();
4306
4311
  } catch {
4312
+ setHiddenAfterResend(false);
4307
4313
  }
4308
4314
  }, [locked, onResend, prompt.userActionId, resendSec, startResendCooldown]);
4309
4315
  const handleCancel = react.useCallback(() => {
@@ -4311,6 +4317,7 @@ function VerificationInline({
4311
4317
  void onCancel(prompt.userActionId);
4312
4318
  }, [busy, onCancel, prompt.userActionId]);
4313
4319
  const description = prompt.message?.trim() || (isNumeric ? `Enter the ${codeLen}-digit code to continue` : "Enter the verification code to continue");
4320
+ if (hiddenAfterResend) return null;
4314
4321
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-ua", role: "group", "aria-label": "Verification required", children: [
4315
4322
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-ua-head", children: [
4316
4323
  /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ShieldCheck, { className: "payman-v2-ua-icon", size: 15, strokeWidth: 1.75, "aria-hidden": true }),
@@ -4406,6 +4413,9 @@ function SchemaFormInline({
4406
4413
  const busy = status === "submitting";
4407
4414
  const stale = status === "stale";
4408
4415
  const locked = busy || stale || expired;
4416
+ const isUserConfirmation = prompt.subAction === "UserConfirmation";
4417
+ const messageFormat = prompt.metadata?.["payman/messageFormat"];
4418
+ const renderMarkdown = messageFormat === "markdown";
4409
4419
  const setValue = (key, value) => {
4410
4420
  setValues((prev) => ({ ...prev, [key]: value }));
4411
4421
  setErrors((prev) => {
@@ -4431,8 +4441,8 @@ function SchemaFormInline({
4431
4441
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "payman-v2-ua-title", children: "Action required" }),
4432
4442
  typeof secondsLeft === "number" && !stale && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "payman-v2-ua-timer", children: expired ? "Expired" : `${secondsLeft}s` })
4433
4443
  ] }),
4434
- prompt.message?.trim() && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "payman-v2-ua-desc", children: prompt.message }),
4435
- stale ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "payman-v2-ua-stale", children: "This request is no longer available." }) : fields.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "payman-v2-ua-desc", children: "This action has no inputs to fill." }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "payman-v2-ua-form", children: fields.map(([key, field]) => {
4444
+ prompt.message?.trim() && (renderMarkdown ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "payman-v2-ua-markdown", children: /* @__PURE__ */ jsxRuntime.jsx(MarkdownRendererV2, { content: prompt.message }) }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "payman-v2-ua-desc", children: prompt.message })),
4445
+ stale ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "payman-v2-ua-stale", children: "This request is no longer available." }) : fields.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "payman-v2-ua-form", children: fields.map(([key, field]) => {
4436
4446
  const widget = classifyField(field);
4437
4447
  const label = field.title || key;
4438
4448
  const required = isRequired(schema, key);
@@ -4505,7 +4515,7 @@ function SchemaFormInline({
4505
4515
  className: "payman-v2-ua-btn payman-v2-ua-btn-primary",
4506
4516
  disabled: locked,
4507
4517
  onClick: handleSubmit,
4508
- children: busy ? "Submitting\u2026" : "Submit"
4518
+ children: busy ? "Submitting\u2026" : isUserConfirmation ? "Confirm" : "Submit"
4509
4519
  }
4510
4520
  ),
4511
4521
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -4561,10 +4571,25 @@ function useExpiryCountdown(prompt) {
4561
4571
  const expired = initial !== void 0 && secondsLeft === 0;
4562
4572
  return [secondsLeft, expired];
4563
4573
  }
4564
- function UserActionInline({ prompt, onSubmit, onCancel, onResend }) {
4574
+ function UserActionInline({
4575
+ prompt,
4576
+ onSubmit,
4577
+ onCancel,
4578
+ onResend,
4579
+ onExpired
4580
+ }) {
4565
4581
  const [secondsLeft, expired] = useExpiryCountdown(prompt);
4582
+ react.useEffect(() => {
4583
+ if (expired && prompt.kind !== "notification") onExpired?.();
4584
+ }, [expired, onExpired, prompt.kind]);
4566
4585
  let body;
4567
- if (prompt.kind === "verification") {
4586
+ if (expired && prompt.kind !== "notification") {
4587
+ const note = {
4588
+ id: `${prompt.userActionId}-expired`,
4589
+ message: prompt.kind === "verification" ? "Verification Request Expired" : "User Form Expired"
4590
+ };
4591
+ body = /* @__PURE__ */ jsxRuntime.jsx(NotificationInline, { notification: note });
4592
+ } else if (prompt.kind === "verification") {
4568
4593
  body = /* @__PURE__ */ jsxRuntime.jsx(
4569
4594
  VerificationInline,
4570
4595
  {
@@ -4604,10 +4629,23 @@ function UserActionInline({ prompt, onSubmit, onCancel, onResend }) {
4604
4629
  }
4605
4630
  var SCROLL_THRESHOLD2 = 100;
4606
4631
  var USER_SCROLL_UP_EPSILON = 4;
4632
+ var PROMPT_KEY_SEPARATOR = "";
4633
+ function getPromptSlotKey(prompt) {
4634
+ return prompt.toolCallId || prompt.userActionId;
4635
+ }
4636
+ function getPromptViewKey(prompt) {
4637
+ return [
4638
+ getPromptSlotKey(prompt),
4639
+ prompt.userActionId,
4640
+ prompt.subAction ?? "",
4641
+ prompt.expirySeconds ?? "",
4642
+ prompt.message ?? ""
4643
+ ].join(PROMPT_KEY_SEPARATOR);
4644
+ }
4607
4645
  var MessageListV2 = react.forwardRef(
4608
4646
  function MessageListV22({
4609
4647
  messages,
4610
- isStreaming: _isStreaming = false,
4648
+ isStreaming = false,
4611
4649
  onEditUserMessage,
4612
4650
  onRetryUserMessage,
4613
4651
  onImageClick,
@@ -4629,6 +4667,7 @@ var MessageListV2 = react.forwardRef(
4629
4667
  const scrollInnerRef = react.useRef(null);
4630
4668
  const isNearBottomRef = react.useRef(true);
4631
4669
  const [showScrollBtn, setShowScrollBtn] = react.useState(false);
4670
+ const [expiredPromptViewState, setExpiredPromptViewState] = react.useState({});
4632
4671
  const prevCountRef = react.useRef(messages.length);
4633
4672
  const pauseStickUntilUserMessageRef = react.useRef(false);
4634
4673
  const followingBottomRef = react.useRef(true);
@@ -4639,6 +4678,81 @@ var MessageListV2 = react.forwardRef(
4639
4678
  if (!el) return 0;
4640
4679
  return el.scrollHeight - el.scrollTop - el.clientHeight;
4641
4680
  }, []);
4681
+ const messageActivityFingerprint = react.useMemo(() => {
4682
+ const last = messages[messages.length - 1];
4683
+ const promptFingerprint = (userActionPrompts ?? []).map((prompt) => `${getPromptViewKey(prompt)}:${prompt.status}`).join(PROMPT_KEY_SEPARATOR);
4684
+ const notificationFingerprint = (notifications ?? []).map((notification) => notification.id).join(PROMPT_KEY_SEPARATOR);
4685
+ if (!last) {
4686
+ return [
4687
+ 0,
4688
+ isStreaming ? "streaming" : "idle",
4689
+ promptFingerprint,
4690
+ notificationFingerprint
4691
+ ].join(PROMPT_KEY_SEPARATOR);
4692
+ }
4693
+ return [
4694
+ messages.length,
4695
+ isStreaming ? "streaming" : "idle",
4696
+ last.id,
4697
+ last.role,
4698
+ last.content ?? "",
4699
+ last.isStreaming ? "streaming" : "done",
4700
+ last.streamProgress ?? "",
4701
+ last.steps?.length ?? 0,
4702
+ last.errorDetails ?? "",
4703
+ promptFingerprint,
4704
+ notificationFingerprint
4705
+ ].join(PROMPT_KEY_SEPARATOR);
4706
+ }, [isStreaming, messages, notifications, userActionPrompts]);
4707
+ const handleUserActionExpired = react.useCallback(
4708
+ (promptKey) => {
4709
+ setExpiredPromptViewState((prev) => {
4710
+ if (prev[promptKey]) return prev;
4711
+ return {
4712
+ ...prev,
4713
+ [promptKey]: { baseline: messageActivityFingerprint, hidden: false }
4714
+ };
4715
+ });
4716
+ },
4717
+ [messageActivityFingerprint]
4718
+ );
4719
+ react.useEffect(() => {
4720
+ setExpiredPromptViewState((prev) => {
4721
+ let changed = false;
4722
+ const next = {};
4723
+ for (const [key, state] of Object.entries(prev)) {
4724
+ if (!state.hidden && state.baseline !== messageActivityFingerprint) {
4725
+ next[key] = { ...state, hidden: true };
4726
+ changed = true;
4727
+ } else {
4728
+ next[key] = state;
4729
+ }
4730
+ }
4731
+ return changed ? next : prev;
4732
+ });
4733
+ }, [messageActivityFingerprint]);
4734
+ react.useEffect(() => {
4735
+ const livePromptKeys = new Set((userActionPrompts ?? []).map(getPromptViewKey));
4736
+ setExpiredPromptViewState((prev) => {
4737
+ let changed = false;
4738
+ const next = {};
4739
+ for (const [key, state] of Object.entries(prev)) {
4740
+ if (livePromptKeys.has(key)) {
4741
+ next[key] = state;
4742
+ } else {
4743
+ changed = true;
4744
+ }
4745
+ }
4746
+ return changed ? next : prev;
4747
+ });
4748
+ }, [userActionPrompts]);
4749
+ const visibleUserActionPrompts = react.useMemo(
4750
+ () => userActionPrompts?.filter((prompt) => {
4751
+ const promptKey = getPromptViewKey(prompt);
4752
+ return !expiredPromptViewState[promptKey]?.hidden;
4753
+ }),
4754
+ [expiredPromptViewState, userActionPrompts]
4755
+ );
4642
4756
  const pinToBottom = react.useCallback((behavior = "instant") => {
4643
4757
  const el = scrollRef.current;
4644
4758
  if (!el) return;
@@ -4775,16 +4889,20 @@ var MessageListV2 = react.forwardRef(
4775
4889
  },
4776
4890
  note.id
4777
4891
  )),
4778
- userActionPrompts?.map((prompt) => /* @__PURE__ */ jsxRuntime.jsx(
4779
- UserActionInline,
4780
- {
4781
- prompt,
4782
- onSubmit: onSubmitUserAction ?? noop,
4783
- onCancel: onCancelUserAction ?? noop,
4784
- onResend: onResendUserAction ?? noop
4785
- },
4786
- prompt.toolCallId || prompt.userActionId
4787
- ))
4892
+ visibleUserActionPrompts?.map((prompt) => {
4893
+ const promptKey = getPromptViewKey(prompt);
4894
+ return /* @__PURE__ */ jsxRuntime.jsx(
4895
+ UserActionInline,
4896
+ {
4897
+ prompt,
4898
+ onSubmit: onSubmitUserAction ?? noop,
4899
+ onCancel: onCancelUserAction ?? noop,
4900
+ onResend: onResendUserAction ?? noop,
4901
+ onExpired: () => handleUserActionExpired(promptKey)
4902
+ },
4903
+ promptKey
4904
+ );
4905
+ })
4788
4906
  ]
4789
4907
  }
4790
4908
  )