feat: add Infron as an open_code gateway provider - #126
Conversation
Infron is an OpenAI-compatible inference gateway that serves the standard <provider>/<model> ids, so wiring it in is a base-URL change rather than a model-mapping exercise: infron/moonshotai/kimi-k2.6 routes the same model the bare id names, and nothing else in a deployment moves. - docker/opencode.json: the OpenCode provider block moves out of the two Dockerfiles into one shared file both images COPY, so they cannot drift apart. It now declares infron (@ai-sdk/openai-compatible) next to the existing provider; a provider with no key set is never selected, so shipping both costs nothing at runtime. - INFRON_API_KEY follows the same resolution chain the existing gateway key does (Python and the Go port): with only that key present, SWE-AF auto-selects open_code and defaults to infron/deepseek/deepseek-v4-flash. - A gateway key that was already honored before Infron existed keeps precedence, so adding an Infron key never silently reroutes an existing deployment. - Manifests offer INFRON_API_KEY as a third llm_provider option; README and .env.example document the prefix swap. No behavior change for any existing deployment: every new path is gated on INFRON_API_KEY being the only gateway key present.
d00aabc to
d6b950d
Compare
AbirAbbas
left a comment
There was a problem hiding this comment.
Thanks for the disclosed, well-tested integration. The precedence logic is correct and symmetric in both swe_af/execution/schemas.py and go/internal/config/resolve.go (verified: an existing gateway key always wins, the two *_only_env() predicates are mutually exclusive by construction), and the shared docker/opencode.json extraction is a genuine improvement over the duplicated inline JSON. But the branch is three commits behind main and the staleness is now load-bearing. Requesting changes:
- Rebase onto current main (
ef508a8). Four files conflict (schemas.py,resolve.go, bothagentfield-package.yamls) — all mechanical. - Stale model constants: #132 renamed the shared open_code default to
deepseek-v4-flash-0731._INFRON_AUTO_DEFAULT_MODEL/infronAutoDefaultModelstill sayinfron/deepseek/deepseek-v4-flash, and two tests copied from the pre-#132 tree (test_explicit_open_code_keeps_minimax,test_model_ids_unchanged_after_prefix_swap) auto-merge cleanly and then fail. Bump both constants to-0731, add that model id todocker/opencode.json'sinfron.modelslist (OpenCode can't resolve it otherwise — your owntest_infron_declares_modelsexplains why), and updatetests/test_dockerfile.pyto match. - The headline claim breaks inside the project's own images: both Dockerfiles bake
ENV HARNESS_MODEL=openrouter/moonshotai/kimi-k2.6, which sits above the auto-gateway default in the resolution cascade. AnINFRON_API_KEY-only container deployment therefore resolves every model to an OpenRouter id with no OpenRouter key and dies on auth. Document the requiredSWE_DEFAULT_MODELoverride for Infron the same way the README already does for Codex, or make the baked default gateway-aware. INFRON_API_KEYnever reaches the container: all five compose service env blocks (docker-compose.yml×2,docker-compose.go.yml×2,docker-compose.local.yml) enumerate provider vars explicitly and none pass it through, so the documented.envpath is broken end-to-end.- Re-validate after the rebase: the PR's current
make check/go testnumbers were measured against the old base.
Separate from the code review: adding INFRON_API_KEY to require_one_of.llm_provider promotes Infron into the af install wizard on equal footing with Anthropic/OpenRouter for every installer. That's a maintainer policy decision rather than a review item and is still being weighed — if it ends up moved to optional, everything else above still stands.
Brings the branch up to date with main (13 commits) and resolves the conflicts the staleness created. Resolution notes: - main's Agent-Field#97 extracted the OpenCode provider JSON into a repo-root opencode.json that both Dockerfiles COPY, which is the same refactor this branch was doing into docker/opencode.json. Dropped the branch's copy and added the infron provider block to the root file instead, so there is still exactly one config and the MiniMax providers main added are untouched. Both Dockerfiles keep main's COPY line verbatim. - main's Agent-Field#132 renamed the shared open_code default to deepseek-v4-flash-0731. Bumped _INFRON_AUTO_DEFAULT_MODEL / infronAutoDefaultModel to match, declared that id in the infron provider's models list so OpenCode can resolve it, and updated the two tests that were written against the pre-Agent-Field#132 default. - main's Agent-Field#142 scoped the HARNESS_MODEL cascade step to the open_code runtime. An INFRON_API_KEY-only deployment auto-selects open_code, so the images' baked openrouter/... HARNESS_MODEL still overrides the Infron auto default. Documented the required HARNESS_MODEL override in README and .env.example and pinned both halves of that behaviour in tests/test_model_config.py rather than changing the baked default. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The .env path the README documents was broken end to end: all five service env blocks enumerate provider variables explicitly, so an INFRON_API_KEY in .env never reached a container. Add it alongside OPENROUTER_API_KEY in swe-agent and swe-fast (docker-compose.yml), swe-agent-go and swe-fast-go (docker-compose.go.yml) and swe-agent (docker-compose.local.yml), and update the SWE_DEFAULT_RUNTIME comments that still said the auto-select only looks at an OpenRouter key. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
I pushed the rebase-equivalent onto your branch as a merge from main plus two commits, so it's current and CI is green again. On the review items: main's #97 turned out to have done the same config extraction you did, into a repo-root Local runs on the merged head: One thing I deliberately left alone: |
Summary
open_codegateway provider. Infron is an OpenAI-compatible inference gateway serving the standard<provider>/<model>ids, so wiring it in is a base-URL change rather than a model-mapping exercise:infron/moonshotai/kimi-k2.6routes the same model the bare id names, and nothing else in a deployment moves.Disclosure: I work on Infron. Everything below is checkable from the diff and the commands under Validation.
docker/opencode.jsonCOPY, so they cannot drift apart. Declaresinfron(@ai-sdk/openai-compatible) next to the existing provider.Dockerfile,go/Dockerfileecho '{...}'config withCOPY docker/opencode.json.swe_af/execution/schemas.py_infron_only_env()+_INFRON_AUTO_DEFAULT_MODEL, following the existing gateway path through_default_runtime,_default_planning_model, andresolve_runtime_models.go/internal/config/resolve.goinfronOnlyEnv,infronAutoDefaultModel).agentfield-package.yaml,go/agentfield-package.yamlINFRON_API_KEYoffered as a thirdllm_provideroption..env.example,README.mdtests/test_model_config.py,tests/test_dockerfile.py,go/internal/config/config_test.goBehavior
With only an
INFRON_API_KEYset (noANTHROPIC_API_KEY, no other gateway key, noSWE_DEFAULT_RUNTIME), SWE-AF auto-selects theopen_coderuntime and defaults toinfron/deepseek/deepseek-v4-flash— the same rule the existing gateway path already follows, with the prefix swapped.A gateway key that was already honored before Infron existed keeps precedence. Adding an Infron key never silently reroutes an existing deployment; moving traffic across is an explicit act (drop the other key, or set
SWE_DEFAULT_MODEL=infron/...). A provider with no key set is never selected, so shipping both in the image costs nothing at runtime.Validation
Rebased on
mainat7a8dba0and re-run today.make check—python -m pytest tests/ -q: 1154 passed, 1 skipped, 0 failed, pluspython -m compileall -q swe_af/clean(note for anyone reproducing:
tests/conftest.pyrequiresAGENTFIELD_SERVERto be set to a local address, e.g.AGENTFIELD_SERVER=http://localhost:9999, or every test errors at fixture setup)cd go && go test ./...— 27 packages ok, 0 failures (Go 1.23.4)cd go && go build ./...clean;gofmt -l internal/config/cleantests/test_model_config.py,tests/test_dockerfile.py) pass, includingtest_both_dockerfiles_share_one_opencode_config, which pins the new shared-config invariant.moonshotai/kimi-k2.6,minimax/minimax-m2.5andz-ai/glm-5.2overhttps://llm.onerouter.pro/v1return well-formed completions with usage accounting, on both the sync and the streaming path, under the same ids already used in the image.Behavior Impact
INFRON_API_KEYbeing the only gateway key present, and an existing key wins ties.Notes
docker/opencode.jsonextraction is the one structural change. It was the cleanest way to avoid a ~900-characterecholine and to stop the Python and Go images from drifting;test_both_dockerfiles_share_one_opencode_confignow pins that. Happy to inline it back into both Dockerfiles if you would rather keep the diff to a single mechanism.@ai-sdk/openai-compatibleproviders are not in models.dev, so the model list has to be explicit. I listed the eight open-weight models SWE-AF realistically uses (Kimi K2.6 / K2.7-Code / K3, DeepSeek V4 Flash/Pro, MiniMax M2.5/M3, GLM-5.2). Easy to extend.infron/...work for AgentField apps generally: feat(sdk/go/ai): support the Infron gateway agentfield#874. The two are independent; either can land alone.