FN-7754: seed OpenAI GPT-5.6 Codex models into pi createFnAgent registry

Wires the GPT-5.6 codenamed OpenAI Codex models (gpt-5.6-luna/sol/terra) into the engine pi model-registry seeding surface, mirroring the dashboard's /api/models supplemental merge so the models are no longer missing from pi.

- Call mergeSupplementalOpenAiCodexModels() in createFnAgent (packages/engine/src/pi.ts) alongside the existing Anthropic supplemental merge
- Add regression tests covering synthesis of missing GPT-5.6 rows and dedupe against pinned catalog entries
- Update docs/settings-reference.md to describe the additive surfacing on both /api/models and the engine/pi registry-seeding path
- Add a patch changeset for @runfusion/fusion

Files changed:
 .changeset/fn-7754-openai-gpt-5-6-pi-surface.md    |  7 +++
 docs/settings-reference.md                         |  2 +-
 .../src/__tests__/pi-create-fn-agent.test.ts       | 63 ++++++++++++++++++++++
 packages/engine/src/pi.ts                          |  6 +++
 4 files changed, 77 insertions(+), 1 deletion(-)

Fusion-Task-Id: FN-7754

Fusion-Task-Lineage: b61b6812-c94b-46d8-b187-445ccdd6e4e9

Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
gsxdsm
2026-07-09 21:30:34 -07:00
parent 9ce0b49054
commit d2c2a4cab1
4 changed files with 77 additions and 1 deletions

View File

@@ -0,0 +1,7 @@
---
"@runfusion/fusion": patch
---
summary: The latest OpenAI GPT-5.6 models now appear everywhere, not just the Settings model list.
category: fix
dev: Wires mergeSupplementalOpenAiCodexModels into the engine pi createFnAgent registry-seeding surface (packages/engine/src/pi.ts) alongside the existing mergeSupplementalAnthropicModels call, mirroring register-model-routes.ts. FN-7745 only wired the dashboard /api/models route, so gpt-5.6-luna/sol/terra were absent on the pi surface. Additive, dedupe-safe; adds a pi-create-fn-agent regression test.

View File

@@ -977,7 +977,7 @@ When the Cursor Runtime plugin (`fusion-plugin-cursor-runtime`) is installed and
When the Grok Runtime plugin (`fusion-plugin-grok-runtime`) is installed and the `useGrokCli` toggle is enabled (Settings → Authentication), Grok CLI-discovered models (`grok models`) are surfaced additively in `/api/models` under the `grok-cli` provider — id/name derived from the discovered model id/label. This surfacing is fetched through a short-TTL, single-flight cache so the model picker never spawns `grok` on every request; a missing/failed/unavailable Grok CLI binary simply yields zero `grok-cli` rows without affecting other providers. Disabling `useGrokCli` hides all `grok-cli` rows. Unlike Cursor (OAuth/session auth), Grok is API-key auth: the Settings card's status text guides operators to `GROK_API_KEY` or `~/.grok/user-settings.json` when the binary is available but no key is configured.
The three GPT-5.6 codenamed OpenAI Codex variants (`gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`) are additively surfaced under the `openai-codex` provider (FN-7745, mirroring the Anthropic/Z.ai supplemental-merge pattern above) so they appear in `/api/models` whenever `openai-codex` is configured — deduped against any pinned pi-ai catalog row that already carries one of the ids.
The three GPT-5.6 codenamed OpenAI Codex variants (`gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`) are additively surfaced under the `openai-codex` provider (FN-7745/FN-7754, mirroring the Anthropic/Z.ai supplemental-merge pattern above) so they appear both in dashboard `/api/models` and the engine/pi `createFnAgent` registry-seeding surface whenever `openai-codex` is configured — deduped against any pinned pi-ai catalog row that already carries one of the ids.
### Planning model

View File

