Files
openclaw/src/plugin-sdk/provider-model-shared.ts
2026-04-10 20:56:43 +01:00

156 lines
5.1 KiB
TypeScript

// Shared model/catalog helpers for provider plugins.
//
// Keep provider-owned exports out of this subpath so plugin loaders can import it
// without recursing through provider-specific facades.
import type { BedrockDiscoveryConfig, ModelDefinitionConfig } from "../config/types.models.js";
import {
buildAnthropicReplayPolicyForModel,
buildGoogleGeminiReplayPolicy,
buildHybridAnthropicOrOpenAIReplayPolicy,
buildNativeAnthropicReplayPolicyForModel,
buildOpenAICompatibleReplayPolicy,
buildPassthroughGeminiSanitizingReplayPolicy,
buildStrictAnthropicReplayPolicy,
resolveTaggedReasoningOutputMode,
sanitizeGoogleGeminiReplayHistory,
} from "../plugins/provider-replay-helpers.js";
import type { ProviderPlugin } from "../plugins/types.js";
import type {
ProviderReasoningOutputModeContext,
ProviderReplayPolicyContext,
ProviderSanitizeReplayHistoryContext,
} from "./plugin-entry.js";
import {
normalizeAntigravityPreviewModelId,
normalizeGooglePreviewModelId,
normalizeNativeXaiModelId,
} from "./provider-model-id-normalize.js";
export type { ModelApi, ModelProviderConfig } from "../config/types.models.js";
export type {
BedrockDiscoveryConfig,
ModelCompatConfig,
ModelDefinitionConfig,
} from "../config/types.models.js";
export type {
ProviderEndpointClass,
ProviderEndpointResolution,
} from "../agents/provider-attribution.js";
export type { ProviderPlugin } from "../plugins/types.js";
export type { KilocodeModelCatalogEntry } from "../plugins/provider-model-kilocode.js";
export { DEFAULT_CONTEXT_TOKENS } from "../agents/defaults.js";
export { resolveProviderEndpoint } from "../agents/provider-attribution.js";
export {
applyModelCompatPatch,
hasToolSchemaProfile,
hasNativeWebSearchTool,
normalizeModelCompat,
resolveUnsupportedToolSchemaKeywords,
resolveToolCallArgumentsEncoding,
} from "../plugins/provider-model-compat.js";
export { normalizeProviderId } from "../agents/provider-id.js";
export {
buildAnthropicReplayPolicyForModel,
buildGoogleGeminiReplayPolicy,
buildHybridAnthropicOrOpenAIReplayPolicy,
buildNativeAnthropicReplayPolicyForModel,
buildOpenAICompatibleReplayPolicy,
buildPassthroughGeminiSanitizingReplayPolicy,
resolveTaggedReasoningOutputMode,
sanitizeGoogleGeminiReplayHistory,
buildStrictAnthropicReplayPolicy,
};
export {
createMoonshotThinkingWrapper,
resolveMoonshotThinkingType,
} from "../agents/pi-embedded-runner/moonshot-thinking-stream-wrappers.js";
export {
cloneFirstTemplateModel,
matchesExactOrPrefix,
} from "../plugins/provider-model-helpers.js";
import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js";
export function getModelProviderHint(modelId: string): string | null {
const trimmed = normalizeOptionalLowercaseString(modelId);
if (!trimmed) {
return null;
}
const slashIndex = trimmed.indexOf("/");
if (slashIndex <= 0) {
return null;
}
return trimmed.slice(0, slashIndex) || null;
}
export function isProxyReasoningUnsupportedModelHint(modelId: string): boolean {
return getModelProviderHint(modelId) === "x-ai";
}
export {
normalizeAntigravityPreviewModelId,
normalizeGooglePreviewModelId,
normalizeNativeXaiModelId,
};
export type ProviderReplayFamily =
| "openai-compatible"
| "anthropic-by-model"
| "google-gemini"
| "passthrough-gemini"
| "hybrid-anthropic-openai";
type ProviderReplayFamilyHooks = Pick<
ProviderPlugin,
"buildReplayPolicy" | "sanitizeReplayHistory" | "resolveReasoningOutputMode"
>;
type BuildProviderReplayFamilyHooksOptions =
| { family: "openai-compatible" }
| { family: "anthropic-by-model" }
| { family: "google-gemini" }
| { family: "passthrough-gemini" }
| {
family: "hybrid-anthropic-openai";
anthropicModelDropThinkingBlocks?: boolean;
};
export function buildProviderReplayFamilyHooks(
options: BuildProviderReplayFamilyHooksOptions,
): ProviderReplayFamilyHooks {
switch (options.family) {
case "openai-compatible":
return {
buildReplayPolicy: (ctx: ProviderReplayPolicyContext) =>
buildOpenAICompatibleReplayPolicy(ctx.modelApi),
};
case "anthropic-by-model":
return {
buildReplayPolicy: ({ modelId }: ProviderReplayPolicyContext) =>
buildAnthropicReplayPolicyForModel(modelId),
};
case "google-gemini":
return {
buildReplayPolicy: () => buildGoogleGeminiReplayPolicy(),
sanitizeReplayHistory: (ctx: ProviderSanitizeReplayHistoryContext) =>
sanitizeGoogleGeminiReplayHistory(ctx),
resolveReasoningOutputMode: (_ctx: ProviderReasoningOutputModeContext) =>
resolveTaggedReasoningOutputMode(),
};
case "passthrough-gemini":
return {
buildReplayPolicy: ({ modelId }: ProviderReplayPolicyContext) =>
buildPassthroughGeminiSanitizingReplayPolicy(modelId),
};
case "hybrid-anthropic-openai":
return {
buildReplayPolicy: (ctx: ProviderReplayPolicyContext) =>
buildHybridAnthropicOrOpenAIReplayPolicy(ctx, {
anthropicModelDropThinkingBlocks: options.anthropicModelDropThinkingBlocks,
}),
};
}
throw new Error("Unsupported provider replay family");
}