mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 21:07:01 -06:00
refactor(agents): absorb model helper fragments (#112805)
* refactor(agents): absorb model helper fragments * refactor(agents): keep absorbed helpers internal
This commit is contained in:
committed by
GitHub
parent
19d17bc3c4
commit
9dd306de79
@@ -1,15 +1,9 @@
|
||||
/**
|
||||
* Runtime seam for auth-profile store loading.
|
||||
* Tests can stub this facade without importing the full auth profile store
|
||||
* implementation.
|
||||
*/
|
||||
import { ensureAuthProfileStore as ensureAuthProfileStoreImpl } from "./auth-profiles/store.js";
|
||||
|
||||
type EnsureAuthProfileStore = typeof import("./auth-profiles/store.js").ensureAuthProfileStore;
|
||||
|
||||
/** Ensure an auth-profile store using the production store implementation. */
|
||||
export function ensureAuthProfileStore(
|
||||
...args: Parameters<EnsureAuthProfileStore>
|
||||
): ReturnType<EnsureAuthProfileStore> {
|
||||
return ensureAuthProfileStoreImpl(...args);
|
||||
}
|
||||
/** Runtime auth-profile facade for lazy model selection and fallback paths. */
|
||||
export { resolveAuthProfileOrder } from "./auth-profiles/order.js";
|
||||
export { ensureAuthProfileStore, loadAuthProfileStoreForRuntime } from "./auth-profiles/store.js";
|
||||
export {
|
||||
getSoonestCooldownExpiry,
|
||||
isProfileInCooldown,
|
||||
maybeReprobeWhamBlockedProfiles,
|
||||
resolveProfilesUnavailableReason,
|
||||
} from "./auth-profiles/usage.js";
|
||||
|
||||
@@ -11,6 +11,7 @@ import { applyExtraParamsToAgent } from "./extra-params.js";
|
||||
import type { ProviderThinkLevel } from "./utils.js";
|
||||
|
||||
type ExtraParamsTestApi = {
|
||||
supportsGptParallelToolCallsPayload(api: unknown): boolean;
|
||||
setProviderRuntimeDepsForTest(
|
||||
deps:
|
||||
| Partial<{
|
||||
|
||||
@@ -35,7 +35,6 @@ import {
|
||||
} from "../../plugins/provider-hook-runtime.js";
|
||||
import type { ProviderRuntimeModel } from "../../plugins/provider-runtime-model.types.js";
|
||||
import { resolveModelExtraParamSources } from "../model-extra-params.js";
|
||||
import { supportsGptParallelToolCallsPayload } from "../provider-api-families.js";
|
||||
import { resolveProviderRequestPolicyConfig } from "../provider-request-config.js";
|
||||
import type { AgentRuntimeTransport } from "../runtime-plan/types.js";
|
||||
import type { StreamFn } from "../runtime/index.js";
|
||||
@@ -63,8 +62,20 @@ const providerRuntimeDeps = {
|
||||
|
||||
let preparedExtraParamsCache = new WeakMap<OpenClawConfig, Map<string, Record<string, unknown>>>();
|
||||
const REQUEST_SCOPED_EXTRA_PARAM_KEYS = new Set(["response_format", "responseFormat", "stop"]);
|
||||
const GPT_PARALLEL_TOOL_CALLS_APIS = new Set([
|
||||
"openai-completions",
|
||||
"openai-responses",
|
||||
"openai-chatgpt-responses",
|
||||
"azure-openai-responses",
|
||||
]);
|
||||
|
||||
/** True when a provider API accepts GPT parallel-tool-call payload settings. */
|
||||
function supportsGptParallelToolCallsPayload(api: unknown): boolean {
|
||||
return typeof api === "string" && GPT_PARALLEL_TOOL_CALLS_APIS.has(api);
|
||||
}
|
||||
|
||||
const testing = {
|
||||
supportsGptParallelToolCallsPayload,
|
||||
setProviderRuntimeDepsForTest(
|
||||
deps: Partial<typeof defaultProviderRuntimeDeps> | undefined,
|
||||
): void {
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
/**
|
||||
* Formats configured model aliases for prompt-visible model guidance.
|
||||
*/
|
||||
import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
|
||||
/** Builds deterministic prompt lines for configured model aliases. */
|
||||
export function buildModelAliasLines(cfg?: OpenClawConfig) {
|
||||
const models = cfg?.agents?.defaults?.models ?? {};
|
||||
const entries: Array<{ alias: string; model: string }> = [];
|
||||
for (const [keyRaw, entryRaw] of Object.entries(models)) {
|
||||
const model = normalizeOptionalString(keyRaw) ?? "";
|
||||
if (!model) {
|
||||
continue;
|
||||
}
|
||||
const alias =
|
||||
normalizeOptionalString((entryRaw as { alias?: string } | undefined)?.alias) ?? "";
|
||||
if (!alias) {
|
||||
continue;
|
||||
}
|
||||
entries.push({ alias, model });
|
||||
}
|
||||
return entries
|
||||
.toSorted((a, b) => a.alias.localeCompare(b.alias))
|
||||
.map((entry) => `- ${entry.alias}: ${entry.model}`);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
// Verifies model catalog lookup scope for custom and manifest-owned models.
|
||||
import { describe, expect, it } from "vitest";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { resolveModelCatalogScope } from "./model-catalog-scope.js";
|
||||
import { resolveModelCatalogScope } from "./model-discovery-context.js";
|
||||
|
||||
describe("resolveModelCatalogScope", () => {
|
||||
it("keeps explicit custom provider models scoped to that provider", () => {
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
/**
|
||||
* Resolves model catalog scope from config and discovery options.
|
||||
*/
|
||||
import { findNormalizedProviderValue } from "@openclaw/model-catalog-core/provider-id";
|
||||
import { normalizeUniqueSingleOrTrimmedStringList } from "@openclaw/normalization-core/string-normalization";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
|
||||
function providerConfigDeclaresModel(
|
||||
providerConfig: { models?: readonly { id?: string }[] } | undefined,
|
||||
model: string,
|
||||
): boolean {
|
||||
const trimmedModel = model.trim();
|
||||
return Boolean(
|
||||
trimmedModel &&
|
||||
providerConfig?.models?.some((candidate) => candidate.id?.trim() === trimmedModel),
|
||||
);
|
||||
}
|
||||
|
||||
/** Resolves provider/model refs used to scope model catalog discovery. */
|
||||
export function resolveModelCatalogScope(params: {
|
||||
cfg?: OpenClawConfig;
|
||||
provider: string;
|
||||
model: string;
|
||||
}): { providerRefs: string[]; modelRefs: string[] } {
|
||||
const provider = params.provider.trim();
|
||||
const model = params.model.trim();
|
||||
const providerConfig = findNormalizedProviderValue(params.cfg?.models?.providers, provider);
|
||||
const modelRefs = providerConfigDeclaresModel(providerConfig, model)
|
||||
? [provider && model ? `${provider}/${model}` : model]
|
||||
: [provider && model ? `${provider}/${model}` : model, model];
|
||||
// Scope ordering feeds deterministic discovery and prompt/cache inputs.
|
||||
return {
|
||||
providerRefs: normalizeUniqueSingleOrTrimmedStringList([provider, providerConfig?.api]),
|
||||
modelRefs: normalizeUniqueSingleOrTrimmedStringList(modelRefs),
|
||||
};
|
||||
}
|
||||
@@ -3,6 +3,8 @@
|
||||
* Keeps callers from reaching into runtime config or plugin metadata snapshot
|
||||
* plumbing directly.
|
||||
*/
|
||||
import { findNormalizedProviderValue } from "@openclaw/model-catalog-core/provider-id";
|
||||
import { normalizeUniqueSingleOrTrimmedStringList } from "@openclaw/normalization-core/string-normalization";
|
||||
import { getRuntimeConfig } from "../config/config.js";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { getCurrentPluginMetadataSnapshot } from "../plugins/current-plugin-metadata-snapshot.js";
|
||||
@@ -10,6 +12,36 @@ import { resolvePluginMetadataSnapshot } from "../plugins/plugin-metadata-snapsh
|
||||
import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "./agent-scope.js";
|
||||
import type { PluginModelCatalogMetadataSnapshot } from "./plugin-model-catalog.js";
|
||||
|
||||
function providerConfigDeclaresModel(
|
||||
providerConfig: { models?: readonly { id?: string }[] } | undefined,
|
||||
model: string,
|
||||
): boolean {
|
||||
const trimmedModel = model.trim();
|
||||
return Boolean(
|
||||
trimmedModel &&
|
||||
providerConfig?.models?.some((candidate) => candidate.id?.trim() === trimmedModel),
|
||||
);
|
||||
}
|
||||
|
||||
/** Resolves provider/model refs used to scope model catalog discovery. */
|
||||
export function resolveModelCatalogScope(params: {
|
||||
cfg?: OpenClawConfig;
|
||||
provider: string;
|
||||
model: string;
|
||||
}): { providerRefs: string[]; modelRefs: string[] } {
|
||||
const provider = params.provider.trim();
|
||||
const model = params.model.trim();
|
||||
const providerConfig = findNormalizedProviderValue(params.cfg?.models?.providers, provider);
|
||||
const modelRefs = providerConfigDeclaresModel(providerConfig, model)
|
||||
? [provider && model ? `${provider}/${model}` : model]
|
||||
: [provider && model ? `${provider}/${model}` : model, model];
|
||||
// Scope ordering feeds deterministic discovery and prompt/cache inputs.
|
||||
return {
|
||||
providerRefs: normalizeUniqueSingleOrTrimmedStringList([provider, providerConfig?.api]),
|
||||
modelRefs: normalizeUniqueSingleOrTrimmedStringList(modelRefs),
|
||||
};
|
||||
}
|
||||
|
||||
/** Resolve the workspace directory model discovery should use for agent scope. */
|
||||
export function resolveModelWorkspaceDir(
|
||||
cfg: OpenClawConfig | undefined,
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
/**
|
||||
* Runtime auth profile barrel for fallback/provider selection code.
|
||||
*
|
||||
* These exports keep the hot runtime path on the auth-profile submodules without
|
||||
* pulling the broader model config surface into provider fallback logic.
|
||||
*/
|
||||
export { resolveAuthProfileOrder } from "./auth-profiles/order.js";
|
||||
export { ensureAuthProfileStore, loadAuthProfileStoreForRuntime } from "./auth-profiles/store.js";
|
||||
export {
|
||||
getSoonestCooldownExpiry,
|
||||
isProfileInCooldown,
|
||||
maybeReprobeWhamBlockedProfiles,
|
||||
resolveProfilesUnavailableReason,
|
||||
} from "./auth-profiles/usage.js";
|
||||
@@ -16,7 +16,7 @@ type ModelFallbackTestApi = {
|
||||
hasFallbackCandidates: boolean;
|
||||
now: number;
|
||||
probeThrottleKey: string;
|
||||
authRuntime: typeof import("./model-fallback-auth.runtime.js");
|
||||
authRuntime: typeof import("./auth-profiles.runtime.js");
|
||||
authStore: AuthProfileStore;
|
||||
profileIds: string[];
|
||||
}): CooldownDecision;
|
||||
|
||||
@@ -200,7 +200,7 @@ const authRuntimeMock = vi.hoisted(() => {
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock("./model-fallback-auth.runtime.js", () => authRuntimeMock.runtime);
|
||||
vi.mock("./auth-profiles.runtime.js", () => authRuntimeMock.runtime);
|
||||
|
||||
const makeCfg = makeModelFallbackCfg;
|
||||
let authTempRoot = "";
|
||||
|
||||
@@ -361,10 +361,10 @@ type ModelFallbackClassifiedResult<T> = Pick<
|
||||
"result" | "provider" | "model"
|
||||
>;
|
||||
|
||||
type ModelFallbackAuthRuntime = typeof import("./model-fallback-auth.runtime.js");
|
||||
type ModelFallbackAuthRuntime = typeof import("./auth-profiles.runtime.js");
|
||||
|
||||
const modelFallbackAuthRuntimeLoader = createLazyImportLoader<ModelFallbackAuthRuntime>(
|
||||
() => import("./model-fallback-auth.runtime.js"),
|
||||
() => import("./auth-profiles.runtime.js"),
|
||||
);
|
||||
const MAX_FALLBACK_CANDIDATE_CACHE_ENTRIES = 256;
|
||||
const fallbackCandidateCache = new Map<string, ModelCandidate[]>();
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
/**
|
||||
* Filters provider/model refs for model picker visibility.
|
||||
*/
|
||||
import { normalizeProviderId } from "@openclaw/model-catalog-core/provider-id";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { listCliRuntimeProviderIds } from "./cli-backends.js";
|
||||
|
||||
// Retired provider ids and CLI runtime aliases are implementation surfaces, not
|
||||
// model picker choices. Hide them while keeping real provider/model refs visible.
|
||||
const RETIRED_MODEL_PICKER_PROVIDERS = new Set(["codex", "codex-cli"]);
|
||||
|
||||
/** True for retired provider ids that should stay out of model selection surfaces. */
|
||||
export function isRetiredModelPickerProvider(provider: string): boolean {
|
||||
return RETIRED_MODEL_PICKER_PROVIDERS.has(normalizeProviderId(provider));
|
||||
}
|
||||
|
||||
/** Creates a provider visibility predicate for model picker rendering. */
|
||||
export function createModelPickerVisibleProviderPredicate(
|
||||
params: { config?: OpenClawConfig; env?: NodeJS.ProcessEnv; includeSetupRegistry?: boolean } = {},
|
||||
): (provider: string) => boolean {
|
||||
const cliRuntimeProviders = new Set(
|
||||
listCliRuntimeProviderIds({
|
||||
config: params.config,
|
||||
env: params.env,
|
||||
includeSetupRegistry: params.includeSetupRegistry ?? false,
|
||||
}),
|
||||
);
|
||||
return (provider: string): boolean => {
|
||||
const normalized = normalizeProviderId(provider);
|
||||
return !isRetiredModelPickerProvider(normalized) && !cliRuntimeProviders.has(normalized);
|
||||
};
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/** Lifecycle-backed model-registry view for command paths. */
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import {
|
||||
loadPreparedAgentModelRegistry,
|
||||
type LoadPreparedAgentModelRegistryOptions,
|
||||
} from "./prepared-model-registry.js";
|
||||
import type { ModelRegistry } from "./sessions/index.js";
|
||||
|
||||
/** Options controlling the prepared registry view. */
|
||||
type LoadAgentModelRegistryOptions = LoadPreparedAgentModelRegistryOptions & {
|
||||
readOnly?: boolean;
|
||||
};
|
||||
|
||||
/** Forks a registry from the generation prepared by the owning command lifecycle. */
|
||||
export async function loadAgentModelRegistry(
|
||||
config: OpenClawConfig,
|
||||
options: LoadAgentModelRegistryOptions = {},
|
||||
): Promise<{ agentDir: string; config: OpenClawConfig; registry: ModelRegistry }> {
|
||||
return await loadPreparedAgentModelRegistry(config, options);
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import { testing as cliBackendsTesting } from "./cli-backends.test-support.js";
|
||||
import {
|
||||
createModelPickerVisibleProviderPredicate,
|
||||
isRetiredModelPickerProvider,
|
||||
} from "./model-picker-visibility.js";
|
||||
} from "./model-runtime-aliases.js";
|
||||
import {
|
||||
areRuntimeModelRefsEquivalent,
|
||||
isCliRuntimeProvider,
|
||||
|
||||
@@ -15,6 +15,30 @@ import {
|
||||
import { resolveModelRuntimePolicy } from "./model-runtime-policy.js";
|
||||
import { resolveProviderIdForAuth } from "./provider-auth-aliases.js";
|
||||
|
||||
const RETIRED_MODEL_PICKER_PROVIDERS = new Set(["codex", "codex-cli"]);
|
||||
|
||||
/** True for retired provider ids that should stay out of model selection surfaces. */
|
||||
export function isRetiredModelPickerProvider(provider: string): boolean {
|
||||
return RETIRED_MODEL_PICKER_PROVIDERS.has(normalizeProviderId(provider));
|
||||
}
|
||||
|
||||
/** Creates a provider visibility predicate for model picker rendering. */
|
||||
export function createModelPickerVisibleProviderPredicate(
|
||||
params: { config?: OpenClawConfig; env?: NodeJS.ProcessEnv; includeSetupRegistry?: boolean } = {},
|
||||
): (provider: string) => boolean {
|
||||
const cliRuntimeProviders = new Set(
|
||||
listCliRuntimeProviderIds({
|
||||
config: params.config,
|
||||
env: params.env,
|
||||
includeSetupRegistry: params.includeSetupRegistry ?? false,
|
||||
}),
|
||||
);
|
||||
return (provider: string): boolean => {
|
||||
const normalized = normalizeProviderId(provider);
|
||||
return !isRetiredModelPickerProvider(normalized) && !cliRuntimeProviders.has(normalized);
|
||||
};
|
||||
}
|
||||
|
||||
/** True for CLI runtime provider ids such as `claude-cli` and `google-gemini-cli`. */
|
||||
export function isCliRuntimeProvider(
|
||||
provider: string,
|
||||
|
||||
@@ -3,12 +3,39 @@
|
||||
* preserved secret fields. Setup and doctor flows use this boundary to update
|
||||
* model catalogs without discarding existing credentials.
|
||||
*/
|
||||
import { normalizeProviderId } from "@openclaw/model-catalog-core/provider-id";
|
||||
import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce";
|
||||
import { isNonSecretApiKeyMarker } from "./model-auth-markers.js";
|
||||
import { resolveCatalogOwnedModelCompat } from "./model-compat-catalog.js";
|
||||
import { normalizeProviderMapKeys } from "./models-config.providers.keys.js";
|
||||
import type { ProviderConfig } from "./models-config.providers.secrets.js";
|
||||
|
||||
export function normalizeProviderMapKeys<T>(
|
||||
providers: Record<string, T> | null | undefined,
|
||||
): Record<string, T> {
|
||||
const normalized: Record<string, T> = {};
|
||||
const canonicalKeys = new Set<string>();
|
||||
for (const [key, value] of Object.entries(providers ?? {})) {
|
||||
const providerKey = normalizeProviderId(key);
|
||||
if (!providerKey) {
|
||||
continue;
|
||||
}
|
||||
if (key === providerKey) {
|
||||
canonicalKeys.add(providerKey);
|
||||
// A prior alias inserted this key at the alias's position. Reinsert it so
|
||||
// canonical spelling also controls deterministic provider order.
|
||||
delete normalized[providerKey];
|
||||
normalized[providerKey] = value;
|
||||
continue;
|
||||
}
|
||||
// Exact canonical spelling wins over aliases regardless of object order.
|
||||
// Without one, the later variant wins, matching existing trim-collision behavior.
|
||||
if (!canonicalKeys.has(providerKey)) {
|
||||
normalized[providerKey] = value;
|
||||
}
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
/** Existing provider config shape that may carry persisted secret/base URL fields. */
|
||||
export type ExistingProviderConfig = ProviderConfig & {
|
||||
apiKey?: string;
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
/** Canonical provider-key handling shared by models.json merge boundaries. */
|
||||
import { normalizeProviderId } from "@openclaw/model-catalog-core/provider-id";
|
||||
|
||||
export function normalizeProviderMapKeys<T>(
|
||||
providers: Record<string, T> | null | undefined,
|
||||
): Record<string, T> {
|
||||
const normalized: Record<string, T> = {};
|
||||
const canonicalKeys = new Set<string>();
|
||||
for (const [key, value] of Object.entries(providers ?? {})) {
|
||||
const providerKey = normalizeProviderId(key);
|
||||
if (!providerKey) {
|
||||
continue;
|
||||
}
|
||||
if (key === providerKey) {
|
||||
canonicalKeys.add(providerKey);
|
||||
// A prior alias inserted this key at the alias's position. Reinsert it so
|
||||
// canonical spelling also controls deterministic provider order.
|
||||
delete normalized[providerKey];
|
||||
normalized[providerKey] = value;
|
||||
continue;
|
||||
}
|
||||
// Exact canonical spelling wins over aliases regardless of object order.
|
||||
// Without one, the later variant wins, matching existing trim-collision behavior.
|
||||
if (!canonicalKeys.has(providerKey)) {
|
||||
normalized[providerKey] = value;
|
||||
}
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
resolveNonEnvSecretRefHeaderValueMarker,
|
||||
resolveEnvSecretRefHeaderValueMarker,
|
||||
} from "./model-auth-markers.js";
|
||||
import { normalizeProviderMapKeys } from "./models-config.providers.keys.js";
|
||||
import { normalizeProviderMapKeys } from "./models-config.merge.js";
|
||||
import type { ProviderConfig, SecretDefaults } from "./models-config.providers.secrets.js";
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
} from "./prepared-model-runtime.js";
|
||||
import { AuthStorage, type ModelRegistry } from "./sessions/index.js";
|
||||
|
||||
export type LoadPreparedAgentModelRegistryOptions = {
|
||||
type LoadPreparedAgentModelRegistryOptions = {
|
||||
agentId?: string;
|
||||
agentDir?: string;
|
||||
loadAvailability?: boolean;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Verifies provider API family helpers gate GPT parallel tool-call payloads.
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { supportsGptParallelToolCallsPayload } from "./provider-api-families.js";
|
||||
import { testing as extraParamsTesting } from "./embedded-agent-runner/extra-params.test-support.js";
|
||||
|
||||
describe("provider api families", () => {
|
||||
it.each([
|
||||
@@ -9,11 +9,13 @@ describe("provider api families", () => {
|
||||
"openai-chatgpt-responses",
|
||||
"azure-openai-responses",
|
||||
])("classifies %s as supporting the GPT parallel_tool_calls payload patch", (api) => {
|
||||
expect(supportsGptParallelToolCallsPayload(api)).toBe(true);
|
||||
expect(extraParamsTesting.supportsGptParallelToolCallsPayload(api)).toBe(true);
|
||||
});
|
||||
|
||||
it("rejects unrelated APIs", () => {
|
||||
expect(supportsGptParallelToolCallsPayload("anthropic-messages")).toBe(false);
|
||||
expect(supportsGptParallelToolCallsPayload(undefined)).toBe(false);
|
||||
expect(extraParamsTesting.supportsGptParallelToolCallsPayload("anthropic-messages")).toBe(
|
||||
false,
|
||||
);
|
||||
expect(extraParamsTesting.supportsGptParallelToolCallsPayload(undefined)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
/**
|
||||
* Small API-family predicates used when constructing provider payloads. The
|
||||
* sets here encode transport-level compatibility, not provider identity.
|
||||
*/
|
||||
const GPT_PARALLEL_TOOL_CALLS_APIS = new Set([
|
||||
"openai-completions",
|
||||
"openai-responses",
|
||||
"openai-chatgpt-responses",
|
||||
"azure-openai-responses",
|
||||
]);
|
||||
|
||||
/** True when a provider API accepts GPT parallel-tool-call payload settings. */
|
||||
export function supportsGptParallelToolCallsPayload(api: unknown): boolean {
|
||||
return typeof api === "string" && GPT_PARALLEL_TOOL_CALLS_APIS.has(api);
|
||||
}
|
||||
@@ -4,10 +4,10 @@
|
||||
* This module gathers agent/config knobs before rendering the canonical system
|
||||
* prompt so callers do not duplicate owner, TTS, alias, memory, or FS policy.
|
||||
*/
|
||||
import { normalizeOptionalString } from "@openclaw/normalization-core/string-coerce";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { buildTtsSystemPromptHint } from "../tts/tts-settings.js";
|
||||
import { resolveAgentConfig } from "./agent-scope.js";
|
||||
import { buildModelAliasLines } from "./model-alias-lines.js";
|
||||
import { resolveOwnerDisplaySetting } from "./owner-display.js";
|
||||
import { buildAgentSystemPrompt } from "./system-prompt.js";
|
||||
import { resolveEffectiveToolFsWorkspaceOnly } from "./tool-fs-policy.js";
|
||||
@@ -31,6 +31,20 @@ type ConfiguredAgentSystemPromptParams = AgentSystemPromptRenderParams & {
|
||||
agentId?: string;
|
||||
};
|
||||
|
||||
function buildModelAliasLines(cfg?: OpenClawConfig) {
|
||||
const entries: Array<{ alias: string; model: string }> = [];
|
||||
for (const [keyRaw, entryRaw] of Object.entries(cfg?.agents?.defaults?.models ?? {})) {
|
||||
const model = normalizeOptionalString(keyRaw) ?? "";
|
||||
const alias = normalizeOptionalString(entryRaw?.alias) ?? "";
|
||||
if (model && alias) {
|
||||
entries.push({ alias, model });
|
||||
}
|
||||
}
|
||||
return entries
|
||||
.toSorted((a, b) => a.alias.localeCompare(b.alias))
|
||||
.map((entry) => `- ${entry.alias}: ${entry.model}`);
|
||||
}
|
||||
|
||||
/** Resolves all config-derived system prompt fields for an agent. */
|
||||
function resolveAgentSystemPromptConfig(params: {
|
||||
config?: OpenClawConfig;
|
||||
|
||||
@@ -17,7 +17,6 @@ import {
|
||||
resolvePreparedExtraParams,
|
||||
} from "./embedded-agent-runner/extra-params.js";
|
||||
import { testing as extraParamsTesting } from "./embedded-agent-runner/extra-params.test-support.js";
|
||||
import { supportsGptParallelToolCallsPayload } from "./provider-api-families.js";
|
||||
|
||||
beforeEach(() => {
|
||||
installNoopProviderRuntimeDeps();
|
||||
@@ -74,14 +73,14 @@ describe("transport params runtime contract (embedded OpenClaw/OpenAI path)", ()
|
||||
it.each(GPT_PARALLEL_TOOL_CALLS_PAYLOAD_APIS)(
|
||||
"advertises %s as accepting the GPT parallel_tool_calls payload patch",
|
||||
(api) => {
|
||||
expect(supportsGptParallelToolCallsPayload(api)).toBe(true);
|
||||
expect(extraParamsTesting.supportsGptParallelToolCallsPayload(api)).toBe(true);
|
||||
},
|
||||
);
|
||||
|
||||
it.each(UNRELATED_TOOL_CALLS_PAYLOAD_APIS)(
|
||||
"does not advertise %s as accepting the GPT parallel_tool_calls payload patch",
|
||||
(api) => {
|
||||
expect(supportsGptParallelToolCallsPayload(api)).toBe(false);
|
||||
expect(extraParamsTesting.supportsGptParallelToolCallsPayload(api)).toBe(false);
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ import {
|
||||
resolveLogicalVisibleModelCatalog,
|
||||
type ModelCatalogAuthChecker,
|
||||
} from "../../agents/model-catalog-visibility.js";
|
||||
import { isRetiredModelPickerProvider } from "../../agents/model-picker-visibility.js";
|
||||
import { createProviderAuthChecker } from "../../agents/model-provider-auth.js";
|
||||
import { isRetiredModelPickerProvider } from "../../agents/model-runtime-aliases.js";
|
||||
import { modelCatalogLogicalKey } from "../../agents/model-selection-shared.js";
|
||||
import {
|
||||
buildModelAliasIndex,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/** Registry-loading adapters for model-list row construction. */
|
||||
import { loadAgentModelRegistry } from "../../agents/model-registry-loader.js";
|
||||
import { shouldSuppressBuiltInModel } from "../../agents/model-suppression.js";
|
||||
/** Registry-loading adapters for model-list row construction. */
|
||||
import { loadPreparedAgentModelRegistry as loadAgentModelRegistry } from "../../agents/prepared-model-registry.js";
|
||||
import type { OpenClawConfig } from "../../config/types.openclaw.js";
|
||||
import type { ModelRegistry } from "../../llm/model-registry.js";
|
||||
import type { Model } from "../../llm/types.js";
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/** Model registry access helpers for `openclaw models list`. */
|
||||
import { loadAgentModelRegistry } from "../../agents/model-registry-loader.js";
|
||||
import {
|
||||
shouldSuppressBuiltInModel,
|
||||
shouldSuppressBuiltInModelFromManifest,
|
||||
} from "../../agents/model-suppression.js";
|
||||
/** Model registry access helpers for `openclaw models list`. */
|
||||
import { loadPreparedAgentModelRegistry as loadAgentModelRegistry } from "../../agents/prepared-model-registry.js";
|
||||
import type { OpenClawConfig } from "../../config/types.openclaw.js";
|
||||
import type { ModelRegistry } from "../../llm/model-registry.js";
|
||||
import type { Model } from "../../llm/types.js";
|
||||
|
||||
@@ -11,12 +11,12 @@ import {
|
||||
} from "../agents/model-catalog-visibility.js";
|
||||
import type { ModelCatalogEntry } from "../agents/model-catalog.js";
|
||||
import type { ModelCatalogSnapshot } from "../agents/model-catalog.types.js";
|
||||
import { createModelPickerVisibleProviderPredicate } from "../agents/model-picker-visibility.js";
|
||||
import {
|
||||
createProviderAuthChecker,
|
||||
type ProviderModelAuthChecker,
|
||||
} from "../agents/model-provider-auth.js";
|
||||
import { formatLiteralProviderPrefixedModelRef } from "../agents/model-ref-shared.js";
|
||||
import { createModelPickerVisibleProviderPredicate } from "../agents/model-runtime-aliases.js";
|
||||
import {
|
||||
buildConfiguredModelCatalog,
|
||||
buildModelAliasIndex,
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
normalizeLowercaseStringOrEmpty,
|
||||
normalizeOptionalString,
|
||||
} from "@openclaw/normalization-core/string-coerce";
|
||||
import { resolveModelCatalogScope } from "../agents/model-catalog-scope.js";
|
||||
import { resolveModelCatalogScope } from "../agents/model-discovery-context.js";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { getLoadedRuntimePluginRegistry } from "./active-runtime-registry.js";
|
||||
import {
|
||||
|
||||
Reference in New Issue
Block a user