Files
openclaw/src/agents/schema-normalization-runtime-contract.test.ts
EVA 860dad268d [codex] Add contract-first Pi/Codex runtime plan suite (#71096)
* test: add pi codex runtime contract coverage

* test: expand pi codex tool runtime contracts

* test: tighten tool runtime contracts

* test: reset tool contract param cache

* test: document codex tool middleware fixture

* test: type pi tool contract events

* test: satisfy pi tool contract test types

* test: cover tool media telemetry contracts

* test: reset plugin runtime after tool contracts

* test: add auth profile runtime contracts

* test: strengthen auth profile runtime contracts

* test: clarify auth profile contract fixtures

* test: expand auth profile contract matrix

* test: assert unrelated cli auth isolation

* test: expand auth profile contract matrix

* test: tighten auth profile contract expectations

* test: add outcome fallback runtime contracts

* test: strengthen outcome fallback contracts

* test: isolate outcome fallback contracts

* test: cover codex terminal outcome signals

* test: expand terminal fallback contracts

* test: add delivery no reply runtime contracts

* test: document json no-reply delivery gap

* test: align delivery contract fixtures

* test: add transcript repair runtime contracts

* test: tighten transcript repair contracts

* test: add prompt overlay runtime contracts

* test: tighten prompt overlay contract scope

* test: type prompt overlay contracts

* test: add schema normalization runtime contracts

* test: clarify schema normalization contract gaps

* test: simplify schema normalization contracts

* test: tighten schema normalization contract gaps

* test: cover compaction schema contract

* test: satisfy schema contract lint

* test: add transport params runtime contracts

* test: tighten transport params contract scope

* test: isolate transport params contracts

* test: lock exact transport defaults

* feat: add agent runtime plan foundation

* fix: preserve codex harness auth profiles

* fix: route followup delivery through runtime plan

* fix: normalize parameter-free openai tool schemas

* fix: satisfy runtime plan type checks

* fix: narrow followup delivery runtime planning

* fix: apply codex app-server auth profiles

* fix: classify codex terminal outcomes

* fix: prevent harness auth leakage into unrelated cli providers

* feat: expand agent runtime plan policy contract

* fix: route pi runtime policy through runtime plan

* fix: route codex runtime policy through runtime plan

* fix: route fallback outcome classification through runtime plan

* refactor: make runtime plan contracts topology-safe

* fix: restore runtime plan test type coverage

* fix: align runtime plan schema contract assertions

* fix: stabilize incomplete turn runtime tests

* fix: stabilize codex native web search test

* fix: preserve codex auth profile secret refs

* fix: keep runtime resolved refs canonical

* fix: preserve permissive nested openai schemas

* fix: accept Codex auth provider aliases

* test: update media-only groups mock

* fix: resolve runtime plan rebase checks

* fix: resolve runtime plan rebase checks

---------

Co-authored-by: Eva <eva@100yen.org>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-04-24 18:34:01 +01:00

108 lines
4.6 KiB
TypeScript

import type { StreamFn } from "@mariozechner/pi-agent-core";
import { describe, expect, it } from "vitest";
import {
createNativeOpenAIResponsesModel,
createParameterFreeTool,
createPermissiveTool,
createStrictCompatibleTool,
normalizedParameterFreeSchema,
} from "../../test/helpers/agents/schema-normalization-runtime-contract.js";
import { buildProviderToolCompatFamilyHooks } from "../plugin-sdk/provider-tools.js";
import { buildOpenAIResponsesParams } from "./openai-transport-stream.js";
import { convertTools as convertWebSocketTools } from "./openai-ws-message-conversion.js";
import { createOpenAIResponsesContextManagementWrapper } from "./pi-embedded-runner/openai-stream-wrappers.js";
describe("OpenAI transport schema normalization runtime contract", () => {
it("keeps HTTP Responses and WebSocket strict decisions aligned for the same tool set", () => {
const tools = [createStrictCompatibleTool(), createPermissiveTool()] as never;
const httpParams = buildOpenAIResponsesParams(
createNativeOpenAIResponsesModel() as never,
{ systemPrompt: "system", messages: [], tools } as never,
undefined,
) as { tools?: Array<{ strict?: boolean; parameters?: unknown }> };
const wsTools = convertWebSocketTools(tools, { strict: true });
expect(httpParams.tools?.map((tool) => tool.strict)).toEqual([false, false]);
expect(wsTools.map((tool) => tool.strict)).toEqual([false, false]);
});
it("normalizes parameter-free tool schemas to the same strict-compatible object shape for HTTP Responses and WebSocket", () => {
const tools = [createParameterFreeTool()] as never;
const httpParams = buildOpenAIResponsesParams(
createNativeOpenAIResponsesModel() as never,
{ systemPrompt: "system", messages: [], tools } as never,
undefined,
) as { tools?: Array<{ strict?: boolean; parameters?: unknown }> };
const wsTools = convertWebSocketTools(tools, { strict: true });
const normalizedSchema = normalizedParameterFreeSchema();
expect(httpParams.tools?.[0]?.strict).toBe(true);
expect(wsTools[0]?.strict).toBe(true);
expect(httpParams.tools?.[0]?.parameters).toEqual(normalizedSchema);
expect(wsTools[0]?.parameters).toEqual(normalizedSchema);
});
it("keeps provider-prepared parameter-free schemas strict-compatible across HTTP Responses and WebSocket", () => {
const hooks = buildProviderToolCompatFamilyHooks("openai");
const tools = hooks.normalizeToolSchemas({
provider: "openai",
modelId: "gpt-5.4",
modelApi: "openai-responses",
tools: [createParameterFreeTool()] as never,
}) as never;
const httpParams = buildOpenAIResponsesParams(
createNativeOpenAIResponsesModel() as never,
{ systemPrompt: "system", messages: [], tools } as never,
undefined,
) as { tools?: Array<{ strict?: boolean; parameters?: unknown }> };
const wsTools = convertWebSocketTools(tools, { strict: true });
const normalizedSchema = normalizedParameterFreeSchema();
expect(httpParams.tools?.[0]?.strict).toBe(true);
expect(wsTools[0]?.strict).toBe(true);
expect(httpParams.tools?.[0]?.parameters).toEqual(normalizedSchema);
expect(wsTools[0]?.parameters).toEqual(normalizedSchema);
});
it("passes prepared executable schemas through compaction-triggered Responses requests", () => {
const hooks = buildProviderToolCompatFamilyHooks("openai");
const tools = hooks.normalizeToolSchemas({
provider: "openai",
modelId: "gpt-5.4",
modelApi: "openai-responses",
tools: [createParameterFreeTool()] as never,
}) as never;
const model = createNativeOpenAIResponsesModel() as never;
let payload:
| { context_management?: unknown; tools?: Array<{ parameters?: unknown }> }
| undefined;
const baseStreamFn: StreamFn = (modelArg, contextArg, optionsArg) => {
payload = buildOpenAIResponsesParams(
modelArg,
{
...(contextArg as unknown as Record<string, unknown>),
systemPrompt: "system",
messages: [],
tools,
} as never,
optionsArg as never,
) as typeof payload;
optionsArg?.onPayload?.(payload, modelArg);
return {} as ReturnType<StreamFn>;
};
const streamFn = createOpenAIResponsesContextManagementWrapper(baseStreamFn, {
responsesServerCompaction: true,
});
void streamFn(model, { systemPrompt: "system", messages: [], tools } as never, {});
expect(payload?.context_management).toEqual([
{
type: "compaction",
compact_threshold: 140_000,
},
]);
expect(payload?.tools?.[0]?.parameters).toEqual(normalizedParameterFreeSchema());
});
});