import fs from "node:fs"; import os from "node:os"; import path from "node:path"; type OpenClawConfig = Record; type AgentEntry = Record; const CLAUDE_CONTRACTOR_MODEL = "contractor-agent/contractor-claude-bridge"; const GEMINI_CONTRACTOR_MODEL = "contractor-agent/contractor-gemini-bridge"; function readConfig(): { config: OpenClawConfig; configPath: string } { const configPath = path.join(os.homedir(), ".openclaw", "openclaw.json"); const raw = fs.readFileSync(configPath, "utf8"); return { config: JSON.parse(raw) as OpenClawConfig, configPath }; } function writeConfig(configPath: string, config: OpenClawConfig): void { fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf8"); } /** * Verify that an agent is configured with the contractor bridge model. * Called after createBaseAgent() — the model is already set by `openclaw agents add`, * so this is just a sanity check that throws if something went wrong. * * We intentionally do NOT write a custom `runtime.type` — OpenClaw's schema only * allows "embedded" or "acp", and contractor agents are identified by their model. */ function markContractorAgent(agentId: string, expectedModel: string, configPath: string, config: OpenClawConfig): void { const agents = (config.agents as { list?: AgentEntry[] } | undefined)?.list; if (!agents) throw new Error("agents.list not found in openclaw.json"); const agent = agents.find((a) => a.id === agentId); if (!agent) throw new Error(`agent ${agentId} not found in openclaw.json`); if (agent.model !== expectedModel) { throw new Error( `agent ${agentId} model is "${String(agent.model)}", expected "${expectedModel}"`, ); } // Ensure tools are enabled so OpenClaw includes tool definitions in every // chat completions request — needed for the MCP proxy to expose them to Claude/Gemini. if (!agent.tools) { agent.tools = { profile: "full" }; writeConfig(configPath, config); } } export function markAgentAsClaudeContractor(agentId: string, _workspace: string): void { const { config, configPath } = readConfig(); markContractorAgent(agentId, CLAUDE_CONTRACTOR_MODEL, configPath, config); } export function markAgentAsGeminiContractor(agentId: string, _workspace: string): void { const { config, configPath } = readConfig(); markContractorAgent(agentId, GEMINI_CONTRACTOR_MODEL, configPath, config); }