@agent-native/core 0.84.23 → 0.84.25

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 (66) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +12 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/agent/production-agent.ts +8 -6
  5. package/corpus/core/src/agent/run-manager.ts +57 -6
  6. package/corpus/core/src/client/AssistantChat.tsx +82 -15
  7. package/corpus/core/src/client/active-run-state.ts +22 -0
  8. package/corpus/core/src/client/chat/message-components.tsx +2 -1
  9. package/corpus/core/src/client/chat/tool-call-display.tsx +18 -2
  10. package/corpus/core/src/client/sse-event-processor.ts +196 -51
  11. package/corpus/core/src/client/tool-display.ts +1 -1
  12. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +15 -13
  13. package/corpus/templates/clips/.agents/skills/video-sharing/SKILL.md +4 -2
  14. package/corpus/templates/clips/app/components/player/share-dialog.tsx +11 -2
  15. package/corpus/templates/clips/app/i18n/ar-SA.ts +4 -0
  16. package/corpus/templates/clips/app/i18n/de-DE.ts +4 -0
  17. package/corpus/templates/clips/app/i18n/en-US.ts +4 -0
  18. package/corpus/templates/clips/app/i18n/es-ES.ts +4 -0
  19. package/corpus/templates/clips/app/i18n/fr-FR.ts +4 -0
  20. package/corpus/templates/clips/app/i18n/hi-IN.ts +4 -0
  21. package/corpus/templates/clips/app/i18n/ja-JP.ts +4 -0
  22. package/corpus/templates/clips/app/i18n/ko-KR.ts +4 -0
  23. package/corpus/templates/clips/app/i18n/pt-BR.ts +4 -0
  24. package/corpus/templates/clips/app/i18n/zh-CN.ts +4 -0
  25. package/corpus/templates/clips/app/i18n/zh-TW.ts +4 -0
  26. package/corpus/templates/clips/app/routes/embed.$shareId.tsx +31 -3
  27. package/corpus/templates/clips/changelog/2026-07-01-clip-embeds-now-render-as-a-clean-video-only-player-without-.md +6 -0
  28. package/corpus/templates/clips/changelog/2026-07-01-shared-clips-can-now-copy-a-ready-to-send-prompt-that-tells-.md +6 -0
  29. package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -1
  30. package/corpus/templates/clips/chrome-extension/src/github-preview-content.ts +2 -2
  31. package/corpus/templates/clips/chrome-extension/src/github-preview.ts +41 -31
  32. package/dist/agent/production-agent.d.ts.map +1 -1
  33. package/dist/agent/production-agent.js +8 -6
  34. package/dist/agent/production-agent.js.map +1 -1
  35. package/dist/agent/run-manager.d.ts.map +1 -1
  36. package/dist/agent/run-manager.js +56 -4
  37. package/dist/agent/run-manager.js.map +1 -1
  38. package/dist/client/AssistantChat.d.ts +2 -1
  39. package/dist/client/AssistantChat.d.ts.map +1 -1
  40. package/dist/client/AssistantChat.js +74 -18
  41. package/dist/client/AssistantChat.js.map +1 -1
  42. package/dist/client/active-run-state.d.ts +2 -0
  43. package/dist/client/active-run-state.d.ts.map +1 -1
  44. package/dist/client/active-run-state.js +17 -0
  45. package/dist/client/active-run-state.js.map +1 -1
  46. package/dist/client/chat/message-components.d.ts.map +1 -1
  47. package/dist/client/chat/message-components.js +3 -1
  48. package/dist/client/chat/message-components.js.map +1 -1
  49. package/dist/client/chat/tool-call-display.d.ts +3 -1
  50. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  51. package/dist/client/chat/tool-call-display.js +8 -8
  52. package/dist/client/chat/tool-call-display.js.map +1 -1
  53. package/dist/client/sse-event-processor.d.ts +1 -0
  54. package/dist/client/sse-event-processor.d.ts.map +1 -1
  55. package/dist/client/sse-event-processor.js +163 -45
  56. package/dist/client/sse-event-processor.js.map +1 -1
  57. package/dist/client/tool-display.js +1 -1
  58. package/dist/client/tool-display.js.map +1 -1
  59. package/dist/collab/awareness.d.ts +2 -2
  60. package/dist/collab/awareness.d.ts.map +1 -1
  61. package/dist/collab/routes.d.ts +1 -1
  62. package/dist/file-upload/actions/upload-image.d.ts +2 -2
  63. package/dist/notifications/routes.d.ts +3 -3
  64. package/dist/observability/routes.d.ts +6 -6
  65. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  66. package/package.json +1 -1
