mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-06 05:51:15 +08:00
docs: document shared package contracts
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
// Public barrel for shared ACP session, metadata, and runtime helper contracts.
|
||||
|
||||
export * from "./error-format.js";
|
||||
export * from "./meta.js";
|
||||
export * from "./normalize-text.js";
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
// ACP text normalization facade shared with older imports.
|
||||
|
||||
export { normalizeOptionalString as normalizeText } from "@openclaw/normalization-core/string-coerce";
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
// ACP record normalization facade shared with older imports.
|
||||
|
||||
export { asOptionalRecord as asRecord } from "@openclaw/normalization-core/record-coerce";
|
||||
|
||||
@@ -2,6 +2,9 @@ import { normalizeText } from "../normalize-text.js";
|
||||
import type { SessionAcpIdentity, SessionAcpIdentitySource, SessionAcpMeta } from "../types.js";
|
||||
import type { AcpRuntimeHandle, AcpRuntimeStatus } from "./types.js";
|
||||
|
||||
// ACP session identity merge and extraction helpers for resume-safe runtime state.
|
||||
|
||||
/** Normalize a stored identity state value from metadata. */
|
||||
function normalizeIdentityState(value: unknown): SessionAcpIdentity["state"] | undefined {
|
||||
if (value !== "pending" && value !== "resolved") {
|
||||
return undefined;
|
||||
@@ -9,6 +12,7 @@ function normalizeIdentityState(value: unknown): SessionAcpIdentity["state"] | u
|
||||
return value;
|
||||
}
|
||||
|
||||
/** Normalize where an ACP identity observation came from. */
|
||||
function normalizeIdentitySource(value: unknown): SessionAcpIdentitySource | undefined {
|
||||
if (value !== "ensure" && value !== "status" && value !== "event") {
|
||||
return undefined;
|
||||
@@ -16,6 +20,7 @@ function normalizeIdentitySource(value: unknown): SessionAcpIdentitySource | und
|
||||
return value;
|
||||
}
|
||||
|
||||
/** Normalize an identity object and infer pending/resolved state from stable ids. */
|
||||
function normalizeIdentity(
|
||||
identity: SessionAcpIdentity | undefined,
|
||||
): SessionAcpIdentity | undefined {
|
||||
@@ -49,6 +54,7 @@ function normalizeIdentity(
|
||||
|
||||
type IdentityIds = Pick<SessionAcpIdentity, "acpxRecordId" | "acpxSessionId" | "agentSessionId">;
|
||||
|
||||
/** Read identity ids from a runtime handle shape. */
|
||||
function readIdentityIdsFromHandle(handle: AcpRuntimeHandle): IdentityIds {
|
||||
return {
|
||||
acpxRecordId: normalizeText((handle as { acpxRecordId?: unknown }).acpxRecordId),
|
||||
@@ -57,6 +63,7 @@ function readIdentityIdsFromHandle(handle: AcpRuntimeHandle): IdentityIds {
|
||||
};
|
||||
}
|
||||
|
||||
/** Build an identity only when at least one stable id is known. */
|
||||
function buildSessionIdentity(params: {
|
||||
ids: IdentityIds;
|
||||
state: SessionAcpIdentity["state"];
|
||||
@@ -77,6 +84,7 @@ function buildSessionIdentity(params: {
|
||||
};
|
||||
}
|
||||
|
||||
/** Resolve normalized ACP identity from persisted session metadata. */
|
||||
export function resolveSessionIdentityFromMeta(
|
||||
meta: SessionAcpMeta | undefined,
|
||||
): SessionAcpIdentity | undefined {
|
||||
@@ -86,10 +94,12 @@ export function resolveSessionIdentityFromMeta(
|
||||
return normalizeIdentity(meta.identity);
|
||||
}
|
||||
|
||||
/** Return true when an identity has a backend or agent session id. */
|
||||
export function identityHasStableSessionId(identity: SessionAcpIdentity | undefined): boolean {
|
||||
return Boolean(identity?.acpxSessionId || identity?.agentSessionId);
|
||||
}
|
||||
|
||||
/** Resolve the runtime resume id, preferring agent session id over ACP backend id. */
|
||||
export function resolveRuntimeResumeSessionId(
|
||||
identity: SessionAcpIdentity | undefined,
|
||||
): string | undefined {
|
||||
@@ -99,6 +109,7 @@ export function resolveRuntimeResumeSessionId(
|
||||
return normalizeText(identity.agentSessionId) ?? normalizeText(identity.acpxSessionId);
|
||||
}
|
||||
|
||||
/** Return true when identity is absent or still pending. */
|
||||
export function isSessionIdentityPending(identity: SessionAcpIdentity | undefined): boolean {
|
||||
if (!identity) {
|
||||
return true;
|
||||
@@ -106,6 +117,7 @@ export function isSessionIdentityPending(identity: SessionAcpIdentity | undefine
|
||||
return identity.state === "pending";
|
||||
}
|
||||
|
||||
/** Compare identities ignoring lastUpdatedAt timestamp churn. */
|
||||
export function identityEquals(
|
||||
left: SessionAcpIdentity | undefined,
|
||||
right: SessionAcpIdentity | undefined,
|
||||
@@ -127,6 +139,7 @@ export function identityEquals(
|
||||
);
|
||||
}
|
||||
|
||||
/** Merge current and incoming identity observations without downgrading resolved ids. */
|
||||
export function mergeSessionIdentity(params: {
|
||||
current: SessionAcpIdentity | undefined;
|
||||
incoming: SessionAcpIdentity | undefined;
|
||||
@@ -174,6 +187,7 @@ export function mergeSessionIdentity(params: {
|
||||
return next;
|
||||
}
|
||||
|
||||
/** Create a pending identity from an ensure-session handle. */
|
||||
export function createIdentityFromEnsure(params: {
|
||||
handle: AcpRuntimeHandle;
|
||||
now: number;
|
||||
@@ -186,6 +200,7 @@ export function createIdentityFromEnsure(params: {
|
||||
});
|
||||
}
|
||||
|
||||
/** Create an identity from a runtime event handle. */
|
||||
export function createIdentityFromHandleEvent(params: {
|
||||
handle: AcpRuntimeHandle;
|
||||
now: number;
|
||||
@@ -199,6 +214,7 @@ export function createIdentityFromHandleEvent(params: {
|
||||
});
|
||||
}
|
||||
|
||||
/** Create an identity from runtime status output. */
|
||||
export function createIdentityFromStatus(params: {
|
||||
status: AcpRuntimeStatus | undefined;
|
||||
now: number;
|
||||
@@ -230,6 +246,7 @@ export function createIdentityFromStatus(params: {
|
||||
};
|
||||
}
|
||||
|
||||
/** Convert ACP identity ids into runtime handle resume identifiers. */
|
||||
export function resolveRuntimeHandleIdentifiersFromIdentity(
|
||||
identity: SessionAcpIdentity | undefined,
|
||||
): { backendSessionId?: string; agentSessionId?: string } {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Public barrel for media URL, MIME, path, and bounded-read helpers.
|
||||
|
||||
export * from "./base64.js";
|
||||
export * from "./constants.js";
|
||||
export * from "./content-length.js";
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
import { normalizeProviderId } from "./provider-id.js";
|
||||
|
||||
// Collects configured model references from OpenClaw config-shaped objects.
|
||||
|
||||
/** Narrow unknown values to plain records. */
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === "object" && value !== null && !Array.isArray(value);
|
||||
}
|
||||
|
||||
/** One configured model reference plus its config path. */
|
||||
export type ConfiguredModelRef = {
|
||||
path: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
/** Agent config keys that can contain direct model references. */
|
||||
export const AGENT_MODEL_CONFIG_KEYS = [
|
||||
"model",
|
||||
"imageModel",
|
||||
@@ -19,6 +24,7 @@ export const AGENT_MODEL_CONFIG_KEYS = [
|
||||
"pdfModel",
|
||||
] as const;
|
||||
|
||||
/** Collect configured model references from agents, channels, hooks, and message config. */
|
||||
export function collectConfiguredModelRefs(
|
||||
config: unknown,
|
||||
options: { includeChannelModelOverrides?: boolean } = {},
|
||||
@@ -117,6 +123,7 @@ export function collectConfiguredModelRefs(
|
||||
return refs;
|
||||
}
|
||||
|
||||
/** Collect only configured model reference values. */
|
||||
export function collectConfiguredModelRefValues(
|
||||
config: unknown,
|
||||
options?: { includeChannelModelOverrides?: boolean },
|
||||
@@ -124,6 +131,7 @@ export function collectConfiguredModelRefValues(
|
||||
return collectConfiguredModelRefs(config, options).map((ref) => ref.value);
|
||||
}
|
||||
|
||||
/** Extract a normalized provider id from a provider/model reference. */
|
||||
export function extractProviderFromModelRef(value: string): string | null {
|
||||
const trimmed = value.trim();
|
||||
const slash = trimmed.indexOf("/");
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Public barrel for model catalog normalization, ids, refs, and types.
|
||||
|
||||
export * from "./configured-model-refs.js";
|
||||
export * from "./model-catalog-normalize.js";
|
||||
export * from "./model-catalog-refs.js";
|
||||
|
||||
@@ -26,6 +26,8 @@ import {
|
||||
type NormalizedModelCatalogRow,
|
||||
} from "./model-catalog-types.js";
|
||||
|
||||
// Normalizes raw provider model catalogs into stable rows for lookup and merging.
|
||||
|
||||
const MODEL_CATALOG_INPUTS = new Set(["text", "image", "document"]);
|
||||
const MODEL_CATALOG_DISCOVERY_MODES = new Set(["static", "refreshable", "runtime"]);
|
||||
const MODEL_CATALOG_STATUSES = new Set(["available", "preview", "deprecated", "disabled"]);
|
||||
@@ -33,14 +35,17 @@ const MODEL_CATALOG_API_SET = new Set<string>(MODEL_CATALOG_APIS);
|
||||
const DEFAULT_MODEL_INPUT: ModelCatalogInput[] = ["text"];
|
||||
const DEFAULT_MODEL_STATUS: ModelCatalogStatus = "available";
|
||||
|
||||
/** Narrow unknown catalog payloads to plain records. */
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === "object" && value !== null && !Array.isArray(value);
|
||||
}
|
||||
|
||||
/** Reject object keys that can mutate prototypes when copied into records. */
|
||||
function isBlockedObjectKey(key: string): boolean {
|
||||
return key === "__proto__" || key === "prototype" || key === "constructor";
|
||||
}
|
||||
|
||||
/** Normalize optional catalog strings. */
|
||||
function normalizeOptionalString(value: unknown): string | undefined {
|
||||
if (typeof value !== "string") {
|
||||
return undefined;
|
||||
@@ -49,6 +54,7 @@ function normalizeOptionalString(value: unknown): string | undefined {
|
||||
return trimmed ? trimmed : undefined;
|
||||
}
|
||||
|
||||
/** Normalize arrays of trimmed strings, dropping invalid entries. */
|
||||
function normalizeTrimmedStringList(value: unknown): string[] {
|
||||
if (!Array.isArray(value)) {
|
||||
return [];
|
||||
@@ -638,6 +644,7 @@ function normalizeModelCatalogDiscovery(
|
||||
return Object.keys(discovery).length > 0 ? discovery : undefined;
|
||||
}
|
||||
|
||||
/** Normalize a raw model catalog object for the set of providers owned by a plugin/manifest. */
|
||||
export function normalizeModelCatalog(
|
||||
value: unknown,
|
||||
params: { ownedProviders: ReadonlySet<string> },
|
||||
@@ -661,6 +668,7 @@ export function normalizeModelCatalog(
|
||||
return Object.keys(catalog).length > 0 ? catalog : undefined;
|
||||
}
|
||||
|
||||
/** Normalize one provider catalog into sorted runtime rows. */
|
||||
export function normalizeModelCatalogProviderRows(params: {
|
||||
provider: string;
|
||||
providerCatalog: ModelCatalogProvider;
|
||||
@@ -722,6 +730,7 @@ export function normalizeModelCatalogProviderRows(params: {
|
||||
return rows.toSorted((a, b) => a.provider.localeCompare(b.provider) || a.id.localeCompare(b.id));
|
||||
}
|
||||
|
||||
/** Normalize all provider catalogs into sorted runtime rows. */
|
||||
export function normalizeModelCatalogRows(params: {
|
||||
providers: Record<string, ModelCatalogProvider>;
|
||||
source: ModelCatalogSource;
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
import { normalizeLowercaseStringOrEmpty } from "./provider-id.js";
|
||||
|
||||
// Stable model catalog ref and merge-key builders.
|
||||
|
||||
/** Normalize provider ids for catalog refs. */
|
||||
export function normalizeModelCatalogProviderId(provider: string): string {
|
||||
return normalizeLowercaseStringOrEmpty(provider);
|
||||
}
|
||||
|
||||
/** Build a provider/model catalog reference. */
|
||||
export function buildModelCatalogRef(provider: string, modelId: string): string {
|
||||
return `${normalizeModelCatalogProviderId(provider)}/${modelId}`;
|
||||
}
|
||||
|
||||
/** Build a case-insensitive merge key for provider/model rows. */
|
||||
export function buildModelCatalogMergeKey(provider: string, modelId: string): string {
|
||||
return `${normalizeModelCatalogProviderId(provider)}::${normalizeLowercaseStringOrEmpty(modelId)}`;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// Shared model catalog data contracts for provider manifests and normalized rows.
|
||||
|
||||
/** Supported API protocols for model catalog entries. */
|
||||
export const MODEL_CATALOG_APIS = [
|
||||
"openai-completions",
|
||||
"openai-responses",
|
||||
@@ -11,8 +14,10 @@ export const MODEL_CATALOG_APIS = [
|
||||
"azure-openai-responses",
|
||||
] as const;
|
||||
|
||||
/** API protocol for a model catalog entry. */
|
||||
export type ModelCatalogApi = (typeof MODEL_CATALOG_APIS)[number];
|
||||
|
||||
/** Supported model thinking/reasoning wire formats. */
|
||||
export const MODEL_CATALOG_THINKING_FORMATS = [
|
||||
"openai",
|
||||
"openrouter",
|
||||
@@ -23,12 +28,15 @@ export const MODEL_CATALOG_THINKING_FORMATS = [
|
||||
"zai",
|
||||
] as const;
|
||||
|
||||
/** Thinking/reasoning wire format for model compatibility. */
|
||||
export type ModelCatalogThinkingFormat = (typeof MODEL_CATALOG_THINKING_FORMATS)[number];
|
||||
|
||||
/** Narrow a string to a supported model catalog thinking format. */
|
||||
export function isModelCatalogThinkingFormat(value: string): value is ModelCatalogThinkingFormat {
|
||||
return (MODEL_CATALOG_THINKING_FORMATS as readonly string[]).includes(value);
|
||||
}
|
||||
|
||||
/** Compatibility flags and provider-specific routing metadata for one model. */
|
||||
export type ModelCatalogCompatConfig = {
|
||||
supportsStore?: boolean;
|
||||
supportsDeveloperRole?: boolean;
|
||||
@@ -63,6 +71,7 @@ export type ModelCatalogCompatConfig = {
|
||||
visibleReasoningDetailTypes?: string[];
|
||||
};
|
||||
|
||||
/** OpenRouter routing preferences copied into request metadata. */
|
||||
export type ModelCatalogOpenRouterRouting = {
|
||||
allow_fallbacks?: boolean;
|
||||
require_parameters?: boolean;
|
||||
@@ -104,11 +113,13 @@ export type ModelCatalogOpenRouterRouting = {
|
||||
};
|
||||
};
|
||||
|
||||
/** Vercel AI Gateway routing preferences. */
|
||||
export type ModelCatalogVercelGatewayRouting = {
|
||||
only?: string[];
|
||||
order?: string[];
|
||||
};
|
||||
|
||||
/** Image input limits for a model. */
|
||||
export type ModelCatalogImageInputConfig = {
|
||||
maxBytes?: number;
|
||||
maxPixels?: number;
|
||||
@@ -117,13 +128,18 @@ export type ModelCatalogImageInputConfig = {
|
||||
tokenMode?: "tile" | "detail" | "provider";
|
||||
};
|
||||
|
||||
/** Media input limits for a model. */
|
||||
export type ModelCatalogMediaInputConfig = {
|
||||
image?: ModelCatalogImageInputConfig;
|
||||
};
|
||||
|
||||
/** Supported input modality for a model. */
|
||||
export type ModelCatalogInput = "text" | "image" | "document";
|
||||
/** Discovery lifecycle for a provider catalog. */
|
||||
export type ModelCatalogDiscovery = "static" | "refreshable" | "runtime";
|
||||
/** Availability state for a model. */
|
||||
export type ModelCatalogStatus = "available" | "preview" | "deprecated" | "disabled";
|
||||
/** Source of a model catalog row. */
|
||||
export type ModelCatalogSource =
|
||||
| "manifest"
|
||||
| "provider-index"
|
||||
@@ -131,6 +147,7 @@ export type ModelCatalogSource =
|
||||
| "config"
|
||||
| "runtime-refresh";
|
||||
|
||||
/** Unified catalog kind across text and generated media models. */
|
||||
export type UnifiedModelCatalogKind =
|
||||
| "text"
|
||||
| "voice"
|
||||
@@ -138,6 +155,7 @@ export type UnifiedModelCatalogKind =
|
||||
| "video_generation"
|
||||
| "music_generation";
|
||||
|
||||
/** Source for unified model catalog entries. */
|
||||
export type UnifiedModelCatalogSource =
|
||||
| "manifest"
|
||||
| "provider-index"
|
||||
@@ -147,6 +165,7 @@ export type UnifiedModelCatalogSource =
|
||||
| "configured"
|
||||
| "runtime-refresh";
|
||||
|
||||
/** Unified model catalog entry for provider/model pickers. */
|
||||
export type UnifiedModelCatalogEntry<TCapabilities = unknown> = {
|
||||
kind: UnifiedModelCatalogKind;
|
||||
provider: string;
|
||||
@@ -164,6 +183,7 @@ export type UnifiedModelCatalogEntry<TCapabilities = unknown> = {
|
||||
warnings?: readonly string[];
|
||||
};
|
||||
|
||||
/** Tiered token cost row. */
|
||||
export type ModelCatalogTieredCost = {
|
||||
input: number;
|
||||
output: number;
|
||||
@@ -172,6 +192,7 @@ export type ModelCatalogTieredCost = {
|
||||
range: [number, number] | [number];
|
||||
};
|
||||
|
||||
/** Token cost metadata for one model. */
|
||||
export type ModelCatalogCost = {
|
||||
input?: number;
|
||||
output?: number;
|
||||
@@ -180,6 +201,7 @@ export type ModelCatalogCost = {
|
||||
tieredPricing?: ModelCatalogTieredCost[];
|
||||
};
|
||||
|
||||
/** Provider manifest model entry. */
|
||||
export type ModelCatalogModel = {
|
||||
id: string;
|
||||
name?: string;
|
||||
@@ -201,6 +223,7 @@ export type ModelCatalogModel = {
|
||||
tags?: string[];
|
||||
};
|
||||
|
||||
/** Provider manifest catalog entry. */
|
||||
export type ModelCatalogProvider = {
|
||||
baseUrl?: string;
|
||||
api?: ModelCatalogApi;
|
||||
@@ -208,12 +231,14 @@ export type ModelCatalogProvider = {
|
||||
models: ModelCatalogModel[];
|
||||
};
|
||||
|
||||
/** Provider alias entry. */
|
||||
export type ModelCatalogAlias = {
|
||||
provider: string;
|
||||
api?: ModelCatalogApi;
|
||||
baseUrl?: string;
|
||||
};
|
||||
|
||||
/** Suppression rule for hiding a provider/model under matching config. */
|
||||
export type ModelCatalogSuppression = {
|
||||
provider: string;
|
||||
model: string;
|
||||
@@ -224,6 +249,7 @@ export type ModelCatalogSuppression = {
|
||||
};
|
||||
};
|
||||
|
||||
/** Raw model catalog manifest shape. */
|
||||
export type ModelCatalog = {
|
||||
providers?: Record<string, ModelCatalogProvider>;
|
||||
aliases?: Record<string, ModelCatalogAlias>;
|
||||
@@ -232,6 +258,7 @@ export type ModelCatalog = {
|
||||
runtimeAugment?: boolean;
|
||||
};
|
||||
|
||||
/** Normalized model catalog row used by runtime lookup and UI surfaces. */
|
||||
export type NormalizedModelCatalogRow = {
|
||||
provider: string;
|
||||
id: string;
|
||||
|
||||
@@ -4,6 +4,9 @@ import {
|
||||
normalizeTogetherModelId,
|
||||
} from "./provider-model-id-normalize.js";
|
||||
|
||||
// Provider model-id normalization policies from manifests plus built-in provider rules.
|
||||
|
||||
/** Manifest-defined normalization rules for one provider. */
|
||||
export type ManifestModelIdNormalizationProvider = {
|
||||
aliases?: Record<string, string>;
|
||||
stripPrefixes?: string[];
|
||||
@@ -14,6 +17,7 @@ export type ManifestModelIdNormalizationProvider = {
|
||||
}[];
|
||||
};
|
||||
|
||||
/** Manifest fragment that can define provider model-id normalization policies. */
|
||||
export type ManifestModelIdNormalizationRecord = {
|
||||
modelIdNormalization?: {
|
||||
providers?: Record<string, ManifestModelIdNormalizationProvider>;
|
||||
@@ -24,6 +28,7 @@ let currentManifestModelIdNormalizationPolicies:
|
||||
| ReadonlyMap<string, ManifestModelIdNormalizationProvider>
|
||||
| undefined;
|
||||
|
||||
/** Collect provider model-id normalization policies from plugin manifests. */
|
||||
export function collectManifestModelIdNormalizationPolicies(
|
||||
plugins: readonly ManifestModelIdNormalizationRecord[],
|
||||
): Map<string, ManifestModelIdNormalizationProvider> {
|
||||
@@ -36,6 +41,7 @@ export function collectManifestModelIdNormalizationPolicies(
|
||||
return policies;
|
||||
}
|
||||
|
||||
/** Replace the process-local manifest normalization policy snapshot. */
|
||||
export function setCurrentManifestModelIdNormalizationRecords(
|
||||
plugins: readonly ManifestModelIdNormalizationRecord[] | undefined,
|
||||
): void {
|
||||
@@ -44,20 +50,24 @@ export function setCurrentManifestModelIdNormalizationRecords(
|
||||
: undefined;
|
||||
}
|
||||
|
||||
/** Return the current process-local manifest normalization policy snapshot. */
|
||||
export function getCurrentManifestModelIdNormalizationPolicies():
|
||||
| ReadonlyMap<string, ManifestModelIdNormalizationProvider>
|
||||
| undefined {
|
||||
return currentManifestModelIdNormalizationPolicies;
|
||||
}
|
||||
|
||||
/** Return true when a model id already includes a provider namespace. */
|
||||
function hasProviderPrefix(modelId: string): boolean {
|
||||
return modelId.includes("/");
|
||||
}
|
||||
|
||||
/** Join a provider prefix and model id with exactly one slash. */
|
||||
function formatPrefixedModelId(prefix: string, modelId: string): string {
|
||||
return `${prefix.replace(/\/+$/u, "")}/${modelId.replace(/^\/+/u, "")}`;
|
||||
}
|
||||
|
||||
/** Strip a duplicated self-provider prefix from a model id. */
|
||||
export function stripSelfProviderModelPrefix(provider: string, model: string): string {
|
||||
const prefix = `${normalizeLowercaseStringOrEmpty(provider)}/`;
|
||||
const trimmed = model.trim();
|
||||
@@ -66,6 +76,7 @@ export function stripSelfProviderModelPrefix(provider: string, model: string): s
|
||||
: model;
|
||||
}
|
||||
|
||||
/** Apply manifest normalization policies for one provider/model id. */
|
||||
export function normalizeProviderModelIdWithPolicies(params: {
|
||||
provider: string;
|
||||
policies: ReadonlyMap<string, ManifestModelIdNormalizationProvider>;
|
||||
@@ -107,6 +118,7 @@ export function normalizeProviderModelIdWithPolicies(params: {
|
||||
return modelId;
|
||||
}
|
||||
|
||||
/** Apply built-in provider-specific model id normalization rules. */
|
||||
export function normalizeBuiltInProviderModelId(provider: string, model: string): string {
|
||||
const normalizedProvider = normalizeLowercaseStringOrEmpty(provider);
|
||||
if (
|
||||
@@ -174,6 +186,7 @@ export function normalizeBuiltInProviderModelId(provider: string, model: string)
|
||||
return model;
|
||||
}
|
||||
|
||||
/** Apply manifest policies and built-in normalization to a static provider/model id. */
|
||||
export function normalizeStaticProviderModelIdWithPolicies(
|
||||
provider: string,
|
||||
model: string,
|
||||
@@ -192,6 +205,7 @@ export function normalizeStaticProviderModelIdWithPolicies(
|
||||
return normalizeBuiltInProviderModelId(normalizedProvider, manifestModelId);
|
||||
}
|
||||
|
||||
/** Normalize a configured provider/model catalog reference using current policies. */
|
||||
export function normalizeConfiguredProviderCatalogModelId(
|
||||
provider: string,
|
||||
model: string,
|
||||
@@ -201,6 +215,7 @@ export function normalizeConfiguredProviderCatalogModelId(
|
||||
return normalizeConfiguredProviderCatalogModelRef(providerModel);
|
||||
}
|
||||
|
||||
/** Normalize embedded Google model aliases inside provider/model catalog refs. */
|
||||
export function normalizeConfiguredProviderCatalogModelRef(providerModel: string): string {
|
||||
const googlePrefix = "google/";
|
||||
if (!providerModel.startsWith(googlePrefix)) {
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Public barrel for shared coercion and normalization helpers.
|
||||
|
||||
export * from "./number-coercion.js";
|
||||
export * from "./record-coerce.js";
|
||||
export * from "./string-coerce.js";
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
// External code plugin package.json compatibility and validation contracts.
|
||||
|
||||
/** JSON object shape accepted by package contract helpers. */
|
||||
export type JsonObject = Record<string, unknown>;
|
||||
|
||||
/** Compatibility metadata extracted from an external plugin package. */
|
||||
export type ExternalPluginCompatibility = {
|
||||
pluginApiRange?: string;
|
||||
builtWithOpenClawVersion?: string;
|
||||
@@ -7,25 +11,30 @@ export type ExternalPluginCompatibility = {
|
||||
minGatewayVersion?: string;
|
||||
};
|
||||
|
||||
/** One validation issue for an external plugin package. */
|
||||
export type ExternalPluginValidationIssue = {
|
||||
fieldPath: string;
|
||||
message: string;
|
||||
};
|
||||
|
||||
/** Validation result plus any normalized compatibility metadata. */
|
||||
export type ExternalCodePluginValidationResult = {
|
||||
compatibility?: ExternalPluginCompatibility;
|
||||
issues: ExternalPluginValidationIssue[];
|
||||
};
|
||||
|
||||
/** Required package.json field paths for external code plugin packages. */
|
||||
export const EXTERNAL_CODE_PLUGIN_REQUIRED_FIELD_PATHS = [
|
||||
"openclaw.compat.pluginApi",
|
||||
"openclaw.build.openclawVersion",
|
||||
] as const;
|
||||
|
||||
/** Narrow unknown values to plain records. */
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === "object" && value !== null && !Array.isArray(value);
|
||||
}
|
||||
|
||||
/** Normalize optional package metadata strings. */
|
||||
function normalizeOptionalString(value: unknown): string | undefined {
|
||||
if (typeof value !== "string") {
|
||||
return undefined;
|
||||
@@ -34,6 +43,7 @@ function normalizeOptionalString(value: unknown): string | undefined {
|
||||
return trimmed ? trimmed : undefined;
|
||||
}
|
||||
|
||||
/** Read OpenClaw package.json blocks without trusting caller input shape. */
|
||||
function readOpenClawBlock(packageJson: unknown) {
|
||||
const root = isRecord(packageJson) ? packageJson : undefined;
|
||||
const openclaw = isRecord(root?.openclaw) ? root.openclaw : undefined;
|
||||
@@ -43,6 +53,7 @@ function readOpenClawBlock(packageJson: unknown) {
|
||||
return { root, openclaw, compat, build, install };
|
||||
}
|
||||
|
||||
/** Normalize compatibility metadata from an external plugin package.json. */
|
||||
export function normalizeExternalPluginCompatibility(
|
||||
packageJson: unknown,
|
||||
): ExternalPluginCompatibility | undefined {
|
||||
@@ -74,6 +85,7 @@ export function normalizeExternalPluginCompatibility(
|
||||
return Object.keys(compatibility).length > 0 ? compatibility : undefined;
|
||||
}
|
||||
|
||||
/** List missing required field paths for an external code plugin package.json. */
|
||||
export function listMissingExternalCodePluginFieldPaths(packageJson: unknown): string[] {
|
||||
const { compat, build } = readOpenClawBlock(packageJson);
|
||||
const missing: string[] = [];
|
||||
@@ -86,6 +98,7 @@ export function listMissingExternalCodePluginFieldPaths(packageJson: unknown): s
|
||||
return missing;
|
||||
}
|
||||
|
||||
/** Validate an external code plugin package.json against required compatibility fields. */
|
||||
export function validateExternalCodePluginPackageJson(
|
||||
packageJson: unknown,
|
||||
): ExternalCodePluginValidationResult {
|
||||
|
||||
Reference in New Issue
Block a user