PROXY_CODEX_API openai-responses per sage-4331, untested
This commit is contained in:
1 parent
57bcdebf97
commit
ef0939e351
5 files changed
+36
-19
No files matched your search
@@ -274,3 +274,11 @@ GLM compatibility finding: thinkingFormat=zai-generated thinking.type=enabled/cl
|
||||
Both GPT shapes pass on the stand-in openai-compatibility credential route. This does not distinguish them for the Codex-login route; no Codex OAuth/auth file exists in this experiment. Evidence is INCONCLUSIVE for the production GPT choice. PROXY_CODEX_API remains null/PENDING; no source or API selection changed. Sage rules or takes to Mos per plan item5; first real Codex-auth turn stays row209 phaseA step7.
|
||||
|
||||
Niceness: attempt2 entry/emitted turn values19, explicit setPriority at entry/child start and100ms restore over owned descendants. Host policy temporarily changed processes to16 eight times; corrections restored19, disclosed here. Initial fetch end16 and failed inspection guard are retained separately, not represented as clean19 throughout. Full safe request/response receipts in evidence/offline-attempt2.txt; no auth/header value recorded. Process cleanup reports remainingManagedChildren0. Sweep over worktree and owned evidence root found same six pre-existing tool services only, no proxy/pi/timeout/chromium test leftovers. Lane B free. No mutants or other test files run.
|
||||
|
||||
## API choice and active-tool follow-up — sage-4331
|
||||
|
||||
Sage's ruling: PROXY_CODEX_API=openai-responses. The evidence does not separate the two shapes: both pass through pinned8.0.42. This is a tie broken on reasoning; it is NOT an evidence-decided pick. Sage's reason: Codex upstream speaks Responses natively and Responses carries pi's reasoning summary field, while completions drops that field; expected fewer translations/lost fields on the real route. This reasoning is a lead decision, not a claim of an authenticated Codex experiment. Row209 phaseA step7 verifies first real Codex turn; change the single constant if it fails there, with no runtime fallback/env switch. Earlier PENDING logs/notes remain historical evidence.
|
||||
|
||||
Set constant/remove pending refusal; GPT route test asserts openai-responses on mosaic-proxy-codex. Replaced temporary pending-refusal test with generated single-provider/responses/key-reference assertions per ruling. No other production change. Active plug-in docs updated.
|
||||
|
||||
Evidence script adds glm-tool mode: one GLM turn only, same pinned verified binary and isolated setup, distinct attempt3-tool root, active built-in read tool but stand-in still returns text only. Capture tool_stream and tool names before/after proxy, never header/auth values. No actual tool execution is demanded by stand-in, so this checks wire-field survival, not arbitrary tool-call semantics. Rehash before launch, no fetch,30s catalog readiness with counts,50s timeout-k10 for one turn,own descendants restored nice19. Commit untested before cleared run; then proxy-bundle and proxy-harness each whole once. No other runs/mutants.
|
||||
@@ -31,12 +31,13 @@ if (mode === 'fetch') {
|
||||
writeFileSync(join(root, 'installed.json'), JSON.stringify(installed) + '\n', { mode: 0o600, flag: 'wx' });
|
||||
emit({ phase: 'fetch', version: PIN.version, binarySha256: PIN.binary.sha256,
|
||||
panelVersion: PIN.panel.version, panelSha256: PIN.panel.sha256, enteredNice, nice: getPriority(0), verified: true });
|
||||
} else if (mode === 'offline') {
|
||||
} else if (mode === 'offline' || mode === 'glm-tool') {
|
||||
const withTool = mode === 'glm-tool';
|
||||
if (readlinkSync('/proc/self/ns/net') === process.env.P3_HOST_NET_NS) throw Error('network namespace was not isolated');
|
||||
if (Object.keys(networkInterfaces()).some(name => name !== 'lo')) throw Error('loopback-only namespace required');
|
||||
// Re-hash the already fetched assets; this function performs no network I/O.
|
||||
const installed = verifyInstall(join(root, 'data'), PIN);
|
||||
const attemptRoot = join(root, 'attempt2');
|
||||
const attemptRoot = join(root, withTool ? 'attempt3-tool' : 'attempt2');
|
||||
mkdirSync(attemptRoot, { mode: 0o700 });
|
||||
setPriority(0, 19);
|
||||
emit({ phase: 'isolation', interfaces: Object.keys(networkInterfaces()), enteredNice, nice: getPriority(0), version: PIN.version,
|
||||
@@ -60,6 +61,8 @@ if (mode === 'fetch') {
|
||||
...(Object.hasOwn(body, 'thinking') ? { thinking: body.thinking } : {}),
|
||||
...(Object.hasOwn(body, 'reasoning_effort') ? { reasoning_effort: body.reasoning_effort } : {}),
|
||||
...(Object.hasOwn(body, 'enable_thinking') ? { enable_thinking: body.enable_thinking } : {}),
|
||||
...(Object.hasOwn(body, 'tool_stream') ? { tool_stream: body.tool_stream } : {}),
|
||||
...(Array.isArray(body.tools) ? { toolNames: body.tools.map(tool => tool.function?.name) } : {}),
|
||||
...(Object.hasOwn(body, 'stream_options') ? { stream_options: body.stream_options } : {}),
|
||||
...(Object.hasOwn(body, 'max_tokens') ? { max_tokens: body.max_tokens } : {}),
|
||||
...(Object.hasOwn(body, 'max_completion_tokens') ? { max_completion_tokens: body.max_completion_tokens } : {}) });
|
||||
@@ -163,11 +166,12 @@ if (mode === 'fetch') {
|
||||
});
|
||||
const tapPort = await listen(tap);
|
||||
if (tapPort === 8317) throw Error('reserved host-proxy port excluded');
|
||||
for (const [name, api, model, compat] of [
|
||||
const scenarios = [
|
||||
['gpt-responses', 'openai-responses', 'gpt-fixture', null],
|
||||
['gpt-completions', 'openai-completions', 'gpt-fixture', null],
|
||||
['glm-completions', 'openai-completions', 'glm-fixture', { thinkingFormat: 'zai', zaiToolStream: true }],
|
||||
]) {
|
||||
];
|
||||
for (const [name, api, model, compat] of (withTool ? scenarios.filter(([name]) => name === 'glm-completions') : scenarios)) {
|
||||
const turnHome = join(attemptRoot, name, 'home');
|
||||
const agentDir = join(turnHome, '.pi', 'agent');
|
||||
mkdirSync(agentDir, { recursive: true, mode: 0o700 });
|
||||
@@ -177,18 +181,19 @@ if (mode === 'fetch') {
|
||||
writeFileSync(join(agentDir, 'settings.json'), JSON.stringify({ retry: { enabled: false, maxRetries: 0, provider: { maxRetries: 0 } } }) + '\n', { mode: 0o600, flag: 'wx' });
|
||||
const reqStart = requests.length, upstreamStart = upstreamRequests.length, responseStart = responses.length;
|
||||
const pi = managed(['50', '/usr/bin/node', join(repo, 'node_modules/@earendil-works/pi-coding-agent/dist/cli.js'),
|
||||
'--no-extensions', '--no-skills', '--no-prompt-templates', '--no-themes', '--no-context-files', '--no-session', '--no-tools',
|
||||
'--no-extensions', '--no-skills', '--no-prompt-templates', '--no-themes', '--no-context-files', '--no-session',
|
||||
...(withTool ? ['--tools', 'read'] : ['--no-tools']),
|
||||
'--provider', 'p332-probe', '--model', model, '--thinking', 'low', '-p', 'Reply P332_OFFLINE_OK only.'],
|
||||
{ env: { HOME: turnHome, PI_CODING_AGENT_DIR: agentDir, ANTHROPIC_API_KEY: fakeKeys[0] } });
|
||||
let stdout = '', stderr = '';
|
||||
pi.stdout.on('data', bytes => { stdout += bytes; });
|
||||
pi.stderr.on('data', bytes => { stderr += bytes; });
|
||||
const [exit, signal] = await once(pi, 'close');
|
||||
emit({ phase: 'turn', name, api, exit, signal, marker: stdout.includes(marker),
|
||||
emit({ phase: 'turn', name: withTool ? `${name}-tool` : name, api, exit, signal, marker: stdout.includes(marker),
|
||||
piRequests: requests.slice(reqStart), proxyResponses: responses.slice(responseStart), upstreamRequests: upstreamRequests.slice(upstreamStart),
|
||||
...(exit !== 0 ? { stderr: redact(stderr).slice(0, 1200), stdout: redact(stdout).slice(0, 1200) } : {}), nice: getPriority(0) });
|
||||
}
|
||||
emit({ phase: 'conclusion', limitation: 'Stand-in openai-compatibility credential only; no Codex OAuth credential or real-auth turn. API value remains PENDING.' });
|
||||
emit({ phase: 'conclusion', limitation: 'Stand-in openai-compatibility credential only; no Codex OAuth credential or real-auth turn. This script never selects the production API.' });
|
||||
emit({ phase: 'nice-corrections', restoredTo: 19, observedBeforeRestore: corrections });
|
||||
} catch (error) {
|
||||
emit({ phase: 'error', message: error.message, proxyDiagnostic: redact(proxyText).slice(-3000) });
|
||||
@@ -203,4 +208,4 @@ if (mode === 'fetch') {
|
||||
for (const server of [tap, upstream].filter(Boolean)) { server.closeAllConnections(); await new Promise(ok => server.close(ok)); }
|
||||
emit({ phase: 'cleanup', remainingManagedChildren: children.size });
|
||||
}
|
||||
} else { throw Error('fetch or offline phase required'); }
|
||||
} else { throw Error('fetch, offline or glm-tool phase required'); }
|
||||
@@ -64,16 +64,20 @@ test('P3 GPT route selects a stack-owned provider instead of pi Codex OAuth', t
|
||||
const providers = JSON.parse(b.text).providers;
|
||||
assert.equal(Object.hasOwn(providers, 'openai-codex'), false);
|
||||
const gpt = providers['mosaic-proxy-codex'];
|
||||
assert.equal(gpt.api, 'openai-responses');
|
||||
assert.equal(gpt.baseUrl, 'http://127.0.0.1:12345/v1');
|
||||
assert.deepEqual(gpt.models.map(m => m.id), ['gpt-fixture']);
|
||||
assert.equal(b.env.PI_PROVIDER, 'mosaic-proxy-codex');
|
||||
// Assert the one chosen API after the authorized pinned-binary probe, before claiming GREEN.
|
||||
});
|
||||
|
||||
test('P3 a declared Codex route refuses generation while the build-time API is PENDING', t => {
|
||||
assert.throws(() => build(t, 'g', { baseUrl: 'http://127.0.0.1:12345', key: 'fx332-agent-a' }, {
|
||||
test('P3 a declared Codex route generates only the single build-time responses provider', t => {
|
||||
const b = build(t, 'g', { baseUrl: 'http://127.0.0.1:12345', key: 'fx332-agent-a' }, {
|
||||
g: models.g,
|
||||
}), /proxy GPT API is PENDING build-time evidence/);
|
||||
});
|
||||
const providers = JSON.parse(b.text).providers;
|
||||
assert.deepEqual(Object.keys(providers), ['mosaic-proxy-codex']);
|
||||
assert.equal(providers['mosaic-proxy-codex'].api, 'openai-responses');
|
||||
assert.equal(providers['mosaic-proxy-codex'].apiKey, '$ANTHROPIC_API_KEY');
|
||||
});
|
||||
|
||||
test('P3 models file is private, references the one session key, and stores no executable values or keys', t => {
|
||||
|
||||
@@ -352,6 +352,7 @@ Pi writes private, fresh run-local `home/.pi/agent/models.json`, with
|
||||
`$ANTHROPIC_API_KEY` references. Anthropic uses messages at the proxy root; GLM
|
||||
uses completions at `/v1` with z.ai compatibility fields. GPT uses the stack-owned
|
||||
`mosaic-proxy-codex` provider, never pi's Codex OAuth provider. Its build-time API
|
||||
value is currently PENDING: declarations of that route refuse generation until
|
||||
the separately approved offline probe supplies evidence. There is no runtime
|
||||
API selection or fallback.
|
||||
value is `openai-responses` per Sage's sage-4331 ruling: both shapes passed the
|
||||
pinned offline probe, so this is a reasoning-based tie-break rather than an
|
||||
evidence-decided pick. Row209 phase A step7 verifies the first real Codex turn.
|
||||
There is no runtime API selection or fallback.
|
||||
@@ -13,9 +13,9 @@ export const interfaceVersion = 1;
|
||||
const REPO = fileURLToPath(new URL("../../../../", import.meta.url));
|
||||
const PACKAGE = "@earendil-works/pi-coding-agent";
|
||||
const BIN = join(REPO, "node_modules", ".bin", "pi");
|
||||
// PENDING: choose exactly once from the separately cleared, pinned-proxy probe.
|
||||
// Neither an environment override nor a runtime fallback may pick this value.
|
||||
const PROXY_CODEX_API = null;
|
||||
// Sage sage-4331: reasoning-based tie-break; both pinned-proxy shapes passed.
|
||||
// First real Codex verification remains row209 phase A step7. No runtime switch.
|
||||
const PROXY_CODEX_API = "openai-responses";
|
||||
const PROXY_PROVIDERS = Object.freeze({ anthropic: "anthropic", glm: "mosaic-proxy-glm", codex: "mosaic-proxy-codex" });
|
||||
const EXTENSION = fileURLToPath(new URL("../../../harness/src/pi-extension.mjs", import.meta.url));
|
||||
// Row 66 (#1559): the unslop check, loaded as a second extension. It logs to MOSAIC_UNSLOP_LOG,
|
||||
@@ -75,7 +75,6 @@ export function bundle({ dir, models, proxy = null }) {
|
||||
const route = entry.route;
|
||||
if (!Object.hasOwn(PROXY_PROVIDERS, route)) throw new Error("proxy model has no supported route");
|
||||
const provider = PROXY_PROVIDERS[route];
|
||||
if (route === "codex" && PROXY_CODEX_API === null) throw new Error("proxy GPT API is PENDING build-time evidence");
|
||||
if (typeof entry.model !== "string" || !entry.model || entry.model.startsWith("!")) throw new Error("unsafe proxy model id");
|
||||
const api = route === "anthropic" ? "anthropic-messages"
|
||||
: route === "glm" ? "openai-completions" : PROXY_CODEX_API;
|
||||
|
||||
Reference in new issue
Block a user