@@ -54,6 +54,14 @@ function isPreparingActionActivity(ev) {
54
54
  const label = (ev.label ?? "").trim().toLowerCase();
55
55
  return label.startsWith("preparing ") && label.includes(" action");
56
56
  }
57
+ function isMeaningfulProgressEvent(ev, actionPreparationProgress) {
58
+ if (ev.type === "stream_keepalive")
59
+ return false;
60
+ if (ev.type === "activity" && isPreparingActionActivity(ev)) {
61
+ return actionPreparationProgress === true;
62
+ }
63
+ return true;
64
+ }
57
65
  function baseActivityLabel(ev, tool) {
58
66
  return humanizeToolLabelText(ev.label ?? "Working", tool);
59
67
  }
@@ -110,16 +118,25 @@ function updatePreparingActionState(state, ev, now) {
110
118
  if (ev.type === "activity" && isPreparingActionActivity(ev)) {
111
119
  const tool = ev.tool?.trim() || undefined;
112
120
  if (!tool)
113
- return;
121
+ return false;
114
122
  if (state.tool !== tool || state.startedAt === undefined) {
115
123
  state.tool = tool;
116
124
  state.startedAt = now;
125
+ state.lastProgressAt = undefined;
126
+ state.lastProgressBytes = undefined;
117
127
  }
118
- // Every tool-input activity is a throttled proof the model is still
119
- // streaming this action's argument. Treat it as progress so large inputs
120
- // that take many seconds/minutes to stream are NOT flagged as stalled.
121
- state.lastProgressAt = now;
122
- return;
128
+ const progressBytes = activityProgressBytes(ev);
129
+ const previousBytes = state.lastProgressBytes ?? 0;
130
+ if (progressBytes !== undefined) {
131
+ state.lastProgressBytes = Math.max(previousBytes, progressBytes);
132
+ }
133
+ if (progressBytes !== undefined && progressBytes > previousBytes) {
134
+ // A byte increase is proof the model is still streaming this action's
135
+ // argument. Repeated zero-byte prep activity is only a heartbeat.
136
+ state.lastProgressAt = now;
137
+ return true;
138
+ }
139
+ return false;
123
140
  }
124
141
  if (ev.type === "clear" ||
125
142
  ev.type === "text" ||
@@ -131,7 +148,9 @@ function updatePreparingActionState(state, ev, now) {
131
148
  state.tool = undefined;
132
149
  state.startedAt = undefined;
133
150
  state.lastProgressAt = undefined;
151
+ state.lastProgressBytes = undefined;
134
152
  }
153
+ return undefined;
135
154
  }
136
155
  function hasStalledPreparingAction(state, now) {
137
156
  // Fire only when a tool input has gone SILENT — no further streaming deltas
@@ -140,8 +159,9 @@ function hasStalledPreparingAction(state, now) {
140
159
  // heartbeat, so an actively-streaming large output keeps resetting this and
141
160
  // survives; a genuinely stuck prep (keepalive-only, no deltas) trips it.
142
161
  return (state.tool !== undefined &&
143
- state.lastProgressAt !== undefined &&
144
- now - state.lastProgressAt >= SSE_ACTION_PREPARATION_STALL_TIMEOUT_MS);
162
+ state.startedAt !== undefined &&
163
+ now - (state.lastProgressAt ?? state.startedAt) >=
164
+ SSE_ACTION_PREPARATION_STALL_TIMEOUT_MS);
145
165
  }
146
166
  async function readChunkWithProgressTimeout(reader, lastMeaningfulEventAt) {
147
167
  const elapsed = Date.now() - lastMeaningfulEventAt;
@@ -284,6 +304,66 @@ function pendingToolNames(content) {
284
304
  }
285
305
  return { activity: [...activity], running: [...running] };
286
306
  }
307
+ function contentSnapshot(content) {
308
+ return content.map((part) => {
309
+ if (part.type === "text")
310
+ return { ...part };
311
+ return {
312
+ ...part,
313
+ args: { ...part.args },
314
+ ...(part.mcpApp ? { mcpApp: { ...part.mcpApp } } : {}),
315
+ ...(part.chatUI ? { chatUI: { ...part.chatUI } } : {}),
316
+ ...(part.approval ? { approval: { ...part.approval } } : {}),
317
+ ...(part.structuredMeta
318
+ ? { structuredMeta: { ...part.structuredMeta } }
319
+ : {}),
320
+ };
321
+ });
322
+ }
323
+ function repeatSignatureValue(value) {
324
+ try {
325
+ return JSON.stringify(value);
326
+ }
327
+ catch {
328
+ return String(value ?? "");
329
+ }
330
+ }
331
+ function completedToolRepeatSignature(part) {
332
+ if (part.result === undefined ||
333
+ part.activity === true ||
334
+ part.approval ||
335
+ part.mcpApp ||
336
+ part.chatUI ||
337
+ part.structuredMeta) {
338
+ return null;
339
+ }
340
+ return [
341
+ part.toolName,
342
+ part.argsText,
343
+ repeatSignatureValue(part.args),
344
+ part.result,
345
+ part.isError === true ? "error" : "",
346
+ part.completedSideEffect === true ? "side-effect" : "",
347
+ ].join("\u0000");
348
+ }
349
+ function coalesceCompletedToolRepeat(content, completedIndex) {
350
+ const current = content[completedIndex];
351
+ const previous = content[completedIndex - 1];
352
+ if (!current ||
353
+ !previous ||
354
+ current.type !== "tool-call" ||
355
+ previous.type !== "tool-call") {
356
+ return;
357
+ }
358
+ const currentSignature = completedToolRepeatSignature(current);
359
+ if (!currentSignature ||
360
+ currentSignature !== completedToolRepeatSignature(previous)) {
361
+ return;
362
+ }
363
+ previous.repeatCount =
364
+ (previous.repeatCount ?? 1) + (current.repeatCount ?? 1);
365
+ content.splice(completedIndex, 1);
366
+ }
287
367
  function formatToolNames(tools) {
288
368
  const names = tools.map(humanizeToolName);
289
369
  if (names.length === 0)
@@ -366,7 +446,7 @@ export function processEvent(ev, content, toolCallCounter, tabId, state) {
366
446
  }
367
447
  return {
368
448
  action: "yield",
369
- result: { content: [...content] },
449
+ result: { content: contentSnapshot(content) },
370
450
  };
371
451
  }
372
452
  if (ev.type === "stream_keepalive") {
@@ -399,7 +479,7 @@ export function processEvent(ev, content, toolCallCounter, tabId, state) {
399
479
  }
400
480
  return {
401
481
  action: "yield",
402
- result: { content: [...content] },
482
+ result: { content: contentSnapshot(content) },
403
483
  };
404
484
  }
405
485
  if (ev.type === "tool_start") {
@@ -449,7 +529,7 @@ export function processEvent(ev, content, toolCallCounter, tabId, state) {
449
529
  }
450
530
  return {
451
531
  action: "yield",
452
- result: { content: [...content] },
532
+ result: { content: contentSnapshot(content) },
453
533
  };
454
534
  }
455
535
  if (ev.type === "approval_required") {
@@ -470,7 +550,7 @@ export function processEvent(ev, content, toolCallCounter, tabId, state) {
470
550
  }
471
551
  return {
472
552
  action: "yield",
473
- result: { content: [...content] },
553
+ result: { content: contentSnapshot(content) },
474
554
  };
475
555
  }
476
556
  if (ev.type === "tool_done") {
@@ -506,11 +586,12 @@ export function processEvent(ev, content, toolCallCounter, tabId, state) {
506
586
  if (part.activity !== true && part.isError !== true) {
507
587
  markCompletedToolAfterAssistantText(state, part.toolName);
508
588
  }
589
+ coalesceCompletedToolRepeat(content, doneIdx);
509
590
  }
510
591
  }
511
592
  return {
512
593
  action: "yield",
513
- result: { content: [...content] },
594
+ result: { content: contentSnapshot(content) },
514
595
  };
515
596
  }
