Repository navigation
feat(agent): provider-neutral loop + codex app-server transport - #25
Merged
Merged
Conversation
Converge the two AI-provider paths so the funfa loop lives once, in
capability-verb form, with provider differences isolated to thin bindings.
Part A — provider-neutral loop:
- Rewrite all four SKILL.md files in capability verbs (no tool names);
drop funfa's `## Tools` section.
- Add agent/prompt.ts: LOOP_BODY, API_BINDING, CODEX_BINDING, and one
buildLoopPrompt({binding, inlineSkills, skills}) assembling both paths.
- Wire propose.ts to it (delete buildSystemPrompt/buildSkillsPrompt).
- prompt.test.ts drift guard: loop body byte-identical across providers.
Part B — codex exec -> codex app-server:
- Pin the v2 protocol from `codex app-server generate-json-schema` on
0.135.0 (curated under apps/cli/vendor/). System prompt rides
thread/start.developerInstructions; turn/start.outputSchema constrains
the answer; envelope omits jsonrpc; output streams via
item/agentMessage/delta -> turn/completed.
- Add codex-app-server.ts (minimal NDJSON JSON-RPC client, injectable
transport) + codex-protocol.ts (hand-authored types + MIN_CODEX_VERSION).
- codex-cli.ts drives the app-server flow by default with a
MIN_CODEX_VERSION gate; FUNFA_CODEX_TRANSPORT=exec falls back to the
legacy path. Consent gate / write / render unchanged.
- codex-app-server.test.ts (fake transport) + updated codex-cli.test.ts.
Both transports verified e2e (FUNFA_FAKE_HARDWARE). 90 tests +
check-types + ultracite green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The vision for funfa is one loop that behaves identically across providers. Before this PR the four
SKILL.mdfiles were written against funfa's specific tool harness (all five tool names leaked into the bodies), so the codex path needed a big override preamble — and the two prompts could silently drift. This converges them.Part A — provider-neutral loop + thin bindings
SKILL.mdfiles rewritten in capability verbs (no tool names);funfa/SKILL.md's## Toolssection removed.apps/cli/src/agent/prompt.ts:LOOP_BODY,API_BINDING,CODEX_BINDING, and onebuildLoopPrompt({ binding, inlineSkills, skills })that assembles both providers' prompts.propose.tsrewired to it (deletedbuildSystemPrompt/buildSkillsPrompt).prompt.test.tsdrift guard: asserts the loop body is byte-identical (and appears exactly once) across the API and codex prompts, so they can't silently diverge.Editing the loop is now a one-file markdown edit for every provider.
Part B — codex
exec→codex app-servercodex app-server generate-json-schemaon the local 0.135.0 binary (curated reference underapps/cli/vendor/codex-app-server-schema/). Notable 0.135.0 facts: system prompt ridesthread/start.developerInstructions(plain string, notcollaborationMode.settings.developer_instructions);sandboxis the bare string"read-only"; the JSON-RPC envelope omitsjsonrpc; the final answer streams viaitem/agentMessage/delta→turn/completedand is constrained byturn/start.outputSchema.codex-app-server.ts(minimal NDJSON JSON-RPC client with an injectable transport) +codex-protocol.ts(hand-authored minimal types +MIN_CODEX_VERSION).codex-cli.tsdrives the app-server flow by default (injecting the same provider-neutral loop viadeveloperInstructions), gated onMIN_CODEX_VERSION.FUNFA_CODEX_TRANSPORT=execfalls back to the legacycodex exec --output-schemapath. The consent gate / on-disk write / render (applySubmitPlan) are unchanged.codex-app-server.test.ts(fake-transport unit tests) + updatedcodex-cli.test.ts.Honest scope note
app-server's approval callbacks are about codex's own shell/file actions. funfa runs codex read-only (
approvalPolicy: never), so there's nothing to approve mid-loop — funfa's whole-plan "Accept this plan?" gate stays post-hoc. The real win from app-server is the cleandeveloperInstructionsprompt seam + preserved structured output + streaming. The transport is officially experimental, hence the version gate and theexecescape hatch. (Approach mirrorspingdotgg/t3code, which drivescodex app-serverthe same way.)Verification
bun run check-types: clean ·bun run check(Ultracite): clean ·bun test: 90 pass, 0 fail (incl. compile smoke + new prompt-drift and app-server-client tests).FUNFA_FAKE_HARDWAREAMD RX 7800 XT): real structured plan for appid 48190, hardware-filtered, codex-web-sourced, consent gate fired, written to disk (exit 0).🤖 Generated with Claude Code