authorgravatar for me@t3.ggTheo Browne <me@t3.gg> 2026-08-27 22:29:30-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-08-27 22:29:30-07:00
log2fbe313096b54a3422e101ed1bcc3589f6cf371c
tree16fea27b34e8b57301819e0bb0158a05e769cc1e
parent850e4582e4c828b1533a400bf56a532721239198
signature Signed by PGP key B5690EEEBB952194

fix(desktop): allow preview automation in agent-created threads (#8483)


4 files changed, 54 insertions(+), 5 deletions(-)

apps/desktop/src/ipc/methods/preview.test.ts+43
......@@ -1,4 +1,5 @@
11import { it as effectIt } from "@effect/vitest";
2import { PreviewAutomationStatus } from "@t3tools/contracts";
23import * as Cause from "effect/Cause";
34import * as Effect from "effect/Effect";
45import * as Exit from "effect/Exit";
......@@ -51,4 +52,46 @@ describe("preview IPC methods", () => {
5152 },
5253 ),
5354 );
55
56 effectIt.effect("returns automation status for long runtime tab ids", () =>
57 Effect.gen(function* () {
58 const tabId =
59 `["environment-1","thread:delegated-task:${"a".repeat(120)}",` +
60 `"server-epoch-1","preview-1"]`;
61 const status = {
62 available: false,
63 visible: true,
64 tabId,
65 url: null,
66 title: null,
67 loading: false,
68 };
69 const manager = PreviewManager.PreviewManager.of({
70 automationStatus: () => Effect.succeed(status),
71 } as unknown as PreviewManager.PreviewManager["Service"]);
72
73 expect(tabId.length).toBeGreaterThan(128);
74 expect(
75 yield* PreviewIpc.automationStatus
76 .handler({ tabId })
77 .pipe(Effect.provideService(PreviewManager.PreviewManager, manager)),
78 ).toEqual(status);
79 }),
80 );
81
82 it("keeps the public automation status tab id limit", () => {
83 const encode = Schema.encodeUnknownSync(PreviewAutomationStatus);
84 const tabId = "t".repeat(129);
85
86 expect(() =>
87 encode({
88 available: false,
89 visible: true,
90 tabId,
91 url: null,
92 title: null,
93 loading: false,
94 }),
95 ).toThrow();
96 });
5497});
apps/desktop/src/ipc/methods/preview.ts+2-2
......@@ -5,6 +5,7 @@ import {
55 DesktopPreviewAutomationEvaluateInputSchema,
66 DesktopPreviewAutomationPressInputSchema,
77 DesktopPreviewAutomationScrollInputSchema,
8 DesktopPreviewAutomationStatusSchema,
89 DesktopPreviewAutomationTypeInputSchema,
910 DesktopPreviewAutomationWaitForInputSchema,
1011 DesktopPreviewConfigInputSchema,
......@@ -20,7 +21,6 @@ import {
2021 DesktopPreviewWebviewConfigSchema,
2122 PreviewAnnotationSubmissionResultSchema,
2223 PreviewAutomationSnapshot,
23 PreviewAutomationStatus,
2424} from "@t3tools/contracts";
2525import * as Effect from "effect/Effect";
2626import * as Schema from "effect/Schema";
......@@ -282,7 +282,7 @@ export const copyArtifactToClipboard = DesktopIpc.makeIpcMethod({
282282export const automationStatus = DesktopIpc.makeIpcMethod({
283283 channel: IpcChannels.PREVIEW_AUTOMATION_STATUS_CHANNEL,
284284 payload: DesktopPreviewTabInputSchema,
285 result: PreviewAutomationStatus,
285 result: DesktopPreviewAutomationStatusSchema,
286286 handler: Effect.fn("desktop.ipc.preview.automationStatus")(function* ({ tabId }) {
287287 const manager = yield* PreviewManager.PreviewManager;
288288 return yield* manager.automationStatus(tabId);
apps/desktop/src/preview/Manager.ts+2-2
......@@ -7,6 +7,7 @@
77 */
88import type {
99 DesktopPreviewAnnotationTheme,
10 DesktopPreviewAutomationStatus,
1011 DesktopPreviewColorScheme,
1112 DesktopPreviewFavicon,
1213 DesktopPreviewPointerEvent,
......@@ -25,7 +26,6 @@ import type {
2526 PreviewAutomationNetworkEntry,
2627 PreviewAutomationScrollInput,
2728 PreviewAutomationSnapshot,
28 PreviewAutomationStatus,
2929 PreviewAutomationTypeInput,
3030 PreviewAutomationWaitForInput,
3131} from "@t3tools/contracts";
......@@ -4089,7 +4089,7 @@ export class PreviewManager extends Context.Service<
40894089 ) => Effect.Effect<DesktopPreviewRecordingArtifact, PreviewManagerError>;
40904090 readonly automationStatus: (
40914091 tabId: string,
4092 ) => Effect.Effect<PreviewAutomationStatus, PreviewManagerError>;
4092 ) => Effect.Effect<DesktopPreviewAutomationStatus, PreviewManagerError>;
40934093 readonly automationSnapshot: (
40944094 tabId: string,
40954095 ) => Effect.Effect<PreviewAutomationSnapshot, PreviewManagerError>;
packages/contracts/src/ipc.ts+7-1
......@@ -584,6 +584,12 @@ export const DesktopPreviewTabIdSchema = Schema.String.check(Schema.isTrimmed())
584584 Schema.isNonEmpty(),
585585);
586586
587export const DesktopPreviewAutomationStatusSchema = Schema.Struct({
588 ...PreviewAutomationStatus.fields,
589 tabId: Schema.NullOr(DesktopPreviewTabIdSchema),
590});
591export type DesktopPreviewAutomationStatus = typeof DesktopPreviewAutomationStatusSchema.Type;
592
587593export const DesktopPreviewNavStatusSchema = Schema.Union([
588594 Schema.Struct({ kind: Schema.Literal("Idle") }),
589595 Schema.Struct({
......@@ -1217,7 +1223,7 @@ export interface DesktopPreviewBridge {
12171223 onFrame: (listener: (frame: DesktopPreviewRecordingFrame) => void) => () => void;
12181224 };
12191225 automation: {
1220 status: (tabId: string) => Promise<PreviewAutomationStatus>;
1226 status: (tabId: string) => Promise<DesktopPreviewAutomationStatus>;
12211227 snapshot: (tabId: string) => Promise<PreviewAutomationSnapshot>;
12221228 click: (tabId: string, input: PreviewAutomationClickInput) => Promise<void>;
12231229 type: (tabId: string, input: PreviewAutomationTypeInput) => Promise<void>;