UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

343 lines (342 loc) • 16 kB
import { c as normalizeOptionalLowercaseString } from "./string-coerce-1VuiLaaR.mjs"; import { a as writeRuntimeJson, r as defaultRuntime } from "./runtime-DlO3PTAd.mjs"; import { n as sanitizeTerminalText } from "./safe-text-SY_CvCi3.mjs"; import { p as shortenHomePath } from "./utils-DgZn2dLu.mjs"; import { t as formatCliCommand } from "./command-format-DwEdrDKL.mjs"; import { n as normalizeAgentId } from "./agent-id-D1-Q6vR4.mjs"; import "./session-key-C09ow4h0.mjs"; import { n as normalizeAccountId, t as DEFAULT_ACCOUNT_ID } from "./account-id-DbRsdayc.mjs"; import { s as listExplicitConfiguredChannelIdsForConfig } from "./channel-presence-policy-BwRBBDhQ.mjs"; import { n as isChannelVisibleInConfiguredLists } from "./channel-meta-BgTks57p.mjs"; import { t as normalizeAnyChannelId } from "./registry-normalize-BvpWSO2L.mjs"; import { _ as recordAgentDatabaseAdmissions, d as hasAgentDatabaseAdmissions, l as evaluateAgentDatabaseAdmissions } from "./agent-database-admission-dWNS6Rcs.mjs"; import { i as readAgentProvenanceForDisplay, n as listAgentProvenance } from "./agent-provenance-H6O0H8k6.mjs"; import "./channel-plugin-ids-CyAmLWKz.mjs"; import { r as resolveMissingOfficialExternalChannelPluginRepairHints } from "./official-external-plugin-repair-hints-DdqohUAG.mjs"; import "./plugins-9R-VsYQh.mjs"; import { i as listRouteBindings } from "./bindings-Cw_QSeBA.mjs"; import { t as listReadOnlyChannelPluginsForConfig } from "./read-only-BUz6WPkw.mjs"; import { n as resolveChannelAccount } from "./account-resolution-DCHDXWZ0.mjs"; import { i as resolveChannelDefaultAccountId } from "./helpers-Bm4RKejp.mjs"; import { r as hasConfiguredUnavailableCredentialStatus } from "./account-snapshot-fields-e1ulxwox.mjs"; import { i as resolveChannelAccountState, n as projectChannelAccountDisplayState, r as resolveChannelAccountLinked } from "./account-state-CXuFP2J6.mjs"; import { n as buildAgentSummaries } from "./agents.config-CEaxMlw1.mjs"; import { t as describeBinding } from "./agents.binding-format-B08nnBYq.mjs"; import "./agents.bindings-sJhmQ6HM.mjs"; import { t as requireValidConfig } from "./config-validation-BnPsZc0_.mjs"; //#region src/commands/agents.providers.ts function providerAccountKey(provider, accountId) { return `${provider}:${normalizeAccountId(accountId)}`; } function recordProviderAccountStatus(index, entry) { const key = providerAccountKey(entry.provider, entry.accountId); if (!index.has(key) || entry.accountId === normalizeAccountId(entry.accountId)) index.set(key, entry); } function resolveProviderChannelId(params) { const resolved = normalizeAnyChannelId(params.rawChannelId); if (resolved) return resolved; const fallback = normalizeOptionalLowercaseString(params.rawChannelId); return fallback && params.metadataByProvider.has(fallback) ? fallback : null; } function buildProviderSummaryMetadataIndex(cfg) { const metadata = new Map(listReadOnlyChannelPluginsForConfig(cfg, { includeSetupFallbackPlugins: false }).map((plugin) => [plugin.id, { label: plugin.meta.label, defaultAccountId: resolveChannelDefaultAccountId({ plugin, cfg, accountIds: plugin.config.listAccountIds(cfg) }), visibleInConfiguredLists: isChannelVisibleInConfiguredLists(plugin.meta) }])); const missingChannelIds = listExplicitConfiguredChannelIdsForConfig(cfg).filter((channelId) => !metadata.has(channelId)); const missingHints = resolveMissingOfficialExternalChannelPluginRepairHints({ config: cfg, channelIds: missingChannelIds }); for (const hint of missingHints) metadata.set(hint.channelId, { label: hint.label, defaultAccountId: DEFAULT_ACCOUNT_ID, visibleInConfiguredLists: true, repairHint: hint.repairHint }); return metadata; } function isUnresolvedSecretRefResolutionError(error) { return error instanceof Error && typeof error.message === "string" && /unresolved SecretRef/i.test(error.message); } function formatChannelAccountLabel(params) { return `${params.providerLabel ?? params.provider} ${params.name?.trim() ? `${params.accountId} (${params.name.trim()})` : params.accountId}`; } function formatProviderState(entry) { return `${entry.state}${entry.enabled === false && entry.state !== "disabled" ? ", disabled" : ""}`; } async function resolveReadOnlyAccount(params) { if (params.plugin.config.inspectAccount) return await params.plugin.config.inspectAccount(params.cfg, params.accountId); return resolveChannelAccount(params); } async function buildProviderStatusIndex(cfg) { const map = /* @__PURE__ */ new Map(); for (const plugin of listReadOnlyChannelPluginsForConfig(cfg, { includeSetupFallbackPlugins: false })) { const accountIds = plugin.config.listAccountIds(cfg); for (const accountId of accountIds) { let account; try { account = await resolveReadOnlyAccount({ plugin, cfg, accountId }); } catch (error) { if (!isUnresolvedSecretRefResolutionError(error)) throw error; recordProviderAccountStatus(map, { provider: plugin.id, providerLabel: plugin.meta.label, accountId, state: "configured unavailable", configured: true, visibleInConfiguredLists: isChannelVisibleInConfiguredLists(plugin.meta) }); continue; } if (!account) continue; const snapshot = plugin.config.describeAccount?.(account, cfg); const enabled = plugin.config.isEnabled ? plugin.config.isEnabled(account, cfg) : typeof snapshot?.enabled === "boolean" ? snapshot.enabled : account.enabled; const configured = plugin.config.isConfigured ? await plugin.config.isConfigured(account, cfg) : snapshot?.configured; const resolvedEnabled = typeof enabled === "boolean" ? enabled : true; const resolvedConfigured = typeof configured === "boolean" ? configured : true; const inspectedConfigured = account.configured; const configuredIntent = typeof inspectedConfigured === "boolean" ? inspectedConfigured : snapshot?.configured === true; const configuredUnavailable = !resolvedConfigured && configuredIntent && (hasConfiguredUnavailableCredentialStatus(snapshot) || hasConfiguredUnavailableCredentialStatus(account)); const linkState = resolvedConfigured && plugin.config.isLinked ? await plugin.config.isLinked(account, cfg) : void 0; const linked = resolveChannelAccountLinked(linkState, snapshot?.linked); const fallbackState = plugin.status?.resolveAccountState?.({ account, cfg, configured: resolvedConfigured, enabled: resolvedEnabled }); const state = configuredUnavailable ? "configured unavailable" : projectChannelAccountDisplayState(resolveChannelAccountState({ enabled: resolvedEnabled, configured: resolvedConfigured, linked }), fallbackState); const name = snapshot?.name ?? account.name; recordProviderAccountStatus(map, { provider: plugin.id, providerLabel: plugin.meta.label, accountId, name, state, enabled, configured: configuredUnavailable || configured, visibleInConfiguredLists: isChannelVisibleInConfiguredLists(plugin.meta) }); } } return map; } function resolveBindingAccountId(binding) { const accountId = binding.match.accountId?.trim(); return accountId === "*" ? accountId : normalizeAccountId(accountId); } function shouldShowProviderEntry(params) { if ((params.entry.visibleInConfiguredLists ?? params.metadataByProvider.get(params.entry.provider)?.visibleInConfiguredLists) === false) { const providerConfig = params.cfg[params.entry.provider]; return Boolean(params.entry.configured) || Boolean(providerConfig); } return Boolean(params.entry.configured); } function formatProviderEntry(entry) { return `${formatChannelAccountLabel(entry)}: ${formatProviderState(entry)}`; } function formatMissingProviderEntry(params) { const label = formatChannelAccountLabel({ provider: params.provider, providerLabel: params.metadata?.label, accountId: params.accountId }); if (params.metadata?.repairHint) return `${label}: missing plugin - ${params.metadata.repairHint}`; return `${label}: unknown`; } function summarizeBindings(cfg, bindings, metadataByProvider = buildProviderSummaryMetadataIndex(cfg)) { const seen = /* @__PURE__ */ new Map(); for (const binding of bindings) { const channel = resolveProviderChannelId({ rawChannelId: binding.match.channel, metadataByProvider }); if (!channel) continue; const accountId = resolveBindingAccountId(binding); const key = `${channel}:${accountId}`; if (!seen.has(key)) { const label = formatChannelAccountLabel({ provider: channel, providerLabel: metadataByProvider.get(channel)?.label, accountId }); seen.set(key, label); } } return [...seen.values()]; } function listProvidersForAgent(params) { let allProviderEntries; const metadataByProvider = params.providerMetadata ?? buildProviderSummaryMetadataIndex(params.cfg); if (params.bindings.length > 0) { const linesByAccount = /* @__PURE__ */ new Map(); for (const binding of params.bindings) { const channel = resolveProviderChannelId({ rawChannelId: binding.match.channel, metadataByProvider }); if (!channel) continue; const accountId = resolveBindingAccountId(binding); const statuses = accountId === "*" ? (allProviderEntries ??= [...params.providerStatus.values()]).filter((entry) => entry.provider === channel) : [params.providerStatus.get(providerAccountKey(channel, accountId))]; for (const status of statuses.length > 0 ? statuses : [void 0]) linesByAccount.set(status ? providerAccountKey(channel, status.accountId) : `${channel}:${accountId}`, status ? formatProviderEntry(status) : formatMissingProviderEntry({ provider: channel, accountId, metadata: metadataByProvider.get(channel) })); } return [...linesByAccount.values()]; } const providerLines = []; if (params.summaryIsDefault) { const seenProviders = /* @__PURE__ */ new Set(); for (const entry of params.providerStatus.values()) if (shouldShowProviderEntry({ entry, cfg: params.cfg, metadataByProvider })) { providerLines.push(formatProviderEntry(entry)); seenProviders.add(entry.provider); } for (const [provider, metadata] of metadataByProvider.entries()) { if (!metadata.repairHint || seenProviders.has(provider)) continue; providerLines.push(formatMissingProviderEntry({ provider, accountId: metadata.defaultAccountId, metadata })); } } return providerLines; } //#endregion //#region src/commands/agents.commands.list.ts function formatSummaryHeader(summary) { const safe = sanitizeTerminalText; const defaultTag = `${summary.isDefault ? " (default)" : ""}${summary.status === "degraded" ? " (degraded)" : ""}`; return summary.name && summary.name !== summary.id ? `${safe(summary.id)}${defaultTag} (${safe(summary.name)})` : `${safe(summary.id)}${defaultTag}`; } function formatSummary(summary) { const safe = sanitizeTerminalText; const header = formatSummaryHeader(summary); const identityParts = [summary.identityEmoji, summary.identityName].filter((part) => Boolean(part)).map(safe); const identityLine = identityParts.length > 0 ? identityParts.join(" ") : null; const identitySource = summary.identitySource === "identity" ? "IDENTITY.md" : summary.identitySource === "config" ? "config" : null; const lines = [`- ${header}`]; if (summary.admissionRefusal) { lines.push(` Refused: ${safe(summary.admissionRefusal.reason)}`); lines.push(` Repair: ${safe(summary.admissionRefusal.repairHint)}`); } if (identityLine) lines.push(` Identity: ${identityLine}${identitySource ? ` (${identitySource})` : ""}`); lines.push(` Workspace: ${safe(shortenHomePath(summary.workspace))}`); lines.push(` Agent dir: ${safe(shortenHomePath(summary.agentDir))}`); if (summary.model) lines.push(` Model: ${safe(summary.model)}`); lines.push(` Routing rules: ${summary.bindings}`); if (summary.routes?.length) lines.push(` Routing: ${summary.routes.map(safe).join(", ")}`); for (const [heading, entries] of [[" Providers:", summary.providers], [" Routing rules:", summary.bindingDetails]]) if (entries?.length) { lines.push(heading); for (const entry of entries) lines.push(` - ${safe(entry)}`); } return lines.join("\n"); } function formatAgentTree(summaries, provenance) { const summaryById = new Map(summaries.map((summary) => [summary.id, summary])); const provenanceById = new Map(provenance.map((record) => [record.agentId, record])); const childrenById = /* @__PURE__ */ new Map(); const roots = []; for (const summary of summaries) { const creatorAgentId = provenanceById.get(summary.id)?.creatorAgentId; if (creatorAgentId && creatorAgentId !== summary.id && summaryById.has(creatorAgentId)) { const children = childrenById.get(creatorAgentId) ?? []; children.push(summary); childrenById.set(creatorAgentId, children); } else roots.push(summary); } const lines = []; const visited = /* @__PURE__ */ new Set(); const append = (summary, depth) => { if (visited.has(summary.id)) return; visited.add(summary.id); lines.push(`${" ".repeat(depth)}- ${formatSummaryHeader(summary)}`); for (const child of childrenById.get(summary.id) ?? []) append(child, depth + 1); }; roots.forEach((summary) => append(summary, 0)); summaries.forEach((summary) => append(summary, 0)); return lines; } async function agentsListCommand(opts, runtime = defaultRuntime) { const cfg = await requireValidConfig(runtime, { adoptPluginMetadata: true }); if (!cfg) return; if (!hasAgentDatabaseAdmissions()) recordAgentDatabaseAdmissions(await evaluateAgentDatabaseAdmissions(cfg)); const summaries = await buildAgentSummaries(cfg); const provenance = opts.tree ? await listAgentProvenance() : []; if (opts.json) { const records = await readAgentProvenanceForDisplay(summaries.map((summary) => summary.id)); const recordsById = new Map(records.map((record) => [record.agentId, record])); for (const summary of summaries) { const record = recordsById.get(summary.id); if (record) { summary.createdVia = record.createdVia; summary.creatorAgentId = record.creatorAgentId; summary.createdAt = record.createdAtMs; } } } const bindingMap = /* @__PURE__ */ new Map(); for (const binding of listRouteBindings(cfg)) { const agentId = normalizeAgentId(binding.agentId); const list = bindingMap.get(agentId) ?? []; list.push(binding); bindingMap.set(agentId, list); } if (opts.bindings) for (const summary of summaries) { const bindings = bindingMap.get(summary.id) ?? []; if (bindings.length > 0) summary.bindingDetails = bindings.map((binding) => describeBinding(binding)); } const includeProviderDetails = !opts.json && !opts.tree || opts.bindings === true; const providerStatus = includeProviderDetails ? await buildProviderStatusIndex(cfg) : null; const providerMetadata = includeProviderDetails ? buildProviderSummaryMetadataIndex(cfg) : null; for (const summary of summaries) { const bindings = bindingMap.get(summary.id) ?? []; if (includeProviderDetails && providerStatus && providerMetadata) { const routes = summarizeBindings(cfg, bindings, providerMetadata); if (routes.length > 0) summary.routes = routes; else if (summary.isDefault) summary.routes = ["default (no explicit rules)"]; const providerLines = listProvidersForAgent({ summaryIsDefault: summary.isDefault, cfg, bindings, providerStatus, providerMetadata }); if (providerLines.length > 0) summary.providers = providerLines; } } if (opts.json) { writeRuntimeJson(runtime, summaries); return; } if (opts.tree) { runtime.log(["Agents:", ...formatAgentTree(summaries, provenance)].join("\n")); return; } const lines = ["Agents:", ...summaries.map(formatSummary)]; lines.push("Routing rules map channel/account/peer to an agent. Use --bindings for full rules."); lines.push(`Channel status reflects local config/creds. For live health: ${formatCliCommand("openclaw channels status --probe")}.`); runtime.log(lines.join("\n")); } //#endregion export { agentsListCommand };