UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

242 lines (241 loc) 11.4 kB
import { c as normalizeOptionalLowercaseString } from "./string-coerce-CIXf7egm.js"; import { d as normalizeStringEntries, f as normalizeStringEntriesLower } from "./string-normalization-DsCfAx8q.js"; import "./session-key-BnWWjqNc.js"; import { n as normalizeAccountId } from "./account-id-CETVCrTz.js"; import { t as normalizeAnyChannelId } from "./registry-normalize-CY8V_nbx.js"; import "./registry-COqNvmCg.js"; import { t as resolveAccountEntry } from "./account-lookup-CvFhSs3G.js"; import "./message-channel-constants-2zSoJXQC.js"; import { t as formatSkillsForPromptBounded } from "./skill-prompt-limits-AF9diYak.js"; import { g as resolveChannelPromptCapabilities } from "./openclaw-tools-CNOZOjlX.js"; import { r as loadSkillLibrarySelection } from "./selection-NYtFFG08.js"; import { a as loadWorkspaceSkills, o as normalizeWorkspaceSkillRoots, r as loadMergedWorkspaceSkills } from "./workspace-skill-loader-_a5Sci8B.js"; import { t as resolveSkillRuntimeConfig } from "./runtime-config-C9Ktnk7G.js"; import { c as resolveThreadBindingSpawnPolicy, u as supportsAutomaticThreadBindingSpawn } from "./thread-bindings-policy-BzrpAQe3.js"; import path from "node:path"; //#region src/agents/embedded-agent-runner/sandbox-skills.ts /** * Sandbox skill runtime input selection. * * Sandboxed runs must build prompt-facing skill entries from readable in-sandbox * copies instead of reusing host-path snapshots. */ const MATERIALIZED_SKILLS_WORKSPACE_CONTAINER_PARTS = [".openclaw", "sandbox-skills"]; function containerJoin(root, ...parts) { const normalizedRoot = root.replace(/\\/g, "/").replace(/\/+$/, "") || "/"; const suffix = parts.map((part) => part.replace(/^\/+|\/+$/g, "")).filter(Boolean).join("/"); return suffix ? `${normalizedRoot}/${suffix}` : normalizedRoot; } function pathEscapesRoot(relativePath) { return relativePath === ".." || relativePath.startsWith(`..${path.sep}`) || path.isAbsolute(relativePath); } function mapPathFromWorkspaceToContainer(params) { if (!params.filePath || !path.isAbsolute(params.filePath)) return params.filePath; const relativePath = path.relative(path.resolve(params.sourceWorkspaceDir), path.resolve(params.filePath)); if (pathEscapesRoot(relativePath)) return params.filePath; if (!relativePath) return params.targetWorkspaceDir.replace(/\\/g, "/"); return containerJoin(params.targetWorkspaceDir, ...relativePath.split(path.sep).filter(Boolean)); } function mapSandboxSkillEntriesForPrompt(params) { if (!params.entries || params.skillsWorkspaceDir === params.skillsPromptWorkspaceDir) return params.entries; return params.entries.map((entry) => { const filePath = mapPathFromWorkspaceToContainer({ filePath: entry.skill.filePath, sourceWorkspaceDir: params.skillsWorkspaceDir, targetWorkspaceDir: params.skillsPromptWorkspaceDir }) ?? entry.skill.filePath; const baseDir = mapPathFromWorkspaceToContainer({ filePath: entry.skill.baseDir, sourceWorkspaceDir: params.skillsWorkspaceDir, targetWorkspaceDir: params.skillsPromptWorkspaceDir }) ?? entry.skill.baseDir; const sourceInfoPath = mapPathFromWorkspaceToContainer({ filePath: entry.skill.sourceInfo.path, sourceWorkspaceDir: params.skillsWorkspaceDir, targetWorkspaceDir: params.skillsPromptWorkspaceDir }) ?? entry.skill.sourceInfo.path; const sourceInfoBaseDir = mapPathFromWorkspaceToContainer({ filePath: entry.skill.sourceInfo.baseDir, sourceWorkspaceDir: params.skillsWorkspaceDir, targetWorkspaceDir: params.skillsPromptWorkspaceDir }); return { ...entry, skill: { ...entry.skill, filePath, baseDir, sourceInfo: { ...entry.skill.sourceInfo, path: sourceInfoPath, ...sourceInfoBaseDir === void 0 ? {} : { baseDir: sourceInfoBaseDir } } } }; }); } function createSandboxPromptEntryLoader(params) { return () => mapSandboxSkillEntriesForPrompt({ entries: params.loadEntries(), skillsWorkspaceDir: params.skillsWorkspaceDir, skillsPromptWorkspaceDir: params.skillsPromptWorkspaceDir }) ?? []; } function mapSandboxSkillUsagePaths(params) { if (!params.paths || params.skillsWorkspaceDir === params.skillsPromptWorkspaceDir) return params.paths; return params.paths.map((entry) => ({ ...entry, readPath: mapPathFromWorkspaceToContainer({ filePath: entry.readPath, sourceWorkspaceDir: params.skillsWorkspaceDir, targetWorkspaceDir: params.skillsPromptWorkspaceDir }) ?? entry.readPath })); } function resolveSandboxSkillRuntimeInputs(params) { if (params.sandbox?.enabled === true) { const skillsWorkspaceDir = params.sandbox.skillsWorkspaceDir ?? params.skillsAnchorWorkspace; const skillsPromptWorkspaceDir = params.sandbox.workspaceAccess === "rw" && params.sandbox.skillsWorkspaceDir && params.sandbox.containerWorkdir ? containerJoin(params.sandbox.containerWorkdir, ...MATERIALIZED_SKILLS_WORKSPACE_CONTAINER_PARTS) : params.sandbox.containerWorkdir ?? skillsWorkspaceDir; let selectedSnapshot; if (params.skillsSnapshot?.librarySelections?.length) { const usage = mapSandboxSkillUsagePaths({ paths: params.sandbox.skillUsagePaths, skillsWorkspaceDir, skillsPromptWorkspaceDir }); const resolvedSkills = params.skillsSnapshot.resolvedSkills?.map((skill) => { const materialized = usage?.find((item) => item.skillName === skill.name); if (!materialized) throw new Error(`Selected skill ${skill.name} was not delivered to the sandbox.`); return { ...skill, filePath: materialized.readPath, baseDir: path.posix.dirname(materialized.readPath) }; }); if (!resolvedSkills) throw new Error("Selected skill snapshot must be hydrated before sandbox delivery."); selectedSnapshot = { ...params.skillsSnapshot, resolvedSkills, prompt: formatSkillsForPromptBounded({ skills: resolvedSkills, preserveOrder: true }) }; } return { ...params.sandbox.skillsEligibility ? { skillsEligibility: params.sandbox.skillsEligibility } : {}, skillsPromptWorkspaceDir, skillsSnapshot: selectedSnapshot, skillsWorkspaceDir, workspaceOnly: true }; } return { skillsPromptWorkspaceDir: params.skillsAnchorWorkspace, skillsSnapshot: params.skillsSnapshot, skillsWorkspaceDir: params.skillsAnchorWorkspace, workspaceOnly: false }; } /** Rewrites host-generated explicit skill references to the prepared runtime's exact copies. */ function remapSkillReferencePaths(text, paths) { return (paths ?? []).reduce((result, item) => result.replaceAll(item.skillFile, item.readPath), text); } //#endregion //#region src/skills/runtime/embedded-run-entries.ts /** Resolves skill entries embedded into a run payload into runtime-visible entries. */ function resolveEmbeddedRunSkillEntries(params) { const shouldLoadSkillEntries = !params.skillsSnapshot || !params.skillsSnapshot.resolvedSkills; const config = resolveSkillRuntimeConfig(params.config); const skillRoots = params.skillsSnapshot?.skillRoots ?? normalizeWorkspaceSkillRoots({ agentWorkspaceDir: params.workspaceDir, ...params.executionSkillsDir ? { executionSkillsDir: params.executionSkillsDir } : {} }); let cachedSkillEntries; const loadSkillEntries = () => { if (cachedSkillEntries) return cachedSkillEntries; const options = { config, agentId: params.agentId, ...params.eligibility ? { eligibility: params.eligibility } : {}, ...params.skillsSnapshot?.skillFilter ? { skillFilter: params.skillsSnapshot.skillFilter } : {}, ...params.skillsSnapshot?.skillOverrides ? { skillOverrides: params.skillsSnapshot.skillOverrides } : {}, ...params.workspaceOnly === true ? { workspaceOnly: true } : {} }; cachedSkillEntries = skillRoots.executionSkillsDir ? loadMergedWorkspaceSkills({ ...skillRoots, ...options }) : loadWorkspaceSkills(params.workspaceDir, options); if (params.skillsSnapshot?.librarySelections?.length && params.workspaceOnly !== true) cachedSkillEntries.push(...loadSkillLibrarySelection(params.skillsSnapshot.librarySelections)); return cachedSkillEntries; }; return { shouldLoadSkillEntries, skillEntries: shouldLoadSkillEntries ? loadSkillEntries() : [], loadSkillEntries, preserveEntryOrder: skillRoots.executionSkillsDir !== void 0 }; } //#endregion //#region src/config/channel-capabilities.ts const isStringArray = (value) => Array.isArray(value) && value.every((entry) => typeof entry === "string"); function normalizeCapabilities(capabilities) { if (!isStringArray(capabilities)) return; const normalized = normalizeStringEntries(capabilities); return normalized.length > 0 ? normalized : void 0; } /** Resolves normalized string capabilities for a channel/account config pair. */ function resolveChannelCapabilities(params) { const cfg = params.cfg; const channel = normalizeAnyChannelId(params.channel); if (!cfg || !channel) return; const channelConfig = cfg.channels?.[channel]; if (!channelConfig) return; const normalizedAccountId = normalizeAccountId(params.accountId); const accounts = channelConfig.accounts; return normalizeCapabilities((accounts && typeof accounts === "object" ? resolveAccountEntry(accounts, normalizedAccountId) : void 0)?.capabilities) ?? normalizeCapabilities(channelConfig.capabilities); } //#endregion //#region src/agents/runtime-capabilities.ts /** * Runtime channel capability collector. * * Agent startup uses this to merge configured channel capabilities with prompt * tools and thread-bound spawn features that depend on channel policy. */ const THREAD_BOUND_SUBAGENT_SPAWN_CAPABILITY = "threadbound-subagent-spawn"; const THREAD_BOUND_ACP_SPAWN_CAPABILITY = "threadbound-acp-spawn"; function mergeRuntimeCapabilities(base, additions = []) { const merged = [...base ?? []]; const seen = new Set(normalizeStringEntriesLower(merged)); for (const capability of additions) { const normalizedCapability = normalizeOptionalLowercaseString(capability); if (!normalizedCapability || seen.has(normalizedCapability)) continue; seen.add(normalizedCapability); merged.push(capability); } return merged.length > 0 ? merged : void 0; } /** Collects the effective runtime capabilities for a channel/account pair. */ function collectRuntimeChannelCapabilities(params) { if (!params.channel) return; const internalChannelCapabilities = params.channel === "webchat" ? ["markdownDetails"] : []; const threadSpawnCapabilities = []; if (params.cfg && supportsAutomaticThreadBindingSpawn(params.channel)) for (const [kind, capability] of [["subagent", THREAD_BOUND_SUBAGENT_SPAWN_CAPABILITY], ["acp", THREAD_BOUND_ACP_SPAWN_CAPABILITY]]) { const policy = resolveThreadBindingSpawnPolicy({ cfg: params.cfg, channel: params.channel, accountId: params.accountId ?? void 0, kind }); if (policy.enabled && policy.spawnEnabled) threadSpawnCapabilities.push(capability); } const channelPromptCapabilities = params.cfg ? resolveChannelPromptCapabilities(params) : []; return mergeRuntimeCapabilities(resolveChannelCapabilities(params), [ ...channelPromptCapabilities, ...internalChannelCapabilities, ...threadSpawnCapabilities ]); } //#endregion export { mapSandboxSkillUsagePaths as a, mapSandboxSkillEntriesForPrompt as i, resolveEmbeddedRunSkillEntries as n, remapSkillReferencePaths as o, createSandboxPromptEntryLoader as r, resolveSandboxSkillRuntimeInputs as s, collectRuntimeChannelCapabilities as t };