docs: document codex root plugin modules

This commit is contained in:
Peter Steinberger
2026-06-04 08:16:35 -04:00
parent 8b477d2887
commit f60943717e
8 changed files with 80 additions and 4 deletions

View File

@@ -1,3 +1,7 @@
/**
* Doctor contract hooks for Codex plugin config migrations and session-route
* ownership warnings.
*/
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
import type { DoctorSessionRouteStateOwner } from "openclaw/plugin-sdk/runtime-doctor";
@@ -17,6 +21,7 @@ function hasRetiredDynamicToolsProfile(value: unknown): boolean {
return Object.hasOwn(asRecord(value) ?? {}, "codexDynamicToolsProfile");
}
/** Legacy Codex config keys that doctor should report or repair. */
export const legacyConfigRules: LegacyConfigRule[] = [
{
path: ["plugins", "entries", "codex", "config"],
@@ -26,6 +31,9 @@ export const legacyConfigRules: LegacyConfigRule[] = [
},
];
/**
* Removes retired Codex plugin config keys while preserving unrelated config.
*/
export function normalizeCompatibilityConfig({ cfg }: { cfg: OpenClawConfig }): {
config: OpenClawConfig;
changes: string[];
@@ -56,6 +64,7 @@ export function normalizeCompatibilityConfig({ cfg }: { cfg: OpenClawConfig }):
};
}
/** Session/auth ownership metadata used by doctor route-state checks. */
export const sessionRouteStateOwners: DoctorSessionRouteStateOwner[] = [
{
id: "codex",

View File

@@ -1,3 +1,6 @@
/**
* Codex app-server agent harness registration and lazy runtime boundaries.
*/
import type {
AgentHarness,
ContextEngineHostCapability,
@@ -19,8 +22,13 @@ const CODEX_APP_SERVER_CONTEXT_ENGINE_HOST_CAPABILITIES = [
"thread-bootstrap-projection",
] as const satisfies readonly ContextEngineHostCapability[];
/** Public model-listing types exposed for Codex app-server catalog callers. */
export type { CodexAppServerListModelsOptions, CodexAppServerModel, CodexAppServerModelListResult };
/**
* Creates the Codex app-server harness used for attempts, side questions,
* compaction, reset, and disposal.
*/
export function createCodexAppServerAgentHarness(options?: {
id?: string;
label?: string;
@@ -51,6 +59,8 @@ export function createCodexAppServerAgentHarness(options?: {
};
},
runAttempt: async (params) => {
// Keep app-server runtime code behind lazy imports so plugin discovery and
// cold provider catalog reads do not pull in the whole Codex runtime.
const { runCodexAppServerAttempt } = await import("./src/app-server/run-attempt.js");
return runCodexAppServerAttempt(params, {
pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig,

View File

@@ -1,3 +1,7 @@
/**
* Bundled Codex plugin entry: app-server harness, model provider, media
* understanding, migration provider, CLI-session commands, and binding hooks.
*/
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
import { mutateConfigFile } from "openclaw/plugin-sdk/config-mutation";
import { resolveLivePluginConfigObject } from "openclaw/plugin-sdk/plugin-config-runtime";
@@ -28,6 +32,8 @@ export default definePluginEntry({
const resolveCurrentConfig = () =>
api.runtime.config?.current ? (api.runtime.config.current() as OpenClawConfig) : undefined;
const resolveCurrentPluginConfig = () =>
// Codex plugin config can change at runtime; resolve from live config for
// harness attempts and binding claims instead of keeping startup values.
resolveLivePluginConfigObject(
resolveCurrentConfig,
"codex",
@@ -92,6 +98,8 @@ export default definePluginEntry({
mutate: async (update) => {
await mutateConfigFile({
mutate: (draft) => {
// Create the nested plugin config path on demand so codex
// plugin commands can enable/update Codex-managed plugins.
const root = draft as Record<string, unknown>;
root.plugins = (root.plugins ?? {}) as Record<string, unknown>;
const pluginsBlock = root.plugins as Record<string, unknown>;

View File

@@ -1,3 +1,7 @@
/**
* Codex-backed media understanding provider for bounded image description and
* structured extraction turns.
*/
import {
type JsonSchemaObject,
validateJsonSchemaValue,
@@ -39,11 +43,16 @@ const DEFAULT_CODEX_IMAGE_MODEL =
FALLBACK_CODEX_MODELS[0]?.id;
const DEFAULT_CODEX_IMAGE_PROMPT = "Describe the image.";
/** Dependencies and plugin config for Codex media-understanding calls. */
export type CodexMediaUnderstandingProviderOptions = {
pluginConfig?: unknown;
clientFactory?: CodexAppServerClientFactory;
};
/**
* Builds the media-understanding provider that delegates image tasks to an
* isolated Codex app-server session.
*/
export function buildCodexMediaUnderstandingProvider(
options: CodexMediaUnderstandingProviderOptions = {},
): MediaUnderstandingProvider {
@@ -127,6 +136,8 @@ async function runBoundedCodexVisionTurn(params: BoundedCodexVisionTurnParams):
});
const timeoutMs = resolveTimerTimeoutMs(params.timeoutMs, 100, 100);
const ownsClient = !params.options.clientFactory;
// Tests inject a client factory; production creates an isolated app-server
// client so media tasks cannot reuse the interactive attempt session.
const client = params.options.clientFactory
? await params.options.clientFactory(appServer.start, params.profile)
: await import("./src/app-server/shared-client.js").then(
@@ -160,6 +171,8 @@ async function runBoundedCodexVisionTurn(params: BoundedCodexVisionTurnParams):
sandbox: "read-only",
serviceName: "OpenClaw",
developerInstructions: params.developerInstructions,
// Media workers are bounded read-only turns; native code mode and
// dynamic tools stay disabled to avoid side effects while inspecting media.
config: buildCodexRuntimeThreadConfig(undefined, { nativeCodeModeEnabled: false }),
environments: [],
dynamicTools: [],

View File

@@ -1,3 +1,6 @@
/**
* Codex prompt-overlay facade for GPT-5 behavior and heartbeat guidance.
*/
import {
GPT5_BEHAVIOR_CONTRACT,
GPT5_HEARTBEAT_PROMPT_OVERLAY,
@@ -5,15 +8,19 @@ import {
resolveGpt5SystemPromptContribution,
} from "openclaw/plugin-sdk/provider-model-shared";
/** GPT-5 behavior contract re-exported under the Codex provider namespace. */
export const CODEX_GPT5_BEHAVIOR_CONTRACT = GPT5_BEHAVIOR_CONTRACT;
/** Heartbeat prompt overlay re-exported under the Codex provider namespace. */
export const CODEX_GPT5_HEARTBEAT_PROMPT_OVERLAY = GPT5_HEARTBEAT_PROMPT_OVERLAY;
/** Resolves the Codex system-prompt contribution for GPT-5-family models. */
export function resolveCodexSystemPromptContribution(
params: Parameters<typeof resolveGpt5SystemPromptContribution>[0],
) {
return resolveGpt5SystemPromptContribution(params);
}
/** Renders the Codex prompt overlay text for supported GPT-5-family models. */
export function renderCodexPromptOverlay(
params: Parameters<typeof renderGpt5PromptOverlay>[0],
): string | undefined {

View File

@@ -1,16 +1,23 @@
/**
* Codex provider catalog constants and model definition helpers.
*/
import type {
ModelDefinitionConfig,
ModelProviderConfig,
} from "openclaw/plugin-sdk/provider-model-shared";
import type { CodexAppServerModel } from "./src/app-server/models.js";
/** Provider id used by Codex model refs. */
export const CODEX_PROVIDER_ID = "codex";
/** Synthetic base URL used to route Codex app-server model requests. */
export const CODEX_BASE_URL = "https://chatgpt.com/backend-api";
/** Synthetic auth marker understood by Codex app-server runtime paths. */
export const CODEX_APP_SERVER_AUTH_MARKER = "codex-app-server";
const DEFAULT_CONTEXT_WINDOW = 272_000;
const DEFAULT_MAX_TOKENS = 128_000;
/** Offline fallback catalog used when live app-server discovery is unavailable. */
export const FALLBACK_CODEX_MODELS = [
{
id: "gpt-5.5",
@@ -31,6 +38,9 @@ export const FALLBACK_CODEX_MODELS = [
},
] satisfies CodexAppServerModel[];
/**
* Converts a Codex app-server model record into OpenClaw provider model config.
*/
export function buildCodexModelDefinition(model: {
id: string;
model: string;
@@ -55,6 +65,7 @@ export function buildCodexModelDefinition(model: {
};
}
/** Builds the synthetic Codex provider config for a model list. */
export function buildCodexProviderConfig(models: CodexAppServerModel[]): ModelProviderConfig {
return {
baseUrl: CODEX_BASE_URL,

View File

@@ -1,3 +1,7 @@
/**
* Static provider discovery entry for Codex, used before the full plugin entry
* is loaded.
*/
import type { ProviderCatalogContext } from "openclaw/plugin-sdk/provider-catalog-shared";
import type { ProviderPlugin } from "openclaw/plugin-sdk/provider-model-shared";
import {
@@ -20,6 +24,7 @@ async function runCodexCatalog(ctx: ProviderCatalogContext) {
});
}
/** Provider discovery descriptor with static fallback and synthetic auth. */
export const codexProviderDiscovery: ProviderPlugin = {
id: CODEX_PROVIDER_ID,
label: "Codex",

View File

@@ -1,3 +1,6 @@
/**
* Codex provider plugin and live app-server model catalog discovery.
*/
import { createSubsystemLogger } from "openclaw/plugin-sdk/core";
import { resolvePluginConfigObject } from "openclaw/plugin-sdk/plugin-config-runtime";
import type { ProviderRuntimeModel } from "openclaw/plugin-sdk/plugin-entry";
@@ -52,6 +55,10 @@ type BuildCatalogOptions = {
onDiscoveryFailure?: (error: unknown) => void;
};
/**
* Builds the Codex provider plugin, including setup metadata, catalog discovery,
* dynamic model resolution, and prompt/thinking hooks.
*/
export function buildCodexProvider(options: BuildCodexProviderOptions = {}): ProviderPlugin {
return {
id: CODEX_PROVIDER_ID,
@@ -116,6 +123,10 @@ export function buildCodexProvider(options: BuildCodexProviderOptions = {}): Pro
};
}
/**
* Builds the Codex model catalog from live app-server discovery, falling back
* to built-in model records when discovery is disabled or unavailable.
*/
export async function buildCodexProviderCatalog(
options: BuildCatalogOptions = {},
): Promise<{ provider: ModelProviderConfig }> {
@@ -166,6 +177,8 @@ async function listModelsBestEffort(params: {
const models: CodexAppServerModel[] = [];
let cursor: string | undefined;
do {
// App-server model listing is paginated; collect every visible model so
// aliases and picker rows match the current Codex account.
const result = await params.listModels({
timeoutMs: params.timeoutMs,
limit: MODEL_DISCOVERY_PAGE_LIMIT,
@@ -231,10 +244,10 @@ function isKnownXHighCodexModel(modelId: string): boolean {
);
}
// Exported so adapter request paths (thread-lifecycle.resolveReasoningEffort)
// can branch on model-family enum support: modern Codex models use the
// none/low/medium/high/xhigh effort enum and reject "minimal", which is the
// CLI default. (#71946)
/**
* Returns true for Codex models that use the modern reasoning effort enum and
* reject the legacy CLI `minimal` default.
*/
export function isModernCodexModel(modelId: string): boolean {
const lower = modelId.trim().toLowerCase();
return (