fix(ci): repair plugin boundary and bootstrap regressions

This commit is contained in:
Peter Steinberger 2026-04-04 12:57:28 +01:00
parent a5836343df
commit dd771f1dc6
No known key found for this signature in database
8 changed files with 103 additions and 40 deletions

View File

@ -44,18 +44,19 @@ function createGuardrailWrapStreamFn(
};
}
const PROVIDER_ID = "amazon-bedrock";
const CLAUDE_46_MODEL_RE = /claude-(?:opus|sonnet)-4(?:\.|-)6(?:$|[-.])/i;
const ANTHROPIC_BY_MODEL_REPLAY_HOOKS = buildProviderReplayFamilyHooks({
family: "anthropic-by-model",
});
const BEDROCK_CONTEXT_OVERFLOW_PATTERNS = [
/ValidationException.*(?:input is too long|max input token|input token.*exceed)/i,
/ValidationException.*(?:exceeds? the (?:maximum|max) (?:number of )?(?:input )?tokens)/i,
/ModelStreamErrorException.*(?:Input is too long|too many input tokens)/i,
] as const;
export async function registerAmazonBedrockPlugin(api: OpenClawPluginApi): Promise<void> {
// Keep registration-local constants inside the function so partial module
// initialization during test bootstrap cannot trip TDZ reads.
const providerId = "amazon-bedrock";
const claude46ModelRe = /claude-(?:opus|sonnet)-4(?:\.|-)6(?:$|[-.])/i;
const anthropicByModelReplayHooks = buildProviderReplayFamilyHooks({
family: "anthropic-by-model",
});
const bedrockContextOverflowPatterns = [
/ValidationException.*(?:input is too long|max input token|input token.*exceed)/i,
/ValidationException.*(?:exceeds? the (?:maximum|max) (?:number of )?(?:input )?tokens)/i,
/ModelStreamErrorException.*(?:Input is too long|too many input tokens)/i,
] as const;
const guardrail = (api.pluginConfig as Record<string, unknown> | undefined)?.guardrail as
| GuardrailConfig
| undefined;
@ -69,7 +70,7 @@ export async function registerAmazonBedrockPlugin(api: OpenClawPluginApi): Promi
: baseWrapStreamFn;
api.registerProvider({
id: PROVIDER_ID,
id: providerId,
label: "Amazon Bedrock",
docsPath: "/providers/models",
auth: [],
@ -85,17 +86,17 @@ export async function registerAmazonBedrockPlugin(api: OpenClawPluginApi): Promi
}
return {
provider: mergeImplicitBedrockProvider({
existing: ctx.config.models?.providers?.[PROVIDER_ID],
existing: ctx.config.models?.providers?.[providerId],
implicit,
}),
};
},
},
resolveConfigApiKey: ({ env }) => resolveBedrockConfigApiKey(env),
...ANTHROPIC_BY_MODEL_REPLAY_HOOKS,
...anthropicByModelReplayHooks,
wrapStreamFn,
matchesContextOverflowError: ({ errorMessage }) =>
BEDROCK_CONTEXT_OVERFLOW_PATTERNS.some((pattern) => pattern.test(errorMessage)),
bedrockContextOverflowPatterns.some((pattern) => pattern.test(errorMessage)),
classifyFailoverReason: ({ errorMessage }) => {
if (/ThrottlingException|Too many concurrent requests/i.test(errorMessage)) {
return "rate_limit";
@ -106,6 +107,6 @@ export async function registerAmazonBedrockPlugin(api: OpenClawPluginApi): Promi
return undefined;
},
resolveDefaultThinkingLevel: ({ modelId }) =>
CLAUDE_46_MODEL_RE.test(modelId.trim()) ? "adaptive" : undefined,
claude46ModelRe.test(modelId.trim()) ? "adaptive" : undefined,
});
}

View File

