import type { OpenClawConfig } from "../config/types.openclaw.js" ;
import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js" ;
import { resolveAgentExecutionContract, resolveSessionAgentIds } from "./agent-scope.js" ;
/**
* Strip any leading ` provider / ` or ` provider : ` prefix from a model id so the
* bare - name regex matching below works against ` openai / gpt - 5 . 4 ` and
* ` openai : gpt - 5 . 4 ` the same way it does against ` gpt - 5 . 4 ` . Returns the bare
* model id lowercased for comparison .
*
* Without this , auto - activation silently failed on prefixed model ids — a
* user who configured ` model : " openai / gpt - 5 . 4 " ` in their agent config would
* get the pre - PR - H looser default behavior because the regex only matched
* bare names . The adversarial review in # 64227 flagged this as a quality
* gap on completion - gate criterion 1 .
*/
export function stripProviderPrefix(modelId: string): string {
const normalizedModelId = modelId.trim();
const match = /^([^/:]+)[/:](.+)$/.exec(normalizedModelId);
return (match?.[2 ] ?? normalizedModelId).toLowerCase();
}
/**
* Regex that matches the full set of GPT - 5 variants the strict - agentic
* contract should auto - activate for . Intentionally permissive : every
* model id in the gpt - 5 family should opt in by default , not just the
* canonical ` gpt - 5 . 4 ` .
*
* Covers :
* - ` gpt - 5 ` , ` gpt - 5 o ` , ` gpt - 5 o - mini ` ( no separator after ` 5 ` )
* - ` gpt - 5 . 4 ` , ` gpt - 5 . 4 - alt ` , ` gpt - 5 . 0 ` ( dot separator )
* - ` gpt - 5 - preview ` , ` gpt - 5 - turbo ` , ` gpt - 5 - 2025 - 03 ` ( dash separator )
*
* Does NOT cover ` gpt - 4 . 5 ` , ` gpt - 6 ` , or any non - gpt - 5 family member .
*/
const STRICT_AGENTIC_MODEL_ID_PATTERN = /^gpt-5 (?:[.o-]|$)/i;
/**
* Supported provider + model combinations where strict - agentic is the intended
* runtime contract . Kept as a narrow helper so both the execution - contract
* resolver and the ` update_plan ` auto - enable gate converge on the same
* definition of " GPT - 5 - family openai / openai - codex run " . The embedded
* ` mock - openai ` QA lane intentionally piggybacks on that contract so repo QA
* can exercise the same incomplete - turn recovery rules end to end .
*/
export function isStrictAgenticSupportedProviderModel(params: {
provider?: string | null ;
modelId?: string | null ;
}): boolean {
const provider = normalizeLowercaseStringOrEmpty(params.provider ?? "" );
if (provider !== "openai" && provider !== "openai-codex" && provider !== "mock-openai" ) {
return false ;
}
const modelId = typeof params.modelId === "string" ? params.modelId : "" ;
const bareModelId = stripProviderPrefix(modelId);
return STRICT_AGENTIC_MODEL_ID_PATTERN.test(bareModelId);
}
/**
* Returns the effective execution contract for an embedded Pi run .
*
* strict - agentic is a GPT - 5 - family openai / openai - codex - only runtime contract ,
* so an unsupported provider / model pair always collapses to ` " default " `
* regardless of what the caller passed or what config says — the contract
* is inert off - provider . Within the supported lane , the behavior matrix is :
*
* - Supported provider / model + explicit ` " strict - agentic " ` in config
* ( defaults or per - agent override ) ⇒ ` " strict - agentic " ` .
* - Supported provider / model + explicit ` " default " ` in config ⇒ ` " default " `
* ( opt - out honored ) .
* - Supported provider / model + unspecified ⇒ ` " strict - agentic " ` so the
* no - stall completion - gate criterion applies to out - of - the - box GPT - 5 runs
* without requiring every user to set the flag .
* - Unsupported provider / model ( anything that is not openai or openai - codex
* with a gpt - 5 - family model id ) ⇒ ` " default " ` , even when the config
* explicitly sets ` " strict - agentic " ` . The retry guard and blocked - exit
* helpers all check this lane again , so an explicit ` " strict - agentic " `
* on an unsupported lane is a no - op rather than a hard failure .
*
* This means explicit opt - out still works , but the gate criterion
* " GPT - 5 . 4 no longer stalls after planning " now covers unconfigured
* installations , not only users who opted in manually .
*/
export function resolveEffectiveExecutionContract(params: {
config?: OpenClawConfig;
sessionKey?: string;
agentId?: string | null ;
provider?: string | null ;
modelId?: string | null ;
}): "default" | "strict-agentic" {
const { sessionAgentId } = resolveSessionAgentIds({
sessionKey: params.sessionKey,
config: params.config,
agentId: params.agentId ?? undefined,
});
const explicit = resolveAgentExecutionContract(params.config, sessionAgentId);
// strict-agentic is a GPT-5-family openai/openai-codex runtime contract
// regardless of whether it was set explicitly or auto-activated. On an
// unsupported provider/model pair the contract is inert either way, so
// the effective value collapses to "default".
const supported = isStrictAgenticSupportedProviderModel({
provider: params.provider,
modelId: params.modelId,
});
if (!supported) {
return "default" ;
}
if (explicit === "default" ) {
return "default" ;
}
// Explicit strict-agentic OR unspecified-but-supported → strict-agentic.
return "strict-agentic" ;
}
export function isStrictAgenticExecutionContractActive(params: {
config?: OpenClawConfig;
sessionKey?: string;
agentId?: string | null ;
provider?: string | null ;
modelId?: string | null ;
}): boolean {
return resolveEffectiveExecutionContract(params) === "strict-agentic" ;
}
Messung V0.5 in Prozent C=93 H=100 G=96
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet am 2026-06-09)
¤
*© Formatika GbR, Deutschland