import type { ExecutionBackend } from "@/lib/execution/execution-backend"; import type { ExecutionBackendDescription, ExecutionImmediateResult, ExecutionRequest, ExecutionRequestKind, } from "@/lib/execution/types"; import { getClawBackendConfig, isClawBackendConfigured, type ClawBackendConfig, } from "@/lib/execution/backends/claw-config"; import { runClawCommand } from "@/lib/execution/backends/claw-runner"; export const CLAW_BACKEND_ID = "claw-runtime"; export const CLAW_BACKEND = { backendId: CLAW_BACKEND_ID, label: "Claw Runtime", mode: "local", } as const satisfies ExecutionBackendDescription; const SUPPORTED_CLAW_KINDS = new Set([ "master_agent_reply", "thread_reply", ]); type ClawRunnerInput = Parameters[0]; type ClawRunner = (input: ClawRunnerInput) => Promise; export interface ClawBackendSelectionState { enabled: boolean; supportsKinds: ExecutionRequestKind[]; } function createFailedResult(error: string): ExecutionImmediateResult { return { status: "failed", backendId: CLAW_BACKEND_ID, error, }; } export function isClawRequestKindSupported(kind: ExecutionRequestKind) { return SUPPORTED_CLAW_KINDS.has(kind); } export function getClawBackendSelectionState( config: ClawBackendConfig = getClawBackendConfig(), ): ClawBackendSelectionState { return { enabled: isClawBackendConfigured(config), supportsKinds: [...SUPPORTED_CLAW_KINDS], }; } function buildClawPayload(input: ExecutionRequest, config: ClawBackendConfig) { return { kind: input.kind, projectId: input.projectId, requestMessageId: input.requestMessageId, body: input.body, executionPrompt: input.executionPrompt ?? input.body, model: input.modelOverride ?? config.defaultModel, reasoningEffort: input.reasoningEffortOverride ?? "medium", ...(input.targetProjectId ? { targetProjectId: input.targetProjectId } : {}), ...(input.targetThreadId ? { targetThreadId: input.targetThreadId } : {}), ...(input.requestedByAccount ? { requestedByAccount: input.requestedByAccount } : {}), ...(input.requestedByLabel ? { requestedByLabel: input.requestedByLabel } : {}), ...(input.taskId ? { taskId: input.taskId } : {}), }; } export function createClawBackend(options?: { config?: ClawBackendConfig; runner?: ClawRunner; }): ExecutionBackend { const config = options?.config ?? getClawBackendConfig(); const runner = options?.runner ?? runClawCommand; return { backendId: CLAW_BACKEND_ID, async canHandle(input) { return isClawBackendConfigured(config) && isClawRequestKindSupported(input.kind); }, async execute(input) { const canHandle = await this.canHandle(input); if (!canHandle) { return createFailedResult("CLAW_BACKEND_NOT_AVAILABLE"); } return runner({ config, payload: buildClawPayload(input, config), }); }, async describe() { return CLAW_BACKEND; }, }; } export const CLAW_BACKEND_ADAPTER = createClawBackend(); export const createClawBackendForTesting = createClawBackend;