Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
bba9f4b
test(adapters): verify routed Code Mode keeps apply_patch usable
Wibias Aug 13, 2026
e8c1317
test(adapters): cover apply_patch translation round trip
Wibias Aug 13, 2026
38bbb0c
test: extend routed patch regression coverage
Wibias Aug 13, 2026
83a4222
test: correct routed regression assertion
Wibias Aug 13, 2026
89a4c73
test: guard apply_patch across routed adapter nudges
Wibias Aug 13, 2026
add4229
test: enforce catalog nudge coverage completeness
Wibias Aug 13, 2026
f1946dc
test(adapters): assert nested apply_patch declaration survives
Wibias Aug 13, 2026
56bd9cf
test(cursor): pin apply_patch native mutation policy
Wibias Aug 13, 2026
da63a8a
test: pin routed catalog patch contract
Wibias Aug 13, 2026
ff85971
test: cover responses native patch contract
Wibias Aug 13, 2026
9a06659
test: classify every adapter patch strategy
Wibias Aug 13, 2026
8468a28
test: fix responses adapter harness
Wibias Aug 13, 2026
cf7e8ff
normalize routed catalog metadata
Wibias Aug 13, 2026
84f0d37
test: scope catalog patch normalization
Wibias Aug 13, 2026
6534475
test: verify resolved apply_patch strategies
Wibias Aug 13, 2026
87e92f0
test(adapters): add C+ registry conformance gate
Wibias Aug 13, 2026
d88e0e1
refactor(adapters): route construction through registry
Wibias Aug 13, 2026
db0cc98
feat(adapters): add authoritative C+ registry
Wibias Aug 13, 2026
3887f57
test(adapters): narrow C+ bypass detector
Wibias Aug 13, 2026
1841484
test(adapters): add protocol-keyed C+ wire drivers
Wibias Aug 13, 2026
635b86d
test(adapters): execute C+ request conformance for registry
Wibias Aug 13, 2026
9311c38
test(adapters): remove reflective adapter completeness parser
Wibias Aug 13, 2026
6c0c905
test(adapters): add apply_patch conformance contract oracle
Wibias Aug 13, 2026
fa8960c
test(adapters): mutation-test C+ conformance oracle
Wibias Aug 13, 2026
c7c3af7
test(adapters): add provider-native tool response drivers
Wibias Aug 13, 2026
6ecd3c2
test(adapters): release observed request budgets
Wibias Aug 13, 2026
f257c43
test(adapters): round-trip apply_patch through every parsed wire
Wibias Aug 13, 2026
31e540e
fix(adapters): satisfy typed registry construction
Wibias Aug 13, 2026
3c602fc
test(adapters): complete C+ apply_patch conformance matrix
Wibias Aug 13, 2026
8096413
testability(adapters): thread Cursor transport deps through registry …
Wibias Aug 13, 2026
0303880
testability(cursor): pass existing runTurn seam through registry
Wibias Aug 13, 2026
d253feb
test(cursor): exercise registry runTurn path
Wibias Aug 13, 2026
e9b3d3b
test(cursor): align registry runTurn error assertion
Wibias Aug 13, 2026
713cbc5
refactor(adapters): keep generic contracts Cursor-agnostic
Wibias Aug 13, 2026
b1c408d
refactor(adapters): keep Cursor test deps inside registry boundary
Wibias Aug 13, 2026
a4e81d6
test(cursor): match disabled registry transport error
Wibias Aug 13, 2026
e67529e
test(adapters): enforce tool_choice none by wire semantics
Wibias Aug 13, 2026
29fdbc3
test: isolate conformance request observation
Wibias Aug 14, 2026
44bfcf1
fix: isolate MiMo conformance auth
Wibias Aug 14, 2026
57e895d
fix: expose deterministic adapter test deps
Wibias Aug 14, 2026
b86b926
test: preserve explicit routed patch tool type
Wibias Aug 14, 2026
f361cb6
fix: preserve explicit routed patch tool type
Wibias Aug 14, 2026
be4658d
test: cover Cursor apply_patch runTurn roundtrip
Wibias Aug 14, 2026
807b017
test: harden adapter registry conformance
Wibias Aug 14, 2026
00ed5ce
fix: route lab adapter construction through registry
Wibias Aug 14, 2026
472ebd1
test: fix TypeScript AST runtime import
Wibias Aug 14, 2026
b547464
test: use Bun parser for registry enforcement
Wibias Aug 14, 2026
571e511
test: detect adapter factory bypasses without blocking shared imports
Wibias Aug 14, 2026
500b5e7
fix: restore Kiro tool-name assertion after guard refactor
Wibias Aug 14, 2026
2b03b92
fix: preserve MiMo buildRequest compatibility
Wibias Aug 14, 2026
52f3379
fix: harden adapter registry invariants
Wibias Aug 14, 2026
a955d64
test: enforce registry parent types in source gate
Wibias Aug 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions src/adapters/azure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@ import type { IncomingMeta, ProviderAdapter } from "./base";
import type { OcxParsedRequest, OcxProviderConfig } from "../types";
import { createResponsesPassthroughAdapter } from "./openai-responses";