516
597
  if (ev.type === "agent_call") {
@@ -538,7 +619,7 @@ export function processEvent(ev, content, toolCallCounter, tabId, state) {
538
619
  }
539
620
  return {
540
621
  action: "yield",
541
- result: { content: [...content] },
622
+ result: { content: contentSnapshot(content) },
542
623
  };
543
624
  }
544
625
  if (ev.type === "agent_call_text") {
@@ -555,7 +636,7 @@ export function processEvent(ev, content, toolCallCounter, tabId, state) {
555
636
  }
556
637
  return {
557
638
  action: "yield",
558
- result: { content: [...content] },
639
+ result: { content: contentSnapshot(content) },
559
640
  };
560
641
  }
561
642
  // ─── Agent task events (sub-agent chips) ─────────────────────────
@@ -591,7 +672,7 @@ export function processEvent(ev, content, toolCallCounter, tabId, state) {
591
672
  return {
592
673
  action: "missing_api_key",
593
674
  result: {
594
- content: [...content],
675
+ content: contentSnapshot(content),
595
676
  status: { type: "incomplete", reason: "error" },
596
677
  metadata: { custom: { runError } },
597
678
  },
@@ -693,7 +774,7 @@ export function processEvent(ev, content, toolCallCounter, tabId, state) {
693
774
  return {
694
775
  action: "error",
695
776
  result: {
696
- content: [...content],
777
+ content: contentSnapshot(content),
697
778
  status: { type: "incomplete", reason: "error" },
698
779
  metadata: { custom: { runError } },
699
780
  },
@@ -726,7 +807,7 @@ export function processEvent(ev, content, toolCallCounter, tabId, state) {
726
807
  return {
727
808
  action: "error",
728
809
  result: {
729
- content: [...content],
810
+ content: contentSnapshot(content),
730
811
  status: { type: "incomplete", reason: "error" },
731
812
  metadata: { custom: { runError } },
732
813
  },
@@ -743,7 +824,7 @@ export function processEvent(ev, content, toolCallCounter, tabId, state) {
743
824
  return {
744
825
  action: "done",
745
826
  result: {
746
- content: [...content],
827
+ content: contentSnapshot(content),
747
828
  status: { type: "complete", reason: "stop" },
748
829
  metadata: {
749
830
  custom: {
@@ -759,7 +840,7 @@ export function processEvent(ev, content, toolCallCounter, tabId, state) {
759
840
  }
760
841
  return {
761
842
  action: "done",
762
- result: { content: [...content] },
843
+ result: { content: contentSnapshot(content) },
763
844
  };
764
845
  }
765
846
  return { action: "continue" };
@@ -813,13 +894,28 @@ export async function* readSSEStream(body, content, toolCallCounter, tabId, onSe
813
894
  };
814
895
  try {
815
896
  while (true) {
816
- const { done, value } = await readChunkWithProgressTimeout(reader, lastMeaningfulEventAt);
897
+ let readResult;
898
+ try {
899
+ readResult = await readChunkWithProgressTimeout(reader, lastMeaningfulEventAt);
900
+ }
901
+ catch (err) {
902
+ if (err instanceof AgentAutoContinueSignal) {
903
+ throw new AgentAutoContinueSignal({
904
+ reason: err.reason,
905
+ maxIterations: err.maxIterations,
906
+ activityTrail: [...activityTrail],
907
+ errorInfo: err.errorInfo,
908
+ });
909
+ }
910
+ throw err;
911
+ }
912
+ const { done, value } = readResult;
817
913
  if (done)
818
914
  break;
819
915
  buf += decoder.decode(value, { stream: true });
820
916
  const lines = buf.split("\n");
821
917
  buf = lines.pop() ?? "";
822
- let sawDataEvent = false;
918
+ let sawProgressEvent = false;
823
919
  for (const line of lines) {
824
920
  if (!line.startsWith("data: "))
825
921
  continue;
@@ -833,10 +929,12 @@ export async function* readSSEStream(body, content, toolCallCounter, tabId, onSe
833
929
  catch {
834
930
  continue;
835
931
  }
836
- sawDataEvent = true;
837
932
  const now = Date.now();
838
- lastMeaningfulEventAt = now;
839
- updatePreparingActionState(preparingActionState, ev, now);
933
+ const actionPreparationProgress = updatePreparingActionState(preparingActionState, ev, now);
934
+ if (isMeaningfulProgressEvent(ev, actionPreparationProgress)) {
935
+ sawProgressEvent = true;
936
+ lastMeaningfulEventAt = now;
937
+ }
840
938
  // Track sequence number for reconnection
841
939
  if (ev.seq !== undefined && onSeq) {
842
940
  onSeq(ev.seq);
@@ -886,9 +984,12 @@ export async function* readSSEStream(body, content, toolCallCounter, tabId, onSe
886
984
  return;
887
985
  }
888
986
  }
889
- if (!sawDataEvent &&
987
+ if (!sawProgressEvent &&
890
988
  Date.now() - lastMeaningfulEventAt >= SSE_NO_PROGRESS_TIMEOUT_MS) {
891
- throw new AgentAutoContinueSignal({ reason: "no_progress" });
989
+ throw new AgentAutoContinueSignal({
990
+ reason: "no_progress",
991
+ activityTrail: [...activityTrail],
992
+ });
892
993
  }
893
994
  }
894
995
  }
@@ -933,14 +1034,28 @@ export async function readSSEStreamRaw(body, content, toolCallCounter, tabId, on
933
1034
  let emittedLatestContent = false;
934
1035
  try {
935
1036
  while (true) {
936
- const { done, value } = await readChunkWithProgressTimeout(reader, lastMeaningfulEventAt);
1037
+ let readResult;
1038
+ try {
1039
+ readResult = await readChunkWithProgressTimeout(reader, lastMeaningfulEventAt);
1040
+ }
1041
+ catch (err) {
1042
+ if (err instanceof AgentAutoContinueSignal) {
1043
+ throw new AgentAutoContinueSignal({
1044
+ reason: err.reason,
1045
+ maxIterations: err.maxIterations,
1046
+ activityTrail: [...activityTrail],
1047
+ errorInfo: err.errorInfo,
1048
+ });
1049
+ }
1050
+ throw err;
1051
+ }
1052
+ const { done, value } = readResult;
937
1053
  if (done)
938
1054
  break;
939
1055
  buf += decoder.decode(value, { stream: true });
940
1056
  const lines = buf.split("\n");
941
1057
  buf = lines.pop() ?? "";
942
- let updated = false;
943
- let sawDataEvent = false;
1058
+ let sawProgressEvent = false;
944
1059
  for (const line of lines) {
945
1060
  if (!line.startsWith("data: "))
946
1061
  continue;
@@ -954,10 +1069,12 @@ export async function readSSEStreamRaw(body, content, toolCallCounter, tabId, on
954
1069
  catch {
955
1070
  continue;
956
1071
  }
957
- sawDataEvent = true;
958
1072
  const now = Date.now();
959
- lastMeaningfulEventAt = now;
960
- updatePreparingActionState(preparingActionState, ev, now);
1073
+ const actionPreparationProgress = updatePreparingActionState(preparingActionState, ev, now);
1074
+ if (isMeaningfulProgressEvent(ev, actionPreparationProgress)) {
1075
+ sawProgressEvent = true;
1076
+ lastMeaningfulEventAt = now;
1077
+ }
961
1078
  if (ev.seq !== undefined && onSeq) {
962
1079
  onSeq(ev.seq);
963
1080
  }
@@ -991,16 +1108,18 @@ export async function readSSEStreamRaw(body, content, toolCallCounter, tabId, on
991
1108
  action === "done" ||
992
1109
  action === "error" ||
993
1110
  action === "missing_api_key") {
994
- updated = true;
1111
+ onUpdate(contentSnapshot(content));
1112
+ emittedLatestContent = true;
995
1113
  }
996
1114
  if (action === "auto_continue") {
997
- onUpdate([...content]);
1115
+ onUpdate(contentSnapshot(content));
1116
+ emittedLatestContent = true;
998
1117
  throw new AgentAutoContinueSignal(autoContinue
999
1118
  ? { ...autoContinue, activityTrail: [...activityTrail] }
1000
1119
  : { reason: "stream_ended", activityTrail: [...activityTrail] });
1001
1120
  }
1002
1121
  if (hasStalledPreparingAction(preparingActionState, Date.now())) {
1003
- onUpdate([...content]);
1122
+ onUpdate(contentSnapshot(content));
1004
1123
  throw new AgentAutoContinueSignal({
1005
1124
  reason: "no_progress",
1006
1125
  activityTrail: [...activityTrail],
@@ -1009,17 +1128,15 @@ export async function readSSEStreamRaw(body, content, toolCallCounter, tabId, on
1009
1128
  if (action === "done" ||
1010
1129
  action === "error" ||
1011
1130
  action === "missing_api_key") {
1012
- onUpdate([...content]);
1013
1131
  return;
1014
1132
  }
1015
1133
  }
1016
- if (updated) {
1017
- onUpdate([...content]);
1018
- emittedLatestContent = true;
1019
- }
1020
- if (!sawDataEvent &&
1134
+ if (!sawProgressEvent &&
1021
1135
  Date.now() - lastMeaningfulEventAt >= SSE_NO_PROGRESS_TIMEOUT_MS) {
1022
- throw new AgentAutoContinueSignal({ reason: "no_progress" });
1136
+ throw new AgentAutoContinueSignal({
1137
+ reason: "no_progress",
1138
+ activityTrail: [...activityTrail],
1139
+ });
1023
1140
  }
1024
1141
  }
1025
1142
  }
@@ -1031,8 +1148,9 @@ export async function readSSEStreamRaw(body, content, toolCallCounter, tabId, on
1031
1148
  // See readSSEStream: cancellation may race lock release in browsers.
1032
1149
  }
1033
1150
  }
1034
- if (content.length > 0 && !emittedLatestContent)
1035
- onUpdate([...content]);
1151
+ if (content.length > 0 && !emittedLatestContent) {
1152
+ onUpdate(contentSnapshot(content));
1153
+ }
1036
1154
  throw new AgentAutoContinueSignal({ reason: "stream_ended" });
1037
1155
  }
1038
1156
  //# sourceMappingURL=sse-event-processor.js.map