@agent-native/core 0.84.51 → 0.84.52

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.
Files changed (42) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +8 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/agent/run-store.ts +33 -6
  5. package/corpus/core/src/client/AssistantChat.tsx +84 -23
  6. package/corpus/core/src/client/agent-chat-adapter.ts +19 -0
  7. package/corpus/core/src/client/blocks/library/DiffBlock.tsx +7 -5
  8. package/corpus/core/src/client/session-replay.ts +170 -47
  9. package/corpus/core/src/client/sse-event-processor.ts +75 -14
  10. package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +5 -0
  11. package/corpus/templates/analytics/changelog/2026-07-02-agent-chat-can-keep-working-through-longer-data-queries-inst.md +6 -0
  12. package/corpus/templates/analytics/changelog/2026-07-02-session-replay-playback-recovers-from-failed-snapshot-uploads.md +6 -0
  13. package/corpus/templates/analytics/netlify.toml +3 -0
  14. package/corpus/templates/analytics/server/lib/session-replay.ts +9 -5
  15. package/corpus/templates/analytics/server/plugins/agent-chat.ts +3 -0
  16. package/corpus/templates/plan/changelog/2026-07-02-agent-chat-can-keep-working-through-longer-visual-plan-updat.md +6 -0
  17. package/corpus/templates/plan/netlify.toml +3 -0
  18. package/corpus/templates/plan/server/plugins/agent-chat.ts +4 -0
  19. package/dist/agent/run-store.d.ts.map +1 -1
  20. package/dist/agent/run-store.js +30 -6
  21. package/dist/agent/run-store.js.map +1 -1
  22. package/dist/client/AssistantChat.d.ts.map +1 -1
  23. package/dist/client/AssistantChat.js +64 -13
  24. package/dist/client/AssistantChat.js.map +1 -1
  25. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  26. package/dist/client/agent-chat-adapter.js +14 -0
  27. package/dist/client/agent-chat-adapter.js.map +1 -1
  28. package/dist/client/blocks/library/DiffBlock.d.ts.map +1 -1
  29. package/dist/client/blocks/library/DiffBlock.js +6 -5
  30. package/dist/client/blocks/library/DiffBlock.js.map +1 -1
  31. package/dist/client/session-replay.d.ts.map +1 -1
  32. package/dist/client/session-replay.js +134 -39
  33. package/dist/client/session-replay.js.map +1 -1
  34. package/dist/client/sse-event-processor.d.ts +25 -0
  35. package/dist/client/sse-event-processor.d.ts.map +1 -1
  36. package/dist/client/sse-event-processor.js +50 -13
  37. package/dist/client/sse-event-processor.js.map +1 -1
  38. package/dist/collab/routes.d.ts +1 -1
  39. package/dist/notifications/routes.d.ts +1 -1
  40. package/dist/observability/routes.d.ts +5 -5
  41. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  42. package/package.json +1 -1
