Freeze the shared contracts every Media Studio slice builds on: zod DTOs, EDL, platform profile, brand kit, gate and render plan schemas; the media RPC surface with a scaffold router; provider interfaces for sources, inference, rendering, motion graphics and publishing; media background jobs; the Prisma models and migration; and the @rakazo/media domain package signatures. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0138YqDj3ttfayRwuMKKrqVj
147 lines
5.0 KiB
TypeScript
147 lines
5.0 KiB
TypeScript
import type {
|
|
AgentHomeStore,
|
|
AgentRuntime,
|
|
BackgroundJobHandlers,
|
|
JobPublisher,
|
|
MediaJobHandlers,
|
|
MessagingSurface,
|
|
SandboxProvider,
|
|
} from "@rakazo/adapter-kit";
|
|
import { messagingDeliverJob } from "@rakazo/adapter-kit";
|
|
import type { PrismaClient, ThreadEvents } from "@rakazo/db";
|
|
import { getLogger } from "@rakazo/logging";
|
|
import type { CloudAgentConnection } from "./cloud-agent-factory.js";
|
|
import { pollCloudAgent } from "./cloud-agent-poll.js";
|
|
import { expireComputerControl } from "./computer-control.js";
|
|
import { scheduleComputerSleep, sleepComputerIfIdle } from "./computer-idle.js";
|
|
import { performComputerUpdate } from "./computer-update.js";
|
|
import type { createRunExecutor } from "./executor.js";
|
|
import { compactHistory } from "./history-compaction.js";
|
|
import type { MemoryProviderResolver } from "./memory-provider-factory.js";
|
|
import { deliverMessagingOutbound, mirrorMessagingOutbound } from "./messaging-delivery.js";
|
|
import { consolidateProfile } from "./profile-consolidation.js";
|
|
import type { EncryptedSecretStore } from "./secrets.js";
|
|
import { expireTaughtSkillTeaching } from "./teaching-session.js";
|
|
|
|
export function createBackgroundJobHandlers(deps: {
|
|
executor: ReturnType<typeof createRunExecutor>;
|
|
prisma: PrismaClient;
|
|
sandbox: SandboxProvider;
|
|
home: AgentHomeStore;
|
|
jobs: JobPublisher;
|
|
events: ThreadEvents;
|
|
workerId: string;
|
|
runtime: AgentRuntime;
|
|
secretStore: EncryptedSecretStore;
|
|
memoryProviders: MemoryProviderResolver;
|
|
deploymentModelKey?: string;
|
|
messaging?: MessagingSurface;
|
|
cloudAgent?: CloudAgentConnection | null;
|
|
/** Media Studio job handlers; absent when media is not configured for this worker. */
|
|
media?: MediaJobHandlers;
|
|
}): BackgroundJobHandlers {
|
|
const deliverMessaging = async (runId?: string) => {
|
|
if (!deps.messaging) return;
|
|
await deliverMessagingOutbound(
|
|
{ prisma: deps.prisma, messaging: deps.messaging, events: deps.events, jobs: deps.jobs },
|
|
{ runId },
|
|
{
|
|
operationId: `messaging.deliver:${runId ?? "drain"}`,
|
|
traceId: `messaging.deliver:${runId ?? "drain"}`,
|
|
spaceId: "",
|
|
userId: "",
|
|
signal: new AbortController().signal,
|
|
},
|
|
);
|
|
};
|
|
|
|
return {
|
|
...(deps.media ?? mediaDisabledHandlers()),
|
|
"run.continue": async (payload) => {
|
|
await deps.executor.continueRun(payload.runId, deps.workerId);
|
|
// Automatic messaging mirror: once the run's bot messages are durable,
|
|
// copy them into the outbox. Never let mirror failures fail the run.
|
|
if (deps.messaging) {
|
|
await mirrorMessagingOutbound(
|
|
{ prisma: deps.prisma, messaging: deps.messaging, events: deps.events, jobs: deps.jobs },
|
|
payload.runId,
|
|
);
|
|
await deps.jobs.enqueue(messagingDeliverJob()).catch(async (error) => {
|
|
getLogger().error("messaging.deliver enqueue error", error);
|
|
await deliverMessaging();
|
|
});
|
|
}
|
|
},
|
|
"messaging.deliver": async (payload) => {
|
|
await deliverMessaging(payload.runId);
|
|
},
|
|
"routine.wakeup": async (payload) => {
|
|
await deps.executor.wakeRoutine(payload.routineId, payload.scheduledFor);
|
|
},
|
|
"computer.update": async ({ updateId }) => {
|
|
await performComputerUpdate(deps, updateId);
|
|
},
|
|
"computer.sleep": async (payload) => {
|
|
await sleepComputerIfIdle(deps, payload.computerId);
|
|
},
|
|
"computer.control-expire": async (payload) => {
|
|
if (await expireComputerControl(deps, payload.computerId, payload.leaseId)) {
|
|
scheduleComputerSleep(deps.jobs, payload.computerId);
|
|
}
|
|
},
|
|
"skill.teaching-expire": async (payload) => {
|
|
await expireTaughtSkillTeaching(deps, payload.skillId);
|
|
},
|
|
"cloud_agent.poll": async (payload) => {
|
|
await pollCloudAgent(
|
|
{
|
|
prisma: deps.prisma,
|
|
jobs: deps.jobs,
|
|
events: deps.events,
|
|
cloudAgent: deps.cloudAgent,
|
|
},
|
|
payload,
|
|
);
|
|
},
|
|
"history.compact": async (payload) => {
|
|
await compactHistory(
|
|
{
|
|
prisma: deps.prisma,
|
|
runtime: deps.runtime,
|
|
jobs: deps.jobs,
|
|
memoryProviders: deps.memoryProviders,
|
|
deploymentModelKey: deps.deploymentModelKey,
|
|
...(deps.executor.resolveModel ? { resolveModel: deps.executor.resolveModel } : {}),
|
|
},
|
|
payload.threadId,
|
|
);
|
|
},
|
|
"profile.consolidate": async (payload) => {
|
|
await consolidateProfile(
|
|
{
|
|
prisma: deps.prisma,
|
|
runtime: deps.runtime,
|
|
jobs: deps.jobs,
|
|
memoryProviders: deps.memoryProviders,
|
|
resolveModel: (scope) => deps.executor.resolveModel(scope),
|
|
},
|
|
payload.userId,
|
|
);
|
|
},
|
|
};
|
|
}
|
|
|
|
function mediaDisabledHandlers(): MediaJobHandlers {
|
|
const skip = async () => {
|
|
getLogger().warn("media job skipped: Media Studio is not configured on this worker");
|
|
};
|
|
return {
|
|
"media.sync": skip,
|
|
"media.proxy": skip,
|
|
"media.analyze": skip,
|
|
"media.cluster": skip,
|
|
"media.render": skip,
|
|
"media.publish": skip,
|
|
};
|
|
}
|