UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

240 lines (239 loc) 9.67 kB
import { c as resolveUserPath } from "./home-dir-BPhrG-aM.js"; import { h as redactToolPayloadText } from "./redact-BtvPPfTi.js"; import "./utils-P__uGsPB.js"; import { n as sanitizeTerminalText } from "./safe-text-BGBqp1a4.js"; import { r as loadInstalledPluginIndexInstallRecords } from "./installed-plugin-index-record-reader-SXWwf_BU.js"; import { t as resolveModelRuntimePolicy } from "./model-runtime-policy-BAKiaBCi.js"; import { o as modelSelectionShouldEnsureCodexPlugin, s as parseModelRefProvider } from "./openai-routing-Ex_3E9TF.js"; import { r as enablePluginWithCapabilityConsent } from "./enable-3OwjFbBV.js"; import "./installed-plugin-index-records-C06Xozeq.js"; import { t as createPluginCapabilityConsentPrompter } from "./plugin-capability-consent-CaBGom29.js"; import { t as createNonInteractiveLoggingPrompter } from "./non-interactive-prompter-DLCGsi38.js"; import { existsSync } from "node:fs"; import path from "node:path"; //#region src/agents/copilot-routing.ts const GITHUB_COPILOT_PROVIDER_ID = "github-copilot"; /** * Canonical id of the Copilot agent runtime plugin. */ const COPILOT_RUNTIME_ID = "copilot"; function parseModelRefId(model) { if (typeof model !== "string") return; const trimmed = model.trim(); const slash = trimmed.indexOf("/"); if (slash <= 0 || slash === trimmed.length - 1) return; return trimmed.slice(slash + 1); } /** * Returns true when the selected model should trigger the external * `@openclaw/copilot` runtime plugin install. * * Gating contract (review #2, P1): * - Model ref must use the `github-copilot/*` provider prefix. * - The user's config must explicitly opt in by setting * `agentRuntime.id: "copilot"` at the provider, model, or agent scope * (resolved via `resolveModelRuntimePolicy`). * * Without the explicit opt-in we fall through to the built-in GitHub * Copilot provider, which has shipped support for `github-copilot/*` * models for a long time and must not install the runtime plugin for * users who never asked for it. */ function modelSelectionShouldEnsureCopilotRuntimePlugin(params) { if (parseModelRefProvider(params.model) !== GITHUB_COPILOT_PROVIDER_ID) return false; const modelId = parseModelRefId(params.model); return resolveModelRuntimePolicy({ config: params.config, provider: GITHUB_COPILOT_PROVIDER_ID, modelId }).policy?.id?.trim().toLowerCase() === COPILOT_RUNTIME_ID; } //#endregion //#region src/commands/runtime-plugin-install.ts const CODEX_RUNTIME_PLUGIN_ID = "codex"; const CODEX_RUNTIME_PLUGIN_DESCRIPTOR = { pluginId: CODEX_RUNTIME_PLUGIN_ID, label: "Codex", npmSpec: "@openclaw/codex", warningLabel: "Codex", versionBoundToOpenClaw: true }; const COPILOT_RUNTIME_PLUGIN_DESCRIPTOR = { pluginId: "copilot", label: "GitHub Copilot agent runtime", npmSpec: "@openclaw/copilot", warningLabel: "GitHub Copilot" }; function isInstalledRecordPresentOnDisk(record, env) { const installPath = record?.installPath?.trim(); if (!installPath) return false; return existsSync(path.join(resolveUserPath(installPath, env), "package.json")); } function finalizeRequiredRuntimePluginInstall(descriptor, result) { if (result.installed) return { ok: true, cfg: result.cfg, required: true }; const status = result.status === "installed" ? "failed" : result.status; const runtimeLabel = `${descriptor.label}${/runtime$/iu.test(descriptor.label) ? "" : " runtime"}`; return { ok: false, status, message: `${runtimeLabel} is required but unavailable (status: ${status}). Reason: ${redactToolPayloadText(sanitizeTerminalText(result.reason ?? "")).trim() || "The installer did not return a failure reason."} ${status === "failed" || status === "timed_out" ? `Retry setup after checking npm connectivity and the configured registry; install ${descriptor.npmSpec} first if it is still unavailable.` : `Retry setup and allow ${runtimeLabel} to install, or select a model that does not require it.`}` }; } function adaptRuntimePluginInstallIo(params) { const silent = params.output === "silent"; const runtime = { ...params.runtime, error: () => {}, ...silent ? { log: () => {} } : {} }; return { prompter: silent ? createNonInteractiveLoggingPrompter(runtime, (message) => `Runtime plugin install unexpectedly prompted: ${message}`) : { ...params.prompter, note: async () => {} }, runtime }; } async function ensureRuntimePluginForModelSelection(params) { if (!params.shouldEnsure({ cfg: params.cfg, model: params.model, agentId: params.agentId })) return { ok: true, cfg: params.cfg, required: false }; const io = adaptRuntimePluginInstallIo(params); const onCapabilityConsent = params.output === "silent" ? async () => void 0 : createPluginCapabilityConsentPrompter(params.prompter); if (isInstalledRecordPresentOnDisk((await loadInstalledPluginIndexInstallRecords({ env: process.env }))[params.descriptor.pluginId], process.env)) { const repair = await repairRuntimePluginInstallForModelSelection({ cfg: params.cfg, model: params.model, agentId: params.agentId, env: process.env, descriptor: params.descriptor, shouldEnsure: params.shouldEnsure, onCapabilityConsent, beforePersistentEffect: params.beforePersistentEffect }); for (const change of repair.changes) io.runtime.log?.(change); for (const warning of repair.warnings) io.runtime.log?.(`${params.descriptor.warningLabel} update warning: ${warning}`); const enableResult = await enablePluginWithCapabilityConsent(params.cfg, params.descriptor.pluginId, { workspaceDir: params.workspaceDir, onCapabilityConsent, beforePersistentEffect: params.beforePersistentEffect }); return finalizeRequiredRuntimePluginInstall(params.descriptor, { cfg: enableResult.config, installed: enableResult.enabled, status: enableResult.enabled ? "installed" : "failed", ...enableResult.reason ? { reason: enableResult.reason } : {} }); } const { ensureOnboardingPluginInstalled } = await import("./onboarding-plugin-install-CeahhHcF.js"); const result = await ensureOnboardingPluginInstalled({ cfg: params.cfg, entry: { pluginId: params.descriptor.pluginId, label: params.descriptor.label, install: { npmSpec: params.descriptor.npmSpec, defaultChoice: "npm" }, trustedSourceLinkedOfficialInstall: true, ...params.descriptor.versionBoundToOpenClaw ? { versionBoundToOpenClaw: true } : {} }, prompter: io.prompter, runtime: io.runtime, ...params.workspaceDir !== void 0 ? { workspaceDir: params.workspaceDir } : {}, promptInstall: false, autoConfirmSingleSource: true, onCapabilityConsent, beforePersistentEffect: params.beforePersistentEffect }); return finalizeRequiredRuntimePluginInstall(params.descriptor, { cfg: result.cfg, installed: result.installed, status: result.status, ...result.error ? { reason: result.error } : {} }); } /** Repairs missing install records for runtime plugins required by model selection. */ async function repairRuntimePluginInstallForModelSelection(params) { if (!params.shouldEnsure({ cfg: params.cfg, model: params.model, agentId: params.agentId })) return { required: false, changes: [], warnings: [] }; const { repairMissingPluginInstallsForIds } = await import("./missing-configured-plugin-install-BPD5gWYT.js"); const result = await repairMissingPluginInstallsForIds({ cfg: params.cfg, pluginIds: [params.descriptor.pluginId], ...params.env !== void 0 ? { env: params.env } : {}, ...params.onCapabilityConsent ? { onCapabilityConsent: params.onCapabilityConsent } : {}, beforePersistentEffect: params.beforePersistentEffect }); return { required: true, changes: result.changes, warnings: [...result.warnings, ...result.notices ?? []] }; } function createRuntimePluginModelSelectionHelpers(descriptor, shouldEnsure) { return { ensure: (ensureParams) => ensureRuntimePluginForModelSelection({ ...ensureParams, descriptor, shouldEnsure }), repair: (repairParams) => repairRuntimePluginInstallForModelSelection({ ...repairParams, descriptor, shouldEnsure }) }; } const codexRuntimePluginInstall = createRuntimePluginModelSelectionHelpers(CODEX_RUNTIME_PLUGIN_DESCRIPTOR, ({ cfg, model, agentId }) => modelSelectionShouldEnsureCodexPlugin({ config: cfg, model, agentId })); const copilotRuntimePluginInstall = createRuntimePluginModelSelectionHelpers(COPILOT_RUNTIME_PLUGIN_DESCRIPTOR, ({ cfg, model }) => modelSelectionShouldEnsureCopilotRuntimePlugin({ config: cfg, model })); const ensureCodexRuntimePluginForModelSelection = codexRuntimePluginInstall.ensure; const repairCodexRuntimePluginInstallForModelSelection = codexRuntimePluginInstall.repair; const ensureCopilotRuntimePluginForModelSelection = copilotRuntimePluginInstall.ensure; const repairCopilotRuntimePluginInstallForModelSelection = copilotRuntimePluginInstall.repair; createRuntimePluginModelSelectionHelpers(CODEX_RUNTIME_PLUGIN_DESCRIPTOR, () => true).ensure; async function ensureModelSelectionRuntimePlugins(params) { const codex = await ensureCodexRuntimePluginForModelSelection(params); if (!codex.ok) return { ok: false, message: codex.message }; const copilot = await ensureCopilotRuntimePluginForModelSelection({ ...params, cfg: codex.cfg }); return copilot.ok ? { ok: true, cfg: copilot.cfg, codexInstalled: codex.required } : { ok: false, message: copilot.message }; } //#endregion export { repairCopilotRuntimePluginInstallForModelSelection as a, repairCodexRuntimePluginInstallForModelSelection as i, ensureCodexRuntimePluginForModelSelection as n, ensureModelSelectionRuntimePlugins as r, CODEX_RUNTIME_PLUGIN_ID as t };