@@ -1932,6 +1932,69 @@ describe("createFnAgent", () => {
expect(anthropicRegistrations).toHaveLength(0);
});
it("synthesizes OpenAI Codex GPT-5.6 models from supplemental metadata when the pi registry lacks them", async () => {
// FNXC:ModelCatalog 2026-07-09-00:00:
// FN-7754 regression coverage for the createFnAgent registry-seeding surface: a pi catalog with no openai-codex provider/models must still surface all GPT-5.6 codenamed variants through the shared additive supplemental merge.
getAllMock.mockReturnValue([]);
findMock.mockImplementation((provider: string, modelId: string) => ({ provider, id: modelId }));
const { createFnAgent } = await import("../pi.js");
await createFnAgent({
cwd: "/tmp",
systemPrompt: "test",
tools: "readonly",
defaultProvider: "openai-codex",
defaultModelId: "gpt-5.6-luna",
});
expect(registerProviderMock).toHaveBeenCalledWith("openai-codex", expect.objectContaining({
models: expect.arrayContaining([
expect.objectContaining({ id: "gpt-5.6-luna" }),
expect.objectContaining({ id: "gpt-5.6-sol" }),
expect.objectContaining({ id: "gpt-5.6-terra" }),
]),
}));
expect(createAgentSessionMock).toHaveBeenCalledWith(expect.objectContaining({
model: { provider: "openai-codex", id: "gpt-5.6-luna" },
}));
});
it("does not duplicate OpenAI Codex GPT-5.6 rows already present in the pi registry", async () => {
const existingLunaRow = {
provider: "openai-codex",
id: "gpt-5.6-luna",
name: "GPT-5.6 Luna Upstream",
reasoning: true,
input: ["text"],
cost: { input: 1, output: 2 },
contextWindow: 200_000,
maxTokens: 16_000,
};
getAllMock.mockReturnValue([existingLunaRow]);
findMock.mockImplementation((provider: string, modelId: string) => ({ provider, id: modelId }));
const { createFnAgent } = await import("../pi.js");
await createFnAgent({
cwd: "/tmp",
systemPrompt: "test",
tools: "readonly",
defaultProvider: "openai-codex",
defaultModelId: "gpt-5.6-luna",
});
const openAiCodexRegistrations = registerProviderMock.mock.calls.filter(([name]) => name === "openai-codex");
expect(openAiCodexRegistrations).toHaveLength(1);
const registeredProvider = openAiCodexRegistrations[0]?.[1] as { models: Array<{ id: string; name?: string }> };
const registeredModels = registeredProvider.models;
const lunaRows = registeredModels.filter((model) => model.id === "gpt-5.6-luna");
expect(lunaRows).toHaveLength(1);
expect(lunaRows[0]).toMatchObject({ name: "GPT-5.6 Luna Upstream" });
expect(registeredModels).toEqual(expect.arrayContaining([
expect.objectContaining({ id: "gpt-5.6-sol" }),
expect.objectContaining({ id: "gpt-5.6-terra" }),
]));
});
// Restored v0.51.0 behavior: a subscription-OAuth `anthropic/<model>` selection stays on
// the built-in `anthropic` provider (pi-ai POSTs the OAuth token to /v1 with Claude Code
// impersonation). No `/v1`-based `anthropic-subscription` provider is registered, and there

View File

@@ -45,6 +45,7 @@ import {
mergeBuiltInGrokProviderModels,
mergeBuiltInZaiProviderModels,
mergeSupplementalAnthropicModels,
mergeSupplementalOpenAiCodexModels,
registerBuiltInGrokProvider,
registerBuiltInZaiProvider,
resolvePiExtensionProjectRoot,
@@ -2121,6 +2122,11 @@ export async function createFnAgent(options: AgentOptions): Promise<AgentResult>
}
modelRegistry.refresh();
mergeSupplementalAnthropicModels(modelRegistry, (message) => extensionsLog.warn(message));
/*
* FNXC:ModelCatalog 2026-07-09-00:00:
* FN-7754 mirrors the dashboard register-model-routes.ts supplemental merge seam so the GPT-5.6 codenamed OpenAI-Codex models surface on the engine createFnAgent registry-seeding path, not just /api/models. FN-7745 only wired the dashboard surface; this merge is additive and dedupe-safe, so pinned catalog rows win and no duplicate ids are added.
*/
mergeSupplementalOpenAiCodexModels(modelRegistry, (message) => extensionsLog.warn(message));
// Build the pi built-in tool set. We deliberately do NOT use the bundled
// `createCodingTools` / `createReadOnlyTools` presets — they're missing