@ -6,7 +6,6 @@ import type {
ProviderRuntimeModel,
} from "openclaw/plugin-sdk/plugin-entry";
import {
CLAUDE_CLI_PROFILE_ID,
applyAuthProfileConfig,
ensureApiKeyFromOptionEnvOrPrompt,
listProfilesForProvider,
@ -16,16 +15,13 @@ import {
type ProviderAuthResult,
validateApiKeyInput,
} from "openclaw/plugin-sdk/provider-auth";
import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth-api-key";
import { cloneFirstTemplateModel } from "openclaw/plugin-sdk/provider-model-shared";
import { fetchClaudeUsage } from "openclaw/plugin-sdk/provider-usage";
import { buildAnthropicCliBackend } from "./cli-backend.js";
import { buildAnthropicCliMigrationResult, hasClaudeCliAuth } from "./cli-migration.js";
import {
applyAnthropicConfigDefaults,
normalizeAnthropicProviderConfig,
} from "./config-defaults.js";
import { anthropicMediaUnderstandingProvider } from "./media-understanding-provider.js";
import { buildAnthropicReplayPolicy } from "./replay-policy.js";
import {
wrapAnthropicProviderStream,
@ -207,18 +203,61 @@ async function runAnthropicCliMigrationNonInteractive(ctx: {
}
export async function registerAnthropicPlugin(api: OpenClawPluginApi): Promise<void> {
// Be defensive against partially initialized module graphs during test/runtime bootstrap.
const cliBackend =
typeof buildAnthropicCliBackend === "function" ? buildAnthropicCliBackend() : undefined;
if (cliBackend) {
api.registerCliBackend(cliBackend);
const claudeCliProfileId = "anthropic:claude-cli";
const providerId = "anthropic";
const defaultAnthropicModel = "anthropic/claude-sonnet-4-6";
const anthropicOauthAllowlist = [
"anthropic/claude-sonnet-4-6",
"anthropic/claude-opus-4-6",
"anthropic/claude-opus-4-5",
"anthropic/claude-sonnet-4-5",
"anthropic/claude-haiku-4-5",
] as const;
let createApiKeyAuthMethod:
| (typeof import("openclaw/plugin-sdk/provider-auth-api-key"))["createProviderApiKeyAuthMethod"]
| undefined;
let mediaUnderstandingProvider:
| (typeof import("./media-understanding-provider.js"))["anthropicMediaUnderstandingProvider"]
| undefined;
// Avoid touching a partially initialized static binding during cyclic bootstrap.
try {
const cliBackendModule = await import("./cli-backend.js");
const cliBackend =
typeof cliBackendModule.buildAnthropicCliBackend === "function"
? cliBackendModule.buildAnthropicCliBackend()
: undefined;
if (cliBackend) {
api.registerCliBackend(cliBackend);
}
} catch {
// Best-effort during test bootstrap; provider registration still proceeds.
}
try {
const providerApiKeyAuthModule = await import("openclaw/plugin-sdk/provider-auth-api-key");
createApiKeyAuthMethod =
typeof providerApiKeyAuthModule.createProviderApiKeyAuthMethod === "function"
? providerApiKeyAuthModule.createProviderApiKeyAuthMethod
: undefined;
} catch {
createApiKeyAuthMethod = undefined;
}
if (!createApiKeyAuthMethod) {
return;
}
try {
const mediaUnderstandingModule = await import("./media-understanding-provider.js");
mediaUnderstandingProvider =
mediaUnderstandingModule.anthropicMediaUnderstandingProvider ?? undefined;
} catch {
mediaUnderstandingProvider = undefined;
}
api.registerProvider({
id: PROVIDER_ID,
id: providerId,
label: "Anthropic",
docsPath: "/providers/models",
envVars: ["ANTHROPIC_OAUTH_TOKEN", "ANTHROPIC_API_KEY"],
deprecatedProfileIds: [CLAUDE_CLI_PROFILE_ID],
deprecatedProfileIds: [claudeCliProfileId],
oauthProfileIdRepairs: [
{
legacyProfileId: "anthropic:default",
@ -240,7 +279,7 @@ export async function registerAnthropicPlugin(api: OpenClawPluginApi): Promise<v
groupLabel: "Anthropic",
groupHint: "Claude CLI + API key",
modelAllowlist: {
allowedKeys: [...ANTHROPIC_OAUTH_ALLOWLIST].map((model) =>
allowedKeys: [...anthropicOauthAllowlist].map((model) =>
model.replace(/^anthropic\//, "claude-cli/"),
),
initialSelections: ["claude-cli/claude-sonnet-4-6"],
@ -254,8 +293,8 @@ export async function registerAnthropicPlugin(api: OpenClawPluginApi): Promise<v
runtime: ctx.runtime,
}),
},
createProviderApiKeyAuthMethod({
providerId: PROVIDER_ID,
createApiKeyAuthMethod({
providerId,
methodId: "api-key",
label: "Anthropic API key",
hint: "Direct Anthropic API key",
@ -263,7 +302,7 @@ export async function registerAnthropicPlugin(api: OpenClawPluginApi): Promise<v
flagName: "--anthropic-api-key",
envVar: "ANTHROPIC_API_KEY",
promptMessage: "Enter Anthropic API key",
defaultModel: DEFAULT_ANTHROPIC_MODEL,
defaultModel: defaultAnthropicModel,
expectedProviders: ["anthropic"],
wizard: {
choiceId: "apiKey",
@ -300,5 +339,7 @@ export async function registerAnthropicPlugin(api: OpenClawPluginApi): Promise<v
profileId: ctx.profileId,
}),
});
api.registerMediaUnderstandingProvider(anthropicMediaUnderstandingProvider);
if (mediaUnderstandingProvider) {
api.registerMediaUnderstandingProvider(mediaUnderstandingProvider);
}
}

View File

@ -1 +1,6 @@
export type { OpenClawConfig } from "openclaw/plugin-sdk/memory-core";
export type {
MemoryEmbeddingProbeResult,
MemoryProviderStatus,
MemorySyncProgressUpdate,
} from "openclaw/plugin-sdk/memory-core-host-engine-storage";

View File

@ -1,8 +1,18 @@
export { getMemorySearchManager, MemoryIndexManager } from "./src/memory/index.js";
export { memoryRuntime } from "./src/runtime-provider.js";
export {
DEFAULT_LOCAL_MODEL,
getBuiltinMemoryEmbeddingProviderDoctorMetadata,
listBuiltinAutoSelectMemoryEmbeddingProviderDoctorMetadata,
} from "./src/memory/provider-adapters.js";
export {
resolveMemoryCacheSummary,
resolveMemoryFtsState,
resolveMemoryVectorState,
type Tone,
} from "openclaw/plugin-sdk/memory-core-host-status";
export { checkQmdBinaryAvailability } from "openclaw/plugin-sdk/memory-core-host-engine-qmd";
export { hasConfiguredMemorySecretInput } from "openclaw/plugin-sdk/memory-core-host-secret";
export {
auditShortTermPromotionArtifacts,
repairShortTermPromotionArtifacts,

View File

@ -1 +1,5 @@
export { TelegramChannelConfigSchema } from "./src/config-schema.js";
export {
normalizeTelegramCommandDescription,
normalizeTelegramCommandName,
resolveTelegramCustomCommands,
} from "./src/command-config.js";

View File

@ -6,6 +6,12 @@ import {
DefaultResourceLoader,
SessionManager,
} from "@mariozechner/pi-coding-agent";
import {
isOllamaCompatProvider,
resolveOllamaCompatNumCtxEnabled,
shouldInjectOllamaCompatNumCtx,
wrapOllamaCompatNumCtx,
} from "../../../../extensions/ollama/runtime-api.js";
import { resolveHeartbeatPrompt } from "../../../auto-reply/heartbeat.js";
import { resolveChannelCapabilities } from "../../../config/channel-capabilities.js";
import { getMachineDisplayName } from "../../../infra/machine-name.js";
@ -14,12 +20,6 @@ import {
ensureGlobalUndiciStreamTimeouts,
} from "../../../infra/net/undici-global-dispatcher.js";
import { MAX_IMAGE_BYTES } from "../../../media/constants.js";
import {
isOllamaCompatProvider,
resolveOllamaCompatNumCtxEnabled,
shouldInjectOllamaCompatNumCtx,
wrapOllamaCompatNumCtx,
} from "../../../plugin-sdk/ollama.js";
import { getGlobalHookRunner } from "../../../plugins/hook-runner-global.js";
import { resolveToolCallArgumentsEncoding } from "../../../plugins/provider-model-compat.js";
import { isSubagentSessionKey } from "../../../routing/session-key.js";
@ -217,7 +217,7 @@ export {
resolveOllamaCompatNumCtxEnabled,
shouldInjectOllamaCompatNumCtx,
wrapOllamaCompatNumCtx,
} from "../../../plugin-sdk/ollama.js";
} from "../../../../extensions/ollama/runtime-api.js";
export {
decodeHtmlEntitiesInObject,
wrapStreamFnRepairMalformedToolCallArguments,

View File

@ -1,3 +1,4 @@
import { closeTrackedBrowserTabsForSessions } from "../../extensions/browser/runtime-api.js";
import { isSilentReplyText, SILENT_REPLY_TOKEN } from "../auto-reply/tokens.js";
import { cleanupBrowserSessionsForLifecycleEnd } from "../browser-lifecycle-cleanup.js";
import { formatErrorMessage, readErrorName } from "../infra/errors.js";

View File

@ -1,3 +1,4 @@
import { closeTrackedBrowserTabsForSessions } from "../../extensions/browser/runtime-api.js";
import { resolveDefaultAgentId } from "../agents/agent-scope.js";
import { cleanupBrowserSessionsForLifecycleEnd } from "../browser-lifecycle-cleanup.js";
import type { CliDeps } from "../cli/deps.js";