@agent-native/core 0.0.0-beta-20260819181349 → 0.0.0-beta-20260819184657
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/templates/clips/app/components/player/video-player.tsx +12 -0
- package/corpus/templates/clips/app/routes/_app.dictate.tsx +18 -4
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +114 -20
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +83 -78
- package/corpus/templates/mail/actions/view-screen.ts +1 -1
- package/corpus/templates/mail/server/handlers/google-auth.ts +20 -22
- package/corpus/templates/mail/server/lib/gmail-query.ts +5 -2
- package/corpus/templates/plan/app/pages/PlansPage.tsx +0 -12
- package/corpus/templates/plan/changelog/2026-08-19-plan-prompts-now-guide-you-to-connect-ai-before-sending-and-.md +6 -0
- package/dist/a2a/task-store.d.ts +1 -0
- package/dist/a2a/task-store.js +1 -1
- package/dist/agent/observational-memory/store.d.ts +1 -0
- package/dist/agent/observational-memory/store.js +1 -1
- package/dist/agent/run-store.d.ts +1 -0
- package/dist/agent/run-store.js +1 -1
- package/dist/agent/tool-approval-store.d.ts +1 -0
- package/dist/agent/tool-approval-store.js +1 -1
- package/dist/application-state/store.d.ts +1 -0
- package/dist/application-state/store.js +1 -1
- package/dist/browser-sessions/store.d.ts +1 -0
- package/dist/browser-sessions/store.js +1 -1
- package/dist/checkpoints/store.d.ts +1 -0
- package/dist/checkpoints/store.js +1 -1
- package/dist/client/EnvironmentBadge.d.ts +7 -13
- package/dist/client/EnvironmentBadge.js +43 -92
- package/dist/client/agent-chat-adapter.js +22 -10
- package/dist/client/app-providers.js +4 -4
- package/dist/client/chat/message-components.d.ts +4 -0
- package/dist/client/chat/message-components.js +28 -1
- package/dist/client/chat/run-recovery.js +26 -0
- package/dist/client/sse-event-processor.js +13 -8
- package/dist/coding-tools/sandbox/executions-store.d.ts +1 -0
- package/dist/coding-tools/sandbox/executions-store.js +1 -1
- package/dist/collab/awareness-store.d.ts +1 -0
- package/dist/collab/awareness-store.js +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/storage.d.ts +1 -0
- package/dist/collab/storage.js +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/db/client.js +3 -3
- package/dist/db/ddl-guard.js +8 -0
- package/dist/db/migration-runtime.d.ts +23 -0
- package/dist/db/migration-runtime.js +41 -0
- package/dist/db/migrations.d.ts +1 -2
- package/dist/db/migrations.js +2 -24
- package/dist/email-catalog/log.d.ts +1 -0
- package/dist/email-catalog/log.js +1 -1
- package/dist/guards/index.d.ts +1 -0
- package/dist/guards/index.js +1 -0
- package/dist/guards/release-schema-complete.d.ts +22 -0
- package/dist/guards/release-schema-complete.js +144 -0
- package/dist/integrations/a2a-continuations-store.d.ts +1 -0
- package/dist/integrations/a2a-continuations-store.js +1 -1
- package/dist/integrations/awaiting-input-store.d.ts +1 -0
- package/dist/integrations/awaiting-input-store.js +1 -1
- package/dist/integrations/config-store.d.ts +1 -0
- package/dist/integrations/config-store.js +1 -1
- package/dist/integrations/controls-store.d.ts +1 -0
- package/dist/integrations/controls-store.js +1 -1
- package/dist/integrations/identity-links-store.d.ts +1 -0
- package/dist/integrations/identity-links-store.js +1 -1
- package/dist/integrations/installations-store.d.ts +1 -0
- package/dist/integrations/installations-store.js +1 -1
- package/dist/integrations/remote-commands-store.d.ts +1 -0
- package/dist/integrations/remote-commands-store.js +1 -1
- package/dist/integrations/remote-devices-store.d.ts +1 -0
- package/dist/integrations/remote-devices-store.js +1 -1
- package/dist/integrations/remote-push-store.d.ts +1 -0
- package/dist/integrations/remote-push-store.js +1 -1
- package/dist/integrations/remote-run-events-store.d.ts +1 -0
- package/dist/integrations/remote-run-events-store.js +1 -1
- package/dist/integrations/scope-store.d.ts +1 -0
- package/dist/integrations/scope-store.js +1 -1
- package/dist/integrations/thread-mapping-store.d.ts +1 -0
- package/dist/integrations/thread-mapping-store.js +1 -1
- package/dist/integrations/usage-budget-store.d.ts +1 -0
- package/dist/integrations/usage-budget-store.js +1 -1
- package/dist/jobs/run-history.d.ts +1 -0
- package/dist/jobs/run-history.js +1 -1
- package/dist/jobs/scheduler-health.d.ts +1 -0
- package/dist/jobs/scheduler-health.js +1 -1
- package/dist/mcp/approval-store.d.ts +1 -0
- package/dist/mcp/approval-store.js +1 -1
- package/dist/mcp/connect-store.d.ts +1 -0
- package/dist/mcp/connect-store.js +1 -1
- package/dist/mcp/oauth-store.d.ts +1 -0
- package/dist/mcp/oauth-store.js +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/notifications/store.d.ts +1 -0
- package/dist/notifications/store.js +1 -1
- package/dist/oauth-tokens/store.d.ts +1 -0
- package/dist/oauth-tokens/store.js +1 -1
- package/dist/observability/routes.d.ts +6 -6
- package/dist/progress/routes.d.ts +1 -1
- package/dist/progress/store.d.ts +1 -0
- package/dist/progress/store.js +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
- package/dist/provider-api/actions/provider-api.d.ts +13 -13
- package/dist/provider-api/corpus-jobs-store.d.ts +1 -0
- package/dist/provider-api/corpus-jobs-store.js +1 -1
- package/dist/provider-api/custom-registry.d.ts +1 -0
- package/dist/provider-api/custom-registry.js +1 -1
- package/dist/provider-api/quota-governor.d.ts +1 -0
- package/dist/provider-api/quota-governor.js +1 -1
- package/dist/provider-api/staged-datasets-store.d.ts +1 -0
- package/dist/provider-api/staged-datasets-store.js +1 -1
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/resources/store.d.ts +1 -0
- package/dist/resources/store.js +1 -1
- package/dist/search/index.js +3 -0
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/secrets/storage.d.ts +1 -0
- package/dist/secrets/storage.js +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/agent-teams-run-queue.d.ts +1 -0
- package/dist/server/agent-teams-run-queue.js +1 -1
- package/dist/server/auth-marketing.js +3 -1
- package/dist/server/auth.d.ts +1 -0
- package/dist/server/auth.js +1 -1
- package/dist/server/embed-session.d.ts +1 -0
- package/dist/server/embed-session.js +1 -1
- package/dist/server/identity-sso-store.d.ts +1 -0
- package/dist/server/identity-sso-store.js +1 -1
- package/dist/server/onboarding-html.js +121 -1
- package/dist/server/poll.d.ts +2 -0
- package/dist/server/poll.js +19 -1
- package/dist/server/release-migrations.js +5 -0
- package/dist/server/release-schema.d.ts +46 -0
- package/dist/server/release-schema.js +307 -0
- package/dist/settings/store.d.ts +1 -0
- package/dist/settings/store.js +1 -1
- package/dist/shared/environment-lanes.d.ts +28 -0
- package/dist/shared/environment-lanes.js +61 -0
- package/dist/styles/agent-native.css +17 -15
- package/dist/triggers/routes.d.ts +11 -0
- package/dist/triggers/routes.js +10 -0
- package/dist/usage/alerts-store.d.ts +1 -0
- package/dist/usage/alerts-store.js +1 -1
- package/dist/usage/store.d.ts +1 -0
- package/dist/usage/store.js +1 -1
- package/package.json +3 -3
package/corpus/README.md
CHANGED
|
@@ -168,6 +168,7 @@ export interface VideoPlayerHandle {
|
|
|
168
168
|
play: () => Promise<void> | void;
|
|
169
169
|
pause: () => void;
|
|
170
170
|
seek: (ms: number) => void;
|
|
171
|
+
getCurrentOriginalMs: () => number;
|
|
171
172
|
setSpeed: (rate: number) => void;
|
|
172
173
|
toggleMute: () => void;
|
|
173
174
|
toggleCaptions: () => void;
|
|
@@ -1159,6 +1160,17 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
|
|
|
1159
1160
|
play: requestPlay,
|
|
1160
1161
|
pause: pauseVideo,
|
|
1161
1162
|
seek: seekToVisibleMs,
|
|
1163
|
+
getCurrentOriginalMs: () => {
|
|
1164
|
+
const v = videoRef.current;
|
|
1165
|
+
const liveOriginalMs =
|
|
1166
|
+
v &&
|
|
1167
|
+
Number.isFinite(v.currentTime) &&
|
|
1168
|
+
v.currentTime >= 0 &&
|
|
1169
|
+
v.currentTime < 1e7
|
|
1170
|
+
? Math.floor(v.currentTime * 1000)
|
|
1171
|
+
: currentMsRef.current;
|
|
1172
|
+
return liveOriginalMs;
|
|
1173
|
+
},
|
|
1162
1174
|
setSpeed: applySpeed,
|
|
1163
1175
|
toggleMute: () => {
|
|
1164
1176
|
if (videoRef.current) {
|
|
@@ -159,6 +159,10 @@ function dayBucket(iso: string): string {
|
|
|
159
159
|
}
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
+
export function dictationsRefetchInterval(isActive: boolean): number | false {
|
|
163
|
+
return isActive ? 2_000 : false;
|
|
164
|
+
}
|
|
165
|
+
|
|
162
166
|
function sourceMeta(
|
|
163
167
|
source: string | undefined,
|
|
164
168
|
t: ReturnType<typeof useT>,
|
|
@@ -694,10 +698,6 @@ function DownloadDesktopAppCard() {
|
|
|
694
698
|
|
|
695
699
|
export default function DictateRoute() {
|
|
696
700
|
const t = useT();
|
|
697
|
-
const { data, isLoading, isError } = useActionQuery<
|
|
698
|
-
{ dictations: Dictation[] } | Dictation[] | undefined
|
|
699
|
-
>("list-dictations", {}, { retry: false });
|
|
700
|
-
|
|
701
701
|
const { isDesktopApp } = useDesktopPromo();
|
|
702
702
|
const [filter, setFilter] = useState<SourceFilter>("all");
|
|
703
703
|
const [listening, setListening] = useState(false);
|
|
@@ -706,6 +706,20 @@ export default function DictateRoute() {
|
|
|
706
706
|
const [speechSupported, setSpeechSupported] = useState(false);
|
|
707
707
|
const qc = useQueryClient();
|
|
708
708
|
const createDictation = useActionMutation("create-dictation");
|
|
709
|
+
const { data, isLoading, isError } = useActionQuery<
|
|
710
|
+
{ dictations: Dictation[] } | Dictation[] | undefined
|
|
711
|
+
>(
|
|
712
|
+
"list-dictations",
|
|
713
|
+
{},
|
|
714
|
+
{
|
|
715
|
+
retry: false,
|
|
716
|
+
// Action-backed mutations invalidate this query when a desktop-created
|
|
717
|
+
// dictation lands. Poll only while browser work is active or saving,
|
|
718
|
+
// rather than running a permanent interval over idle history.
|
|
719
|
+
refetchInterval: () =>
|
|
720
|
+
dictationsRefetchInterval(listening || createDictation.isPending),
|
|
721
|
+
},
|
|
722
|
+
);
|
|
709
723
|
|
|
710
724
|
const recognitionRef = useRef<SpeechRecognitionLike | null>(null);
|
|
711
725
|
const transcriptRef = useRef("");
|
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
IconSparkles,
|
|
46
46
|
IconExternalLink,
|
|
47
47
|
} from "@tabler/icons-react";
|
|
48
|
-
import { useQuery } from "@tanstack/react-query";
|
|
48
|
+
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
49
49
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
50
50
|
import { createPortal } from "react-dom";
|
|
51
51
|
import {
|
|
@@ -110,6 +110,64 @@ const PROCESSING_STUCK_TIMEOUT_MS = 12 * 60 * 1000;
|
|
|
110
110
|
const READY_MEDIA_SETTLE_POLL_MS = 20 * 1000;
|
|
111
111
|
const READY_MEDIA_SETTLE_POLL_INTERVAL_MS = 1000;
|
|
112
112
|
|
|
113
|
+
type RecordingReaction = {
|
|
114
|
+
id: string;
|
|
115
|
+
emoji: string;
|
|
116
|
+
videoTimestampMs: number;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
type PendingRecordingReaction = RecordingReaction & {
|
|
120
|
+
recordingId: string;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
export function mergeRecordingReactions(
|
|
124
|
+
serverReactions: RecordingReaction[] | undefined,
|
|
125
|
+
pendingReactions: PendingRecordingReaction[],
|
|
126
|
+
recordingId: string | undefined,
|
|
127
|
+
) {
|
|
128
|
+
const seen = new Set<string>();
|
|
129
|
+
const merged: RecordingReaction[] = [];
|
|
130
|
+
const visiblePendingReactions = recordingId
|
|
131
|
+
? pendingReactions.filter(
|
|
132
|
+
(reaction) => reaction.recordingId === recordingId,
|
|
133
|
+
)
|
|
134
|
+
: [];
|
|
135
|
+
|
|
136
|
+
for (const reaction of [
|
|
137
|
+
...(serverReactions ?? []),
|
|
138
|
+
...visiblePendingReactions,
|
|
139
|
+
]) {
|
|
140
|
+
const key = `${reaction.id}:${reaction.emoji}:${reaction.videoTimestampMs}`;
|
|
141
|
+
if (seen.has(key)) continue;
|
|
142
|
+
seen.add(key);
|
|
143
|
+
merged.push(reaction);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return merged;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function removePendingReaction(
|
|
150
|
+
pendingReactions: PendingRecordingReaction[],
|
|
151
|
+
pendingId: string,
|
|
152
|
+
) {
|
|
153
|
+
return pendingReactions.filter((reaction) => reaction.id !== pendingId);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export function handleReactionWrite(
|
|
157
|
+
response: { ok: boolean; status: number },
|
|
158
|
+
refresh: () => Promise<unknown>,
|
|
159
|
+
) {
|
|
160
|
+
if (!response.ok) throw new Error(`react failed: ${response.status}`);
|
|
161
|
+
// The write is authoritative. A transient read failure must not tell the
|
|
162
|
+
// player that the reaction failed.
|
|
163
|
+
void Promise.resolve()
|
|
164
|
+
.then(refresh)
|
|
165
|
+
.catch((refreshError) => {
|
|
166
|
+
console.warn("[clips] reaction refresh failed", refreshError);
|
|
167
|
+
});
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
|
|
113
171
|
export function meta() {
|
|
114
172
|
return [{ title: enMessages.recordingRoute.pageTitle }];
|
|
115
173
|
}
|
|
@@ -263,16 +321,7 @@ export default function RecordingPage() {
|
|
|
263
321
|
// live time bridge, so we fall back to the last position the player reported
|
|
264
322
|
// via onTimeUpdate (seek/initial start).
|
|
265
323
|
const resolvePlaybackMs = useCallback(() => {
|
|
266
|
-
|
|
267
|
-
if (
|
|
268
|
-
typeof liveCt === "number" &&
|
|
269
|
-
Number.isFinite(liveCt) &&
|
|
270
|
-
liveCt >= 0 &&
|
|
271
|
-
liveCt < 1e7
|
|
272
|
-
) {
|
|
273
|
-
return Math.floor(liveCt * 1000);
|
|
274
|
-
}
|
|
275
|
-
return currentMs;
|
|
324
|
+
return playerRef.current?.getCurrentOriginalMs() ?? currentMs;
|
|
276
325
|
}, [currentMs]);
|
|
277
326
|
// The compact layout stacks the panel below the video, so switching tabs
|
|
278
327
|
// alone leaves the user looking at the player. Desktop always renders the
|
|
@@ -310,9 +359,13 @@ export default function RecordingPage() {
|
|
|
310
359
|
recordingId ? { type: "recording" as const, id: recordingId } : null,
|
|
311
360
|
[recordingId],
|
|
312
361
|
);
|
|
362
|
+
const queryClient = useQueryClient();
|
|
313
363
|
const lastPlayerStateWriteRef = useRef(0);
|
|
314
364
|
const readyMediaPollRef = useRef<{ key: string; until: number } | null>(null);
|
|
315
365
|
const [metadataRefreshUntil, setMetadataRefreshUntil] = useState(0);
|
|
366
|
+
const [pendingReactions, setPendingReactions] = useState<
|
|
367
|
+
PendingRecordingReaction[]
|
|
368
|
+
>([]);
|
|
316
369
|
|
|
317
370
|
const playerDataQ = useActionQuery<any>(
|
|
318
371
|
"get-recording-player-data",
|
|
@@ -414,7 +467,15 @@ export default function RecordingPage() {
|
|
|
414
467
|
| "viewer"
|
|
415
468
|
| undefined;
|
|
416
469
|
const comments = playerDataQ.data?.comments ?? [];
|
|
417
|
-
const reactions =
|
|
470
|
+
const reactions = useMemo(
|
|
471
|
+
() =>
|
|
472
|
+
mergeRecordingReactions(
|
|
473
|
+
playerDataQ.data?.reactions,
|
|
474
|
+
pendingReactions,
|
|
475
|
+
recordingId,
|
|
476
|
+
),
|
|
477
|
+
[pendingReactions, playerDataQ.data?.reactions, recordingId],
|
|
478
|
+
);
|
|
418
479
|
const chapters = playerDataQ.data?.chapters ?? [];
|
|
419
480
|
const transcriptSegments = playerDataQ.data?.transcript?.segments ?? [];
|
|
420
481
|
const transcriptFullText = playerDataQ.data?.transcript?.fullText ?? null;
|
|
@@ -1643,11 +1704,10 @@ export default function RecordingPage() {
|
|
|
1643
1704
|
},
|
|
1644
1705
|
)
|
|
1645
1706
|
.then((res) => {
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1707
|
+
return handleReactionWrite(res, () =>
|
|
1708
|
+
playerDataQ.refetch(),
|
|
1709
|
+
);
|
|
1649
1710
|
})
|
|
1650
|
-
.then(() => true)
|
|
1651
1711
|
.catch((err) => {
|
|
1652
1712
|
console.warn("[clips] react failed", err);
|
|
1653
1713
|
return false;
|
|
@@ -1743,6 +1803,18 @@ export default function RecordingPage() {
|
|
|
1743
1803
|
onReact={(emoji) => {
|
|
1744
1804
|
tracking.reportReaction(emoji);
|
|
1745
1805
|
const liveMs = resolvePlaybackMs();
|
|
1806
|
+
const pendingReaction: PendingRecordingReaction = {
|
|
1807
|
+
id: `pending-${Date.now()}-${Math.random()
|
|
1808
|
+
.toString(36)
|
|
1809
|
+
.slice(2)}`,
|
|
1810
|
+
emoji,
|
|
1811
|
+
videoTimestampMs: liveMs,
|
|
1812
|
+
recordingId: recording.id,
|
|
1813
|
+
};
|
|
1814
|
+
setPendingReactions((current) => [
|
|
1815
|
+
...current,
|
|
1816
|
+
pendingReaction,
|
|
1817
|
+
]);
|
|
1746
1818
|
return fetch(
|
|
1747
1819
|
agentNativePath(
|
|
1748
1820
|
"/_agent-native/actions/react-to-recording",
|
|
@@ -1758,12 +1830,34 @@ export default function RecordingPage() {
|
|
|
1758
1830
|
},
|
|
1759
1831
|
)
|
|
1760
1832
|
.then((res) => {
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1833
|
+
const writeSucceeded = handleReactionWrite(
|
|
1834
|
+
res,
|
|
1835
|
+
() =>
|
|
1836
|
+
Promise.all([
|
|
1837
|
+
queryClient.invalidateQueries({
|
|
1838
|
+
queryKey: [
|
|
1839
|
+
"action",
|
|
1840
|
+
"get-recording-player-data",
|
|
1841
|
+
],
|
|
1842
|
+
}),
|
|
1843
|
+
playerDataQ.refetch(),
|
|
1844
|
+
]),
|
|
1845
|
+
);
|
|
1846
|
+
setPendingReactions((current) =>
|
|
1847
|
+
removePendingReaction(
|
|
1848
|
+
current,
|
|
1849
|
+
pendingReaction.id,
|
|
1850
|
+
),
|
|
1851
|
+
);
|
|
1852
|
+
return writeSucceeded;
|
|
1764
1853
|
})
|
|
1765
|
-
.then(() => true)
|
|
1766
1854
|
.catch((err) => {
|
|
1855
|
+
setPendingReactions((current) =>
|
|
1856
|
+
removePendingReaction(
|
|
1857
|
+
current,
|
|
1858
|
+
pendingReaction.id,
|
|
1859
|
+
),
|
|
1860
|
+
);
|
|
1767
1861
|
console.warn("[clips] react failed", err);
|
|
1768
1862
|
return false;
|
|
1769
1863
|
});
|
|
@@ -679,6 +679,7 @@ export default function ShareRoute() {
|
|
|
679
679
|
// an anonymous viewer sees the same controls but triggers the sign-in
|
|
680
680
|
// prompt instead (see `requireSignIn` below).
|
|
681
681
|
const viewerCanComment = Boolean(session) && viewerRole != null;
|
|
682
|
+
const viewerCanUseFullscreenInteractions = !session || viewerCanComment;
|
|
682
683
|
const viewerIsOwner = Boolean(dataQ.data?.data?.viewer?.isOwner);
|
|
683
684
|
const canReshareLink =
|
|
684
685
|
(viewerRole === "viewer" || viewerRole === "commenter") &&
|
|
@@ -1252,66 +1253,85 @@ export default function ShareRoute() {
|
|
|
1252
1253
|
cta={firstCta}
|
|
1253
1254
|
onCtaClick={() => tracking.reportCtaClick()}
|
|
1254
1255
|
onTimeUpdate={(ms) => setCurrentMs(ms)}
|
|
1255
|
-
onCommentClick={
|
|
1256
|
+
onCommentClick={
|
|
1257
|
+
viewerCanUseFullscreenInteractions
|
|
1258
|
+
? () => setPanel("comments")
|
|
1259
|
+
: undefined
|
|
1260
|
+
}
|
|
1256
1261
|
onFullscreenChange={setIsPlayerFullscreen}
|
|
1257
|
-
enableComments={
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1262
|
+
enableComments={
|
|
1263
|
+
recording.enableComments && viewerCanUseFullscreenInteractions
|
|
1264
|
+
}
|
|
1265
|
+
onAddComment={
|
|
1266
|
+
viewerCanUseFullscreenInteractions
|
|
1267
|
+
? () => {
|
|
1268
|
+
if (!session) {
|
|
1269
|
+
requireSignIn("comment");
|
|
1270
|
+
return;
|
|
1271
|
+
}
|
|
1272
|
+
const liveCt = isLoomEmbedBacked
|
|
1273
|
+
? null
|
|
1274
|
+
: playerRef.current?.video?.currentTime;
|
|
1275
|
+
const liveMs =
|
|
1276
|
+
typeof liveCt === "number" &&
|
|
1277
|
+
Number.isFinite(liveCt) &&
|
|
1278
|
+
liveCt >= 0 &&
|
|
1279
|
+
liveCt < 1e7
|
|
1280
|
+
? Math.floor(liveCt * 1000)
|
|
1281
|
+
: currentMs;
|
|
1282
|
+
setCommentAtMs(liveMs);
|
|
1283
|
+
setCommentOpen(true);
|
|
1284
|
+
}
|
|
1285
|
+
: undefined
|
|
1286
|
+
}
|
|
1287
|
+
enableReactions={
|
|
1288
|
+
recording.enableReactions && viewerCanUseFullscreenInteractions
|
|
1289
|
+
}
|
|
1290
|
+
onReact={
|
|
1291
|
+
viewerCanUseFullscreenInteractions
|
|
1292
|
+
? (emoji) => {
|
|
1293
|
+
if (!session) {
|
|
1294
|
+
requireSignIn("react");
|
|
1295
|
+
return false;
|
|
1296
|
+
}
|
|
1297
|
+
tracking.reportReaction(emoji);
|
|
1298
|
+
const liveCt = isLoomEmbedBacked
|
|
1299
|
+
? null
|
|
1300
|
+
: playerRef.current?.video?.currentTime;
|
|
1301
|
+
const liveMs =
|
|
1302
|
+
typeof liveCt === "number" &&
|
|
1303
|
+
Number.isFinite(liveCt) &&
|
|
1304
|
+
liveCt >= 0 &&
|
|
1305
|
+
liveCt < 1e7
|
|
1306
|
+
? Math.floor(liveCt * 1000)
|
|
1307
|
+
: currentMs;
|
|
1308
|
+
return fetch(
|
|
1309
|
+
agentNativePath(
|
|
1310
|
+
"/_agent-native/actions/react-to-recording",
|
|
1311
|
+
),
|
|
1312
|
+
{
|
|
1313
|
+
method: "POST",
|
|
1314
|
+
headers: { "Content-Type": "application/json" },
|
|
1315
|
+
body: JSON.stringify({
|
|
1316
|
+
recordingId: recording.id,
|
|
1317
|
+
emoji,
|
|
1318
|
+
videoTimestampMs: liveMs,
|
|
1319
|
+
}),
|
|
1320
|
+
},
|
|
1321
|
+
)
|
|
1322
|
+
.then((res) => {
|
|
1323
|
+
if (!res.ok)
|
|
1324
|
+
throw new Error(`react failed: ${res.status}`);
|
|
1325
|
+
return dataQ.refetch();
|
|
1326
|
+
})
|
|
1327
|
+
.then(() => true)
|
|
1328
|
+
.catch((err) => {
|
|
1329
|
+
console.warn("[clips] react failed", err);
|
|
1330
|
+
return false;
|
|
1331
|
+
});
|
|
1332
|
+
}
|
|
1333
|
+
: undefined
|
|
1334
|
+
}
|
|
1315
1335
|
className="h-full w-full rounded-none sm:rounded-xl"
|
|
1316
1336
|
/>
|
|
1317
1337
|
{commentOpen && viewerCanComment
|
|
@@ -1354,23 +1374,15 @@ export default function ShareRoute() {
|
|
|
1354
1374
|
{recording.enableComments ? (
|
|
1355
1375
|
<TimestampedCommentButton
|
|
1356
1376
|
enableComments={recording.enableComments}
|
|
1357
|
-
canComment
|
|
1377
|
+
canComment={!session || viewerCanComment}
|
|
1358
1378
|
className="shrink-0"
|
|
1359
1379
|
onOpen={() => {
|
|
1360
1380
|
if (!session) {
|
|
1361
1381
|
requireSignIn("comment");
|
|
1362
1382
|
return;
|
|
1363
1383
|
}
|
|
1364
|
-
const liveCt = isLoomEmbedBacked
|
|
1365
|
-
? null
|
|
1366
|
-
: playerRef.current?.video?.currentTime;
|
|
1367
1384
|
const liveMs =
|
|
1368
|
-
|
|
1369
|
-
Number.isFinite(liveCt) &&
|
|
1370
|
-
liveCt >= 0 &&
|
|
1371
|
-
liveCt < 1e7
|
|
1372
|
-
? Math.floor(liveCt * 1000)
|
|
1373
|
-
: currentMs;
|
|
1385
|
+
playerRef.current?.getCurrentOriginalMs() ?? currentMs;
|
|
1374
1386
|
setCommentAtMs(liveMs);
|
|
1375
1387
|
setCommentOpen(true);
|
|
1376
1388
|
}}
|
|
@@ -1379,22 +1391,15 @@ export default function ShareRoute() {
|
|
|
1379
1391
|
{recording.enableReactions ? (
|
|
1380
1392
|
<ReactionsTray
|
|
1381
1393
|
reactions={reactions}
|
|
1394
|
+
disabled={Boolean(session) && !viewerCanComment}
|
|
1382
1395
|
onReact={(emoji) => {
|
|
1383
1396
|
if (!session) {
|
|
1384
1397
|
requireSignIn("react");
|
|
1385
1398
|
return false;
|
|
1386
1399
|
}
|
|
1387
1400
|
tracking.reportReaction(emoji);
|
|
1388
|
-
const liveCt = isLoomEmbedBacked
|
|
1389
|
-
? null
|
|
1390
|
-
: playerRef.current?.video?.currentTime;
|
|
1391
1401
|
const liveMs =
|
|
1392
|
-
|
|
1393
|
-
Number.isFinite(liveCt) &&
|
|
1394
|
-
liveCt >= 0 &&
|
|
1395
|
-
liveCt < 1e7
|
|
1396
|
-
? Math.floor(liveCt * 1000)
|
|
1397
|
-
: currentMs;
|
|
1402
|
+
playerRef.current?.getCurrentOriginalMs() ?? currentMs;
|
|
1398
1403
|
return fetch(
|
|
1399
1404
|
agentNativePath(
|
|
1400
1405
|
"/_agent-native/actions/react-to-recording",
|
|
@@ -70,7 +70,7 @@ async function fetchEmailList(
|
|
|
70
70
|
|
|
71
71
|
const gmailQuery = buildGmailEmailSearchQuery({ view, q: search });
|
|
72
72
|
const effectiveQuery =
|
|
73
|
-
view === "all" && !search ? "" : gmailQuery || "in:inbox
|
|
73
|
+
view === "all" && !search ? "" : gmailQuery || "in:inbox";
|
|
74
74
|
const { messages } = await listGmailMessages(
|
|
75
75
|
effectiveQuery,
|
|
76
76
|
50,
|
|
@@ -69,17 +69,25 @@ function googleOAuthErrorPayload(
|
|
|
69
69
|
error?.name === "OAuthAccountOwnedByOtherUserError"
|
|
70
70
|
) {
|
|
71
71
|
const account = error.accountId || "This Google account";
|
|
72
|
+
const message = `${account} is connected to another login. Sign out, then sign in with ${account}.`;
|
|
72
73
|
return {
|
|
73
|
-
message
|
|
74
|
+
message,
|
|
74
75
|
code: "account_owner_mismatch",
|
|
75
76
|
accountId: error.accountId,
|
|
76
77
|
};
|
|
77
78
|
}
|
|
78
79
|
|
|
79
80
|
const msg = error?.message || "Unknown error";
|
|
81
|
+
const statusCode = Number(error?.statusCode || error?.status || 0);
|
|
80
82
|
const isPermission =
|
|
83
|
+
error?.oauthErrorCode === "access_denied" ||
|
|
84
|
+
error?.oauthErrorCode === "forbidden" ||
|
|
85
|
+
error?.oauthErrorCode === "insufficient_scope" ||
|
|
81
86
|
msg.includes("Insufficient Permission") ||
|
|
82
|
-
msg.includes("insufficient_scope")
|
|
87
|
+
msg.includes("insufficient_scope") ||
|
|
88
|
+
/insufficient authentication scopes/i.test(msg) ||
|
|
89
|
+
(statusCode === 403 &&
|
|
90
|
+
/\b(?:scope|permission|forbidden|access denied)\b/i.test(msg));
|
|
83
91
|
return {
|
|
84
92
|
message: isPermission
|
|
85
93
|
? "This account wasn't granted the required permissions. Make sure you check all the permission boxes on the consent screen. If the app is in testing mode, add this email as a test user in Google Cloud Console."
|
|
@@ -212,16 +220,11 @@ export const handleGoogleCallback = defineEventHandler(
|
|
|
212
220
|
if (googleError) {
|
|
213
221
|
const errorDesc =
|
|
214
222
|
(query.error_description as string | undefined) || googleError;
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
: `Connection failed: ${errorDesc}`;
|
|
221
|
-
return googleOAuthErrorResponse(event, new Error(userMessage), {
|
|
222
|
-
desktop,
|
|
223
|
-
flowId,
|
|
224
|
-
});
|
|
223
|
+
return googleOAuthErrorResponse(
|
|
224
|
+
event,
|
|
225
|
+
Object.assign(new Error(errorDesc), { oauthErrorCode: googleError }),
|
|
226
|
+
{ desktop, flowId },
|
|
227
|
+
);
|
|
225
228
|
}
|
|
226
229
|
|
|
227
230
|
const code = query.code as string;
|
|
@@ -442,16 +445,11 @@ export const handleGoogleAddAccountCallback = defineEventHandler(
|
|
|
442
445
|
if (googleError) {
|
|
443
446
|
const errorDesc =
|
|
444
447
|
(query.error_description as string | undefined) || googleError;
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
: `Connection failed: ${errorDesc}`;
|
|
451
|
-
return googleOAuthErrorResponse(event, new Error(userMessage), {
|
|
452
|
-
desktop,
|
|
453
|
-
flowId,
|
|
454
|
-
});
|
|
448
|
+
return googleOAuthErrorResponse(
|
|
449
|
+
event,
|
|
450
|
+
Object.assign(new Error(errorDesc), { oauthErrorCode: googleError }),
|
|
451
|
+
{ desktop, flowId },
|
|
452
|
+
);
|
|
455
453
|
}
|
|
456
454
|
|
|
457
455
|
const { redirectUri, owner: stateOwner } = state;
|
|
@@ -6,8 +6,11 @@ import { isSelfAddressedThread } from "@shared/self-notes.js";
|
|
|
6
6
|
import type { EmailMessage } from "@shared/types.js";
|
|
7
7
|
|
|
8
8
|
export const VIEW_QUERIES: Record<string, string> = {
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
// Keep sent replies in a matching Gmail thread. The local thread filter
|
|
10
|
+
// below excludes sent-only threads while preserving received inbox threads
|
|
11
|
+
// whose latest message was sent by the user.
|
|
12
|
+
inbox: "in:inbox",
|
|
13
|
+
unread: "is:unread in:inbox",
|
|
11
14
|
starred: "is:starred",
|
|
12
15
|
sent: "in:sent",
|
|
13
16
|
drafts: "in:drafts",
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SIDEBAR_STATE_CHANGE_EVENT,
|
|
3
|
-
BuilderSetupCard,
|
|
4
3
|
sendToAgentChat,
|
|
5
4
|
setAgentChatContextItem,
|
|
6
5
|
useAgentEngineConfigured,
|
|
@@ -8466,23 +8465,12 @@ function CreatePlanDialog({
|
|
|
8466
8465
|
</DialogDescription>
|
|
8467
8466
|
</DialogHeader>
|
|
8468
8467
|
<div className="grid gap-3">
|
|
8469
|
-
{canCreate && agentMissing ? (
|
|
8470
|
-
<BuilderSetupCard
|
|
8471
|
-
fullWidth
|
|
8472
|
-
onConnected={() =>
|
|
8473
|
-
window.dispatchEvent(
|
|
8474
|
-
new Event("agent-engine:configured-changed"),
|
|
8475
|
-
)
|
|
8476
|
-
}
|
|
8477
|
-
/>
|
|
8478
|
-
) : null}
|
|
8479
8468
|
<div className="rounded-xl border border-border bg-background p-2 shadow-sm">
|
|
8480
8469
|
<PromptComposer
|
|
8481
8470
|
autoFocus
|
|
8482
8471
|
disabled={composerLocked}
|
|
8483
8472
|
attachmentsEnabled={false}
|
|
8484
8473
|
showModelSelector={false}
|
|
8485
|
-
modelStatusChecksEnabled={false}
|
|
8486
8474
|
placeholder={t("plansPage.create.placeholder")}
|
|
8487
8475
|
draftScope="plans:create-plan"
|
|
8488
8476
|
initialText={promptSeed}
|
package/dist/a2a/task-store.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Task, Message, TaskState, Artifact } from "./types.js";
|
|
2
2
|
export declare const MAX_A2A_IDEMPOTENCY_KEY_CHARS = 128;
|
|
3
3
|
export declare const A2A_PERSONAL_OWNER_SCOPE = "__personal__";
|
|
4
|
+
export declare function ensureTable(): Promise<void>;
|
|
4
5
|
export interface A2AApprovalRecord {
|
|
5
6
|
id: string;
|
|
6
7
|
taskId: string;
|
package/dist/a2a/task-store.js
CHANGED
|
@@ -5,7 +5,7 @@ let _initPromise;
|
|
|
5
5
|
export const MAX_A2A_IDEMPOTENCY_KEY_CHARS = 128;
|
|
6
6
|
const A2A_IDEMPOTENCY_INDEX = "idx_a2a_tasks_owner_scope_idempotency";
|
|
7
7
|
export const A2A_PERSONAL_OWNER_SCOPE = "__personal__";
|
|
8
|
-
async function ensureTable() {
|
|
8
|
+
export async function ensureTable() {
|
|
9
9
|
if (!_initPromise) {
|
|
10
10
|
_initPromise = (async () => {
|
|
11
11
|
const client = getDbExec();
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
* runtime even before the migration plugin is registered.
|
|
13
13
|
*/
|
|
14
14
|
import type { ObservationalMemoryEntry, ObservationalMemoryOwner, ObservationalMemoryTier } from "./types.js";
|
|
15
|
+
export declare function ensureTable(): Promise<void>;
|
|
15
16
|
/** Reset the cached ensureTable promise — test-only seam. */
|
|
16
17
|
export declare function __resetObservationalMemoryTableCache(): void;
|
|
17
18
|
export interface InsertObservationalMemoryInput extends ObservationalMemoryOwner {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
import { getDbExec, isPostgres } from "../../db/client.js";
|
|
15
15
|
import { ensureTableExists, ensureIndexExists } from "../../db/ddl-guard.js";
|
|
16
16
|
let tableReady = null;
|
|
17
|
-
async function ensureTable() {
|
|
17
|
+
export async function ensureTable() {
|
|
18
18
|
if (tableReady)
|
|
19
19
|
return tableReady;
|
|
20
20
|
tableReady = (async () => {
|
|
@@ -217,6 +217,7 @@ export declare const IN_FLIGHT_RUN_STALE_GRACE_MS: number;
|
|
|
217
217
|
* is reaped like any other stale run.
|
|
218
218
|
*/
|
|
219
219
|
export declare const IN_FLIGHT_GRACE_MAX_LIVENESS_GAP_MS = 120000;
|
|
220
|
+
export declare function ensureRunTables(): Promise<void>;
|
|
220
221
|
/**
|
|
221
222
|
* Persist a zombie tool-call completion to the ledger. Called by the detached
|
|
222
223
|
* promise continuation after `Promise.race` abandons it. Best-effort — never
|