Complete cloud provider patch MVP
This commit is contained in:
@@ -156,15 +156,42 @@ def call_openai(model_name, prompt, role):
|
||||
except Exception as exc: # honest non-zero, no fake success
|
||||
fail(f"backend_unreachable {type(exc).__name__}: {str(exc)[:120]}")
|
||||
latency_ms = int((time.time() - t0) * 1000)
|
||||
usage = payload.get("usage", {})
|
||||
text, input_tokens, output_tokens = parse_openai_payload(payload)
|
||||
return {
|
||||
"text": (payload["choices"][0]["message"]["content"] or "").strip(),
|
||||
"input_tokens": int(usage.get("prompt_tokens", 0)),
|
||||
"output_tokens": int(usage.get("completion_tokens", 0)),
|
||||
"text": text,
|
||||
"input_tokens": input_tokens,
|
||||
"output_tokens": output_tokens,
|
||||
"latency_ms": latency_ms,
|
||||
}
|
||||
|
||||
|
||||
def parse_openai_payload(payload):
|
||||
try:
|
||||
text = (payload["choices"][0]["message"]["content"] or "").strip()
|
||||
usage = payload["usage"]
|
||||
input_tokens = int(usage["prompt_tokens"])
|
||||
output_tokens = int(usage["completion_tokens"])
|
||||
except (KeyError, IndexError, TypeError, ValueError) as exc:
|
||||
fail(f"provider_usage_invalid openai {type(exc).__name__}: {str(exc)[:80]}")
|
||||
return text, input_tokens, output_tokens
|
||||
|
||||
|
||||
def parse_anthropic_payload(payload):
|
||||
try:
|
||||
content = payload["content"]
|
||||
if not isinstance(content, list):
|
||||
raise TypeError("content is not a list")
|
||||
text = "".join(
|
||||
b.get("text", "") for b in content if isinstance(b, dict) and b.get("type") == "text"
|
||||
).strip()
|
||||
usage = payload["usage"]
|
||||
input_tokens = int(usage["input_tokens"])
|
||||
output_tokens = int(usage["output_tokens"])
|
||||
except (KeyError, TypeError, ValueError) as exc:
|
||||
fail(f"provider_usage_invalid anthropic {type(exc).__name__}: {str(exc)[:80]}")
|
||||
return text, input_tokens, output_tokens
|
||||
|
||||
|
||||
def call_anthropic(model_name, prompt, role):
|
||||
# Endpoint hard-pinned to the allowlisted host (no env override). NOTE: on
|
||||
# current Claude models (Opus 4.8/4.7, Sonnet 5, ...) `temperature`/`top_p`
|
||||
@@ -197,20 +224,14 @@ def call_anthropic(model_name, prompt, role):
|
||||
except Exception as exc: # honest non-zero, no fake success
|
||||
fail(f"backend_unreachable {type(exc).__name__}: {str(exc)[:120]}")
|
||||
latency_ms = int((time.time() - t0) * 1000)
|
||||
# content is a list of blocks; concatenate text blocks. A safety refusal
|
||||
# (stop_reason=="refusal") yields empty text -> extract_verdict fails closed.
|
||||
text = "".join(
|
||||
b.get("text", "") for b in payload.get("content", []) if b.get("type") == "text"
|
||||
).strip()
|
||||
usage = payload.get("usage", {})
|
||||
text, input_tokens, output_tokens = parse_anthropic_payload(payload)
|
||||
return {
|
||||
"text": text,
|
||||
"input_tokens": int(usage.get("input_tokens", 0)),
|
||||
"output_tokens": int(usage.get("output_tokens", 0)),
|
||||
"input_tokens": input_tokens,
|
||||
"output_tokens": output_tokens,
|
||||
"latency_ms": latency_ms,
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("prompt_file")
|
||||
|
||||
@@ -97,7 +97,74 @@ else
|
||||
skip "cloud-unavailable test (ANTHROPIC_API_KEY is set)"
|
||||
fi
|
||||
|
||||
# 8: deliberate failing primary route -> fallback through the REAL router (not exit 9).
|
||||
# 8: cloud response parsers use provider token usage and fail closed on malformed
|
||||
# payloads. This is deterministic: urllib is monkeypatched, so no API key or
|
||||
# network call is needed.
|
||||
python - "$SCRIPTS/model-call.py" <<'PY'
|
||||
import importlib.util
|
||||
import contextlib
|
||||
import io
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
spec = importlib.util.spec_from_file_location("mc", sys.argv[1])
|
||||
mc = importlib.util.module_from_spec(spec); spec.loader.exec_module(mc)
|
||||
os.environ["OPENAI_API_KEY"] = "test-openai-key"
|
||||
os.environ["ANTHROPIC_API_KEY"] = "test-anthropic-key"
|
||||
|
||||
seen = []
|
||||
|
||||
class FakeResp:
|
||||
def __init__(self, payload):
|
||||
self.payload = payload
|
||||
def __enter__(self):
|
||||
return self
|
||||
def __exit__(self, exc_type, exc, tb):
|
||||
return False
|
||||
def read(self):
|
||||
return json.dumps(self.payload).encode()
|
||||
|
||||
def fake_urlopen(req, timeout):
|
||||
seen.append((req.full_url, dict(req.header_items()), json.loads(req.data.decode())))
|
||||
if "openai.com" in req.full_url:
|
||||
return FakeResp({
|
||||
"choices": [{"message": {"content": "SAFE"}}],
|
||||
"usage": {"prompt_tokens": 11, "completion_tokens": 3},
|
||||
})
|
||||
if "anthropic.com" in req.full_url:
|
||||
return FakeResp({
|
||||
"content": [{"type": "text", "text": "APPROVED"}],
|
||||
"usage": {"input_tokens": 17, "output_tokens": 5},
|
||||
})
|
||||
raise AssertionError(req.full_url)
|
||||
|
||||
mc.urllib.request.urlopen = fake_urlopen
|
||||
op = mc.call_openai("gpt-test", "hello", "classify")
|
||||
an = mc.call_anthropic("claude-test", "hello", "judge")
|
||||
assert op["text"] == "SAFE" and op["input_tokens"] == 11 and op["output_tokens"] == 3, op
|
||||
assert an["text"] == "APPROVED" and an["input_tokens"] == 17 and an["output_tokens"] == 5, an
|
||||
assert seen[0][0] == "https://api.openai.com/v1/chat/completions", seen[0]
|
||||
assert seen[1][0] == "https://api.anthropic.com/v1/messages", seen[1]
|
||||
assert seen[0][2]["temperature"] == 0 and seen[0][2]["max_tokens"] == 16, seen[0][2]
|
||||
assert "temperature" not in seen[1][2] and seen[1][2]["max_tokens"] == 16, seen[1][2]
|
||||
|
||||
for fn, bad in (
|
||||
(mc.parse_openai_payload, {"choices": [{"message": {"content": "SAFE"}}]}),
|
||||
(mc.parse_anthropic_payload, {"content": [{"type": "text", "text": "APPROVED"}]}),
|
||||
):
|
||||
try:
|
||||
with contextlib.redirect_stderr(io.StringIO()):
|
||||
fn(bad)
|
||||
except SystemExit as exc:
|
||||
assert exc.code == 2, exc.code
|
||||
else:
|
||||
raise AssertionError(f"{fn.__name__} accepted malformed provider payload")
|
||||
print("ok")
|
||||
PY
|
||||
[[ $? -eq 0 ]] && pass "cloud provider responses parse real usage and reject malformed payloads" || fail "cloud provider parser coverage failed"
|
||||
|
||||
# 9: deliberate failing primary route -> fallback through the REAL router (not exit 9).
|
||||
if [[ "$TUNNEL_UP" -eq 1 ]]; then
|
||||
printf 'Return exactly: OK\n' > "$WORK/f.txt"
|
||||
set +e
|
||||
|
||||
Reference in New Issue
Block a user