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.
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.