Fix built startup import cycles

This commit is contained in:
Tak Hoffman
2026-03-16 23:51:03 -05:00
parent e29c91cfe1
commit 09f52c4dae
14 changed files with 52 additions and 38 deletions

View File

@@ -1,10 +1,10 @@
import { normalizeAnyChannelId } from "../channels/normalize-any.js";
import { getChannelPlugin, listChannelPlugins } from "../channels/plugins/index.js";
import type {
ChannelAgentTool,
ChannelMessageActionName,
ChannelPlugin,
} from "../channels/plugins/types.js";
import { normalizeAnyChannelId } from "../channels/registry.js";
import type { OpenClawConfig } from "../config/config.js";
import { defaultRuntime } from "../runtime.js";

View File

@@ -22,7 +22,7 @@ import {
resolveTotalTokens,
truncateLine,
} from "../shared/subagents-format.js";
import { INTERNAL_MESSAGE_CHANNEL } from "../utils/message-channel.js";
import { INTERNAL_MESSAGE_CHANNEL } from "../utils/internal-message-channel.js";
import { AGENT_LANE_SUBAGENT } from "./lanes.js";
import { abortEmbeddedPiRun } from "./pi-embedded.js";
import { resolveStoredSubagentCapabilities } from "./subagent-capabilities.js";

View File

@@ -1,6 +1,6 @@
import crypto from "node:crypto";
import { callGateway } from "../../gateway/call.js";
import { INTERNAL_MESSAGE_CHANNEL } from "../../utils/message-channel.js";
import { INTERNAL_MESSAGE_CHANNEL } from "../../utils/internal-message-channel.js";
import { AGENT_LANE_NESTED } from "../lanes.js";
import { extractAssistantText, stripToolMessages } from "./sessions-helpers.js";

View File

@@ -8,7 +8,7 @@ import { findFenceSpanAt, isSafeFenceBreak, parseFenceSpans } from "../markdown/
import { resolveAccountEntry } from "../routing/account-lookup.js";
import { normalizeAccountId } from "../routing/session-key.js";
import { chunkTextByBreakResolver } from "../shared/text-chunking.js";
import { INTERNAL_MESSAGE_CHANNEL } from "../utils/message-channel.js";
import { INTERNAL_MESSAGE_CHANNEL } from "../utils/internal-message-channel.js";
export type TextChunkProvider = ChannelId | typeof INTERNAL_MESSAGE_CHANNEL;

View File