export function createAzureAdapter(provider: OcxProviderConfig): ProviderAdapter & { passthrough: true } {
const inner = createResponsesPassthroughAdapter({
export function createAzureAdapter(
provider: OcxProviderConfig,
inner: ProviderAdapter = createResponsesPassthroughAdapter({
...provider,
baseUrl: provider.baseUrl,
});

}),
): ProviderAdapter & { passthrough: true } {
return {
...inner,
name: "azure-openai",
passthrough: true,

async buildRequest(parsed: OcxParsedRequest, incoming: IncomingMeta) {
if (provider.authMode === "forward") {
Expand Down
98 changes: 98 additions & 0 deletions src/adapters/contracts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import type { OcxProviderConfig } from "../types";
import type { ProviderAdapter } from "./base";

export const REQUIRED_ROUTED_TOOL_CONTRACTS = [
"tools.code-mode-nested-helper",
"tools.freeform-exact-roundtrip",
"tools.tool-choice-final-catalog",
"tools.continuation-replay",
] as const;

export type RequiredRoutedToolContract = typeof REQUIRED_ROUTED_TOOL_CONTRACTS[number];

export type MutationContract =
| "mutation.codex-owned"
| "mutation.codex-owned-with-gated-native-fallback";

export type AdapterWire =
| "openai-chat"
| "anthropic"
| "google"
| "command-code"
| "kiro"
| "openai-responses"
| "cursor";

export type AdapterCacheRetention = "none" | "short" | "long";

export interface AdapterFactoryContext {
cacheRetention?: AdapterCacheRetention;
}

export type AdapterFactory = (
provider: OcxProviderConfig,
context: AdapterFactoryContext,
) => ProviderAdapter;

export type AdapterWrapperFactory = (
parent: ProviderAdapter,
provider: OcxProviderConfig,
context: AdapterFactoryContext,
) => ProviderAdapter;

export interface DirectAdapterDefinitionInput {
kind: "direct";
wire: AdapterWire;
mutation: MutationContract;
create: AdapterFactory;
}

export interface WrappedAdapterDefinitionInput {
kind: "wrapper";
extends: string;
wrap: AdapterWrapperFactory;
}

export type AdapterDefinitionInput = DirectAdapterDefinitionInput | WrappedAdapterDefinitionInput;

export type AdapterDefinition<T extends AdapterDefinitionInput = AdapterDefinitionInput> = Readonly<
T & { requiredToolContracts: typeof REQUIRED_ROUTED_TOOL_CONTRACTS }
>;

type ValidAdapterRegistry<T extends Record<string, AdapterDefinitionInput>> = {
[K in keyof T]: T[K] extends WrappedAdapterDefinitionInput
? T[K]["extends"] extends Exclude<keyof T, K>
? T[K]
: never
: T[K];
};

type AssertNever<T extends never> = T;
type _UnknownWrapperParentIsRejected = AssertNever<
ValidAdapterRegistry<{
base: DirectAdapterDefinitionInput;
broken: WrappedAdapterDefinitionInput & { extends: "not-registered" };
}>["broken"]
>;
type _SelfWrapperParentIsRejected = AssertNever<
ValidAdapterRegistry<{
self: WrappedAdapterDefinitionInput & { extends: "self" };
}>["self"]
>;

export function defineAdapterRegistry<const T extends Record<string, AdapterDefinitionInput>>(
definitions: T & ValidAdapterRegistry<T>,
): { readonly [K in keyof T]: AdapterDefinition<T[K]> } {
const registered = Object.fromEntries(
Object.entries(definitions).map(([id, definition]) => [
id,
Object.freeze({
...definition,
requiredToolContracts: REQUIRED_ROUTED_TOOL_CONTRACTS,
}),
]),
);
return Object.freeze(registered) as unknown as {
readonly [K in keyof T]: AdapterDefinition<T[K]>;
};
}
22 changes: 16 additions & 6 deletions src/adapters/mimo-free.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,20 @@ export function injectMimoSystemMarker(body: unknown): unknown {
* 1. JWT from the bootstrap endpoint (cached, auto-refreshed).
* 2. Anti-abuse system marker in the request body.
* 3. Required headers (User-Agent, X-Mimo-Source, x-session-affinity).
* On 401/403, flushes the JWT cache and retries once via fetchResponse.
* On 401, flushes the JWT cache and retries once via fetchResponse.
*/
export function createMimoFreeAdapter(provider: OcxProviderConfig): ProviderAdapter {
const base = createOpenAIChatAdapter(provider);
export interface MimoFreeAdapterDeps {
getJwt?: (signal?: AbortSignal) => Promise<string>;
resetJwt?: () => void;
}

export function createMimoFreeAdapter(
provider: OcxProviderConfig,
deps: MimoFreeAdapterDeps = {},
base: ProviderAdapter = createOpenAIChatAdapter(provider),
): ProviderAdapter {
const getJwt = deps.getJwt ?? getMimoJwt;
const resetJwt = deps.resetJwt ?? resetMimoJwtCache;
// Per-adapter session-affinity id (random, per process instance).
const sessionId = `ses_${Math.random().toString(36).slice(2, 26)}`;

Expand All @@ -203,7 +213,7 @@ export function createMimoFreeAdapter(provider: OcxProviderConfig): ProviderAdap
name: "mimo-free",

async buildRequest(parsed: OcxParsedRequest, incoming: IncomingMeta): Promise<AdapterRequest> {
const jwt = await getMimoJwt();
const jwt = await getJwt(incoming?.abortSignal);

// Let the base adapter build the wire body (handles reasoning, tools, etc.)
// but override the URL and headers after.
Expand Down Expand Up @@ -243,8 +253,8 @@ export function createMimoFreeAdapter(provider: OcxProviderConfig): ProviderAdap
if (response.status === 401) {
// Drain the first response body before issuing the retry.
try { await response.body?.cancel(); } catch { /* already consumed */ }
resetMimoJwtCache();
const freshJwt = await getMimoJwt(ctx?.abortSignal);
resetJwt();
const freshJwt = await getJwt(ctx?.abortSignal);
const retryHeaders = {
...(request.headers as Record<string, string>),
"Authorization": `Bearer ${freshJwt}`,
Expand Down
166 changes: 166 additions & 0 deletions src/adapters/registry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import { createAnthropicAdapter } from "./anthropic";
import { createAzureAdapter } from "./azure";
import type { ProviderAdapter } from "./base";
import { createCursorAdapter, type CursorAdapterDeps } from "./cursor";
import { createGoogleAdapter } from "./google";
import { createKiroAdapter } from "./kiro";
import { createMimoFreeAdapter, type MimoFreeAdapterDeps } from "./mimo-free";
import { createOpenAIChatAdapter } from "./openai-chat";
import { createCommandCodeAdapter } from "./command-code";
import { createResponsesPassthroughAdapter } from "./openai-responses";
import type { OcxProviderConfig } from "../types";
import {
defineAdapterRegistry,
type AdapterDefinition,
type AdapterFactoryContext,
type DirectAdapterDefinitionInput,
} from "./contracts";

type RegistryFactoryContext = AdapterFactoryContext & {
cursorDeps?: CursorAdapterDeps;
mimoDeps?: MimoFreeAdapterDeps;
};

function createRegisteredCursorAdapter(provider: OcxProviderConfig, context: AdapterFactoryContext) {
return createCursorAdapter(provider, (context as RegistryFactoryContext).cursorDeps);
}

function wrapRegisteredMimoFreeAdapter(
parent: ProviderAdapter,
provider: OcxProviderConfig,
context: AdapterFactoryContext,
) {
return createMimoFreeAdapter(
provider,
(context as RegistryFactoryContext).mimoDeps,
parent,
);
}

export const ADAPTER_REGISTRY = defineAdapterRegistry({
"command-code": {
kind: "direct",
wire: "command-code",
mutation: "mutation.codex-owned",
create: provider => createCommandCodeAdapter(provider),
},
"openai-chat": {
kind: "direct",
wire: "openai-chat",
mutation: "mutation.codex-owned",
create: provider => createOpenAIChatAdapter(provider),
},
anthropic: {
kind: "direct",
wire: "anthropic",
mutation: "mutation.codex-owned",
create: (provider, context) => createAnthropicAdapter(provider, context.cacheRetention),
},
"openai-responses": {
kind: "direct",
wire: "openai-responses",
mutation: "mutation.codex-owned",
create: provider => createResponsesPassthroughAdapter(provider),
},
google: {
kind: "direct",
wire: "google",
mutation: "mutation.codex-owned",
create: provider => createGoogleAdapter(provider),
},
kiro: {
kind: "direct",
wire: "kiro",
mutation: "mutation.codex-owned",
create: provider => createKiroAdapter(provider),
},
azure: {
kind: "wrapper",
extends: "openai-responses",
wrap: (parent, provider) => createAzureAdapter(provider, parent),
},
"azure-openai": {
kind: "wrapper",
extends: "openai-responses",
wrap: (parent, provider) => createAzureAdapter(provider, parent),
},
cursor: {
kind: "direct",
wire: "cursor",
mutation: "mutation.codex-owned-with-gated-native-fallback",
create: createRegisteredCursorAdapter,
},
"mimo-free": {
kind: "wrapper",
extends: "openai-chat",
wrap: wrapRegisteredMimoFreeAdapter,
},
});

export type AdapterId = keyof typeof ADAPTER_REGISTRY;
export type RegisteredAdapterDefinition = typeof ADAPTER_REGISTRY[AdapterId];
export type EffectiveAdapterContract = AdapterDefinition<DirectAdapterDefinitionInput>;

export function adapterDefinitions(): Array<[AdapterId, RegisteredAdapterDefinition]> {
return Object.entries(ADAPTER_REGISTRY) as Array<[AdapterId, RegisteredAdapterDefinition]>;
}

export function getAdapterDefinition(adapterId: string): RegisteredAdapterDefinition | undefined {
return ADAPTER_REGISTRY[adapterId as AdapterId];
}

export function effectiveAdapterContract(adapterId: string): EffectiveAdapterContract {
const visited = new Set<string>();
let current = adapterId;

while (true) {
if (visited.has(current)) {
throw new Error(`Adapter wrapper cycle detected at ${current}`);
}
visited.add(current);

const definition = getAdapterDefinition(current);
if (!definition) throw new Error(`Unknown adapter: ${current}`);
if (definition.kind === "direct") return definition;
current = definition.extends;
}
}

function createRegisteredAdapterById(
adapterId: string,
provider: OcxProviderConfig,
context: RegistryFactoryContext,
visited: ReadonlySet<string>,
): ProviderAdapter {
if (visited.has(adapterId)) {
throw new Error(`Adapter wrapper cycle detected at ${adapterId}`);
}

const definition = getAdapterDefinition(adapterId);
if (!definition) throw new Error(`Unknown adapter: ${adapterId}`);

const adapterProvider = provider.adapter === adapterId
? provider
: { ...provider, adapter: adapterId };

if (definition.kind === "direct") {
return definition.create(adapterProvider, context);
}

const nextVisited = new Set(visited);
nextVisited.add(adapterId);
const parent = createRegisteredAdapterById(
definition.extends,
adapterProvider,
context,
nextVisited,
);
return definition.wrap(parent, adapterProvider, context);
}

export function createRegisteredAdapter(
provider: OcxProviderConfig,
context: RegistryFactoryContext = {},
): ProviderAdapter {
return createRegisteredAdapterById(provider.adapter, provider, context, new Set());
}
11 changes: 9 additions & 2 deletions src/lab/conformance/executor.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { createOpenAIChatAdapter } from "../../adapters/openai-chat";
import { createResponsesPassthroughAdapter } from "../../adapters/openai-responses";
import { createRegisteredAdapter } from "../../adapters/registry";
import { bridgeToResponsesSSE, buildResponseJSON } from "../../bridge";
import { anthropicToResponsesTranslation } from "../../claude/inbound";
import { responsesSseToAnthropicSse } from "../../claude/outbound";
Expand All @@ -25,6 +24,14 @@ import {
import { normalizeSseBytes } from "./sse-normalize";
import type { CaseRecord, NormalizedObservation, ScenarioRunResult, ProtocolExecutionContextV1 } from "./types";

function createOpenAIChatAdapter(provider: OcxProviderConfig) {
return createRegisteredAdapter({ ...provider, adapter: "openai-chat" });
}

function createResponsesPassthroughAdapter(provider: OcxProviderConfig) {
return createRegisteredAdapter({ ...provider, adapter: "openai-responses" });
}

export function resolveProtocolExecutionContext(caseRecord: CaseRecord): ProtocolExecutionContextV1 {
const inbound = caseRecord.requirements.inboundProtocols[0] ?? "openai-responses";
const upstream = caseRecord.requirements.upstreamProtocols[0] ?? "openai-chat";
Expand Down
Loading
Loading