@@ -329,7 +329,7 @@ export function resolveAssistantChatRunningStatusLabel({ runningActivityLabel, i
329
329
  if (isAutoResuming)
330
330
  return "Resuming";
331
331
  if (isReconnecting && hasReconnectContent)
332
- return "Continuing";
332
+ return "Still working";
333
333
  return "Thinking";
334
334
  }
335
335
  export const CHAT_STORAGE_PREFIX = "agent-chat:";
@@ -828,7 +828,7 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
828
828
  const textStreaming = showRunningInUI || externalStreaming;
829
829
  // A revealed activity label wins; otherwise keep recovery states calm and
830
830
  // product-facing. Reconnect is transport machinery, so normal replay reads as
831
- // "Continuing" instead of exposing "Reconnecting" mid-chat.
831
+ // ongoing work instead of exposing "Reconnecting" mid-chat.
832
832
  const runningStatusLabel = resolveAssistantChatRunningStatusLabel({
833
833
  runningActivityLabel,
834
834
  isAutoResuming,
@@ -1130,6 +1130,24 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
1130
1130
  const streamReconnect = async () => {
1131
1131
  let noProgressDuringReconnect = false;
1132
1132
  let latestContent = [];
1133
+ const preparingActionState = {};
1134
+ const sameRunStillActive = async () => {
1135
+ try {
1136
+ const res = await fetch(`${apiUrl}/runs/active?threadId=${encodeURIComponent(threadId)}`, { signal: abortCtrl.signal });
1137
+ if (!res.ok)
1138
+ return "unknown";
1139
+ const info = (await res.json());
1140
+ return info.active === true &&
1141
+ String(info.runId ?? "") === runId &&
1142
+ info.status === "running" &&
1143
+ !activeRunLooksStale(info)
1144
+ ? "active"
1145
+ : "inactive";
1146
+ }
1147
+ catch {
1148
+ return "unknown";
1149
+ }
1150
+ };
1133
1151
  const threadPollInterval = afterSeq > 0
1134
1152
  ? window.setInterval(() => {
1135
1153
  if (reconnectRunIdRef.current !== runId)
@@ -1138,11 +1156,22 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
1138
1156
  }, 2000)
1139
1157
  : undefined;
1140
1158
  try {
1141
- const sseRes = await fetch(`${apiUrl}/runs/${encodeURIComponent(runId)}/events?after=${afterSeq}`, { signal: abortCtrl.signal });
1142
- if (sseRes.ok && sseRes.body) {
1143
- const content = [];
1144
- latestContent = content;
1145
- const toolCallCounter = { value: 0 };
1159
+ const content = [];
1160
+ latestContent = content;
1161
+ const toolCallCounter = { value: 0 };
1162
+ while (reconnectRunIdRef.current === runId &&
1163
+ !abortCtrl.signal.aborted) {
1164
+ const reconnectAfterSeq = resolveReconnectAfterSeq(threadId, runId);
1165
+ reconnectTailOnlyRef.current = reconnectAfterSeq > 0;
1166
+ const sseRes = await fetch(`${apiUrl}/runs/${encodeURIComponent(runId)}/events?after=${reconnectAfterSeq}`, { signal: abortCtrl.signal });
1167
+ if (!sseRes.ok || !sseRes.body) {
1168
+ const activeState = await sameRunStillActive();
1169
+ if (activeState !== "inactive") {
1170
+ await new Promise((resolve) => window.setTimeout(resolve, 250));
1171
+ continue;
1172
+ }
1173
+ break;
1174
+ }
1146
1175
  let rafPending = false;
1147
1176
  let latestSnapshot = [];
1148
1177
  const scheduleUpdate = (snapshot) => {
@@ -1155,13 +1184,35 @@ const AssistantChatInner = forwardRef(function AssistantChatInner({ emptyStateTe
1155
1184
  setReconnectContent(latestSnapshot);
1156
1185
  });
1157
1186
  };
1158
- await readSSEStreamRaw(sseRes.body, content, toolCallCounter, tabId, scheduleUpdate, (seq) => {
1159
- markReconnectProgress();
1160
- updateActiveRunSeq(seq);
1161
- });
1162
- if (afterSeq === 0) {
1163
- setReconnectContent([...content]);
1187
+ try {
1188
+ await readSSEStreamRaw(sseRes.body, content, toolCallCounter, tabId, scheduleUpdate, (seq) => {
1189
+ markReconnectProgress();
1190
+ updateActiveRunSeq(seq);
1191
+ }, { preparingActionState });
1192
+ if (reconnectAfterSeq === 0) {
1193
+ setReconnectContent([...content]);
1194
+ }
1195
+ break;
1164
1196
  }
1197
+ catch (err) {
1198
+ if (err instanceof AgentAutoContinueSignal &&
1199
+ err.reason === "stream_ended") {
1200
+ if (reconnectAfterSeq === 0) {
1201
+ setReconnectContent([...content]);
1202
+ }
1203
+ const activeState = await sameRunStillActive();
1204
+ if (activeState !== "inactive") {
1205
+ await new Promise((resolve) => window.setTimeout(resolve, 250));
1206
+ continue;
1207
+ }
1208
+ }
1209
+ throw err;
1210
+ }
1211
+ }
1212
+ if (reconnectTimedOut && abortCtrl.signal.aborted) {
1213
+ const timeoutError = new Error("Reconnect timed out");
1214
+ timeoutError.name = "AbortError";
1215
+ throw timeoutError;
1165
1216
  }
1166
1217
  }
1167
1218
  catch (err) {