@paymanai/payman-ask-sdk 4.0.25 → 4.0.27

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.
@@ -295,6 +295,8 @@ function getEventMessage(event) {
295
295
  }
296
296
  case "RUN_IN_PROGRESS":
297
297
  return event.partialText || "Thinking...";
298
+ case "LLM_CALL_STARTED":
299
+ return event.description || "";
298
300
  case "RUN_COMPLETED":
299
301
  return "Agent run completed";
300
302
  case "RUN_FAILED":
@@ -432,7 +434,8 @@ function createInitialV2State() {
432
434
  finalData: void 0,
433
435
  steps: [],
434
436
  stepCounter: 0,
435
- currentExecutingStepId: void 0
437
+ currentExecutingStepId: void 0,
438
+ trailingActivity: false
436
439
  };
437
440
  }
438
441
  function upsertUserAction(state, req) {
@@ -454,6 +457,7 @@ function processStreamEventV2(rawEvent, state) {
454
457
  if (typeof eventType === "string" && eventType.toUpperCase() === "KEEP_ALIVE") {
455
458
  if (event.executionId) state.executionId = event.executionId;
456
459
  if (event.sessionId) state.sessionId = event.sessionId;
460
+ if (state.finalResponse) state.trailingActivity = true;
457
461
  const description = typeof event.description === "string" ? event.description : "";
458
462
  if (description) {
459
463
  for (let i = state.steps.length - 1; i >= 0; i--) {
@@ -488,7 +492,12 @@ function processStreamEventV2(rawEvent, state) {
488
492
  state.lastEventType = eventType;
489
493
  break;
490
494
  }
495
+ case "LLM_CALL_STARTED":
496
+ if (state.finalResponse) state.trailingActivity = true;
497
+ state.lastEventType = eventType;
498
+ break;
491
499
  case "INTENT_STARTED": {
500
+ if (state.finalResponse) state.trailingActivity = true;
492
501
  const stepId = `step-${state.stepCounter++}`;
493
502
  state.steps.push({
494
503
  id: stepId,
@@ -504,6 +513,7 @@ function processStreamEventV2(rawEvent, state) {
504
513
  break;
505
514
  }
506
515
  case "INTENT_COMPLETED": {
516
+ if (state.finalResponse) state.trailingActivity = true;
507
517
  const intentStep = state.steps.find((s2) => s2.eventType === "INTENT_STARTED" && s2.status === "in_progress");
508
518
  if (intentStep) {
509
519
  intentStep.status = "completed";
@@ -535,6 +545,7 @@ function processStreamEventV2(rawEvent, state) {
535
545
  step2.status = "completed";
536
546
  }
537
547
  });
548
+ state.trailingActivity = false;
538
549
  state.lastEventType = eventType;
539
550
  break;
540
551
  }
@@ -606,6 +617,7 @@ function processStreamEventV2(rawEvent, state) {
606
617
  case "WORKFLOW_ERROR":
607
618
  state.hasError = true;
608
619
  state.errorMessage = event.errorMessage || event.message || "Workflow error";
620
+ state.trailingActivity = false;
609
621
  state.lastEventType = eventType;
610
622
  break;
611
623
  // ---- K2 pipeline stage lifecycle events ----
@@ -894,7 +906,9 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
894
906
  const latestUsefulStep = [...state.steps].reverse().find(
895
907
  (s2) => s2.message && !isBlandStatus(s2.message)
896
908
  );
897
- const currentMessage = useful(activeStep?.message) ?? useful(lastInProgressStep?.message) ?? latestUsefulStep?.message ?? useful(getEventMessage(event)) ?? // Last-resort: every candidate is bland (very first event,
909
+ const eventTypeUpper = typeof event.eventType === "string" ? event.eventType.toUpperCase() : "";
910
+ const liveEventLabel = eventTypeUpper === "KEEP_ALIVE" || eventTypeUpper === "LLM_CALL_STARTED" ? useful(getEventMessage(event)) : void 0;
911
+ const currentMessage = useful(activeStep?.message) ?? useful(lastInProgressStep?.message) ?? liveEventLabel ?? latestUsefulStep?.message ?? useful(getEventMessage(event)) ?? // Last-resort: every candidate is bland (very first event,
898
912
  // nothing useful seen yet). Render the bland label so the
899
913
  // bubble isn't blank.
900
914
  activeStep?.message ?? lastInProgressStep?.message ?? getEventMessage(event);
@@ -919,6 +933,7 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
919
933
  streamingContent: state.finalResponse,
920
934
  content: "",
921
935
  currentMessage,
936
+ hasTrailingActivity: state.trailingActivity,
922
937
  streamProgress: "processing",
923
938
  isError: false,
924
939
  steps: [...state.steps],
@@ -1138,6 +1153,9 @@ function isUserActionExpired(prompt) {
1138
1153
  return left !== void 0 && left <= 0;
1139
1154
  }
1140
1155
  var EMPTY_USER_ACTION_STATE2 = { prompts: [], notifications: [] };
1156
+ function promptSlotKey(p) {
1157
+ return p.toolCallId || p.userActionId;
1158
+ }
1141
1159
  function upsertPrompt(prompts, req) {
1142
1160
  const idx = prompts.findIndex(
1143
1161
  (p) => req.toolCallId ? p.toolCallId === req.toolCallId : p.userActionId === req.userActionId
@@ -1184,6 +1202,7 @@ function useChatV2(config, callbacks = {}) {
1184
1202
  configRef.current = config;
1185
1203
  const messagesRef = react.useRef(messages);
1186
1204
  messagesRef.current = messages;
1205
+ const pendingSubmissionsRef = react.useRef(/* @__PURE__ */ new Map());
1187
1206
  const storeAwareSetMessages = react.useCallback(
1188
1207
  (updater) => {
1189
1208
  const streamUserId = streamUserIdRef.current;
@@ -1218,6 +1237,8 @@ function useChatV2(config, callbacks = {}) {
1218
1237
  if (!config.userId) return EMPTY_USER_ACTION_STATE2;
1219
1238
  return activeStreamStore.get(config.userId)?.userActionState ?? EMPTY_USER_ACTION_STATE2;
1220
1239
  });
1240
+ const userActionStateRef = react.useRef(userActionState);
1241
+ userActionStateRef.current = userActionState;
1221
1242
  const storeAwareSetUserActionState = react.useCallback(
1222
1243
  (updater) => {
1223
1244
  const streamUserId = streamUserIdRef.current;
@@ -1245,6 +1266,12 @@ function useChatV2(config, callbacks = {}) {
1245
1266
  onExecutionTraceClick: (data) => callbacksRef.current.onExecutionTraceClick?.(data),
1246
1267
  onSessionIdChange: (sessionId) => callbacksRef.current.onSessionIdChange?.(sessionId),
1247
1268
  onUserActionRequired: (request) => {
1269
+ const requestSlotKey = promptSlotKey(request);
1270
+ for (const [pendingId, slotKey] of pendingSubmissionsRef.current) {
1271
+ if (slotKey === requestSlotKey) {
1272
+ pendingSubmissionsRef.current.delete(pendingId);
1273
+ }
1274
+ }
1248
1275
  storeAwareSetUserActionState((prev) => ({
1249
1276
  ...prev,
1250
1277
  prompts: upsertPrompt(prev.prompts, request)
@@ -1256,6 +1283,28 @@ function useChatV2(config, callbacks = {}) {
1256
1283
  (prev) => prev.notifications.some((n) => n.id === notification.id) ? prev : { ...prev, notifications: [...prev.notifications, notification] }
1257
1284
  );
1258
1285
  callbacksRef.current.onUserNotification?.(notification);
1286
+ },
1287
+ // A submitted-but-unconfirmed prompt (see `submitUserAction`) is only
1288
+ // safe to drop once the stream has demonstrably moved on. `onEvent`
1289
+ // in useStreamManagerV2 calls `onStepsUpdate` for *every* processed
1290
+ // stream event, unconditionally — so the first time this fires
1291
+ // after a submission, the event in hand is either the rejection
1292
+ // retry (a fresh `USER_ACTION_REQUIRED`, which the handler above
1293
+ // already deleted this pending entry for, earlier in the very same
1294
+ // event) or genuine forward progress (RUN_IN_PROGRESS, a tool call,
1295
+ // content deltas, RUN_COMPLETED, ...). Anything still pending by
1296
+ // the time we get here therefore means the run resumed normally —
1297
+ // clear it.
1298
+ onStepsUpdate: (steps) => {
1299
+ if (pendingSubmissionsRef.current.size > 0) {
1300
+ const resolved = [...pendingSubmissionsRef.current.keys()];
1301
+ pendingSubmissionsRef.current.clear();
1302
+ storeAwareSetUserActionState((prev) => ({
1303
+ ...prev,
1304
+ prompts: prev.prompts.filter((p) => !resolved.includes(p.userActionId))
1305
+ }));
1306
+ }
1307
+ callbacksRef.current.onStepsUpdate?.(steps);
1259
1308
  }
1260
1309
  // eslint-disable-next-line react-hooks/exhaustive-deps
1261
1310
  }), []);
@@ -1391,6 +1440,7 @@ function useChatV2(config, callbacks = {}) {
1391
1440
  [storeAwareSetUserActionState]
1392
1441
  );
1393
1442
  const removePrompt = react.useCallback((userActionId) => {
1443
+ pendingSubmissionsRef.current.delete(userActionId);
1394
1444
  storeAwareSetUserActionState((prev) => ({
1395
1445
  ...prev,
1396
1446
  prompts: prev.prompts.filter((p) => p.userActionId !== userActionId)
@@ -1401,7 +1451,10 @@ function useChatV2(config, callbacks = {}) {
1401
1451
  setPromptStatus(userActionId, "submitting");
1402
1452
  try {
1403
1453
  await submitUserAction(configRef.current, userActionId, content);
1404
- removePrompt(userActionId);
1454
+ const prompt = userActionStateRef.current.prompts.find(
1455
+ (p) => p.userActionId === userActionId
1456
+ );
1457
+ pendingSubmissionsRef.current.set(userActionId, prompt ? promptSlotKey(prompt) : userActionId);
1405
1458
  } catch (error) {
1406
1459
  if (error instanceof UserActionStaleError) {
1407
1460
  setPromptStatus(userActionId, "stale");
@@ -1412,7 +1465,7 @@ function useChatV2(config, callbacks = {}) {
1412
1465
  throw error;
1413
1466
  }
1414
1467
  },
1415
- [removePrompt, setPromptStatus]
1468
+ [setPromptStatus]
1416
1469
  );
1417
1470
  const cancelUserAction2 = react.useCallback(
1418
1471
  async (userActionId) => {
@@ -2636,6 +2689,7 @@ function VerificationBody({
2636
2689
  expired,
2637
2690
  pal,
2638
2691
  accent,
2692
+ isDark,
2639
2693
  onSubmit,
2640
2694
  onCancel,
2641
2695
  onResend
@@ -2698,7 +2752,11 @@ function VerificationBody({
2698
2752
  } catch {
2699
2753
  }
2700
2754
  }, [locked, onResend, prompt.userActionId, resendSec]);
2701
- const description = prompt.message?.trim() || (isNumeric ? `Enter the ${codeLen}-digit code to continue` : "Enter the verification code to continue");
2755
+ const promptMessage = prompt.message?.trim();
2756
+ const description = promptMessage || (isNumeric ? `Enter the ${codeLen}-digit code to continue` : "Enter the verification code to continue");
2757
+ const renderMarkdown = !!promptMessage && prompt.metadata?.["payman/messageFormat"] === "markdown";
2758
+ const mdStyles = isDark ? MD_STYLES_DARK : MD_STYLES_LIGHT;
2759
+ const mdRules = react.useMemo(() => makeMdRules(isDark, accent), [isDark, accent]);
2702
2760
  return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: ub.bodyWrap, children: [
2703
2761
  /* @__PURE__ */ jsxRuntime.jsxs(
2704
2762
  reactNative.ScrollView,
@@ -2708,7 +2766,7 @@ function VerificationBody({
2708
2766
  keyboardShouldPersistTaps: "handled",
2709
2767
  showsVerticalScrollIndicator: false,
2710
2768
  children: [
2711
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [ub.desc, { color: pal.muted }], children: description }),
2769
+ renderMarkdown ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: ub.messageBlock, children: /* @__PURE__ */ jsxRuntime.jsx(Markdown__default.default, { style: mdStyles, rules: mdRules, children: description.replace(/\\n/g, "\n") }) }) : /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [ub.desc, { color: pal.muted }], children: description }),
2712
2770
  isNumeric ? /* @__PURE__ */ jsxRuntime.jsx(
2713
2771
  CodeInput,
2714
2772
  {
@@ -3047,6 +3105,7 @@ function UserActionSheet({
3047
3105
  expired,
3048
3106
  pal,
3049
3107
  accent,
3108
+ isDark,
3050
3109
  onSubmit,
3051
3110
  onCancel,
3052
3111
  onResend