Repository navigation
fix(sdk): fail fast with a clear message when the CodeAF harness has no model key - #1130
Merged
Merged
Conversation
…del key CodeAF is the default harness provider, and with no model key it used to be downloaded and launched anyway, exit 1, and come back as a generic "codeaf exit code 1 (stop=)" result. Each of those launches was also counted by CodeAF's own usage telemetry as a failed session. The provider now checks, before resolving, downloading or launching CodeAF, whether CodeAF could find a key in the child's effective environment (OPENROUTER_API_KEY, an OpenRouter-compatible or custom-endpoint OPENAI_API_KEY, or a saved profile key or model source; unreadable profiles and connected-provider files are allowed). With none it raises HarnessProviderNotConfigured, a HarnessProviderUnavailable subclass, naming OPENROUTER_API_KEY and how to pick another provider, and logs one warning per process. An Agent built with a harness config that resolves to CodeAF warns once at construction. Legacy aforge pins are unchanged. sdk/codeaf-auth-contract.json is the case table the Python, Go and TypeScript suites share. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The Go provider runs the same credential check as the Python SDK before resolving, downloading or launching CodeAF. With no usable key Execute returns a ProviderUnavailableError with NotConfigured set, which prints the shared refusal message and still matches errors.As on the existing type; MissingAuthEnv lists OPENROUTER_API_KEY. The first refusal logs one warning, and agent.New warns once when its HarnessConfig resolves to CodeAF with no key visible. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…o model key The TypeScript provider runs the shared credential check before resolving, downloading or launching CodeAF and throws HarnessProviderNotConfigured, an exported HarnessProviderUnavailable subclass with the shared message and missingAuthEnv ["OPENROUTER_API_KEY"]. The first refusal warns once, and an Agent whose harnessConfig resolves to CodeAF warns once at construction. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The key check guessed ~/.codeaf when every CODEAF_*/AFORGE_* home and profile variable was empty, but CodeAF itself may then use HOME from the child's own environment, a legacy ~/.aforge or a relative directory, and it reads a whitespace-only spelling differently from an unset one. In those cases the SDK now lets the call through and CodeAF decides, instead of refusing a setup that could work. Python also stops accepting NaN/Infinity in config.json, so a malformed profile is allowed the same way in all three SDKs, and the Agent-construction warning can no longer raise. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Contributor
Performance
⚠ Regression detected:
|
…ield skill The embedded skill copy under control-plane/internal/skillkit/skill_data must stay byte-identical to skills/ (scripts/sync-embedded-skills.sh --check), and only the embedded copy had the new paragraph. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Contributor
📊 Coverage gateThresholds from
✅ Gate passedNo surface regressed past the allowed threshold and the aggregate stayed above the floor. |
Contributor
📐 Patch coverage gateThreshold: 80% on lines this PR touches vs
✅ Patch gate passedEvery surface whose lines were touched by this PR has patch coverage at or above the threshold. |
5 tasks done
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.
Summary
CodeAF became the default harness provider in v0.1.143 (#1128). When an agent has no model key, the SDK still downloads and launches CodeAF. CodeAF then exits 1, and the call comes back as a generic
codeaf exit code 1 (stop=): …result. Every one of those launches is also counted by CodeAF's own usage telemetry as a failed session. That has been inflating the error rate in CodeAF's session outcomes since the default changed.Now, before it resolves, downloads or launches CodeAF, each SDK checks whether CodeAF could find a model key. If it could not, the call fails right away with a message the user can act on, and CodeAF is never started:
HarnessProviderNotConfigured, a subclass ofHarnessProviderUnavailable, so existingexcept/instanceofhandlers still catch it.missing_auth_env/missingAuthEnvis["OPENROUTER_API_KEY"].*ProviderUnavailableErrorwithNotConfigured: true, soerrors.Asstill matches. Existing messages are unchanged.envoverrides and the SDK's defaultCODEAF_HOME. CodeAF is treated as having a key when any of these is true:OPENROUTER_API_KEYis set;OPENAI_API_KEYstarts withsk-or-;OPENAI_API_KEYis set and a customCODEAF_BASE_URLpoints away from OpenRouter (for example a local Ollama);api_keyormodel_sources.credentials.jsonorcodex.jsonpresent (connected providers and sign-ins);AFORGE_BINpins, and every call that does have a key.Behaviour change: a keyless CodeAF call used to return an
is_errorresult; it now raises or returns the unavailable-provider error. That is the same way a missing CodeAF binary already behaves.Validation contract
sdk/codeaf-auth-contract.json, 42 cases)Test plan
ruff check .(0.15.22),mypy,./scripts/run_pytest.sh(2864 passed on the first four commits; the five CodeAF test files re-run after the last one, 229 passed)go mod tidy,go build,go vet,go test ./...npm ci,npm run lint,npm test(1332 passed), plus the harness doctor testmain, Pythoncodeaf exit code 1 (stop=)and launched CodeAF each time → 2stop_reason: errorsessionsokmain, GookHarnessProviderNotConfiguredwith the message above, 0 launches, 0 telemetry, one warning (plus one at Agent construction)ok, 1 launch,doneProviderUnavailableError(errors.Astrue,MissingAuthEnv=[OPENROUTER_API_KEY]), 0 launches, one warning (plus one atagent.New)ok,doneHarnessProviderNotConfigured(instanceof HarnessProviderUnavailabletrue), 0 launches, one warning (plus one at construction)ok,doneCODEAF_BIN. Keyless calls refused without downloading anything. The keyed call then downloaded the managed CodeAF and ran.OPENROUTER_API_KEYin the process environment: no warnings, and every call runs as before.🤖 Generated with Claude Code