@truefoundry/assistant-ui-runtime 0.1.3-rc.1 → 0.1.3-rc.2

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
@@ -2830,7 +2830,7 @@ function bindAbort(session, abortSignal) {
2830
2830
  abortSignal.addEventListener("abort", onAbort, { once: true });
2831
2831
  return onAbort;
2832
2832
  }
2833
- async function* streamTurnContent(session, foldState, options, abortSignal, groupRootBaseline) {
2833
+ async function* streamTurnContent(session, foldState, options, abortSignal, groupRootBaseline, onTurnIdAvailable) {
2834
2834
  const previousTurnId = options.previousTurnId === null ? void 0 : options.previousTurnId ?? "auto";
2835
2835
  const turn = session.prepareTurn({
2836
2836
  input: buildTurnInput(options),
@@ -2841,7 +2841,8 @@ async function* streamTurnContent(session, foldState, options, abortSignal, grou
2841
2841
  return;
2842
2842
  }
2843
2843
  try {
2844
- yield* streamTurnEvents(
2844
+ let turnIdNotified = false;
2845
+ for await (const update of streamTurnEvents(
2845
2846
  turn.execute(
2846
2847
  { stream: true },
2847
2848
  {
@@ -2851,7 +2852,16 @@ async function* streamTurnContent(session, foldState, options, abortSignal, grou
2851
2852
  ),
2852
2853
  foldState,
2853
2854
  groupRootBaseline
2854
- );
2855
+ )) {
2856
+ if (!turnIdNotified && turn.id != null) {
2857
+ onTurnIdAvailable?.(turn.id);
2858
+ turnIdNotified = true;
2859
+ }
2860
+ yield update;
2861
+ }
2862
+ if (!turnIdNotified && turn.id != null) {
2863
+ onTurnIdAvailable?.(turn.id);
2864
+ }
2855
2865
  } catch (error) {
2856
2866
  if (error instanceof Error && error.name === "AbortError") {
2857
2867
  return;
@@ -3067,7 +3077,7 @@ function useTrueFoundryAgentMessages({
3067
3077
  [snapshot, projectOptions]
3068
3078
  );
3069
3079
  const runStream = useCallback2(
3070
- (createStream, turnId, isContinuation) => {
3080
+ (createStream, turnIdRef, isContinuation) => {
3071
3081
  const streamGeneration = ++streamGenerationRef.current;
3072
3082
  abortControllerRef.current?.abort();
3073
3083
  const abortController = new AbortController();
@@ -3083,11 +3093,14 @@ function useTrueFoundryAgentMessages({
3083
3093
  if (pending == null || streamGeneration !== streamGenerationRef.current) {
3084
3094
  return;
3085
3095
  }
3086
- const { update, turnId: pendingTurnId, isContinuation: pendingIsContinuation } = pending;
3096
+ const { update, isContinuation: pendingIsContinuation } = pending;
3087
3097
  setSnapshot(
3088
3098
  (prev) => replaceSessionSnapshot(prev, {
3089
3099
  activeStream: {
3090
- turnId: pendingTurnId,
3100
+ // Read from the ref so we always use the latest ID,
3101
+ // including any gateway ID that arrived after the RAf
3102
+ // was scheduled.
3103
+ turnId: turnIdRef.current,
3091
3104
  update,
3092
3105
  isContinuation: pendingIsContinuation
3093
3106
  }
@@ -3095,7 +3108,7 @@ function useTrueFoundryAgentMessages({
3095
3108
  );
3096
3109
  };
3097
3110
  const applyStreamUpdate = (update) => {
3098
- pendingStreamUpdate = { update, turnId, isContinuation };
3111
+ pendingStreamUpdate = { update, isContinuation };
3099
3112
  if (streamUpdateRaf == null) {
3100
3113
  streamUpdateRaf = requestAnimationFrame(flushPendingStreamUpdate);
3101
3114
  }
@@ -3208,7 +3221,7 @@ function useTrueFoundryAgentMessages({
3208
3221
  void 0,
3209
3222
  loadedSnapshot.groupRootBaseline
3210
3223
  ),
3211
- turn.id,
3224
+ { current: turn.id },
3212
3225
  isContinuation
3213
3226
  ).catch(() => void 0);
3214
3227
  }
@@ -3247,6 +3260,7 @@ function useTrueFoundryAgentMessages({
3247
3260
  const isContinuation = "inputs" in options || "resumeMcpAuth" in options && options.resumeMcpAuth === true;
3248
3261
  const continuationTurnId = snapshotRef.current.activeStream?.turnId;
3249
3262
  const turnId = isContinuation && continuationTurnId != null ? continuationTurnId : generateId();
3263
+ const turnIdRef = { current: turnId };
3250
3264
  if ("inputs" in options) {
3251
3265
  applyUserToolResponsesToFold(
3252
3266
  snapshotRef.current.fold,
@@ -3325,10 +3339,25 @@ function useTrueFoundryAgentMessages({
3325
3339
  ...streamHeaders
3326
3340
  },
3327
3341
  signal,
3328
- groupRootBaseline
3342
+ groupRootBaseline,
3343
+ // Rename the optimistic local ID to the gateway turn ID
3344
+ // so that edit/retry can resolve the turn via the gateway.
3345
+ (gatewayTurnId) => {
3346
+ const oldId = turnIdRef.current;
3347
+ if (gatewayTurnId === oldId) return;
3348
+ turnIdRef.current = gatewayTurnId;
3349
+ const renamePendingUser = (prev) => {
3350
+ if (prev.pendingUser?.turnId !== oldId) return prev;
3351
+ return replaceSessionSnapshot(prev, {
3352
+ pendingUser: { ...prev.pendingUser, turnId: gatewayTurnId }
3353
+ });
3354
+ };
3355
+ snapshotRef.current = renamePendingUser(snapshotRef.current);
3356
+ setSnapshot(renamePendingUser);
3357
+ }
3329
3358
  );
3330
3359
  },
3331
- turnId,
3360
+ turnIdRef,
3332
3361
  isContinuation
3333
3362
  );
3334
3363
  },
@@ -3414,7 +3443,7 @@ function useTrueFoundryAgentMessages({
3414
3443
  void 0,
3415
3444
  snapshotRef.current.groupRootBaseline
3416
3445
  ),
3417
- turn.id,
3446
+ { current: turn.id },
3418
3447
  true
3419
3448
  );
3420
3449
  }, [runStream]);