@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.
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +12 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/production-agent.ts +8 -6
- package/corpus/core/src/agent/run-manager.ts +57 -6
- package/corpus/core/src/client/AssistantChat.tsx +82 -15
- package/corpus/core/src/client/active-run-state.ts +22 -0
- package/corpus/core/src/client/chat/message-components.tsx +2 -1
- package/corpus/core/src/client/chat/tool-call-display.tsx +18 -2
- package/corpus/core/src/client/sse-event-processor.ts +196 -51
- package/corpus/core/src/client/tool-display.ts +1 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +15 -13
- package/corpus/templates/clips/.agents/skills/video-sharing/SKILL.md +4 -2
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +11 -2
- package/corpus/templates/clips/app/i18n/ar-SA.ts +4 -0
- package/corpus/templates/clips/app/i18n/de-DE.ts +4 -0
- package/corpus/templates/clips/app/i18n/en-US.ts +4 -0
- package/corpus/templates/clips/app/i18n/es-ES.ts +4 -0
- package/corpus/templates/clips/app/i18n/fr-FR.ts +4 -0
- package/corpus/templates/clips/app/i18n/hi-IN.ts +4 -0
- package/corpus/templates/clips/app/i18n/ja-JP.ts +4 -0
- package/corpus/templates/clips/app/i18n/ko-KR.ts +4 -0
- package/corpus/templates/clips/app/i18n/pt-BR.ts +4 -0
- package/corpus/templates/clips/app/i18n/zh-CN.ts +4 -0
- package/corpus/templates/clips/app/i18n/zh-TW.ts +4 -0
- package/corpus/templates/clips/app/routes/embed.$shareId.tsx +31 -3
- package/corpus/templates/clips/changelog/2026-07-01-clip-embeds-now-render-as-a-clean-video-only-player-without-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-01-shared-clips-can-now-copy-a-ready-to-send-prompt-that-tells-.md +6 -0
- package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -1
- package/corpus/templates/clips/chrome-extension/src/github-preview-content.ts +2 -2
- package/corpus/templates/clips/chrome-extension/src/github-preview.ts +41 -31
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +8 -6
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +56 -4
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +2 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +74 -18
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/active-run-state.d.ts +2 -0
- package/dist/client/active-run-state.d.ts.map +1 -1
- package/dist/client/active-run-state.js +17 -0
- package/dist/client/active-run-state.js.map +1 -1
- package/dist/client/chat/message-components.d.ts.map +1 -1
- package/dist/client/chat/message-components.js +3 -1
- package/dist/client/chat/message-components.js.map +1 -1
- package/dist/client/chat/tool-call-display.d.ts +3 -1
- package/dist/client/chat/tool-call-display.d.ts.map +1 -1
- package/dist/client/chat/tool-call-display.js +8 -8
- package/dist/client/chat/tool-call-display.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts +1 -0
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +163 -45
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/client/tool-display.js +1 -1
- package/dist/client/tool-display.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +6 -6
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/package.json +1 -1
|
@@ -27,6 +27,7 @@ export type ContentPart =
|
|
|
27
27
|
mcpApp?: AgentMcpAppPayload;
|
|
28
28
|
chatUI?: ActionChatUIConfig;
|
|
29
29
|
activity?: boolean;
|
|
30
|
+
repeatCount?: number;
|
|
30
31
|
/**
|
|
31
32
|
* Set when the server emitted an `approval_required` event for this tool
|
|
32
33
|
* call (opt-in `needsApproval` actions). The action did NOT run; the UI
|
|
@@ -152,6 +153,7 @@ type ActivityTrailEntry = AgentActivityTrailEntry;
|
|
|
152
153
|
type PreparingActionState = {
|
|
153
154
|
tool?: string;
|
|
154
155
|
startedAt?: number;
|
|
156
|
+
lastProgressBytes?: number;
|
|
155
157
|
/**
|
|
156
158
|
* Timestamp of the last real streaming progress for the in-preparation tool
|
|
157
159
|
* input. The server emits a throttled `activity` heartbeat per
|
|
@@ -184,6 +186,17 @@ function isPreparingActionActivity(ev: SSEEvent): boolean {
|
|
|
184
186
|
return label.startsWith("preparing ") && label.includes(" action");
|
|
185
187
|
}
|
|
186
188
|
|
|
189
|
+
function isMeaningfulProgressEvent(
|
|
190
|
+
ev: SSEEvent,
|
|
191
|
+
actionPreparationProgress?: boolean,
|
|
192
|
+
): boolean {
|
|
193
|
+
if (ev.type === "stream_keepalive") return false;
|
|
194
|
+
if (ev.type === "activity" && isPreparingActionActivity(ev)) {
|
|
195
|
+
return actionPreparationProgress === true;
|
|
196
|
+
}
|
|
197
|
+
return true;
|
|
198
|
+
}
|
|
199
|
+
|
|
187
200
|
function baseActivityLabel(ev: SSEEvent, tool?: string): string {
|
|
188
201
|
return humanizeToolLabelText(ev.label ?? "Working", tool);
|
|
189
202
|
}
|
|
@@ -253,19 +266,28 @@ function updatePreparingActionState(
|
|
|
253
266
|
state: PreparingActionState,
|
|
254
267
|
ev: SSEEvent,
|
|
255
268
|
now: number,
|
|
256
|
-
) {
|
|
269
|
+
): boolean | undefined {
|
|
257
270
|
if (ev.type === "activity" && isPreparingActionActivity(ev)) {
|
|
258
271
|
const tool = ev.tool?.trim() || undefined;
|
|
259
|
-
if (!tool) return;
|
|
272
|
+
if (!tool) return false;
|
|
260
273
|
if (state.tool !== tool || state.startedAt === undefined) {
|
|
261
274
|
state.tool = tool;
|
|
262
275
|
state.startedAt = now;
|
|
276
|
+
state.lastProgressAt = undefined;
|
|
277
|
+
state.lastProgressBytes = undefined;
|
|
263
278
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
279
|
+
const progressBytes = activityProgressBytes(ev);
|
|
280
|
+
const previousBytes = state.lastProgressBytes ?? 0;
|
|
281
|
+
if (progressBytes !== undefined) {
|
|
282
|
+
state.lastProgressBytes = Math.max(previousBytes, progressBytes);
|
|
283
|
+
}
|
|
284
|
+
if (progressBytes !== undefined && progressBytes > previousBytes) {
|
|
285
|
+
// A byte increase is proof the model is still streaming this action's
|
|
286
|
+
// argument. Repeated zero-byte prep activity is only a heartbeat.
|
|
287
|
+
state.lastProgressAt = now;
|
|
288
|
+
return true;
|
|
289
|
+
}
|
|
290
|
+
return false;
|
|
269
291
|
}
|
|
270
292
|
|
|
271
293
|
if (
|
|
@@ -280,7 +302,9 @@ function updatePreparingActionState(
|
|
|
280
302
|
state.tool = undefined;
|
|
281
303
|
state.startedAt = undefined;
|
|
282
304
|
state.lastProgressAt = undefined;
|
|
305
|
+
state.lastProgressBytes = undefined;
|
|
283
306
|
}
|
|
307
|
+
return undefined;
|
|
284
308
|
}
|
|
285
309
|
|
|
286
310
|
function hasStalledPreparingAction(state: PreparingActionState, now: number) {
|
|
@@ -291,8 +315,9 @@ function hasStalledPreparingAction(state: PreparingActionState, now: number) {
|
|
|
291
315
|
// survives; a genuinely stuck prep (keepalive-only, no deltas) trips it.
|
|
292
316
|
return (
|
|
293
317
|
state.tool !== undefined &&
|
|
294
|
-
state.
|
|
295
|
-
now - state.lastProgressAt >=
|
|
318
|
+
state.startedAt !== undefined &&
|
|
319
|
+
now - (state.lastProgressAt ?? state.startedAt) >=
|
|
320
|
+
SSE_ACTION_PREPARATION_STALL_TIMEOUT_MS
|
|
296
321
|
);
|
|
297
322
|
}
|
|
298
323
|
|
|
@@ -460,6 +485,81 @@ function pendingToolNames(content: ContentPart[]): {
|
|
|
460
485
|
return { activity: [...activity], running: [...running] };
|
|
461
486
|
}
|
|
462
487
|
|
|
488
|
+
function contentSnapshot(content: ContentPart[]): ContentPart[] {
|
|
489
|
+
return content.map((part) => {
|
|
490
|
+
if (part.type === "text") return { ...part };
|
|
491
|
+
return {
|
|
492
|
+
...part,
|
|
493
|
+
args: { ...part.args },
|
|
494
|
+
...(part.mcpApp ? { mcpApp: { ...part.mcpApp } } : {}),
|
|
495
|
+
...(part.chatUI ? { chatUI: { ...part.chatUI } } : {}),
|
|
496
|
+
...(part.approval ? { approval: { ...part.approval } } : {}),
|
|
497
|
+
...(part.structuredMeta
|
|
498
|
+
? { structuredMeta: { ...part.structuredMeta } }
|
|
499
|
+
: {}),
|
|
500
|
+
};
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
function repeatSignatureValue(value: unknown): string {
|
|
505
|
+
try {
|
|
506
|
+
return JSON.stringify(value);
|
|
507
|
+
} catch {
|
|
508
|
+
return String(value ?? "");
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
function completedToolRepeatSignature(
|
|
513
|
+
part: Extract<ContentPart, { type: "tool-call" }>,
|
|
514
|
+
): string | null {
|
|
515
|
+
if (
|
|
516
|
+
part.result === undefined ||
|
|
517
|
+
part.activity === true ||
|
|
518
|
+
part.approval ||
|
|
519
|
+
part.mcpApp ||
|
|
520
|
+
part.chatUI ||
|
|
521
|
+
part.structuredMeta
|
|
522
|
+
) {
|
|
523
|
+
return null;
|
|
524
|
+
}
|
|
525
|
+
return [
|
|
526
|
+
part.toolName,
|
|
527
|
+
part.argsText,
|
|
528
|
+
repeatSignatureValue(part.args),
|
|
529
|
+
part.result,
|
|
530
|
+
part.isError === true ? "error" : "",
|
|
531
|
+
part.completedSideEffect === true ? "side-effect" : "",
|
|
532
|
+
].join("\u0000");
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
function coalesceCompletedToolRepeat(
|
|
536
|
+
content: ContentPart[],
|
|
537
|
+
completedIndex: number,
|
|
538
|
+
): void {
|
|
539
|
+
const current = content[completedIndex];
|
|
540
|
+
const previous = content[completedIndex - 1];
|
|
541
|
+
if (
|
|
542
|
+
!current ||
|
|
543
|
+
!previous ||
|
|
544
|
+
current.type !== "tool-call" ||
|
|
545
|
+
previous.type !== "tool-call"
|
|
546
|
+
) {
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
const currentSignature = completedToolRepeatSignature(current);
|
|
551
|
+
if (
|
|
552
|
+
!currentSignature ||
|
|
553
|
+
currentSignature !== completedToolRepeatSignature(previous)
|
|
554
|
+
) {
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
previous.repeatCount =
|
|
559
|
+
(previous.repeatCount ?? 1) + (current.repeatCount ?? 1);
|
|
560
|
+
content.splice(completedIndex, 1);
|
|
561
|
+
}
|
|
562
|
+
|
|
463
563
|
function formatToolNames(tools: string[]): string {
|
|
464
564
|
const names = tools.map(humanizeToolName);
|
|
465
565
|
if (names.length === 0) return "the promised action";
|
|
@@ -578,7 +678,7 @@ export function processEvent(
|
|
|
578
678
|
}
|
|
579
679
|
return {
|
|
580
680
|
action: "yield",
|
|
581
|
-
result: { content:
|
|
681
|
+
result: { content: contentSnapshot(content) } as ChatModelRunResult,
|
|
582
682
|
};
|
|
583
683
|
}
|
|
584
684
|
|
|
@@ -615,7 +715,7 @@ export function processEvent(
|
|
|
615
715
|
}
|
|
616
716
|
return {
|
|
617
717
|
action: "yield",
|
|
618
|
-
result: { content:
|
|
718
|
+
result: { content: contentSnapshot(content) } as ChatModelRunResult,
|
|
619
719
|
};
|
|
620
720
|
}
|
|
621
721
|
|
|
@@ -672,7 +772,7 @@ export function processEvent(
|
|
|
672
772
|
}
|
|
673
773
|
return {
|
|
674
774
|
action: "yield",
|
|
675
|
-
result: { content:
|
|
775
|
+
result: { content: contentSnapshot(content) } as ChatModelRunResult,
|
|
676
776
|
};
|
|
677
777
|
}
|
|
678
778
|
|
|
@@ -694,7 +794,7 @@ export function processEvent(
|
|
|
694
794
|
}
|
|
695
795
|
return {
|
|
696
796
|
action: "yield",
|
|
697
|
-
result: { content:
|
|
797
|
+
result: { content: contentSnapshot(content) } as ChatModelRunResult,
|
|
698
798
|
};
|
|
699
799
|
}
|
|
700
800
|
|
|
@@ -730,11 +830,12 @@ export function processEvent(
|
|
|
730
830
|
if (part.activity !== true && part.isError !== true) {
|
|
731
831
|
markCompletedToolAfterAssistantText(state, part.toolName);
|
|
732
832
|
}
|
|
833
|
+
coalesceCompletedToolRepeat(content, doneIdx);
|
|
733
834
|
}
|
|
734
835
|
}
|
|
735
836
|
return {
|
|
736
837
|
action: "yield",
|
|
737
|
-
result: { content:
|
|
838
|
+
result: { content: contentSnapshot(content) } as ChatModelRunResult,
|
|
738
839
|
};
|
|
739
840
|
}
|
|
740
841
|
|
|
@@ -764,7 +865,7 @@ export function processEvent(
|
|
|
764
865
|
}
|
|
765
866
|
return {
|
|
766
867
|
action: "yield",
|
|
767
|
-
result: { content:
|
|
868
|
+
result: { content: contentSnapshot(content) } as ChatModelRunResult,
|
|
768
869
|
};
|
|
769
870
|
}
|
|
770
871
|
|
|
@@ -784,7 +885,7 @@ export function processEvent(
|
|
|
784
885
|
}
|
|
785
886
|
return {
|
|
786
887
|
action: "yield",
|
|
787
|
-
result: { content:
|
|
888
|
+
result: { content: contentSnapshot(content) } as ChatModelRunResult,
|
|
788
889
|
};
|
|
789
890
|
}
|
|
790
891
|
|
|
@@ -826,7 +927,7 @@ export function processEvent(
|
|
|
826
927
|
return {
|
|
827
928
|
action: "missing_api_key",
|
|
828
929
|
result: {
|
|
829
|
-
content:
|
|
930
|
+
content: contentSnapshot(content),
|
|
830
931
|
status: { type: "incomplete" as const, reason: "error" as const },
|
|
831
932
|
metadata: { custom: { runError } },
|
|
832
933
|
} as ChatModelRunResult,
|
|
@@ -938,7 +1039,7 @@ export function processEvent(
|
|
|
938
1039
|
return {
|
|
939
1040
|
action: "error",
|
|
940
1041
|
result: {
|
|
941
|
-
content:
|
|
1042
|
+
content: contentSnapshot(content),
|
|
942
1043
|
status: { type: "incomplete" as const, reason: "error" as const },
|
|
943
1044
|
metadata: { custom: { runError } },
|
|
944
1045
|
} as ChatModelRunResult,
|
|
@@ -974,7 +1075,7 @@ export function processEvent(
|
|
|
974
1075
|
return {
|
|
975
1076
|
action: "error",
|
|
976
1077
|
result: {
|
|
977
|
-
content:
|
|
1078
|
+
content: contentSnapshot(content),
|
|
978
1079
|
status: { type: "incomplete" as const, reason: "error" as const },
|
|
979
1080
|
metadata: { custom: { runError } },
|
|
980
1081
|
} as ChatModelRunResult,
|
|
@@ -993,7 +1094,7 @@ export function processEvent(
|
|
|
993
1094
|
return {
|
|
994
1095
|
action: "done",
|
|
995
1096
|
result: {
|
|
996
|
-
content:
|
|
1097
|
+
content: contentSnapshot(content),
|
|
997
1098
|
status: { type: "complete" as const, reason: "stop" as const },
|
|
998
1099
|
metadata: {
|
|
999
1100
|
custom: {
|
|
@@ -1009,7 +1110,7 @@ export function processEvent(
|
|
|
1009
1110
|
}
|
|
1010
1111
|
return {
|
|
1011
1112
|
action: "done",
|
|
1012
|
-
result: { content:
|
|
1113
|
+
result: { content: contentSnapshot(content) } as ChatModelRunResult,
|
|
1013
1114
|
};
|
|
1014
1115
|
}
|
|
1015
1116
|
|
|
@@ -1075,16 +1176,30 @@ export async function* readSSEStream(
|
|
|
1075
1176
|
|
|
1076
1177
|
try {
|
|
1077
1178
|
while (true) {
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1179
|
+
let readResult: ReadableStreamReadResult<Uint8Array>;
|
|
1180
|
+
try {
|
|
1181
|
+
readResult = await readChunkWithProgressTimeout(
|
|
1182
|
+
reader,
|
|
1183
|
+
lastMeaningfulEventAt,
|
|
1184
|
+
);
|
|
1185
|
+
} catch (err) {
|
|
1186
|
+
if (err instanceof AgentAutoContinueSignal) {
|
|
1187
|
+
throw new AgentAutoContinueSignal({
|
|
1188
|
+
reason: err.reason,
|
|
1189
|
+
maxIterations: err.maxIterations,
|
|
1190
|
+
activityTrail: [...activityTrail],
|
|
1191
|
+
errorInfo: err.errorInfo,
|
|
1192
|
+
});
|
|
1193
|
+
}
|
|
1194
|
+
throw err;
|
|
1195
|
+
}
|
|
1196
|
+
const { done, value } = readResult;
|
|
1082
1197
|
if (done) break;
|
|
1083
1198
|
|
|
1084
1199
|
buf += decoder.decode(value, { stream: true });
|
|
1085
1200
|
const lines = buf.split("\n");
|
|
1086
1201
|
buf = lines.pop() ?? "";
|
|
1087
|
-
let
|
|
1202
|
+
let sawProgressEvent = false;
|
|
1088
1203
|
|
|
1089
1204
|
for (const line of lines) {
|
|
1090
1205
|
if (!line.startsWith("data: ")) continue;
|
|
@@ -1097,10 +1212,16 @@ export async function* readSSEStream(
|
|
|
1097
1212
|
} catch {
|
|
1098
1213
|
continue;
|
|
1099
1214
|
}
|
|
1100
|
-
sawDataEvent = true;
|
|
1101
1215
|
const now = Date.now();
|
|
1102
|
-
|
|
1103
|
-
|
|
1216
|
+
const actionPreparationProgress = updatePreparingActionState(
|
|
1217
|
+
preparingActionState,
|
|
1218
|
+
ev,
|
|
1219
|
+
now,
|
|
1220
|
+
);
|
|
1221
|
+
if (isMeaningfulProgressEvent(ev, actionPreparationProgress)) {
|
|
1222
|
+
sawProgressEvent = true;
|
|
1223
|
+
lastMeaningfulEventAt = now;
|
|
1224
|
+
}
|
|
1104
1225
|
|
|
1105
1226
|
// Track sequence number for reconnection
|
|
1106
1227
|
if (ev.seq !== undefined && onSeq) {
|
|
@@ -1162,10 +1283,13 @@ export async function* readSSEStream(
|
|
|
1162
1283
|
}
|
|
1163
1284
|
|
|
1164
1285
|
if (
|
|
1165
|
-
!
|
|
1286
|
+
!sawProgressEvent &&
|
|
1166
1287
|
Date.now() - lastMeaningfulEventAt >= SSE_NO_PROGRESS_TIMEOUT_MS
|
|
1167
1288
|
) {
|
|
1168
|
-
throw new AgentAutoContinueSignal({
|
|
1289
|
+
throw new AgentAutoContinueSignal({
|
|
1290
|
+
reason: "no_progress",
|
|
1291
|
+
activityTrail: [...activityTrail],
|
|
1292
|
+
});
|
|
1169
1293
|
}
|
|
1170
1294
|
}
|
|
1171
1295
|
} finally {
|
|
@@ -1218,18 +1342,31 @@ export async function readSSEStreamRaw(
|
|
|
1218
1342
|
|
|
1219
1343
|
try {
|
|
1220
1344
|
while (true) {
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1345
|
+
let readResult: ReadableStreamReadResult<Uint8Array>;
|
|
1346
|
+
try {
|
|
1347
|
+
readResult = await readChunkWithProgressTimeout(
|
|
1348
|
+
reader,
|
|
1349
|
+
lastMeaningfulEventAt,
|
|
1350
|
+
);
|
|
1351
|
+
} catch (err) {
|
|
1352
|
+
if (err instanceof AgentAutoContinueSignal) {
|
|
1353
|
+
throw new AgentAutoContinueSignal({
|
|
1354
|
+
reason: err.reason,
|
|
1355
|
+
maxIterations: err.maxIterations,
|
|
1356
|
+
activityTrail: [...activityTrail],
|
|
1357
|
+
errorInfo: err.errorInfo,
|
|
1358
|
+
});
|
|
1359
|
+
}
|
|
1360
|
+
throw err;
|
|
1361
|
+
}
|
|
1362
|
+
const { done, value } = readResult;
|
|
1225
1363
|
if (done) break;
|
|
1226
1364
|
|
|
1227
1365
|
buf += decoder.decode(value, { stream: true });
|
|
1228
1366
|
const lines = buf.split("\n");
|
|
1229
1367
|
buf = lines.pop() ?? "";
|
|
1230
1368
|
|
|
1231
|
-
let
|
|
1232
|
-
let sawDataEvent = false;
|
|
1369
|
+
let sawProgressEvent = false;
|
|
1233
1370
|
for (const line of lines) {
|
|
1234
1371
|
if (!line.startsWith("data: ")) continue;
|
|
1235
1372
|
const raw = line.slice(6).trim();
|
|
@@ -1241,10 +1378,16 @@ export async function readSSEStreamRaw(
|
|
|
1241
1378
|
} catch {
|
|
1242
1379
|
continue;
|
|
1243
1380
|
}
|
|
1244
|
-
sawDataEvent = true;
|
|
1245
1381
|
const now = Date.now();
|
|
1246
|
-
|
|
1247
|
-
|
|
1382
|
+
const actionPreparationProgress = updatePreparingActionState(
|
|
1383
|
+
preparingActionState,
|
|
1384
|
+
ev,
|
|
1385
|
+
now,
|
|
1386
|
+
);
|
|
1387
|
+
if (isMeaningfulProgressEvent(ev, actionPreparationProgress)) {
|
|
1388
|
+
sawProgressEvent = true;
|
|
1389
|
+
lastMeaningfulEventAt = now;
|
|
1390
|
+
}
|
|
1248
1391
|
|
|
1249
1392
|
if (ev.seq !== undefined && onSeq) {
|
|
1250
1393
|
onSeq(ev.seq);
|
|
@@ -1287,10 +1430,12 @@ export async function readSSEStreamRaw(
|
|
|
1287
1430
|
action === "error" ||
|
|
1288
1431
|
action === "missing_api_key"
|
|
1289
1432
|
) {
|
|
1290
|
-
|
|
1433
|
+
onUpdate(contentSnapshot(content));
|
|
1434
|
+
emittedLatestContent = true;
|
|
1291
1435
|
}
|
|
1292
1436
|
if (action === "auto_continue") {
|
|
1293
|
-
onUpdate(
|
|
1437
|
+
onUpdate(contentSnapshot(content));
|
|
1438
|
+
emittedLatestContent = true;
|
|
1294
1439
|
throw new AgentAutoContinueSignal(
|
|
1295
1440
|
autoContinue
|
|
1296
1441
|
? { ...autoContinue, activityTrail: [...activityTrail] }
|
|
@@ -1298,7 +1443,7 @@ export async function readSSEStreamRaw(
|
|
|
1298
1443
|
);
|
|
1299
1444
|
}
|
|
1300
1445
|
if (hasStalledPreparingAction(preparingActionState, Date.now())) {
|
|
1301
|
-
onUpdate(
|
|
1446
|
+
onUpdate(contentSnapshot(content));
|
|
1302
1447
|
throw new AgentAutoContinueSignal({
|
|
1303
1448
|
reason: "no_progress",
|
|
1304
1449
|
activityTrail: [...activityTrail],
|
|
@@ -1309,20 +1454,18 @@ export async function readSSEStreamRaw(
|
|
|
1309
1454
|
action === "error" ||
|
|
1310
1455
|
action === "missing_api_key"
|
|
1311
1456
|
) {
|
|
1312
|
-
onUpdate([...content]);
|
|
1313
1457
|
return;
|
|
1314
1458
|
}
|
|
1315
1459
|
}
|
|
1316
1460
|
|
|
1317
|
-
if (updated) {
|
|
1318
|
-
onUpdate([...content]);
|
|
1319
|
-
emittedLatestContent = true;
|
|
1320
|
-
}
|
|
1321
1461
|
if (
|
|
1322
|
-
!
|
|
1462
|
+
!sawProgressEvent &&
|
|
1323
1463
|
Date.now() - lastMeaningfulEventAt >= SSE_NO_PROGRESS_TIMEOUT_MS
|
|
1324
1464
|
) {
|
|
1325
|
-
throw new AgentAutoContinueSignal({
|
|
1465
|
+
throw new AgentAutoContinueSignal({
|
|
1466
|
+
reason: "no_progress",
|
|
1467
|
+
activityTrail: [...activityTrail],
|
|
1468
|
+
});
|
|
1326
1469
|
}
|
|
1327
1470
|
}
|
|
1328
1471
|
} finally {
|
|
@@ -1332,6 +1475,8 @@ export async function readSSEStreamRaw(
|
|
|
1332
1475
|
// See readSSEStream: cancellation may race lock release in browsers.
|
|
1333
1476
|
}
|
|
1334
1477
|
}
|
|
1335
|
-
if (content.length > 0 && !emittedLatestContent)
|
|
1478
|
+
if (content.length > 0 && !emittedLatestContent) {
|
|
1479
|
+
onUpdate(contentSnapshot(content));
|
|
1480
|
+
}
|
|
1336
1481
|
throw new AgentAutoContinueSignal({ reason: "stream_ended" });
|
|
1337
1482
|
}
|
|
@@ -466,6 +466,21 @@ export function SqlChartCard({
|
|
|
466
466
|
<TooltipContent>{t("sqlDashboard.refreshing")}</TooltipContent>
|
|
467
467
|
</Tooltip>
|
|
468
468
|
) : null}
|
|
469
|
+
{editable && onSaveSql ? (
|
|
470
|
+
<ViewSqlPopover
|
|
471
|
+
panel={panel}
|
|
472
|
+
resolvedSql={resolvedSql}
|
|
473
|
+
onSaveSql={onSaveSql}
|
|
474
|
+
>
|
|
475
|
+
<button
|
|
476
|
+
className="p-1 rounded text-muted-foreground hover:text-foreground"
|
|
477
|
+
aria-label={t("sqlDashboard.viewSql")}
|
|
478
|
+
title={t("sqlDashboard.viewSql")}
|
|
479
|
+
>
|
|
480
|
+
<IconCode className="h-3.5 w-3.5" />
|
|
481
|
+
</button>
|
|
482
|
+
</ViewSqlPopover>
|
|
483
|
+
) : null}
|
|
469
484
|
{showPanelMenu ? (
|
|
470
485
|
<DropdownMenu>
|
|
471
486
|
<Tooltip>
|
|
@@ -503,19 +518,6 @@ export function SqlChartCard({
|
|
|
503
518
|
{editable && panel.chartType === "table" ? (
|
|
504
519
|
<DropdownMenuSeparator />
|
|
505
520
|
) : null}
|
|
506
|
-
{editable && onSaveSql ? (
|
|
507
|
-
<ViewSqlPopover
|
|
508
|
-
panel={panel}
|
|
509
|
-
resolvedSql={resolvedSql}
|
|
510
|
-
onSaveSql={onSaveSql}
|
|
511
|
-
>
|
|
512
|
-
<DropdownMenuItem onSelect={(e) => e.preventDefault()}>
|
|
513
|
-
<IconCode className="h-4 w-4 mr-2" />
|
|
514
|
-
{t("sqlDashboard.viewSql")}
|
|
515
|
-
</DropdownMenuItem>
|
|
516
|
-
</ViewSqlPopover>
|
|
517
|
-
) : null}
|
|
518
|
-
{editable ? <DropdownMenuSeparator /> : null}
|
|
519
521
|
{editable && onEdit && (
|
|
520
522
|
<DropdownMenuItem onSelect={() => onEdit()}>
|
|
521
523
|
<IconPencil className="h-4 w-4 mr-2" />
|
|
@@ -184,8 +184,10 @@ These endpoints follow the same access model as `/api/public-recording`:
|
|
|
184
184
|
raw provider URLs.
|
|
185
185
|
|
|
186
186
|
The share popover's "Share with agents" field should copy the agent context URL,
|
|
187
|
-
not raw transcript text.
|
|
188
|
-
|
|
187
|
+
not raw transcript text. Its "Copy agent prompt" field may wrap that URL with
|
|
188
|
+
instructions to fetch transcripts, frames, and browser diagnostics, but it should
|
|
189
|
+
still point agents at the context response so they can fetch only the visual
|
|
190
|
+
context they need.
|
|
189
191
|
|
|
190
192
|
## View counting
|
|
191
193
|
|
|
@@ -324,6 +324,9 @@ function LinkTab({
|
|
|
324
324
|
? tokenizedAgentContextUrl
|
|
325
325
|
: publicAgentContextUrl;
|
|
326
326
|
const agentShareDisabled = isPending || !isPublic || !agentContextUrl;
|
|
327
|
+
const agentPrompt = agentContextUrl
|
|
328
|
+
? t("shareDialog.agentPrompt", { agentContextUrl })
|
|
329
|
+
: "";
|
|
327
330
|
|
|
328
331
|
return (
|
|
329
332
|
<div className="space-y-4">
|
|
@@ -351,6 +354,12 @@ function LinkTab({
|
|
|
351
354
|
disabled={agentShareDisabled}
|
|
352
355
|
/>
|
|
353
356
|
|
|
357
|
+
<CopyField
|
|
358
|
+
label={t("shareDialog.copyAgentPrompt")}
|
|
359
|
+
value={agentPrompt}
|
|
360
|
+
disabled={agentShareDisabled}
|
|
361
|
+
/>
|
|
362
|
+
|
|
354
363
|
{isPublic && hasPassword ? (
|
|
355
364
|
<p className="text-xs text-muted-foreground">
|
|
356
365
|
{t("shareDialog.agentTokenDescription")}
|
|
@@ -452,8 +461,8 @@ function ClipsEmbedConfigurator({
|
|
|
452
461
|
|
|
453
462
|
const code =
|
|
454
463
|
mode === "responsive"
|
|
455
|
-
? `<div style="position:relative;padding-bottom:56.25%;height:0"><iframe src="${src}" frameborder="0" allowfullscreen allow="autoplay; picture-in-picture" style="position:absolute;inset:0;width:100%;height:100
|
|
456
|
-
: `<iframe src="${src}" width="${width}" height="${height}" frameborder="0" allowfullscreen allow="autoplay; picture-in-picture"></iframe>`;
|
|
464
|
+
? `<div style="position:relative;padding-bottom:56.25%;height:0;background:#000;overflow:hidden"><iframe src="${src}" title="${t("shareDialog.embedIframeTitle")}" frameborder="0" scrolling="no" allowfullscreen allow="autoplay; fullscreen; picture-in-picture" style="position:absolute;inset:0;width:100%;height:100%;border:0;background:#000;overflow:hidden"></iframe></div>`
|
|
465
|
+
: `<iframe src="${src}" title="${t("shareDialog.embedIframeTitle")}" width="${width}" height="${height}" frameborder="0" scrolling="no" allowfullscreen allow="autoplay; fullscreen; picture-in-picture" style="display:block;max-width:100%;border:0;background:#000;overflow:hidden"></iframe>`;
|
|
457
466
|
|
|
458
467
|
return (
|
|
459
468
|
<div className="space-y-3">
|
|
@@ -415,6 +415,9 @@ const messages = {
|
|
|
415
415
|
embed: "تضمين",
|
|
416
416
|
shareLink: "رابط المشاركة",
|
|
417
417
|
shareWithAgents: "شارك مع الوكلاء",
|
|
418
|
+
copyAgentPrompt: "نسخ مطالبة الوكيل",
|
|
419
|
+
agentPrompt:
|
|
420
|
+
"اجلب عنوان URL لسياق وكيل Clips هذا: {{agentContextUrl}}. استخدم transcript.segments للسياق المنطوق، واجلب recommendedFrames أو عناوين URL الخاصة بواجهة API للإطارات لرؤية الشاشة، وتحقق من browserDiagnostics إن وجدت لسجلات وحدة التحكم المنقحة وبيانات طلبات fetch/XHR الوصفية.",
|
|
418
421
|
agentTokenDescription:
|
|
419
422
|
"يستخدم هذا الوكيل URL رمزًا مميزًا قصير العمر، بحيث يمكن للعملاء قراءة المقطع دون الكشف عن كلمة المرور.",
|
|
420
423
|
gifPreview: "معاينة GIF",
|
|
@@ -428,6 +431,7 @@ const messages = {
|
|
|
428
431
|
askOwnerPublic: "اطلب من المالك نشره.",
|
|
429
432
|
responsive: "مستجيب (16:9)",
|
|
430
433
|
fixedSize: "حجم ثابت",
|
|
434
|
+
embedIframeTitle: "فيديو Clips",
|
|
431
435
|
width: "عرض",
|
|
432
436
|
height: "ارتفاع",
|
|
433
437
|
autoplay: "التشغيل التلقائي",
|
|
@@ -432,6 +432,9 @@ const messages = {
|
|
|
432
432
|
embed: "Einbetten",
|
|
433
433
|
shareLink: "Teillink",
|
|
434
434
|
shareWithAgents: "Mit Agenten teilen",
|
|
435
|
+
copyAgentPrompt: "Agent-Prompt kopieren",
|
|
436
|
+
agentPrompt:
|
|
437
|
+
"Rufe diese Clips-Agent-Kontext-URL ab: {{agentContextUrl}}. Verwende transcript.segments fuer den gesprochenen Kontext, rufe recommendedFrames oder die Frame-API-URLs ab, um den Bildschirm zu sehen, und pruefe browserDiagnostics, falls vorhanden, fuer redigierte Konsolenprotokolle und fetch/XHR-Anfragemetadaten.",
|
|
435
438
|
agentTokenDescription:
|
|
436
439
|
"Dieser Agent URL verwendet ein kurzlebiges Token, sodass Agenten den Clip lesen können, ohne das Passwort preiszugeben.",
|
|
437
440
|
gifPreview: "GIF-Vorschau",
|
|
@@ -445,6 +448,7 @@ const messages = {
|
|
|
445
448
|
askOwnerPublic: "Bitten Sie den Eigentümer, es öffentlich zu machen.",
|
|
446
449
|
responsive: "Responsiv (16:9)",
|
|
447
450
|
fixedSize: "Feste Größe",
|
|
451
|
+
embedIframeTitle: "Clips-Video",
|
|
448
452
|
width: "Breite",
|
|
449
453
|
height: "Höhe",
|
|
450
454
|
autoplay: "Übersetzt: Autoplay",
|
|
@@ -415,6 +415,9 @@ const messages = {
|
|
|
415
415
|
embed: "Embed",
|
|
416
416
|
shareLink: "Share link",
|
|
417
417
|
shareWithAgents: "Share with agents",
|
|
418
|
+
copyAgentPrompt: "Copy agent prompt",
|
|
419
|
+
agentPrompt:
|
|
420
|
+
"Fetch this Clips agent context URL: {{agentContextUrl}}. Use transcript.segments for spoken context, fetch recommendedFrames or the frame API URLs to see the screen, and check browserDiagnostics if present for redacted console logs and fetch/XHR request metadata.",
|
|
418
421
|
agentTokenDescription:
|
|
419
422
|
"This agent URL uses a short-lived token, so agents can read the clip without exposing the password.",
|
|
420
423
|
gifPreview: "GIF preview",
|
|
@@ -428,6 +431,7 @@ const messages = {
|
|
|
428
431
|
askOwnerPublic: "Ask the owner to make it public.",
|
|
429
432
|
responsive: "Responsive (16:9)",
|
|
430
433
|
fixedSize: "Fixed size",
|
|
434
|
+
embedIframeTitle: "Clips video",
|
|
431
435
|
width: "Width",
|
|
432
436
|
height: "Height",
|
|
433
437
|
autoplay: "Autoplay",
|
|
@@ -427,6 +427,9 @@ const messages = {
|
|
|
427
427
|
embed: "Insertar",
|
|
428
428
|
shareLink: "Enlace para compartir",
|
|
429
429
|
shareWithAgents: "Compartir con agentes",
|
|
430
|
+
copyAgentPrompt: "Copiar indicación para agente",
|
|
431
|
+
agentPrompt:
|
|
432
|
+
"Obtén esta URL de contexto para agentes de Clips: {{agentContextUrl}}. Usa transcript.segments para el contexto hablado, obtén recommendedFrames o las URLs de la API de fotogramas para ver la pantalla y revisa browserDiagnostics si está presente para ver registros de consola redactados y metadatos de solicitudes fetch/XHR.",
|
|
430
433
|
agentTokenDescription:
|
|
431
434
|
"Este agente URL utiliza un token de corta duración, por lo que los agentes pueden leer el clip sin exponer la contraseña.",
|
|
432
435
|
gifPreview: "vista previa de GIF",
|
|
@@ -440,6 +443,7 @@ const messages = {
|
|
|
440
443
|
askOwnerPublic: "Pídele al propietario que lo haga público.",
|
|
441
444
|
responsive: "Responsivo (16:9)",
|
|
442
445
|
fixedSize: "Tamaño fijo",
|
|
446
|
+
embedIframeTitle: "Video de Clips",
|
|
443
447
|
width: "Ancho",
|
|
444
448
|
height: "Altura",
|
|
445
449
|
autoplay: "Reproducción automática",
|
|
@@ -427,6 +427,9 @@ const messages = {
|
|
|
427
427
|
embed: "Intégrer",
|
|
428
428
|
shareLink: "Lien de partage",
|
|
429
429
|
shareWithAgents: "Partager avec les agents",
|
|
430
|
+
copyAgentPrompt: "Copier le prompt pour agent",
|
|
431
|
+
agentPrompt:
|
|
432
|
+
"Récupère cette URL de contexte Clips pour agent : {{agentContextUrl}}. Utilise transcript.segments pour le contexte parlé, récupère recommendedFrames ou les URLs de l'API d'images pour voir l'écran, et consulte browserDiagnostics s'il est présent pour les journaux de console expurgés et les métadonnées de requêtes fetch/XHR.",
|
|
430
433
|
agentTokenDescription:
|
|
431
434
|
"Cet agent URL utilise un jeton de courte durée, afin que les agents puissent lire le clip sans exposer le mot de passe.",
|
|
432
435
|
gifPreview: "aperçu de GIF",
|
|
@@ -440,6 +443,7 @@ const messages = {
|
|
|
440
443
|
askOwnerPublic: "Demandez au propriétaire de le rendre public.",
|
|
441
444
|
responsive: "Réactif (16:9)",
|
|
442
445
|
fixedSize: "Taille fixe",
|
|
446
|
+
embedIframeTitle: "Video Clips",
|
|
443
447
|
width: "Largeur",
|
|
444
448
|
height: "Hauteur",
|
|
445
449
|
autoplay: "Lecture automatique",
|
|
@@ -412,6 +412,9 @@ const messages = {
|
|
|
412
412
|
embed: "एम्बेड",
|
|
413
413
|
shareLink: "शेयर लिंक",
|
|
414
414
|
shareWithAgents: "एजेंटों के साथ साझा करें",
|
|
415
|
+
copyAgentPrompt: "एजेंट प्रॉम्प्ट कॉपी करें",
|
|
416
|
+
agentPrompt:
|
|
417
|
+
"यह Clips एजेंट संदर्भ URL प्राप्त करें: {{agentContextUrl}}। बोले गए संदर्भ के लिए transcript.segments का उपयोग करें, स्क्रीन देखने के लिए recommendedFrames या फ्रेम API URL प्राप्त करें, और यदि browserDiagnostics मौजूद हो तो संशोधित कंसोल लॉग और fetch/XHR अनुरोध मेटाडेटा जांचें।",
|
|
415
418
|
agentTokenDescription:
|
|
416
419
|
"यह एजेंट URL एक अल्पकालिक टोकन का उपयोग करता है, ताकि एजेंट पासवर्ड उजागर किए बिना क्लिप पढ़ सकें।",
|
|
417
420
|
gifPreview: "GIF पूर्वावलोकन",
|
|
@@ -425,6 +428,7 @@ const messages = {
|
|
|
425
428
|
askOwnerPublic: "मालिक से इसे सार्वजनिक करने के लिए कहें.",
|
|
426
429
|
responsive: "प्रतिक्रियाशील (16:9)",
|
|
427
430
|
fixedSize: "निश्चित आकार",
|
|
431
|
+
embedIframeTitle: "Clips वीडियो",
|
|
428
432
|
width: "चौड़ाई",
|
|
429
433
|
height: "ऊंचाई",
|
|
430
434
|
autoplay: "स्वत: प्ले",
|