///
import * as NodeCrypto from "node:crypto";
import { beforeEach, vi } from "vite-plus/test";
import { describe, expect, it } from "@effect/vitest";
import Constants from "expo-constants";
import * as Cause from "effect/Cause";
import type { LiveActivity } from "expo-widgets";
import * as DateTime from "effect/DateTime";
import * as TestClock from "effect/testing/TestClock";
import { makeRawThreadShell } from "../../test-fixtures";
import * as Effect from "effect/Effect";
import * as Deferred from "effect/Deferred";
import * as Exit from "effect/Exit";
import * as Fiber from "effect/Fiber";
import * as Layer from "effect/Layer";
import { Cookies, FetchHttpClient, HttpClientRequest, HttpClientResponse } from "effect/http";
import * as Option from "effect/Option";
import { Atom } from "effect/reactivity";
import { ManagedRelay } from "@t3tools/client-runtime/relay";
import { PrimaryConnectionTarget } from "@t3tools/client-runtime/connection";
import type { EnvironmentCatalogState } from "@t3tools/client-runtime/state/connections";
import type { EnvironmentShellState } from "@t3tools/client-runtime/state/shell";
import {
EnvironmentId,
ProjectId,
ProviderInstanceId,
ThreadId,
type OrchestrationProjectShell,
} from "@t3tools/contracts";
import type { RelayAgentActivitySnapshotResponse } from "@t3tools/contracts/relay";
import { verifyDpopProof } from "@t3tools/shared/dpop";
import * as Dpop from "../cloud/dpop";
import * as ManagedRelayLayer from "../cloud/managedRelayLayer";
import {
clearAgentAwarenessRegistrationRecord,
loadAgentAwarenessRegistrationRecord,
loadOrCreateAgentAwarenessDeviceId,
loadPreferences,
saveAgentAwarenessRegistrationRecord,
} from "../../persistence/imperative";
import type { Preferences } from "../../persistence/mobile-preferences";
import { makeRelayDeviceRegistrationRequest } from "./registrationPayload";
import {
__resetAgentAwarenessRemoteRegistrationForTest,
armAgentAwarenessLiveActivityForLocalWork,
getAgentAwarenessRegistrationStatus,
refreshActiveLiveActivityRemoteRegistration,
refreshAgentAwarenessRegistration,
registerLiveActivityPushToken,
releaseAgentAwarenessRelayTokenProvider,
setAgentAwarenessRelayTokenProvider,
updateAgentAwarenessRegistrationPreferences,
type AgentAwarenessRegistrationError,
} from "./remoteRegistration";
import type { AgentActivityProps } from "../../widgets/AgentActivity";
import { publishAgentActivityWidget } from "./agentLiveActivity";
import {
agentActivityTimeline,
AGENT_ACTIVITY_FRESHNESS_MS,
} from "../../widgets/agentActivityTimeline";
import * as Notifications from "expo-notifications";
import { Platform } from "react-native";
import { configureAndroidAgentNotifications } from "./androidNotifications";
import {
agentWidgetToken,
configureAgentWidgetRefresh,
clearAgentWidgetRefresh,
} from "./agentWidgetRefresh";
vi.mock("./agentWidgetRefresh", () => ({
agentWidgetToken: vi.fn(() => null),
configureAgentWidgetRefresh: vi.fn(),
clearAgentWidgetRefresh: vi.fn(),
}));
vi.mock("./androidNotifications", () => ({
supportsAndroidAgentNotifications: vi.fn(() => true),
configureAndroidAgentNotifications: vi.fn(),
clearAndroidAgentNotifications: vi.fn(),
}));
import { appAtomRegistry } from "../../state/atom-registry";
import { environmentCatalog } from "../../connection/catalog";
import { environmentShell } from "../../state/shell";
const secureStore = vi.hoisted(() => new Map());
const widgetMocks = vi.hoisted(() => ({
dismissEnded: vi.fn(),
getInstances: vi.fn<() => ReadonlyArray>>>(() => []),
start: vi.fn(() => ({})),
}));
const environmentConfigsMock = vi.hoisted(() => ({
configs: new Map<
string,
{ environment: { capabilities: { agentActivityPublishing?: boolean } } }
>(),
}));
const backgroundRuntime = vi.hoisted(() => ({
pending: [] as Array<{
readonly operation: unknown;
readonly resolve: (exit: Exit.Exit) => void;
}>,
}));
const appStateMock = vi.hoisted(() => ({
currentState: "active",
listeners: [] as Array<(state: string) => void>,
}));
const registrationRecordStore = vi.hoisted(() => ({
current: null as {
readonly identity: string;
readonly signature: string;
readonly pushToStartToken?: string;
} | null,
}));
vi.mock("expo-constants", () => ({
default: {
expoConfig: {
version: "1.0.0",
extra: {},
},
},
}));
vi.mock("expo-widgets", () => ({
addPushToStartTokenListener: vi.fn(() => ({ remove: vi.fn() })),
}));
vi.mock("./agentLiveActivity", () => ({
dismissEndedAgentLiveActivities: widgetMocks.dismissEnded,
getAgentLiveActivities: widgetMocks.getInstances,
startAgentLiveActivity: widgetMocks.start,
publishAgentActivityWidget: vi.fn(() => true),
}));
// Keep the native connection boundary synthetic while exercising the real atom
// registry and widget observer used by the registered app callbacks.
vi.mock("../../state/atom-registry", async () => {
const { AtomRegistry } = await import("effect/reactivity");
return { appAtomRegistry: AtomRegistry.make() };
});
vi.mock("../../state/server", async () => {
const { Atom } = await import("effect/reactivity");
return { environmentServerConfigsAtom: Atom.make(() => environmentConfigsMock.configs) };
});
vi.mock("../../connection/catalog", async () => {
const { Atom } = await import("effect/reactivity");
return {
environmentCatalog: {
catalogValueAtom: Atom.make({ isReady: true, entries: new Map() }),
},
};
});
vi.mock("../../state/shell", async () => {
const { Atom } = await import("effect/reactivity");
const Option = await import("effect/Option");
return {
environmentShell: {
stateValueAtom: Atom.family((_id: EnvironmentId) =>
Atom.make({
status: "empty",
generation: 0,
removedAt: new Map(),
snapshot: Option.none(),
error: Option.none(),
}),
),
},
};
});
vi.mock("expo-notifications", () => ({
AndroidImportance: { NONE: 0, HIGH: 4 },
getNotificationChannelAsync: vi.fn(() => Promise.resolve(null)),
addPushTokenListener: vi.fn(() => ({ remove: vi.fn() })),
getDevicePushTokenAsync: vi.fn(() => Promise.resolve({ type: "ios", data: "apns-token" })),
getPermissionsAsync: vi.fn(() => Promise.resolve({ granted: true })),
}));
vi.mock("expo-crypto", () => ({
CryptoDigestAlgorithm: {
SHA1: "SHA-1",
SHA256: "SHA-256",
SHA384: "SHA-384",
SHA512: "SHA-512",
},
getRandomBytes: (byteCount: number) => new Uint8Array(NodeCrypto.randomBytes(byteCount)),
getRandomBytesAsync: (byteCount: number) =>
Promise.resolve(new Uint8Array(NodeCrypto.randomBytes(byteCount))),
digest: (algorithm: string, data: unknown) => {
if (!(data instanceof Uint8Array)) {
return Promise.reject(new TypeError("expo-crypto digest data must be a typed array."));
}
return Promise.resolve(
new Uint8Array(NodeCrypto.createHash(algorithm).update(data).digest()).buffer,
);
},
}));
vi.mock("expo", async () => {
const { createNodeDpopKeysModule } = await import("../cloud/dpop.testing");
const dpopKeys = createNodeDpopKeysModule();
return { requireNativeModule: () => dpopKeys };
});
vi.mock("expo-secure-store", () => ({
getItemAsync: (key: string) => Promise.resolve(secureStore.get(key) ?? null),
setItemAsync: (key: string, value: string) => {
secureStore.set(key, value);
return Promise.resolve();
},
}));
vi.mock("react-native", () => ({
Platform: {
get OS() {
return "ios";
},
get Version() {
return "18.0";
},
},
AppState: {
get currentState() {
return appStateMock.currentState;
},
addEventListener: (_event: string, listener: (state: string) => void) => {
appStateMock.listeners.push(listener);
return {
remove: () => {
const index = appStateMock.listeners.indexOf(listener);
if (index >= 0) {
appStateMock.listeners.splice(index, 1);
}
},
};
},
},
}));
vi.mock("../../lib/runtime", () => ({
runtime: {
runPromiseExit: (operation: unknown) =>
new Promise((resolve) => {
backgroundRuntime.pending.push({ operation, resolve });
}),
},
}));
vi.mock("../../persistence/imperative", () => ({
loadAgentAwarenessDeviceId: vi.fn(() => Promise.resolve("device-1")),
loadOrCreateAgentAwarenessDeviceId: vi.fn(() => Promise.resolve("device-1")),
loadPreferences: vi.fn(() => Promise.resolve({ liveActivitiesEnabled: false })),
loadAgentAwarenessRegistrationRecord: vi.fn(() =>
Promise.resolve(registrationRecordStore.current),
),
saveAgentAwarenessRegistrationRecord: vi.fn((record: { identity: string; signature: string }) => {
registrationRecordStore.current = record;
return Promise.resolve();
}),
clearAgentAwarenessRegistrationRecord: vi.fn(() => {
registrationRecordStore.current = null;
return Promise.resolve();
}),
}));
function proofIat(proof: string): number {
const payload = proof.split(".")[1];
if (!payload) {
throw new Error("Missing DPoP payload.");
}
const decoded = JSON.parse(Buffer.from(payload, "base64url").toString("utf8")) as {
readonly iat: number;
};
return decoded.iat;
}
const activeAgentActivityRow = {
environmentId: "env-1" as EnvironmentId,
threadId: "thread-1" as ThreadId,
projectTitle: "Project",
threadTitle: "Thread",
modelTitle: "gpt-5.4",
phase: "running" as const,
status: "Working",
updatedAt: "2026-05-25T13:07:00.000Z",
deepLink: "/threads/env-1/thread-1",
};
const activeAgentActivitySnapshot = {
aggregate: {
title: "T3 Code",
subtitle: "Agent work in progress",
activeCount: 1,
updatedAt: "2026-05-25T13:07:00.000Z",
activities: [activeAgentActivityRow],
},
} satisfies RelayAgentActivitySnapshotResponse;
function snapshotRelayLayer(
getAgentActivitySnapshot: (
input: Parameters[0],
) => Effect.Effect<
RelayAgentActivitySnapshotResponse,
ManagedRelay.ManagedRelayClientError
> = () => Effect.succeed(activeAgentActivitySnapshot),
) {
Constants.expoConfig!.extra = {
relay: {
url: "https://relay.example.test/",
},
};
return Layer.succeed(
ManagedRelay.ManagedRelayClient,
ManagedRelay.ManagedRelayClient.of({
relayUrl: "https://relay.example.test",
getT3ChatLink: () => Effect.die("unused"),
createT3ChatLinkRequest: () => Effect.die("unused"),
unlinkT3Chat: () => Effect.die("unused"),
listEnvironments: () => Effect.die("unused"),
listDevices: () => Effect.die("unused"),
createEnvironmentLinkChallenge: () => Effect.die("unused"),
linkEnvironment: () => Effect.die("unused"),
unlinkEnvironment: () => Effect.die("unused"),
getEnvironmentStatus: () => Effect.die("unused"),
connectEnvironment: () => Effect.die("unused"),
registerDevice: () => Effect.die("unused"),
unregisterDevice: () => Effect.die("unused"),
registerLiveActivity: () => Effect.succeed({ ok: true }),
getAgentActivitySnapshot,
resetTokenCache: Effect.void,
}),
);
}
const layerRelayTest = ManagedRelayLayer.layer("https://relay.example.test").pipe(
Layer.provide(Layer.mergeAll(FetchHttpClient.layer, Dpop.layer)),
);
function setTestAtom(atom: Atom.Atom, value: A): void {
if (!Atom.isWritable(atom)) throw new Error("Expected a writable fixture atom");
appAtomRegistry.set(atom, value);
}
const liveEnvironmentId = EnvironmentId.make("env-1");
const liveShellUpdatedAt = "2026-10-02T12:00:00.000Z";
const liveProjectId = ProjectId.make("project-1");
function setLiveShell(
phase: "starting" | "running" | "ready" | null,
status: EnvironmentShellState["status"] = "live",
now = liveShellUpdatedAt,
): void {
const project: OrchestrationProjectShell = {
id: liveProjectId,
title: "Live project",
workspaceRoot: "/synthetic/project",
defaultModelSelection: null,
scripts: [],
createdAt: now,
updatedAt: now,
};
const thread = makeRawThreadShell({
id: ThreadId.make("local-thread"),
projectId: liveProjectId,
title: "Live task",
modelSelection: { instanceId: ProviderInstanceId.make("codex"), model: "test-model" },
createdAt: DateTime.makeUnsafe(now),
updatedAt: DateTime.makeUnsafe(now),
status: phase === "ready" ? "completed" : (phase ?? "idle"),
});
setTestAtom(environmentShell.stateValueAtom(liveEnvironmentId), {
status,
generation: 0,
removedAt: new Map(),
error: Option.none(),
snapshot: Option.some({
projects: [project],
threads: phase === null ? [] : [thread],
snapshotSequence: 1,
archivedThreads: [],
schemaVersion: 1,
}),
});
}
function addLiveEnvironment(): void {
setTestAtom(environmentCatalog.catalogValueAtom, {
isReady: true,
entries: new Map([
[
liveEnvironmentId,
{
target: new PrimaryConnectionTarget({
environmentId: liveEnvironmentId,
label: "Live environment",
httpBaseUrl: "https://local.example.test",
wsBaseUrl: "wss://local.example.test/ws",
}),
profile: Option.none(),
enabled: true,
},
],
]),
});
setLiveShell(null);
}
const runBackgroundOperations = Effect.fn("TestRemoteRegistration.runBackgroundOperations")(
function* () {
let idlePasses = 0;
// oxlint-disable-next-line t3code/no-polling-loop-in-tests -- This harness drains mocked runtime jobs and their promise continuations, not external I/O or elapsed time.
for (;;) {
yield* Effect.promise(() => Promise.resolve());
const pending = backgroundRuntime.pending.shift();
if (!pending) {
idlePasses++;
if (idlePasses >= 3) {
return;
}
continue;
}
idlePasses = 0;
const exit = yield* Effect.exit(
pending.operation as Effect.Effect<
unknown,
AgentAwarenessRegistrationError,
ManagedRelay.ManagedRelayClient
>,
);
yield* Effect.sync(() => {
pending.resolve(exit);
});
}
},
);
describe("makeRelayDeviceRegistrationRequest", () => {
beforeEach(() => {
vi.restoreAllMocks();
// Freshness windows compare against fixture timestamps, not the runner clock.
vi.spyOn(Date, "now").mockReturnValue(Date.parse(liveShellUpdatedAt));
vi.mocked(Notifications.getDevicePushTokenAsync).mockResolvedValue({
type: "ios",
data: "apns-token",
});
vi.mocked(Notifications.getPermissionsAsync).mockReset();
vi.mocked(Notifications.getPermissionsAsync).mockResolvedValue({
granted: true,
} as Awaited>);
vi.mocked(Notifications.getNotificationChannelAsync).mockResolvedValue(null);
vi.unstubAllGlobals();
vi.stubGlobal("__DEV__", false);
secureStore.clear();
backgroundRuntime.pending.length = 0;
Constants.expoConfig!.extra = {};
__resetAgentAwarenessRemoteRegistrationForTest();
appAtomRegistry.reset();
appStateMock.currentState = "active";
appStateMock.listeners.length = 0;
registrationRecordStore.current = null;
vi.mocked(saveAgentAwarenessRegistrationRecord).mockClear();
vi.mocked(loadAgentAwarenessRegistrationRecord).mockClear();
vi.mocked(clearAgentAwarenessRegistrationRecord).mockClear();
vi.mocked(loadOrCreateAgentAwarenessDeviceId).mockResolvedValue("device-1");
vi.mocked(loadPreferences).mockReset();
vi.mocked(loadPreferences).mockResolvedValue({ liveActivitiesEnabled: false } as Preferences);
widgetMocks.getInstances.mockReset();
widgetMocks.getInstances.mockReturnValue([]);
widgetMocks.start.mockReset();
widgetMocks.start.mockReturnValue({
getId: () => "activity-1",
getPushToken: () => Promise.resolve(null),
addPushTokenListener: vi.fn(),
});
widgetMocks.dismissEnded.mockReset();
environmentConfigsMock.configs.clear();
vi.mocked(publishAgentActivityWidget).mockReset().mockReturnValue(true);
vi.mocked(agentWidgetToken).mockReset().mockReturnValue(null);
vi.mocked(configureAgentWidgetRefresh).mockClear();
vi.mocked(clearAgentWidgetRefresh).mockClear();
});
it.effect.each(["unchanged", "sign-out", "account switch"] as const)(
"keeps existing Live Activity tokens with their owner across %s during widget refresh",
(transition) =>
Effect.gen(function* () {
const readStarted = yield* Deferred.make();
const finishRead = yield* Deferred.make();
const activity = {
getId: () => "activity-1",
getPushToken: vi.fn(() => Promise.resolve("old-account-activity-token")),
addPushTokenListener: vi.fn(),
end: vi.fn(() => Promise.resolve()),
};
widgetMocks.getInstances.mockReturnValue([activity]);
const register = vi.fn(
() => Effect.succeed({ ok: true }),
);
const client = yield* ManagedRelay.ManagedRelayClient;
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("user-a-token"), "user-a");
backgroundRuntime.pending.length = 0;
const refresh = yield* refreshActiveLiveActivityRemoteRegistration().pipe(
Effect.provideService(ManagedRelay.ManagedRelayClient, {
...client,
registerLiveActivity: register,
getAgentActivitySnapshot: () =>
Deferred.succeed(readStarted, undefined).pipe(
Effect.andThen(Deferred.await(finishRead)),
Effect.as(activeAgentActivitySnapshot),
),
}),
Effect.forkChild,
);
yield* Deferred.await(readStarted);
if (transition !== "unchanged") {
setAgentAwarenessRelayTokenProvider(null);
expect(activity.end).toHaveBeenCalledExactlyOnceWith("immediate");
widgetMocks.getInstances.mockReturnValue([]);
if (transition === "account switch") {
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("user-b-token"), "user-b");
}
}
yield* Deferred.succeed(finishRead, undefined);
yield* Fiber.join(refresh);
if (transition === "unchanged") {
expect(register).toHaveBeenCalledExactlyOnceWith({
clerkToken: "user-a-token",
payload: { deviceId: "device-1", activityPushToken: "old-account-activity-token" },
});
} else {
expect(register).not.toHaveBeenCalled();
expect(activity.getPushToken).not.toHaveBeenCalled();
}
}).pipe(Effect.provide(snapshotRelayLayer()), Effect.scoped),
);
it.effect.each(
(["global", "scoped"] as const).flatMap((blockedRead) =>
(["scope change", "sign-out", "account switch", "background"] as const).map((transition) => ({
blockedRead,
transition,
})),
),
)(
"keeps final relay priming independent of $transition during $blockedRead without crossing account ownership",
({ blockedRead, transition }) =>
Effect.gen(function* () {
if (blockedRead === "scoped") addLiveEnvironment();
vi.mocked(loadPreferences).mockResolvedValue({
liveActivitiesEnabled: true,
} as Preferences);
const readStarted = yield* Deferred.make();
const finishRead = yield* Deferred.make();
const activity = {
getId: () => "activity-1",
getPushToken: vi.fn(() => Promise.resolve("activity-token")),
addPushTokenListener: vi.fn(),
};
widgetMocks.start.mockReturnValue(activity);
const remoteSnapshot: RelayAgentActivitySnapshotResponse = {
aggregate: {
...activeAgentActivitySnapshot.aggregate,
activities: activeAgentActivitySnapshot.aggregate.activities.map((row) => ({
...row,
environmentId: EnvironmentId.make("remote-environment"),
})),
},
};
let globalReads = 0;
let scopedReads = 0;
const layer = snapshotRelayLayer(({ excludedEnvironmentIds }) => {
const kind = excludedEnvironmentIds ? "scoped" : "global";
const ordinal = excludedEnvironmentIds ? ++scopedReads : ++globalReads;
const snapshot = excludedEnvironmentIds
? { ...remoteSnapshot, excludedEnvironmentIds }
: remoteSnapshot;
return ordinal === 1 && kind === blockedRead
? Deferred.succeed(readStarted, undefined).pipe(
Effect.andThen(Deferred.await(finishRead)),
Effect.as(snapshot),
)
: Effect.succeed(snapshot);
});
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a");
backgroundRuntime.pending.length = 0;
const prime = yield* refreshActiveLiveActivityRemoteRegistration().pipe(
Effect.provide(layer),
Effect.forkChild,
);
yield* Deferred.await(readStarted);
if (transition === "scope change") {
if (blockedRead === "global") addLiveEnvironment();
else
setTestAtom(environmentCatalog.catalogValueAtom, {
isReady: true,
entries: new Map(),
});
// The in-flight read rechecks the scope before publishing; no second
// foreground reconciliation is needed before that first response.
expect(backgroundRuntime.pending).toHaveLength(0);
} else if (transition === "background") {
appStateMock.currentState = "background";
for (const listener of appStateMock.listeners) listener("background");
} else {
setAgentAwarenessRelayTokenProvider(null);
if (transition === "account switch")
setAgentAwarenessRelayTokenProvider(
() => Promise.resolve("clerk-token-user-b"),
"user-b",
);
}
const widgetBeforeRelease = vi.mocked(publishAgentActivityWidget).mock.lastCall?.[0];
yield* Deferred.succeed(finishRead, undefined);
yield* Fiber.join(prime);
if (transition === "scope change") {
expect({ globalReads, scopedReads }).toEqual({
globalReads: 1,
scopedReads: 1,
});
expect(backgroundRuntime.pending).toHaveLength(0);
expect(widgetMocks.start).toHaveBeenCalledExactlyOnceWith(
expect.objectContaining({
activeCount: 1,
activities: remoteSnapshot.aggregate!.activities,
}),
expect.any(Date),
);
} else if (transition === "background") {
expect(widgetMocks.start).not.toHaveBeenCalled();
expect(activity.getPushToken).not.toHaveBeenCalled();
appStateMock.currentState = "active";
for (const listener of appStateMock.listeners) listener("active");
expect(backgroundRuntime.pending).toHaveLength(1);
const foreground = backgroundRuntime.pending.shift();
if (!foreground) throw new Error("Expected foreground Live Activity reconciliation");
const exit = yield* Effect.exit(
foreground.operation as Effect.Effect,
).pipe(Effect.provide(layer));
foreground.resolve(exit);
expect(Exit.isSuccess(exit)).toBe(true);
expect(widgetMocks.start).toHaveBeenCalledExactlyOnceWith(
expect.objectContaining({
activeCount: 1,
activities: remoteSnapshot.aggregate!.activities,
}),
expect.any(Date),
);
expect(activity.getPushToken).toHaveBeenCalledTimes(1);
expect(backgroundRuntime.pending).toHaveLength(0);
} else {
expect(globalReads).toBe(1);
expect(widgetMocks.start).not.toHaveBeenCalled();
expect(activity.getPushToken).not.toHaveBeenCalled();
expect(widgetBeforeRelease?.activities).toEqual([]);
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(widgetBeforeRelease);
}
}).pipe(Effect.scoped),
);
it.each(["sign-out", "account switch"])(
"does not restore local-work widget data after %s during preference loading",
async (transition) => {
let finishPreferences!: (preferences: Preferences) => void;
const preferences = new Promise((resolve) => {
finishPreferences = resolve;
});
vi.mocked(loadPreferences).mockReturnValueOnce(preferences);
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a");
environmentConfigsMock.configs.set("env-1", {
environment: { capabilities: { agentActivityPublishing: true } },
});
armAgentAwarenessLiveActivityForLocalWork({
environmentId: "env-1" as EnvironmentId,
threadTitle: "Previous account thread",
projectTitle: "Previous account project",
});
expect(loadPreferences).toHaveBeenCalledTimes(1);
// Register the same catch/then depth after the production continuation.
// Its receipt settles after the already-registered preference callback,
// without a timer, polling, or executing queued relay operations.
const preferenceCallbackDrained = preferences.catch(() => null).then(() => undefined);
setAgentAwarenessRelayTokenProvider(null);
if (transition === "account switch") {
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-b"), "user-b");
}
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({
activeCount: transition === "account switch" ? null : 0,
activities: [],
}),
);
finishPreferences({ liveActivitiesEnabled: true } as Preferences);
await preferenceCallbackDrained;
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({
activeCount: transition === "account switch" ? null : 0,
activities: [],
}),
);
expect(widgetMocks.start).not.toHaveBeenCalled();
},
);
it("still arms local work after a same-account token refresh during preference loading", async () => {
let finishPreferences!: (preferences: Preferences) => void;
const preferences = new Promise((resolve) => {
finishPreferences = resolve;
});
vi.mocked(loadPreferences).mockReturnValueOnce(preferences);
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a");
environmentConfigsMock.configs.set("env-1", {
environment: { capabilities: { agentActivityPublishing: true } },
});
armAgentAwarenessLiveActivityForLocalWork({
environmentId: "env-1" as EnvironmentId,
threadTitle: "Current account thread",
projectTitle: "Current account project",
});
const preferenceCallbackDrained = preferences.catch(() => null).then(() => undefined);
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("refreshed-token-user-a"), "user-a");
finishPreferences({ liveActivitiesEnabled: true } as Preferences);
await preferenceCallbackDrained;
expect(widgetMocks.start).toHaveBeenCalledTimes(1);
expect(widgetMocks.start).toHaveBeenLastCalledWith(
expect.objectContaining({
activeCount: 1,
activities: [expect.objectContaining({ threadTitle: "Current account thread" })],
}),
expect.any(Date),
);
expect(publishAgentActivityWidget).toHaveBeenCalledExactlyOnceWith(
expect.objectContaining({ activeCount: null, activities: [] }),
);
});
it("disables push features in Personal Team relay registrations", () => {
Constants.expoConfig!.extra = { iosPersonalTeamBuild: true };
expect(
makeRelayDeviceRegistrationRequest({
deviceId: "device-1",
label: "Julius's iPhone",
iosMajorVersion: 18,
appVersion: "1.0.0",
pushToken: "apns-token",
pushToStartToken: "push-to-start-token",
notificationsEnabled: true,
preferences: {},
}).preferences,
).toMatchObject({
liveActivitiesEnabled: false,
notificationsEnabled: false,
});
});
it.effect("registers one push-token listener per Live Activity across wrappers", () => {
const addPushTokenListener = vi.fn();
// getInstances() returns a new wrapper for the same native activity each call.
const wrapper = () => ({
getId: () => "activity-1",
getPushToken: vi.fn(() => Promise.resolve(null)),
addPushTokenListener,
});
return Effect.gen(function* () {
expect(yield* registerLiveActivityPushToken({ activity: wrapper() as never })).toBe(false);
expect(yield* registerLiveActivityPushToken({ activity: wrapper() as never })).toBe(false);
expect(addPushTokenListener).toHaveBeenCalledTimes(1);
}).pipe(Effect.provide(layerRelayTest));
});
it.effect("registers a Live Activity push token that rotates after registration", () => {
const registeredTokens: Array = [];
vi.stubGlobal("fetch", async (request: RequestInfo | URL, init?: RequestInit) => {
const url = request instanceof Request ? request.url : String(request);
if (url.endsWith("/v1/client/dpop-token")) {
return Response.json({
access_token: "relay-dpop-token",
issued_token_type: "urn:ietf:params:oauth:token-type:access_token",
token_type: "DPoP",
expires_in: 300,
scope: "mobile:registration",
});
}
if (url.endsWith("/v1/mobile/live-activities")) {
const body = request instanceof Request ? await request.text() : String(init?.body);
registeredTokens.push(
(JSON.parse(body) as { readonly activityPushToken: string }).activityPushToken,
);
}
return Response.json({ ok: true });
});
Constants.expoConfig!.extra = { relay: { url: "https://relay.example.test/" } };
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"));
let tokenListener: ((event: { readonly pushToken: string }) => void) | undefined;
const activity = {
getId: () => "activity-1",
getPushToken: vi.fn(() => Promise.resolve("activity-token")),
addPushTokenListener: vi.fn((listener: typeof tokenListener) => {
tokenListener = listener;
return { remove: vi.fn() };
}),
};
return Effect.gen(function* () {
yield* runBackgroundOperations();
expect(yield* registerLiveActivityPushToken({ activity: activity as never })).toBe(true);
tokenListener?.({ pushToken: "rotated-activity-token" });
yield* runBackgroundOperations();
expect(registeredTokens).toEqual(["activity-token", "rotated-activity-token"]);
}).pipe(
Effect.provideService(FetchHttpClient.Fetch, globalThis.fetch),
Effect.provide(layerRelayTest),
);
});
it.effect("registers a rotated Live Activity token only after an older registration", () => {
const arrivals: Array = [];
let openOldRequest: (() => void) | undefined;
const oldRequestGate = new Promise((resolve) => {
openOldRequest = resolve;
});
let markOldRequestArrived: (() => void) | undefined;
const oldRequestArrived = new Promise((resolve) => {
markOldRequestArrived = resolve;
});
vi.stubGlobal("fetch", async (request: RequestInfo | URL, init?: RequestInit) => {
const url = request instanceof Request ? request.url : String(request);
if (url.endsWith("/v1/client/dpop-token")) {
return Response.json({
access_token: "relay-dpop-token",
issued_token_type: "urn:ietf:params:oauth:token-type:access_token",
token_type: "DPoP",
expires_in: 300,
scope: "mobile:registration",
});
}
if (url.endsWith("/v1/mobile/live-activities")) {
const body = request instanceof Request ? await request.text() : String(init?.body);
const token = (JSON.parse(body) as { readonly activityPushToken: string })
.activityPushToken;
arrivals.push(token);
if (token === "activity-token") {
markOldRequestArrived?.();
await oldRequestGate;
}
}
return Response.json({ ok: true });
});
Constants.expoConfig!.extra = { relay: { url: "https://relay.example.test/" } };
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"));
let tokenListener: ((event: { readonly pushToken: string }) => void) | undefined;
const activity = {
getId: () => "activity-1",
getPushToken: vi.fn(() => Promise.resolve("activity-token")),
addPushTokenListener: vi.fn((listener: typeof tokenListener) => {
tokenListener = listener;
return { remove: vi.fn() };
}),
};
return Effect.gen(function* () {
yield* runBackgroundOperations();
const lookup = yield* Effect.forkChild(
registerLiveActivityPushToken({ activity: activity as never }),
);
yield* Effect.promise(() => oldRequestArrived);
tokenListener?.({ pushToken: "rotated-activity-token" });
const deviceIdLookups = vi.mocked(loadOrCreateAgentAwarenessDeviceId).mock.calls.length;
const rotated = backgroundRuntime.pending.shift()!;
// Starting immediately runs the listener's registration until it suspends: on the
// activity lock, or, without one, at its device-id lookup.
const rotatedRegistration = yield* Effect.forkChild(
Effect.exit(
rotated.operation as Effect.Effect<
unknown,
AgentAwarenessRegistrationError,
ManagedRelay.ManagedRelayClient
>,
),
{ startImmediately: true },
);
expect(vi.mocked(loadOrCreateAgentAwarenessDeviceId).mock.calls).toHaveLength(
deviceIdLookups,
);
expect(arrivals).toEqual(["activity-token"]);
openOldRequest?.();
yield* Fiber.join(lookup);
rotated.resolve(yield* Fiber.join(rotatedRegistration));
expect(arrivals).toEqual(["activity-token", "rotated-activity-token"]);
}).pipe(
Effect.provideService(FetchHttpClient.Fetch, globalThis.fetch),
Effect.provide(layerRelayTest),
);
});
it.effect("still registers the active card when ended-card cleanup throws", () => {
const registrations: unknown[] = [];
vi.stubGlobal("fetch", async (input: RequestInfo | URL, init?: RequestInit) => {
const request = new Request(input, init);
if (request.url.endsWith("/v1/client/dpop-token")) {
return Response.json({
access_token: "relay-dpop-token",
issued_token_type: "urn:ietf:params:oauth:token-type:access_token",
token_type: "DPoP",
expires_in: 300,
scope: "mobile:registration",
});
}
if (request.url.endsWith("/v1/mobile/live-activities")) {
registrations.push(await request.json());
}
return Response.json({ ok: true });
});
Constants.expoConfig!.extra = { relay: { url: "https://relay.example.test/" } };
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"));
const activity = {
getId: () => "activity-1",
getPushToken: vi.fn(() => Promise.resolve("activity-token")),
addPushTokenListener: vi.fn(),
end: vi.fn(),
};
return Effect.gen(function* () {
yield* runBackgroundOperations();
widgetMocks.dismissEnded.mockReset();
widgetMocks.dismissEnded.mockImplementation(() => {
throw new Error("Cannot find function dismissEnded");
});
widgetMocks.getInstances.mockReturnValue([activity] as never);
for (const listener of appStateMock.listeners) listener("active");
yield* runBackgroundOperations();
expect(widgetMocks.dismissEnded).toHaveBeenCalledOnce();
expect(registrations).toEqual([
{ deviceId: "device-1", activityPushToken: "activity-token" },
]);
expect(activity.end).not.toHaveBeenCalled();
expect(widgetMocks.start).not.toHaveBeenCalled();
}).pipe(
Effect.provideService(FetchHttpClient.Fetch, globalThis.fetch),
Effect.provide(layerRelayTest),
);
});
it.effect("refreshes the widget after a delayed Live Activity push token registers", () => {
let onPushToken: ((event: { pushToken: string }) => void) | undefined;
const activity = {
getId: () => "activity-1",
getPushToken: vi.fn(() => Promise.resolve(null)),
addPushTokenListener: vi.fn((listener: (event: { pushToken: string }) => void) => {
onPushToken = listener;
return { remove: vi.fn() };
}),
};
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"));
return Effect.gen(function* () {
expect(yield* registerLiveActivityPushToken({ activity: activity as never })).toBe(false);
expect(onPushToken).toBeDefined();
onPushToken?.({ pushToken: "delayed-activity-token" });
yield* runBackgroundOperations();
expect(publishAgentActivityWidget).toHaveBeenCalledWith(
expect.objectContaining({
activeCount: 1,
subtitle: "Agent work in progress",
}),
);
}).pipe(Effect.provide(snapshotRelayLayer()));
});
it.effect("publishes the home-screen widget when a Live Activity is already armed", () => {
const activity = {
getId: () => "activity-1",
getPushToken: vi.fn(() => Promise.resolve("activity-token")),
addPushTokenListener: vi.fn(),
start: vi.fn(),
update: vi.fn(),
end: vi.fn(),
};
widgetMocks.getInstances.mockReturnValue([activity] as never);
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"));
return Effect.gen(function* () {
yield* refreshActiveLiveActivityRemoteRegistration();
expect(publishAgentActivityWidget).toHaveBeenCalledWith(
expect.objectContaining({
activeCount: 1,
subtitle: "Agent work in progress",
activities: [expect.objectContaining({ status: "Working" })],
}),
);
expect(widgetMocks.start).not.toHaveBeenCalled();
expect(activity.start).not.toHaveBeenCalled();
}).pipe(Effect.provide(snapshotRelayLayer()));
});
it.effect("publishes the home-screen widget when Live Activities are disabled", () => {
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"));
return Effect.gen(function* () {
yield* refreshActiveLiveActivityRemoteRegistration();
expect(publishAgentActivityWidget).toHaveBeenCalledWith(
expect.objectContaining({
activeCount: 1,
subtitle: "Agent work in progress",
}),
);
expect(widgetMocks.start).not.toHaveBeenCalled();
}).pipe(Effect.provide(snapshotRelayLayer()));
});
it("ends local Live Activities and clears the home-screen widget on cloud sign-out", () => {
widgetMocks.dismissEnded.mockReset();
const end = vi.fn(() => Promise.resolve());
const activity = {
getId: () => "activity-1",
getPushToken: vi.fn(() => Promise.resolve("activity-token")),
addPushTokenListener: vi.fn(),
end,
};
widgetMocks.getInstances.mockReturnValue([activity] as never);
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"));
expect(appStateMock.listeners).toHaveLength(1);
setAgentAwarenessRelayTokenProvider(null);
expect(end).toHaveBeenCalledWith("immediate");
expect(publishAgentActivityWidget).toHaveBeenCalledWith(
expect.objectContaining({
title: "T3 Code",
subtitle: "Sign in to see agent activity",
isSignedOut: true,
activeCount: 0,
activities: [],
}),
);
widgetMocks.dismissEnded.mockReset();
expect(appStateMock.listeners).toHaveLength(0);
vi.mocked(publishAgentActivityWidget).mockClear();
vi.mocked(clearAgentWidgetRefresh).mockClear();
setAgentAwarenessRelayTokenProvider(null);
expect(clearAgentWidgetRefresh).toHaveBeenCalledOnce();
expect(publishAgentActivityWidget).toHaveBeenCalledWith(
expect.objectContaining({ isSignedOut: true, subtitle: "Sign in to see agent activity" }),
);
});
it.effect("registers the APNs device when cloud auth becomes available", () => {
addLiveEnvironment();
setLiveShell("running");
let nativeObservation: Parameters[0] | undefined;
vi.mocked(publishAgentActivityWidget).mockImplementation((props) => {
nativeObservation = props;
return true;
});
vi.mocked(agentWidgetToken).mockImplementation((_identity, url) => {
if (url) nativeObservation = undefined;
return "a".repeat(64);
});
let recoveryAtRegistration: Parameters | undefined;
const fetchMock = vi.fn((request: RequestInfo | URL) => {
const url = request instanceof Request ? request.url : String(request);
if (url.endsWith("/v1/mobile/devices")) {
recoveryAtRegistration = vi.mocked(configureAgentWidgetRefresh).mock.lastCall;
}
return Promise.resolve(
Response.json(
url.endsWith("/v1/client/dpop-token")
? {
access_token: "relay-dpop-token",
issued_token_type: "urn:ietf:params:oauth:token-type:access_token",
token_type: "DPoP",
expires_in: 300,
scope: "mobile:registration",
}
: { ok: true },
),
);
});
vi.stubGlobal("fetch", fetchMock);
Constants.expoConfig!.extra = {
relay: {
url: "https://relay.example.test/",
},
};
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a");
return Effect.gen(function* () {
yield* runBackgroundOperations();
expect(nativeObservation?.activities).toEqual([
expect.objectContaining({ threadId: "local-thread", phase: "running" }),
]);
expect(agentWidgetToken).toHaveBeenLastCalledWith("user-a", "https://relay.example.test");
expect(recoveryAtRegistration).toEqual(["https://relay.example.test", "a".repeat(64)]);
const deviceCall = fetchMock.mock.calls.find((call) => {
const request = call[0];
const url = request instanceof Request ? request.url : String(request);
return url === "https://relay.example.test/v1/mobile/devices";
});
expect(deviceCall).toBeDefined();
const [request, init] = deviceCall as unknown as [unknown, RequestInit | undefined];
const url = request instanceof Request ? request.url : String(request);
const method = request instanceof Request ? request.method : init?.method;
const headers = request instanceof Request ? request.headers : new Headers(init?.headers);
const dpop = headers.get("dpop");
expect(url).toBe("https://relay.example.test/v1/mobile/devices");
expect(method).toBe("POST");
expect(headers.get("authorization")).toBe("DPoP relay-dpop-token");
expect(dpop).toEqual(expect.any(String));
if (!dpop) {
throw new Error("Missing DPoP header.");
}
expect(
verifyDpopProof({
proof: dpop,
method: "POST",
url: "https://relay.example.test/v1/mobile/devices",
expectedAccessToken: "relay-dpop-token",
nowEpochSeconds: proofIat(dpop),
}),
).toMatchObject({ ok: true });
const payload =
request instanceof Request
? yield* Effect.promise(() => request.json())
: JSON.parse(String(init?.body));
expect(payload.widgetAccessToken).toBe("a".repeat(64));
expect(configureAgentWidgetRefresh).toHaveBeenLastCalledWith(
"https://relay.example.test",
"a".repeat(64),
);
expect(getAgentAwarenessRegistrationStatus()).toBe("registered");
releaseAgentAwarenessRelayTokenProvider();
expect(clearAgentWidgetRefresh).not.toHaveBeenCalled();
setAgentAwarenessRelayTokenProvider(null);
expect(clearAgentWidgetRefresh).toHaveBeenCalledOnce();
}).pipe(Effect.provide(layerRelayTest));
});
it.effect("keeps a registered status when a later refresh fails", () => {
Constants.expoConfig!.extra = {
relay: {
url: "https://relay.example.test/",
},
};
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"));
return Effect.gen(function* () {
yield* runBackgroundOperations();
expect(getAgentAwarenessRegistrationStatus()).toBe("registered");
vi.mocked(loadOrCreateAgentAwarenessDeviceId).mockRejectedValueOnce(
new Error("transient failure"),
);
yield* refreshAgentAwarenessRegistration();
expect(getAgentAwarenessRegistrationStatus()).toBe("registered");
}).pipe(Effect.provide(layerRelayTest));
});
it.effect("does not re-register the same account when nothing has changed", () => {
Constants.expoConfig!.extra = {
relay: {
url: "https://relay.example.test/",
},
};
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"));
return Effect.gen(function* () {
yield* refreshAgentAwarenessRegistration();
expect(getAgentAwarenessRegistrationStatus()).toBe("registered");
expect(saveAgentAwarenessRegistrationRecord).toHaveBeenCalledTimes(1);
expect(registrationRecordStore.current).not.toBeNull();
vi.mocked(saveAgentAwarenessRegistrationRecord).mockClear();
yield* refreshAgentAwarenessRegistration();
expect(getAgentAwarenessRegistrationStatus()).toBe("registered");
expect(saveAgentAwarenessRegistrationRecord).not.toHaveBeenCalled();
}).pipe(Effect.provide(layerRelayTest));
});
it.effect("continues queued device registration after a failed auth lookup", () => {
Constants.expoConfig!.extra = {
relay: {
url: "https://relay.example.test/",
},
};
const tokenProvider = vi
.fn<() => Promise>()
.mockRejectedValueOnce(new Error("auth unavailable"))
.mockResolvedValue("clerk-token-user-a");
setAgentAwarenessRelayTokenProvider(tokenProvider);
const tokenListener = vi.mocked(Notifications.addPushTokenListener).mock.calls.at(-1)?.[0];
expect(tokenListener).toBeDefined();
tokenListener?.({ type: "ios", data: "rotated-apns-token" } as never);
return Effect.gen(function* () {
yield* runBackgroundOperations();
expect(backgroundRuntime.pending).toHaveLength(0);
// Device registration retries after the first auth miss, and the
// home-screen widget refresh independently reads the relay token.
expect(tokenProvider).toHaveBeenCalledTimes(3);
}).pipe(Effect.provide(layerRelayTest));
});
it.effect.each(["ios", "android"] as const)(
"does not enable %s notifications when a token rotates after permission is revoked",
(os) => {
vi.mocked(loadPreferences).mockResolvedValue({ liveActivitiesEnabled: true });
vi.spyOn(Platform, "OS", "get").mockReturnValue(os);
vi.spyOn(Platform, "Version", "get").mockReturnValue(os === "ios" ? 18 : 36);
vi.mocked(Notifications.getDevicePushTokenAsync).mockResolvedValue({
type: os,
data: "initial",
});
const registrations: unknown[] = [];
vi.stubGlobal("fetch", async (input: RequestInfo | URL, init?: RequestInit) => {
const request = new Request(input, init);
if (request.url.endsWith("/v1/client/dpop-token")) {
return Response.json({
access_token: "dpop",
issued_token_type: "urn:ietf:params:oauth:token-type:access_token",
token_type: "DPoP",
expires_in: 300,
scope: "mobile:registration",
});
}
registrations.push(await request.json());
return Response.json({ ok: true });
});
Constants.expoConfig!.extra = { relay: { url: "https://permission-relay.example.test" } };
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk"), "user-a");
return Effect.gen(function* () {
yield* runBackgroundOperations();
expect(registrations.at(-1)).toMatchObject({
preferences: { notificationsEnabled: true, liveActivitiesEnabled: true },
});
vi.mocked(Notifications.getPermissionsAsync).mockResolvedValueOnce({
granted: false,
} as Awaited>);
const listener = vi.mocked(Notifications.addPushTokenListener).mock.calls.at(-1)![0];
listener({ type: os, data: "rotated" });
yield* runBackgroundOperations();
expect(registrations.at(-1)).toMatchObject({
preferences: { notificationsEnabled: false, liveActivitiesEnabled: os === "ios" },
});
if (os === "android") {
expect(registrations.at(-1)).toMatchObject({ pushToken: "rotated" });
vi.mocked(Notifications.getPermissionsAsync).mockResolvedValueOnce({
granted: false,
} as Awaited>);
yield* refreshAgentAwarenessRegistration();
expect(registrations.at(-1)).toMatchObject({
pushToken: "initial",
preferences: { notificationsEnabled: false, liveActivitiesEnabled: false },
});
} else {
expect(registrations.at(-1)).not.toHaveProperty("pushToken");
}
}).pipe(
Effect.provideService(FetchHttpClient.Fetch, globalThis.fetch),
Effect.provide(
ManagedRelayLayer.layer("https://permission-relay.example.test").pipe(
Layer.provide(Layer.mergeAll(FetchHttpClient.layer, Dpop.layer)),
),
),
);
},
);
it.effect.each(["blocked", "unavailable"] as const)(
"keeps Android push delivery registered when the alert channel is %s",
(channelState) => {
vi.mocked(loadPreferences).mockResolvedValue({ liveActivitiesEnabled: true });
vi.spyOn(Platform, "OS", "get").mockReturnValue("android");
vi.spyOn(Platform, "Version", "get").mockReturnValue(36);
vi.mocked(Notifications.getDevicePushTokenAsync).mockResolvedValue({
type: "android",
data: "fcm-token",
});
vi.mocked(Notifications.getNotificationChannelAsync).mockResolvedValue({
id: "agent-alerts",
name: "Agent alerts",
importance: Notifications.AndroidImportance.NONE,
} as Awaited>);
if (channelState === "unavailable") {
vi.mocked(Notifications.getNotificationChannelAsync).mockRejectedValue(
new Error("Android channel lookup failed"),
);
}
const registrations: unknown[] = [];
vi.stubGlobal("fetch", async (input: RequestInfo | URL, init?: RequestInit) => {
const request = new Request(input, init);
if (request.url.endsWith("/v1/client/dpop-token")) {
return Response.json({
access_token: "dpop",
issued_token_type: "urn:ietf:params:oauth:token-type:access_token",
token_type: "DPoP",
expires_in: 300,
scope: "mobile:registration",
});
}
registrations.push(await request.json());
return Response.json({ ok: true });
});
Constants.expoConfig!.extra = { relay: { url: "https://relay.example.test" } };
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk"), "user-a");
return Effect.gen(function* () {
yield* runBackgroundOperations();
expect(registrations.at(-1)).toMatchObject({
pushToken: "fcm-token",
preferences: { notificationsEnabled: false, liveActivitiesEnabled: true },
});
expect(getAgentAwarenessRegistrationStatus()).toBe("registered");
const listener = vi.mocked(Notifications.addPushTokenListener).mock.calls.at(-1)![0];
listener({ type: "android", data: "rotated-fcm-token" });
yield* runBackgroundOperations();
expect(registrations.at(-1)).toMatchObject({
pushToken: "rotated-fcm-token",
preferences: { notificationsEnabled: false, liveActivitiesEnabled: true },
});
vi.mocked(Notifications.getNotificationChannelAsync).mockResolvedValue(null);
yield* refreshAgentAwarenessRegistration();
expect(registrations.at(-1)).toMatchObject({
pushToken: "fcm-token",
preferences: { notificationsEnabled: true },
});
}).pipe(
Effect.provideService(FetchHttpClient.Fetch, globalThis.fetch),
Effect.provide(layerRelayTest),
);
},
);
it.effect("preserves relay rejection errors with React Native response headers", () => {
vi.spyOn(Platform, "OS", "get").mockReturnValue("android");
vi.mocked(Notifications.getDevicePushTokenAsync).mockResolvedValue({
type: "android",
data: "fcm-token",
});
const rejectedResponse = new Response("Unsupported device platform", { status: 400 });
Object.defineProperty(rejectedResponse.headers, "getSetCookie", { value: undefined });
vi.stubGlobal("fetch", (request: RequestInfo | URL) => {
const url = request instanceof Request ? request.url : String(request);
const response = url.endsWith("/v1/client/dpop-token")
? Response.json({
access_token: "relay-dpop-token",
issued_token_type: "urn:ietf:params:oauth:token-type:access_token",
token_type: "DPoP",
expires_in: 300,
scope: "mobile:registration",
})
: rejectedResponse;
Object.defineProperty(response.headers, "getSetCookie", { value: undefined });
return Promise.resolve(response);
});
Constants.expoConfig!.extra = { relay: { url: "https://relay.example.test" } };
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a");
return Effect.gen(function* () {
// Hermes' compiled error hashing reads the response's cookie getter.
const httpResponse = HttpClientResponse.fromWeb(
HttpClientRequest.post("https://relay.example.test/v1/mobile/devices"),
rejectedResponse,
);
expect(httpResponse.cookies).toEqual(Cookies.empty);
const result = yield* Effect.exit(
updateAgentAwarenessRegistrationPreferences({ liveActivitiesEnabled: true }),
);
expect(Exit.isFailure(result)).toBe(true);
if (Exit.isFailure(result)) {
expect(Cause.hasDies(result.cause)).toBe(false);
expect(Cause.squash(result.cause)).toBeInstanceOf(
ManagedRelay.ManagedRelayRequestFailedError,
);
}
expect(getAgentAwarenessRegistrationStatus()).toBe("failed");
expect(saveAgentAwarenessRegistrationRecord).not.toHaveBeenCalled();
}).pipe(Effect.provide(layerRelayTest));
});
it.effect(
"does not reconfigure or register a detached Android account from an in-flight operation",
() => {
vi.spyOn(Platform, "OS", "get").mockReturnValue("android");
vi.spyOn(Platform, "Version", "get").mockReturnValue(36);
Constants.expoConfig!.extra = { relay: { url: "https://relay.example.test" } };
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token"), "user-a");
releaseAgentAwarenessRelayTokenProvider();
vi.mocked(configureAndroidAgentNotifications).mockClear();
return Effect.gen(function* () {
yield* runBackgroundOperations();
expect(configureAndroidAgentNotifications).not.toHaveBeenCalled();
expect(saveAgentAwarenessRegistrationRecord).not.toHaveBeenCalled();
}).pipe(Effect.provide(layerRelayTest));
},
);
it.effect("refreshes the home-screen widget after arming local agent work", () => {
const activity = {
getId: () => "activity-1",
getPushToken: vi.fn(() => Promise.resolve("activity-token")),
addPushTokenListener: vi.fn(),
};
widgetMocks.start.mockReturnValueOnce(activity);
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"));
backgroundRuntime.pending.length = 0;
environmentConfigsMock.configs.set("env-1", {
environment: { capabilities: { agentActivityPublishing: true } },
});
const preferences = Promise.resolve({
liveActivitiesEnabled: true,
} as Preferences);
vi.mocked(loadPreferences).mockReturnValueOnce(preferences);
armAgentAwarenessLiveActivityForLocalWork({
environmentId: "env-1" as EnvironmentId,
threadTitle: "Fix the flaky test",
projectTitle: "t3code",
});
const preferenceCallbackDrained = preferences.catch(() => null).then(() => undefined);
return Effect.gen(function* () {
yield* Effect.promise(() => preferenceCallbackDrained);
yield* runBackgroundOperations();
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({
activeCount: 1,
subtitle: "Agent work in progress",
activities: [expect.objectContaining({ status: "Working" })],
}),
);
}).pipe(Effect.provide(snapshotRelayLayer()));
});
it.effect("refreshes the home-screen widget when local Live Activities are disabled", () => {
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"));
backgroundRuntime.pending.length = 0;
environmentConfigsMock.configs.set("env-1", {
environment: { capabilities: { agentActivityPublishing: true } },
});
const preferences = Promise.resolve({
liveActivitiesEnabled: false,
} as Preferences);
vi.mocked(loadPreferences).mockReturnValueOnce(preferences);
armAgentAwarenessLiveActivityForLocalWork({
environmentId: "env-1" as EnvironmentId,
threadTitle: "Fix the flaky test",
projectTitle: "t3code",
});
const preferenceCallbackDrained = preferences.catch(() => null).then(() => undefined);
return Effect.gen(function* () {
yield* Effect.promise(() => preferenceCallbackDrained);
yield* runBackgroundOperations();
expect(widgetMocks.start).not.toHaveBeenCalled();
expect(publishAgentActivityWidget).toHaveBeenCalledTimes(2);
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({
activeCount: 1,
activities: [expect.objectContaining({ status: "Working" })],
}),
);
}).pipe(Effect.provide(snapshotRelayLayer()));
});
it.effect("refreshes the home-screen widget when a local Live Activity is already armed", () => {
widgetMocks.getInstances.mockReturnValueOnce([{}] as never);
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"));
backgroundRuntime.pending.length = 0;
environmentConfigsMock.configs.set("env-1", {
environment: { capabilities: { agentActivityPublishing: true } },
});
const preferences = Promise.resolve({
liveActivitiesEnabled: true,
} as Preferences);
vi.mocked(loadPreferences).mockReturnValueOnce(preferences);
armAgentAwarenessLiveActivityForLocalWork({
environmentId: "env-1" as EnvironmentId,
threadTitle: "Fix the flaky test",
projectTitle: "t3code",
});
const preferenceCallbackDrained = preferences.catch(() => null).then(() => undefined);
return Effect.gen(function* () {
yield* Effect.promise(() => preferenceCallbackDrained);
yield* runBackgroundOperations();
expect(widgetMocks.start).not.toHaveBeenCalled();
expect(publishAgentActivityWidget).toHaveBeenCalledTimes(2);
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({
activeCount: 1,
activities: [expect.objectContaining({ status: "Working" })],
}),
);
}).pipe(Effect.provide(snapshotRelayLayer()));
});
it.effect("refreshes the home-screen widget when local Live Activity arming fails", () => {
widgetMocks.start.mockImplementationOnce(() => {
throw new Error("start failed");
});
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"));
backgroundRuntime.pending.length = 0;
environmentConfigsMock.configs.set("env-1", {
environment: { capabilities: { agentActivityPublishing: true } },
});
vi.mocked(loadPreferences).mockResolvedValueOnce({
liveActivitiesEnabled: true,
} as Preferences);
armAgentAwarenessLiveActivityForLocalWork({
environmentId: "env-1" as EnvironmentId,
threadTitle: "Fix the flaky test",
projectTitle: "t3code",
});
return Effect.gen(function* () {
yield* runBackgroundOperations();
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({
activeCount: 1,
subtitle: "Agent work in progress",
activities: [expect.objectContaining({ status: "Working" })],
}),
);
}).pipe(Effect.provide(snapshotRelayLayer()));
});
it.effect("discards an older widget snapshot when a newer refresh finishes first", () =>
Effect.gen(function* () {
const firstReadStarted = yield* Deferred.make();
const finishFirstRead = yield* Deferred.make();
const olderSnapshot = {
aggregate: {
...activeAgentActivitySnapshot.aggregate,
updatedAt: "2026-05-25T13:06:00.000Z",
activities: [
{
...activeAgentActivityRow,
status: "Older status",
updatedAt: "2026-05-25T13:06:00.000Z",
},
],
},
} satisfies RelayAgentActivitySnapshotResponse;
let readCount = 0;
const layer = snapshotRelayLayer(() => {
readCount++;
if (readCount === 1) {
return Deferred.succeed(firstReadStarted, undefined).pipe(
Effect.andThen(Deferred.await(finishFirstRead)),
Effect.as(olderSnapshot),
);
}
return Effect.succeed(activeAgentActivitySnapshot);
});
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"));
backgroundRuntime.pending.length = 0;
const olderRefresh = yield* refreshActiveLiveActivityRemoteRegistration().pipe(
Effect.provide(layer),
Effect.forkChild,
);
yield* Deferred.await(firstReadStarted);
yield* refreshActiveLiveActivityRemoteRegistration().pipe(Effect.provide(layer));
yield* Deferred.succeed(finishFirstRead, undefined);
yield* Fiber.join(olderRefresh);
expect(publishAgentActivityWidget).toHaveBeenCalledTimes(2);
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({
activities: [expect.objectContaining({ status: "Working" })],
}),
);
}).pipe(Effect.scoped),
);
it.effect("does not prime a Live Activity from a read a newer one replaced", () =>
Effect.gen(function* () {
const firstReadStarted = yield* Deferred.make();
const finishFirstRead = yield* Deferred.make();
let readCount = 0;
const layer = snapshotRelayLayer(() => {
readCount++;
if (readCount === 1) {
return Deferred.succeed(firstReadStarted, undefined).pipe(
Effect.andThen(Deferred.await(finishFirstRead)),
Effect.as(activeAgentActivitySnapshot),
);
}
return Effect.succeed({ aggregate: null });
});
vi.mocked(loadPreferences).mockResolvedValue({ liveActivitiesEnabled: true } as Preferences);
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"));
backgroundRuntime.pending.length = 0;
const olderRefresh = yield* refreshActiveLiveActivityRemoteRegistration().pipe(
Effect.provide(layer),
Effect.forkChild,
);
yield* Deferred.await(firstReadStarted);
yield* refreshActiveLiveActivityRemoteRegistration().pipe(Effect.provide(layer));
yield* Deferred.succeed(finishFirstRead, undefined);
yield* Fiber.join(olderRefresh);
expect(widgetMocks.start).not.toHaveBeenCalled();
}).pipe(Effect.scoped),
);
it.effect("keeps the native local-work seed separate from an in-flight widget snapshot", () =>
Effect.gen(function* () {
const readStarted = yield* Deferred.make();
const finishRead = yield* Deferred.make();
const layer = snapshotRelayLayer(() =>
Deferred.succeed(readStarted, undefined).pipe(
Effect.andThen(Deferred.await(finishRead)),
Effect.as({ aggregate: null }),
),
);
const activity = {
getId: () => "activity-1",
getPushToken: vi.fn(() => Promise.resolve("activity-token")),
addPushTokenListener: vi.fn(),
};
widgetMocks.getInstances
.mockReturnValueOnce([])
.mockReturnValueOnce([])
.mockReturnValue([activity] as never);
widgetMocks.start.mockReturnValueOnce(activity);
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"));
environmentConfigsMock.configs.set("env-1", {
environment: { capabilities: { agentActivityPublishing: true } },
});
const preferences = Promise.resolve({
liveActivitiesEnabled: true,
} as Preferences);
vi.mocked(loadPreferences).mockReturnValue(preferences);
const refresh = yield* refreshActiveLiveActivityRemoteRegistration().pipe(
Effect.provide(layer),
Effect.forkChild,
);
yield* Deferred.await(readStarted);
armAgentAwarenessLiveActivityForLocalWork({
environmentId: "env-1" as EnvironmentId,
threadTitle: "Fix the flaky test",
projectTitle: "t3code",
});
const preferenceCallbackDrained = preferences.catch(() => null).then(() => undefined);
yield* Effect.promise(() => preferenceCallbackDrained);
yield* Deferred.succeed(finishRead, undefined);
yield* Fiber.join(refresh);
expect(widgetMocks.start).toHaveBeenCalledExactlyOnceWith(
expect.objectContaining({
activeCount: 1,
activities: [expect.objectContaining({ status: "Connecting" })],
}),
expect.any(Date),
);
expect(publishAgentActivityWidget).toHaveBeenCalledTimes(2);
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({
activeCount: 0,
activities: [],
}),
);
}).pipe(Effect.scoped),
);
it.effect.each(["global", "scoped"] as const)(
"adopts a local arm made during the final %s snapshot read instead of priming twice",
(blockedRead) =>
Effect.gen(function* () {
addLiveEnvironment();
const preferences = Promise.resolve({ liveActivitiesEnabled: true } as Preferences);
vi.mocked(loadPreferences).mockReturnValue(preferences);
environmentConfigsMock.configs.set("env-1", {
environment: { capabilities: { agentActivityPublishing: true } },
});
const readStarted = yield* Deferred.make();
const finishRead = yield* Deferred.make();
let finishToken!: (token: string) => void;
let tokenReadStarted!: () => void;
const pendingToken = new Promise((resolve) => {
finishToken = resolve;
});
const tokenRead = new Promise((resolve) => {
tokenReadStarted = resolve;
});
const makeActivity = () => ({
getId: () => "activity-1",
getPushToken: vi.fn(() => Promise.resolve("activity-token")),
addPushTokenListener: vi.fn(),
});
const activities: Array> = [];
widgetMocks.getInstances.mockImplementation(() => activities as never);
widgetMocks.start.mockImplementation(() => {
const activity = makeActivity();
if (activities.length === 0)
activity.getPushToken.mockImplementationOnce(() => {
tokenReadStarted();
return pendingToken;
});
activities.push(activity);
return activity;
});
let globalReads = 0;
let scopedReads = 0;
const layer = snapshotRelayLayer(({ excludedEnvironmentIds }) => {
const kind = excludedEnvironmentIds ? "scoped" : "global";
const ordinal = excludedEnvironmentIds ? ++scopedReads : ++globalReads;
const snapshot = excludedEnvironmentIds
? { aggregate: null, excludedEnvironmentIds }
: activeAgentActivitySnapshot;
return ordinal === 1 && kind === blockedRead
? Deferred.succeed(readStarted, undefined).pipe(
Effect.andThen(Deferred.await(finishRead)),
Effect.as(snapshot),
)
: Effect.succeed(snapshot);
});
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a");
backgroundRuntime.pending.length = 0;
const refresh = yield* refreshActiveLiveActivityRemoteRegistration().pipe(
Effect.provide(layer),
Effect.forkChild,
);
yield* Deferred.await(readStarted);
armAgentAwarenessLiveActivityForLocalWork({
environmentId: liveEnvironmentId,
projectTitle: "Live project",
threadTitle: "Local task",
});
yield* Effect.promise(() => preferences.catch(() => null).then(() => undefined));
expect(widgetMocks.start).toHaveBeenCalledTimes(1);
const pending = backgroundRuntime.pending.shift();
if (!pending) throw new Error("Expected local token registration");
const localRegistration = yield* Effect.exit(
pending.operation as Effect.Effect,
).pipe(Effect.provide(layer), Effect.forkChild);
yield* Effect.promise(() => tokenRead);
yield* Deferred.succeed(finishRead, undefined);
const startsBeforeTokenResolved = widgetMocks.start.mock.calls.length;
finishToken("activity-token");
yield* Fiber.join(refresh);
pending.resolve(yield* Fiber.join(localRegistration));
expect({ global: globalReads, scoped: scopedReads }).toEqual({ global: 2, scoped: 2 });
expect(startsBeforeTokenResolved).toBe(1);
expect(activities).toHaveLength(1);
}).pipe(Effect.scoped),
);
it.effect("does not prime a Live Activity after cloud sign-out", () =>
Effect.gen(function* () {
let preferencesStarted!: () => void;
let finishPreferences!: (preferences: Preferences) => void;
const started = new Promise((resolve) => {
preferencesStarted = resolve;
});
const preferences = new Promise((resolve) => {
finishPreferences = resolve;
});
vi.mocked(loadPreferences).mockImplementationOnce(() => {
preferencesStarted();
return preferences;
});
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"));
const refresh = yield* refreshActiveLiveActivityRemoteRegistration().pipe(
Effect.provide(snapshotRelayLayer()),
Effect.forkChild,
);
yield* Effect.promise(() => started);
setAgentAwarenessRelayTokenProvider(null);
finishPreferences({ liveActivitiesEnabled: true } as Preferences);
yield* Fiber.join(refresh);
expect(widgetMocks.start).not.toHaveBeenCalled();
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({
subtitle: "Sign in to see agent activity",
isSignedOut: true,
activeCount: 0,
activities: [],
}),
);
}).pipe(Effect.scoped),
);
it.effect("does not prime from a snapshot that became idle while preferences loaded", () =>
Effect.gen(function* () {
let preferencesStarted!: () => void;
let finishPreferences!: (preferences: Preferences) => void;
const started = new Promise((resolve) => {
preferencesStarted = resolve;
});
const preferences = new Promise((resolve) => {
finishPreferences = resolve;
});
vi.mocked(loadPreferences).mockImplementationOnce(() => {
preferencesStarted();
return preferences;
});
let snapshot: RelayAgentActivitySnapshotResponse = activeAgentActivitySnapshot;
const readSnapshot = vi.fn(() => Effect.succeed(snapshot));
const layer = snapshotRelayLayer(readSnapshot);
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"));
const refresh = yield* refreshActiveLiveActivityRemoteRegistration().pipe(
Effect.provide(layer),
Effect.forkChild,
);
yield* Effect.promise(() => started);
expect(readSnapshot).not.toHaveBeenCalled();
snapshot = { aggregate: null };
finishPreferences({ liveActivitiesEnabled: true } as Preferences);
yield* Fiber.join(refresh);
expect(readSnapshot).toHaveBeenCalledTimes(1);
expect(widgetMocks.start).not.toHaveBeenCalled();
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({
subtitle: "No active agents",
activeCount: 0,
activities: [],
}),
);
}).pipe(Effect.scoped),
);
it.effect.each([false, true])(
"publishes later local shell work after the registered local-start refresh was idle (Live Activities %s)",
(liveActivitiesEnabled) => {
addLiveEnvironment();
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a");
backgroundRuntime.pending.length = 0;
const activity = {
getId: () => "activity-1",
getPushToken: vi.fn(() => Promise.resolve("activity-token")),
addPushTokenListener: vi.fn(),
};
widgetMocks.start.mockReturnValueOnce(activity);
const preferences = Promise.resolve({ liveActivitiesEnabled } as Preferences);
vi.mocked(loadPreferences).mockReturnValue(preferences);
armAgentAwarenessLiveActivityForLocalWork({
environmentId: liveEnvironmentId,
threadTitle: "Live task",
projectTitle: "Live project",
});
const preferencesDrained = preferences.catch(() => null).then(() => undefined);
return Effect.gen(function* () {
yield* Effect.promise(() => preferencesDrained);
expect(widgetMocks.start).toHaveBeenCalledTimes(liveActivitiesEnabled ? 1 : 0);
yield* runBackgroundOperations();
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({ activeCount: 0, activities: [] }),
);
setLiveShell("starting");
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({
activeCount: 1,
activities: [
expect.objectContaining({ threadTitle: "Live task", status: "Connecting" }),
],
}),
);
setLiveShell("running");
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({
activeCount: 1,
activities: [expect.objectContaining({ threadTitle: "Live task", status: "Working" })],
}),
);
setLiveShell("ready");
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({
activeCount: 0,
activities: [expect.objectContaining({ threadTitle: "Live task", status: "Done" })],
}),
);
setLiveShell(null);
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({ activeCount: 0, activities: [] }),
);
expect(backgroundRuntime.pending).toHaveLength(0);
}).pipe(Effect.provide(snapshotRelayLayer(() => Effect.succeed({ aggregate: null }))));
},
);
it.effect.each(["completed", "multiple running"] as const)(
"keeps %s widget rows when delayed local arming is followed by a relay failure",
(state) =>
Effect.gen(function* () {
addLiveEnvironment();
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a");
backgroundRuntime.pending.length = 0;
yield* refreshActiveLiveActivityRemoteRegistration().pipe(
Effect.provide(snapshotRelayLayer(() => Effect.succeed({ aggregate: null }))),
);
setLiveShell("running");
const activity = {
getId: () => "activity-1",
getPushToken: vi.fn(() => Promise.resolve("activity-token")),
addPushTokenListener: vi.fn(),
};
widgetMocks.start.mockReturnValueOnce(activity);
let finishPreferences!: (preferences: Preferences) => void;
const preferences = new Promise((resolve) => {
finishPreferences = resolve;
});
vi.mocked(loadPreferences).mockReturnValueOnce(preferences);
armAgentAwarenessLiveActivityForLocalWork({
environmentId: liveEnvironmentId,
threadTitle: "Live task",
projectTitle: "Live project",
});
const preferenceCallbackDrained = preferences.catch(() => null).then(() => undefined);
expect(widgetMocks.start).not.toHaveBeenCalled();
if (state === "completed") {
setLiveShell("ready");
} else {
const shell = appAtomRegistry.get(environmentShell.stateValueAtom(liveEnvironmentId));
const snapshot = Option.getOrThrow(shell.snapshot);
const thread = snapshot.threads[0];
if (!thread) throw new Error("Expected the running fixture thread");
setTestAtom(environmentShell.stateValueAtom(liveEnvironmentId), {
...shell,
snapshot: Option.some({
...snapshot,
threads: [
thread,
{ ...thread, id: ThreadId.make("second-thread"), title: "Second live task" },
],
}),
});
}
const observed = vi.mocked(publishAgentActivityWidget).mock.lastCall?.[0];
expect(observed?.activeCount).toBe(state === "completed" ? 0 : 2);
expect(observed?.activities).toHaveLength(state === "completed" ? 1 : 2);
finishPreferences({ liveActivitiesEnabled: true } as Preferences);
yield* Effect.promise(() => preferenceCallbackDrained);
expect(widgetMocks.start).toHaveBeenCalledExactlyOnceWith(
expect.objectContaining({
activeCount: 1,
activities: [expect.objectContaining({ status: "Connecting" })],
}),
expect.any(Date),
);
expect(backgroundRuntime.pending).toHaveLength(1);
const pending = backgroundRuntime.pending.shift();
if (!pending) throw new Error("Expected the local activity registration operation");
let failedReads = 0;
const failedRelay = snapshotRelayLayer(() => {
failedReads++;
return Effect.fail(
new ManagedRelay.ManagedRelayRequestFailedError({
action: "read relay agent activity snapshot",
transportFailed: true,
cause: new Error("Synthetic snapshot transport failure"),
}),
);
});
const exit = yield* Effect.exit(
pending.operation as Effect.Effect,
).pipe(Effect.provide(failedRelay));
pending.resolve(exit);
expect(Exit.isSuccess(exit)).toBe(true);
expect(failedReads).toBe(1);
expect(activity.getPushToken).toHaveBeenCalledTimes(1);
expect(backgroundRuntime.pending).toHaveLength(0);
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(observed);
}),
);
it.effect("does not let a delayed idle relay response hide current live work", () =>
Effect.gen(function* () {
addLiveEnvironment();
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a");
backgroundRuntime.pending.length = 0;
const readStarted = yield* Deferred.make();
const finishRead = yield* Deferred.make();
const layer = snapshotRelayLayer(() =>
Deferred.succeed(readStarted, undefined).pipe(
Effect.andThen(Deferred.await(finishRead)),
Effect.as({ aggregate: null }),
),
);
const refresh = yield* refreshActiveLiveActivityRemoteRegistration().pipe(
Effect.provide(layer),
Effect.forkChild,
);
yield* Deferred.await(readStarted);
setLiveShell("running");
yield* Deferred.succeed(finishRead, undefined);
yield* Fiber.join(refresh);
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({
activeCount: 1,
activities: [expect.objectContaining({ threadTitle: "Live task", status: "Working" })],
}),
);
}).pipe(Effect.scoped),
);
it.effect.each(["cached", "synchronizing"] as const)(
"preserves last-observed work instead of false idle on %s",
(status) =>
Effect.gen(function* () {
addLiveEnvironment();
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a");
backgroundRuntime.pending.length = 0;
yield* refreshActiveLiveActivityRemoteRegistration().pipe(
Effect.provide(snapshotRelayLayer(() => Effect.succeed({ aggregate: null }))),
);
setLiveShell("running");
expect(vi.mocked(publishAgentActivityWidget).mock.lastCall?.[0]?.activeCount).toBe(1);
setLiveShell("running", status);
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({
activeCount: 1,
isStale: true,
activities: [expect.objectContaining({ status: "Working" })],
}),
);
setLiveShell(null);
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({
activeCount: 0,
isStale: false,
activities: [],
}),
);
}),
);
it.effect("does not resurrect older relay Working after observed Done on disconnect", () =>
Effect.gen(function* () {
addLiveEnvironment();
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a");
backgroundRuntime.pending.length = 0;
const earlier = DateTime.formatIso(
DateTime.makeUnsafe(Date.parse(liveShellUpdatedAt) - 1_000),
);
const relaySnapshot: RelayAgentActivitySnapshotResponse = {
aggregate: {
...activeAgentActivitySnapshot.aggregate,
updatedAt: earlier,
activities: [
{
...activeAgentActivityRow,
threadId: ThreadId.make("local-thread"),
updatedAt: earlier,
},
],
},
};
const layer = snapshotRelayLayer(() => Effect.succeed(relaySnapshot));
yield* refreshActiveLiveActivityRemoteRegistration().pipe(Effect.provide(layer));
setLiveShell("running");
setLiveShell("ready");
const observed = vi.mocked(publishAgentActivityWidget).mock.lastCall?.[0];
expect(observed?.activeCount).toBe(0);
setLiveShell("ready", "cached");
yield* refreshActiveLiveActivityRemoteRegistration().pipe(Effect.provide(layer));
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({
activeCount: 0,
isStale: true,
activities: observed?.activities,
}),
);
}),
);
it.effect.each([false, true])(
"keeps widget counts separate from Live Activity opt-out %s",
(disabled) =>
Effect.gen(function* () {
addLiveEnvironment();
setLiveShell("running");
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a");
backgroundRuntime.pending.length = 0;
widgetMocks.getInstances.mockReturnValue([]);
vi.mocked(loadPreferences).mockResolvedValue({
liveActivitiesEnabled: true,
} as Preferences);
const queries: Array | undefined> = [];
const layer = snapshotRelayLayer(({ excludedEnvironmentIds }) => {
queries.push(excludedEnvironmentIds);
return Effect.succeed(
excludedEnvironmentIds
? {
aggregate: null,
excludedEnvironmentIds,
}
: {
...activeAgentActivitySnapshot,
liveActivityAggregate: disabled
? null
: {
...activeAgentActivitySnapshot.aggregate,
activeCount: 6,
workingCount: 4,
attentionCount: 2,
totalCount: 7,
},
},
);
});
yield* refreshActiveLiveActivityRemoteRegistration().pipe(Effect.provide(layer));
expect(queries).toEqual([undefined, [liveEnvironmentId]]);
if (disabled) expect(widgetMocks.start).not.toHaveBeenCalled();
else
expect(widgetMocks.start).toHaveBeenCalledWith(
expect.objectContaining({
activities: activeAgentActivitySnapshot.aggregate.activities,
workingCount: 4,
attentionCount: 2,
totalCount: 7,
}),
expect.any(Date),
);
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({
activeCount: 1,
isStale: false,
activities: [expect.objectContaining({ threadId: "local-thread" })],
}),
);
}),
);
it.effect(
"publishes honest unknown totals for capped older relays without hiding current rows",
() =>
Effect.gen(function* () {
addLiveEnvironment();
setLiveShell("running");
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a");
backgroundRuntime.pending.length = 0;
yield* refreshActiveLiveActivityRemoteRegistration().pipe(
Effect.provide(
snapshotRelayLayer(() =>
Effect.succeed({
aggregate: { ...activeAgentActivitySnapshot.aggregate, activeCount: 12 },
}),
),
),
);
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({
activeCount: null,
isStale: false,
subtitle: "Activity count unavailable",
activities: [expect.objectContaining({ threadId: "local-thread", status: "Working" })],
}),
);
}),
);
it.effect(
"publishes complete local rows when the first relay read fails without inferring a total",
() =>
Effect.gen(function* () {
addLiveEnvironment();
setLiveShell("running");
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a");
backgroundRuntime.pending.length = 0;
yield* refreshActiveLiveActivityRemoteRegistration().pipe(
Effect.provide(
snapshotRelayLayer(() =>
Effect.fail(
new ManagedRelay.ManagedRelayRequestFailedError({
action: "read relay agent activity snapshot",
transportFailed: true,
cause: new Error("Synthetic first read failure"),
}),
),
),
),
);
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({
activeCount: null,
isStale: false,
observedActivities: {
[liveEnvironmentId]: [expect.objectContaining({ threadId: "local-thread" })],
},
activities: [expect.objectContaining({ threadId: "local-thread", status: "Working" })],
}),
);
}),
);
it.effect("re-reads a changed exclusion scope instead of publishing the old scoped total", () =>
Effect.gen(function* () {
addLiveEnvironment();
setLiveShell("running");
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a");
backgroundRuntime.pending.length = 0;
const started = yield* Deferred.make();
const finish = yield* Deferred.make();
const queries: Array | undefined> = [];
const layer = snapshotRelayLayer(({ excludedEnvironmentIds }) => {
queries.push(excludedEnvironmentIds);
if (excludedEnvironmentIds?.length === 1)
return Deferred.succeed(started, undefined).pipe(
Effect.andThen(Deferred.await(finish)),
Effect.as({
aggregate: { ...activeAgentActivitySnapshot.aggregate, activeCount: 12 },
excludedEnvironmentIds,
}),
);
return Effect.succeed({
aggregate: null,
excludedEnvironmentIds: excludedEnvironmentIds ?? [],
});
});
const refresh = yield* refreshActiveLiveActivityRemoteRegistration().pipe(
Effect.provide(layer),
Effect.forkChild,
);
yield* Deferred.await(started);
const other = EnvironmentId.make("other");
const catalog = appAtomRegistry.get(environmentCatalog.catalogValueAtom);
setTestAtom(environmentShell.stateValueAtom(other), {
status: "live",
generation: 0,
removedAt: new Map(),
error: Option.none(),
snapshot: Option.some({
projects: [],
threads: [],
snapshotSequence: 1,
archivedThreads: [],
schemaVersion: 1,
}),
});
setTestAtom(environmentCatalog.catalogValueAtom, {
...catalog,
entries: new Map([
...catalog.entries,
[
other,
{
target: new PrimaryConnectionTarget({
environmentId: other,
label: "Other",
httpBaseUrl: "https://other.example.test",
wsBaseUrl: "wss://other.example.test/ws",
}),
profile: Option.none(),
enabled: true,
},
],
]),
});
yield* Deferred.succeed(finish, undefined);
yield* Fiber.join(refresh);
expect(queries).toEqual([undefined, [liveEnvironmentId], [liveEnvironmentId, other]]);
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({ activeCount: 1, isStale: false }),
);
expect(
vi
.mocked(publishAgentActivityWidget)
.mock.calls.some(([props]) => props.activeCount === 13),
).toBe(false);
}).pipe(Effect.scoped),
);
it.effect("evicts retained observations on catalog removal and account switch", () =>
Effect.gen(function* () {
addLiveEnvironment();
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a");
backgroundRuntime.pending.length = 0;
const layer = snapshotRelayLayer(({ excludedEnvironmentIds }) =>
Effect.succeed({ aggregate: null, excludedEnvironmentIds: excludedEnvironmentIds ?? [] }),
);
yield* refreshActiveLiveActivityRemoteRegistration().pipe(Effect.provide(layer));
setLiveShell("running");
setLiveShell("running", "cached");
expect(vi.mocked(publishAgentActivityWidget).mock.lastCall?.[0]?.isStale).toBe(true);
setTestAtom(environmentCatalog.catalogValueAtom, { isReady: true, entries: new Map() });
yield* refreshActiveLiveActivityRemoteRegistration().pipe(Effect.provide(layer));
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({ activeCount: 0, isStale: false, activities: [] }),
);
addLiveEnvironment();
setLiveShell("running");
setLiveShell("running", "cached");
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-b"), "user-b");
yield* refreshActiveLiveActivityRemoteRegistration().pipe(Effect.provide(layer));
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({ activeCount: 0, isStale: false, activities: [] }),
);
}),
);
it.effect.each(["account switch", "provider remount"] as const)(
"clears the prior account's native widget on %s even when the relay is unavailable",
(transition) =>
Effect.gen(function* () {
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("token-a"), "user-a");
backgroundRuntime.pending.length = 0;
yield* refreshActiveLiveActivityRemoteRegistration().pipe(
Effect.provide(snapshotRelayLayer()),
);
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({
activeCount: 1,
activities: activeAgentActivitySnapshot.aggregate.activities,
}),
);
if (transition === "provider remount") releaseAgentAwarenessRelayTokenProvider();
vi.mocked(clearAgentWidgetRefresh).mockClear();
vi.mocked(agentWidgetToken).mockClear();
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("token-b"), "user-b");
expect(agentWidgetToken).toHaveBeenCalledWith("user-b");
if (transition === "account switch") expect(clearAgentWidgetRefresh).toHaveBeenCalledOnce();
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({ activeCount: null, activities: [] }),
);
backgroundRuntime.pending.length = 0;
yield* refreshActiveLiveActivityRemoteRegistration().pipe(
Effect.provide(
snapshotRelayLayer(() =>
Effect.fail(
new ManagedRelay.ManagedRelayRequestFailedError({
action: "read relay agent activity snapshot",
transportFailed: true,
cause: new Error("offline"),
}),
),
),
),
);
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({ activeCount: null, activities: [] }),
);
}),
);
it.effect("publishes freshness changes even when rows and count are unchanged", () =>
Effect.gen(function* () {
addLiveEnvironment();
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a");
backgroundRuntime.pending.length = 0;
yield* refreshActiveLiveActivityRemoteRegistration().pipe(
Effect.provide(snapshotRelayLayer(() => Effect.succeed({ aggregate: null }))),
);
setLiveShell("running");
setLiveShell("running", "live", "2026-10-02T12:00:00.500Z");
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({
observedActivities: {
[liveEnvironmentId]: [
expect.objectContaining({ updatedAt: "2026-10-02T12:00:00.500Z" }),
],
},
}),
);
const count = vi.mocked(publishAgentActivityWidget).mock.calls.length;
setLiveShell("running", "cached");
expect(publishAgentActivityWidget).toHaveBeenCalledTimes(count + 1);
expect(vi.mocked(publishAgentActivityWidget).mock.lastCall?.[0]?.isStale).toBe(true);
setLiveShell("running", "synchronizing");
expect(publishAgentActivityWidget).toHaveBeenCalledTimes(count + 1);
setLiveShell("running");
expect(publishAgentActivityWidget).toHaveBeenCalledTimes(count + 2);
expect(vi.mocked(publishAgentActivityWidget).mock.lastCall?.[0]?.isStale).toBe(false);
}),
);
it.effect(
"uses live idle and deletion over relay work, retaining local evidence when disconnected",
() => {
addLiveEnvironment();
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a");
backgroundRuntime.pending.length = 0;
return Effect.gen(function* () {
yield* refreshActiveLiveActivityRemoteRegistration();
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({ activeCount: 0, activities: [] }),
);
setLiveShell("running");
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({
activities: [expect.objectContaining({ threadTitle: "Live task" })],
}),
);
setLiveShell("ready", "cached");
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({
activeCount: 1,
isStale: true,
activities: [expect.objectContaining({ threadTitle: "Live task" })],
}),
);
setLiveShell(null);
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({ activeCount: 0, activities: [] }),
);
}).pipe(Effect.provide(snapshotRelayLayer()));
},
);
it.effect("detaches on background and resumes from the latest shell on foreground", () => {
addLiveEnvironment();
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a");
backgroundRuntime.pending.length = 0;
return Effect.gen(function* () {
yield* refreshActiveLiveActivityRemoteRegistration();
setLiveShell("running");
appStateMock.currentState = "background";
for (const listener of appStateMock.listeners) listener("background");
const publishedBeforeBackground = vi.mocked(publishAgentActivityWidget).mock.calls.length;
expect(vi.mocked(publishAgentActivityWidget).mock.lastCall?.[0]?.isStale).toBe(false);
setLiveShell("ready");
expect(publishAgentActivityWidget).toHaveBeenCalledTimes(publishedBeforeBackground);
appStateMock.currentState = "active";
for (const listener of appStateMock.listeners) listener("active");
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({
activeCount: 0,
activities: [expect.objectContaining({ status: "Done" })],
}),
);
expect(backgroundRuntime.pending).toHaveLength(1);
}).pipe(Effect.provide(snapshotRelayLayer(() => Effect.succeed({ aggregate: null }))));
});
it.effect(
"keeps the original deadline when a background relay read cannot validate retained observations",
() => {
addLiveEnvironment();
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a");
backgroundRuntime.pending.length = 0;
return Effect.gen(function* () {
yield* refreshActiveLiveActivityRemoteRegistration();
setLiveShell("running");
appStateMock.currentState = "background";
for (const listener of appStateMock.listeners) listener("background");
setLiveShell(null);
yield* refreshActiveLiveActivityRemoteRegistration();
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({
activeCount: 1,
isStale: false,
activities: [expect.objectContaining({ threadTitle: "Live task" })],
}),
);
}).pipe(Effect.provide(snapshotRelayLayer()));
},
);
it.effect("deduplicates timestamp-only shell updates and same-account observer refreshes", () => {
addLiveEnvironment();
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a");
backgroundRuntime.pending.length = 0;
return Effect.gen(function* () {
yield* refreshActiveLiveActivityRemoteRegistration();
setLiveShell("running");
const count = vi.mocked(publishAgentActivityWidget).mock.calls.length;
setLiveShell("running");
setAgentAwarenessRelayTokenProvider(
() => Promise.resolve("refreshed-token-user-a"),
"user-a",
);
setLiveShell("running");
expect(publishAgentActivityWidget).toHaveBeenCalledTimes(count);
setLiveShell("ready");
expect(publishAgentActivityWidget).toHaveBeenCalledTimes(count + 1);
}).pipe(Effect.provide(snapshotRelayLayer(() => Effect.succeed({ aggregate: null }))));
});
it.effect("retries identical widget content after a failed native publish", () => {
addLiveEnvironment();
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a");
backgroundRuntime.pending.length = 0;
return Effect.gen(function* () {
yield* refreshActiveLiveActivityRemoteRegistration();
vi.mocked(publishAgentActivityWidget).mockReturnValueOnce(false);
setLiveShell("running");
const count = vi.mocked(publishAgentActivityWidget).mock.calls.length;
setLiveShell("running");
expect(publishAgentActivityWidget).toHaveBeenCalledTimes(count + 1);
setLiveShell("running");
expect(publishAgentActivityWidget).toHaveBeenCalledTimes(count + 1);
}).pipe(Effect.provide(snapshotRelayLayer(() => Effect.succeed({ aggregate: null }))));
});
it.effect(
"does not renew disconnected work from a fresh read of an older relay observation",
() =>
Effect.gen(function* () {
const now = Date.parse("2026-10-02T12:00:00.000Z");
const clock = vi.spyOn(Date, "now").mockReturnValue(now);
addLiveEnvironment();
setLiveShell("running");
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("token-a"), "user-a");
backgroundRuntime.pending.length = 0;
const layer = snapshotRelayLayer(() => Effect.succeed({ aggregate: null }));
yield* refreshActiveLiveActivityRemoteRegistration().pipe(Effect.provide(layer));
const deadline = vi.mocked(publishAgentActivityWidget).mock.lastCall![0].expiresAt;
clock.mockReturnValue(now + 60_000);
setLiveShell("running", "cached");
yield* refreshActiveLiveActivityRemoteRegistration().pipe(Effect.provide(layer));
const retained = vi.mocked(publishAgentActivityWidget).mock.lastCall![0];
expect(retained).toMatchObject({ isStale: true, expiresAt: deadline });
expect(retained.activities[0]?.threadTitle).toBe("Live task");
appStateMock.currentState = "background";
for (const listener of appStateMock.listeners) listener("background");
expect(vi.mocked(publishAgentActivityWidget).mock.lastCall![0]).toMatchObject({
isStale: true,
expiresAt: deadline,
});
}),
);
it("renews a confirmed live shell but not an unrelated atom recomputation", () => {
const now = Date.parse("2026-10-02T12:00:00.000Z");
const clock = vi.spyOn(Date, "now").mockReturnValue(now);
addLiveEnvironment();
setLiveShell("running");
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("token-a"), "user-a");
const original = vi.mocked(publishAgentActivityWidget).mock.lastCall![0];
expect(original.expiresAt).toBe(now + AGENT_ACTIVITY_FRESHNESS_MS);
const publications = vi.mocked(publishAgentActivityWidget).mock.calls.length;
clock.mockReturnValue(now + 60_000);
const catalog = appAtomRegistry.get(environmentCatalog.catalogValueAtom);
setTestAtom(environmentCatalog.catalogValueAtom, { ...catalog });
expect(publishAgentActivityWidget).toHaveBeenCalledTimes(publications);
setLiveShell("running");
expect(vi.mocked(publishAgentActivityWidget).mock.lastCall![0].expiresAt).toBe(
now + 60_000 + AGENT_ACTIVITY_FRESHNESS_MS,
);
expect(publishAgentActivityWidget).toHaveBeenCalledTimes(publications + 1);
});
it("does not let an old idle environment expire freshly observed work", () => {
const now = Date.parse("2026-10-02T12:00:00.000Z");
const clock = vi.spyOn(Date, "now").mockReturnValue(now);
addLiveEnvironment();
const other = EnvironmentId.make("idle-environment");
setTestAtom(
environmentShell.stateValueAtom(other),
appAtomRegistry.get(environmentShell.stateValueAtom(liveEnvironmentId)),
);
const catalog = appAtomRegistry.get(environmentCatalog.catalogValueAtom);
setTestAtom(environmentCatalog.catalogValueAtom, {
...catalog,
entries: new Map([
...catalog.entries,
[
other,
{
target: new PrimaryConnectionTarget({
environmentId: other,
label: "Idle",
httpBaseUrl: "https://idle.example.test",
wsBaseUrl: "wss://idle.example.test/ws",
}),
profile: Option.none(),
enabled: true,
},
],
]),
});
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("token-a"), "user-a");
clock.mockReturnValue(now + AGENT_ACTIVITY_FRESHNESS_MS + 60_000);
setLiveShell("running");
expect(vi.mocked(publishAgentActivityWidget).mock.lastCall![0]).toMatchObject({
expiresAt: now + AGENT_ACTIVITY_FRESHNESS_MS * 2 + 60_000,
});
});
it("keeps the full freshness interval for a shell observed late in a minute", () => {
const now = Date.parse("2026-10-02T12:00:59.000Z");
vi.spyOn(Date, "now").mockReturnValue(now);
addLiveEnvironment();
setLiveShell("running");
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("token-a"), "user-a");
expect(vi.mocked(publishAgentActivityWidget).mock.lastCall![0].expiresAt).toBe(
now + AGENT_ACTIVITY_FRESHNESS_MS,
);
});
it.effect.each([
null,
{
...activeAgentActivitySnapshot.aggregate,
activeCount: 0,
activities: [{ ...activeAgentActivityRow, phase: "completed" as const }],
},
])(
"does not expire fresh direct work because an empty or terminal relay read is old: %s",
(aggregate) =>
Effect.gen(function* () {
const now = Date.parse("2026-10-02T12:00:00.000Z");
const clock = vi.spyOn(Date, "now").mockReturnValue(now);
addLiveEnvironment();
setLiveShell("running");
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("token-a"), "user-a");
yield* refreshActiveLiveActivityRemoteRegistration().pipe(
Effect.provide(snapshotRelayLayer(() => Effect.succeed({ aggregate }))),
);
clock.mockReturnValue(now + AGENT_ACTIVITY_FRESHNESS_MS + 59_000);
setLiveShell("running");
expect(vi.mocked(publishAgentActivityWidget).mock.lastCall![0].expiresAt).toBe(
now + AGENT_ACTIVITY_FRESHNESS_MS * 2 + 59_000,
);
}),
);
it.effect("renews unchanged confirmed relay content, but not a failed read", () =>
Effect.gen(function* () {
const now = Date.parse("2026-10-02T12:00:00.000Z");
const clock = vi.spyOn(Date, "now").mockReturnValue(now);
yield* TestClock.setTime(now);
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("token-a"), "user-a");
backgroundRuntime.pending.length = 0;
const layer = snapshotRelayLayer();
yield* refreshActiveLiveActivityRemoteRegistration().pipe(Effect.provide(layer));
const original = vi.mocked(publishAgentActivityWidget).mock.lastCall![0];
expect(original.expiresAt).toBe(now + AGENT_ACTIVITY_FRESHNESS_MS);
clock.mockReturnValue(now + 60_000);
yield* TestClock.setTime(now + 60_000);
yield* refreshActiveLiveActivityRemoteRegistration().pipe(Effect.provide(layer));
const renewed = vi.mocked(publishAgentActivityWidget).mock.lastCall![0];
expect(renewed.activities).toEqual(original.activities);
expect(renewed.expiresAt).toBe(now + 60_000 + AGENT_ACTIVITY_FRESHNESS_MS);
const publications = vi.mocked(publishAgentActivityWidget).mock.calls.length;
clock.mockReturnValue(now + 120_000);
yield* TestClock.setTime(now + 120_000);
yield* refreshActiveLiveActivityRemoteRegistration().pipe(
Effect.provide(
snapshotRelayLayer(() =>
Effect.fail(
new ManagedRelay.ManagedRelayRequestFailedError({
action: "read relay agent activity snapshot",
transportFailed: true,
cause: new Error("offline"),
}),
),
),
),
);
expect(publishAgentActivityWidget).toHaveBeenCalledTimes(publications);
expect(vi.mocked(publishAgentActivityWidget).mock.lastCall![0].expiresAt).toBe(
renewed.expiresAt,
);
}),
);
it.effect("does not renew expiration when an older unchanged relay read finishes last", () =>
Effect.gen(function* () {
const now = Date.parse("2026-10-02T12:00:00.000Z");
const clock = vi.spyOn(Date, "now").mockReturnValue(now);
yield* TestClock.setTime(now);
const started = yield* Deferred.make();
const finish = yield* Deferred.make();
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("token-a"), "user-a");
backgroundRuntime.pending.length = 0;
const older = yield* refreshActiveLiveActivityRemoteRegistration().pipe(
Effect.provide(
snapshotRelayLayer(() =>
Deferred.succeed(started, undefined).pipe(
Effect.andThen(Deferred.await(finish)),
Effect.as(activeAgentActivitySnapshot),
),
),
),
Effect.forkChild,
);
yield* Deferred.await(started);
clock.mockReturnValue(now + 60_000);
yield* TestClock.setTime(now + 60_000);
yield* refreshActiveLiveActivityRemoteRegistration().pipe(
Effect.provide(snapshotRelayLayer()),
);
const publications = vi.mocked(publishAgentActivityWidget).mock.calls.length;
clock.mockReturnValue(now + 120_000);
yield* TestClock.setTime(now + 120_000);
yield* Deferred.succeed(finish, undefined);
yield* Fiber.join(older);
expect(publishAgentActivityWidget).toHaveBeenCalledTimes(publications);
expect(vi.mocked(publishAgentActivityWidget).mock.lastCall![0].expiresAt).toBe(
now + 60_000 + AGENT_ACTIVITY_FRESHNESS_MS,
);
}).pipe(Effect.scoped),
);
it.effect("keeps a slow read's original deadline instead of freshening it on arrival", () =>
Effect.gen(function* () {
const now = Date.parse("2026-10-02T12:00:00.000Z");
const clock = vi.spyOn(Date, "now").mockReturnValue(now);
yield* TestClock.setTime(now);
const started = yield* Deferred.make();
const finish = yield* Deferred.make();
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("token-a"), "user-a");
backgroundRuntime.pending.length = 0;
const refresh = yield* refreshActiveLiveActivityRemoteRegistration().pipe(
Effect.provide(
snapshotRelayLayer(() =>
Deferred.succeed(started, undefined).pipe(
Effect.andThen(Deferred.await(finish)),
Effect.as(activeAgentActivitySnapshot),
),
),
),
Effect.forkChild,
);
yield* Deferred.await(started);
const arrivedAt = now + AGENT_ACTIVITY_FRESHNESS_MS + 1;
clock.mockReturnValue(arrivedAt);
yield* TestClock.setTime(arrivedAt);
yield* Deferred.succeed(finish, undefined);
yield* Fiber.join(refresh);
const publication = vi.mocked(publishAgentActivityWidget).mock.lastCall![0];
expect(publication.expiresAt).toBe(now + AGENT_ACTIVITY_FRESHNESS_MS);
expect(agentActivityTimeline(publication, arrivedAt)).toEqual([
{
date: DateTime.toDateUtc(DateTime.makeUnsafe(arrivedAt)),
props: expect.objectContaining({ isExpired: true, activeCount: -1 }),
},
]);
}).pipe(Effect.scoped),
);
it.effect("renews unchanged live observations and preserves their deadline on background", () =>
Effect.gen(function* () {
const now = Date.parse("2026-10-02T12:00:00.000Z");
const clock = vi.spyOn(Date, "now").mockReturnValue(now);
addLiveEnvironment();
setLiveShell("running");
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("token-a"), "user-a");
backgroundRuntime.pending.length = 0;
const layer = snapshotRelayLayer(({ excludedEnvironmentIds }) =>
Effect.succeed({ aggregate: null, excludedEnvironmentIds: excludedEnvironmentIds ?? [] }),
);
yield* refreshActiveLiveActivityRemoteRegistration().pipe(Effect.provide(layer));
const original = vi.mocked(publishAgentActivityWidget).mock.lastCall![0];
clock.mockReturnValue(now + 60_000);
setLiveShell("running");
yield* refreshActiveLiveActivityRemoteRegistration().pipe(Effect.provide(layer));
const renewed = vi.mocked(publishAgentActivityWidget).mock.lastCall![0];
expect(renewed.activities.map(({ updatedAt: _updatedAt, ...row }) => row)).toEqual(
original.activities.map(({ updatedAt: _updatedAt, ...row }) => row),
);
expect(renewed.expiresAt).toBe(now + 60_000 + AGENT_ACTIVITY_FRESHNESS_MS);
const backgroundedAt = now + 120_000;
clock.mockReturnValue(backgroundedAt);
appStateMock.currentState = "background";
for (const listener of appStateMock.listeners) listener("background");
expect(vi.mocked(publishAgentActivityWidget).mock.lastCall![0]).toMatchObject({
isStale: false,
expiresAt: renewed.expiresAt,
});
const timeline = agentActivityTimeline(renewed, backgroundedAt);
expect(timeline[0]?.props.isExpired).toBeUndefined();
expect(timeline[1]?.date.getTime()).toBe(renewed.expiresAt);
expect(timeline[1]?.props.activities[0]).toMatchObject({
phase: "stale",
status: "Out of date",
});
}),
);
it.effect("detaches the shell publisher on sign-out and provider release", () => {
addLiveEnvironment();
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a");
backgroundRuntime.pending.length = 0;
return Effect.gen(function* () {
yield* refreshActiveLiveActivityRemoteRegistration();
setLiveShell("running");
releaseAgentAwarenessRelayTokenProvider();
const count = vi.mocked(publishAgentActivityWidget).mock.calls.length;
setLiveShell("ready");
expect(publishAgentActivityWidget).toHaveBeenCalledTimes(count);
expect(clearAgentAwarenessRegistrationRecord).not.toHaveBeenCalled();
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"), "user-a");
yield* refreshActiveLiveActivityRemoteRegistration();
setAgentAwarenessRelayTokenProvider(null);
const countAfterSignout = vi.mocked(publishAgentActivityWidget).mock.calls.length;
setLiveShell("running");
expect(publishAgentActivityWidget).toHaveBeenCalledTimes(countAfterSignout);
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({ activeCount: 0, activities: [] }),
);
}).pipe(Effect.provide(snapshotRelayLayer(() => Effect.succeed({ aggregate: null }))));
});
it.effect("does not restore an in-flight widget snapshot after cloud sign-out", () =>
Effect.gen(function* () {
const readStarted = yield* Deferred.make();
const finishRead = yield* Deferred.make();
const layer = snapshotRelayLayer(() =>
Deferred.succeed(readStarted, undefined).pipe(
Effect.andThen(Deferred.await(finishRead)),
Effect.as(activeAgentActivitySnapshot),
),
);
setAgentAwarenessRelayTokenProvider(() => Promise.resolve("clerk-token-user-a"));
backgroundRuntime.pending.length = 0;
const refresh = yield* refreshActiveLiveActivityRemoteRegistration().pipe(
Effect.provide(layer),
Effect.forkChild,
);
yield* Deferred.await(readStarted);
setAgentAwarenessRelayTokenProvider(null);
yield* Deferred.succeed(finishRead, undefined);
yield* Fiber.join(refresh);
expect(publishAgentActivityWidget).toHaveBeenCalledTimes(2);
expect(publishAgentActivityWidget).toHaveBeenLastCalledWith(
expect.objectContaining({
subtitle: "Sign in to see agent activity",
isSignedOut: true,
activeCount: 0,
activities: [],
}),
);
}).pipe(Effect.scoped),
);
});