@@ -1,6 +1,6 @@
import { normalizeAnyChannelId } from "../channels/normalize-any.js";
import { getChannelPlugin, listChannelPlugins } from "../channels/plugins/index.js";
import type { ChannelId, ChannelPlugin } from "../channels/plugins/types.js";
import { normalizeAnyChannelId } from "../channels/registry.js";
import type { OpenClawConfig } from "../config/config.js";
import { normalizeStringEntries } from "../shared/string-normalization.js";
import {

View File

@@ -1,8 +1,9 @@
import { resolveRunModelFallbacksOverride } from "../../agents/agent-scope.js";
import type { NormalizedUsage } from "../../agents/usage.js";
import { normalizeAnyChannelId } from "../../channels/normalize-any.js";
import { getChannelPlugin } from "../../channels/plugins/index.js";
import type { ChannelId, ChannelThreadingToolContext } from "../../channels/plugins/types.js";
import { normalizeAnyChannelId, normalizeChannelId } from "../../channels/registry.js";
import { normalizeChannelId } from "../../channels/registry.js";
import type { OpenClawConfig } from "../../config/config.js";
import { isReasoningTagProvider } from "../../utils/provider-utils.js";
import { estimateUsageCost, formatTokenCount, formatUsd } from "../../utils/usage-format.js";

View File

@@ -1,6 +1,6 @@
import { CHAT_CHANNEL_ORDER } from "../../channels/registry.js";
import { normalizeAtHashSlug } from "../../shared/string-normalization.js";
import { INTERNAL_MESSAGE_CHANNEL } from "../../utils/message-channel.js";
import { INTERNAL_MESSAGE_CHANNEL } from "../../utils/internal-message-channel.js";
export type ExplicitElevatedAllowField = "id" | "from" | "e164" | "name" | "username" | "tag";

View File

@@ -1,4 +1,4 @@
import { INTERNAL_MESSAGE_CHANNEL } from "../../utils/message-channel.js";
import { INTERNAL_MESSAGE_CHANNEL } from "../../utils/internal-message-channel.js";
import type { TypingPolicy } from "../types.js";
export type ResolveRunTypingPolicyParams = {

View File

@@ -0,0 +1,31 @@
import { requireActivePluginRegistry } from "../plugins/runtime.js";
import type { ChannelId } from "./plugins/types.js";
const normalizeChannelKey = (raw?: string | null): string | undefined => {
const normalized = raw?.trim().toLowerCase();
return normalized || undefined;
};
// Normalizes registered channel plugins (bundled or external).
//
// Keep this light at the call site, but note that this helper depends on the
// active plugin runtime and should not be imported from startup-critical
// constants modules.
export function normalizeAnyChannelId(raw?: string | null): ChannelId | null {
const key = normalizeChannelKey(raw);
if (!key) {
return null;
}
const registry = requireActivePluginRegistry();
const hit = registry.channels.find((entry) => {
const id = String(entry.plugin.id ?? "")
.trim()
.toLowerCase();
if (id && id === key) {
return true;
}
return (entry.plugin.meta.aliases ?? []).some((alias) => alias.trim().toLowerCase() === key);
});
return hit?.plugin.id ?? null;
}

View File

@@ -2,7 +2,8 @@ import {
getActivePluginRegistryVersion,
requireActivePluginRegistry,
} from "../../plugins/runtime.js";
import { CHAT_CHANNEL_ORDER, type ChatChannelId, normalizeAnyChannelId } from "../registry.js";
import { normalizeAnyChannelId } from "../normalize-any.js";
import { CHAT_CHANNEL_ORDER, type ChatChannelId } from "../registry.js";
import type { ChannelId, ChannelPlugin } from "./types.js";
function dedupeChannels(channels: ChannelPlugin[]): ChannelPlugin[] {

View File

@@ -1,7 +1,5 @@
import { requireActivePluginRegistry } from "../plugins/runtime.js";
import { CHANNEL_IDS, CHAT_CHANNEL_ORDER, type ChatChannelId } from "./ids.js";
import type { ChannelMeta } from "./plugins/types.js";
import type { ChannelId } from "./plugins/types.js";
export { CHANNEL_IDS, CHAT_CHANNEL_ORDER } from "./ids.js";
export type { ChatChannelId } from "./ids.js";
@@ -144,29 +142,6 @@ export function normalizeChannelId(raw?: string | null): ChatChannelId | null {
return normalizeChatChannelId(raw);
}
// Normalizes registered channel plugins (bundled or external).
//
// Keep this light: we do not import channel plugins here (those are "heavy" and can pull in
// monitors, web login, etc). The plugin registry must be initialized first.
export function normalizeAnyChannelId(raw?: string | null): ChannelId | null {
const key = normalizeChannelKey(raw);
if (!key) {
return null;
}
const registry = requireActivePluginRegistry();
const hit = registry.channels.find((entry) => {
const id = String(entry.plugin.id ?? "")
.trim()
.toLowerCase();
if (id && id === key) {
return true;
}
return (entry.plugin.meta.aliases ?? []).some((alias) => alias.trim().toLowerCase() === key);
});
return hit?.plugin.id ?? null;
}
export function formatChannelPrimerLine(meta: ChatChannelMeta): string {
return `${meta.label}: ${meta.blurb}`;
}

View File

@@ -3,7 +3,7 @@ import {
resolveSandboxConfigForAgent,
resolveSandboxToolPolicyForAgent,
} from "../agents/sandbox.js";
import { normalizeAnyChannelId } from "../channels/registry.js";
import { normalizeAnyChannelId } from "../channels/normalize-any.js";
import type { OpenClawConfig } from "../config/config.js";
import { loadConfig } from "../config/config.js";
import {
@@ -22,7 +22,7 @@ import {
import type { RuntimeEnv } from "../runtime.js";
import { formatDocsLink } from "../terminal/links.js";
import { colorize, isRich, theme } from "../terminal/theme.js";
import { INTERNAL_MESSAGE_CHANNEL } from "../utils/message-channel.js";
import { INTERNAL_MESSAGE_CHANNEL } from "../utils/internal-message-channel.js";
type SandboxExplainOptions = {
session?: string;

View File

@@ -0,0 +1,2 @@
export const INTERNAL_MESSAGE_CHANNEL = "webchat" as const;
export type InternalMessageChannel = typeof INTERNAL_MESSAGE_CHANNEL;

View File

@@ -13,9 +13,13 @@ import {
normalizeGatewayClientName,
} from "../gateway/protocol/client-info.js";
import { getActivePluginRegistry } from "../plugins/runtime.js";
import {
INTERNAL_MESSAGE_CHANNEL,
type InternalMessageChannel,
} from "./internal-message-channel.js";
export const INTERNAL_MESSAGE_CHANNEL = "webchat" as const;
export type InternalMessageChannel = typeof INTERNAL_MESSAGE_CHANNEL;
export { INTERNAL_MESSAGE_CHANNEL } from "./internal-message-channel.js";
export type { InternalMessageChannel } from "./internal-message-channel.js";
const MARKDOWN_CAPABLE_CHANNELS = new Set<string>([
"slack",