Repository navigation
[oss] Offline tests for openai_compat and remote_inproc adapters - #208
Merged
Merged
Conversation
Mock http_post_json (and urlopen underneath it) to pin typed answers, malformed JSON, missing fields, no-retry handling of 429/5xx, timeouts, usage normalisation, reserve estimates and probability extraction. An xfail test records that run() mutates the provider's raw usage dict. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N6vx2pRLRQWgVMnaYC1GXL
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.
What changed
Adds one file,
tests/test_openai_compat_adapter.py(358 lines, test-only). No library code, datasets, results or scoring changed.HTTP is mocked by monkeypatching the module-level
http_post_jsonthat each adapter imports. For timeout and HTTP-error cases the tests patchurllib.request.urlopenunderneath it instead, so the realbase.http_post_jsonpath runs. No sockets are opened.Coverage, pinned to current behaviour:
probs_source="verbalized", the served model name winning over the requested one, URL with the trailing slash stripped, auth headers,timeout_spassthrough, and noexpected/provenance in the request. Also: a missing API key sends no request, andrequest_optionsoverrides and removals work.{"probabilities": ...}object nested under another key is accepted; labels and values are not validated here (the scorer does that).probabilitiesthat is a list or null, null content, list content, no or empty choices, a choice with no message, and a 200 response with an HTML body.error == "HTTP <status>: <body[:300]>". Retry/stop handling lives in the runner (it stops on 401/403/429), which this PR does not touch.ConnectionErrorfrom the transport becomesok=False, status=None. A realsocket.timeoutthroughhttp_post_jsongives"TimeoutError: timed out". Other exceptions propagate.prompt_tokens/completion_tokensare mapped toinput_tokens/output_tokens, OpenAI-style names win when both are present, and null usage givesNones.reserve_estimatereturns 0.232 for $2/$8 per million tokens, 0 when both prices are 0, andNonewhen a price is missing.server_latency_sfolded intoraw.runtime, 429/5xx with no retry, and a timeout.Bugs found (recorded with xfail, not fixed)
OpenAICompatAdapter.runchanges the provider's raw response.res.usage = parsed.get("usage")is the same dict object asparsed["usage"]. Addinginput_tokens/output_tokensto it also adds them toDecisionResult.raw, which the runner hashes and stores as preserved raw evidence.test_raw_response_not_mutatedisxfail(strict=True);test_raw_usage_currently_mutatedpins today's behaviour. A one-line fix would bedict(parsed.get("usage") or {}), but it is left out because this PR must not change library code.Open doubts
choices[0]is not a dict (e.g.[None]) orusageis not a dict, the adapter raisesAttributeError. The runner then records onlyerror="AttributeError"and loses the HTTP status and raw body. I pinned this as current behaviour (pytest.raises) rather than marking it as a bug.{"answer": {"probabilities": ...}}) is accepted, while a top-level object with extra keys is rejected. I pinned this as current behaviour; it may or may not be intended.jsonmessages and could change between Python versions (these ran on 3.13).Verification
Before (main @ 99783d8),
python -m pytest -q:New file alone:
After,
python -m pytest -q:Nothing is left for Sandy: no credentials, network or GPU were needed.
🤖 Generated with Claude Code
https://claude.ai/code/session_01N6vx2pRLRQWgVMnaYC1GXL
Generated by Claude Code