✅ Gremlins MVP: unit and CLI tests with a fake claude
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
"""Fake `claude -p` for the CLI tests. $FAKE_CLAUDE_SCENARIO: ok (default), miss, api_error,
|
||||
noresult, two_models, no_cost, sleep. $FAKE_CLAUDE_LOG: one JSON line per call (argv, pid)."""
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import uuid
|
||||
|
||||
TRAIN_MU = {"inputTokens": 10, "outputTokens": 20, "cacheReadInputTokens": 0,
|
||||
"cacheCreationInputTokens": 1000}
|
||||
TRAIN_COST, CALL_COST = 0.05, 0.02
|
||||
|
||||
|
||||
def opt(name):
|
||||
return sys.argv[sys.argv.index(name) + 1] if name in sys.argv else None
|
||||
|
||||
|
||||
def emit(ev):
|
||||
print(json.dumps(ev), flush=True)
|
||||
|
||||
|
||||
def main():
|
||||
prompt = sys.stdin.buffer.read().decode("utf-8")
|
||||
scen = os.environ.get("FAKE_CLAUDE_SCENARIO", "ok")
|
||||
if os.environ.get("FAKE_CLAUDE_LOG"):
|
||||
with open(os.environ["FAKE_CLAUDE_LOG"], "a", encoding="utf-8") as f:
|
||||
f.write(json.dumps({"argv": sys.argv, "pid": os.getpid(), "prompt_chars": len(prompt)}) + "\n")
|
||||
resume, model = opt("--resume"), opt("--model")
|
||||
# a plain resume (no fork, no --session-id) gets a new id, as `-p` may give one
|
||||
sid = opt("--session-id") or ("resumed-" + uuid.uuid4().hex if resume else str(uuid.uuid4()))
|
||||
read = 1000 if resume and scen != "miss" else 0
|
||||
created = 100 if resume else 1000
|
||||
usage = {"input_tokens": 10, "output_tokens": 20, "cache_creation_input_tokens": created,
|
||||
"cache_read_input_tokens": read,
|
||||
"cache_creation": {"ephemeral_1h_input_tokens": created, "ephemeral_5m_input_tokens": 0}}
|
||||
emit({"type": "system", "subtype": "init", "session_id": sid, "model": model})
|
||||
emit({"type": "assistant", "session_id": sid, "message": {"id": "m1", "usage": usage}})
|
||||
if scen == "sleep":
|
||||
time.sleep(60)
|
||||
if scen == "noresult":
|
||||
sys.exit(1)
|
||||
mu = {"inputTokens": 10, "outputTokens": 20, "cacheReadInputTokens": read,
|
||||
"cacheCreationInputTokens": created}
|
||||
cost = CALL_COST if resume else TRAIN_COST
|
||||
if resume: # the session's totals include the base's training call
|
||||
mu = {k: v + TRAIN_MU[k] for k, v in mu.items()}
|
||||
cost += TRAIN_COST
|
||||
res = {"type": "result", "subtype": "success", "is_error": False, "session_id": sid,
|
||||
"result": "done", "num_turns": 1, "usage": usage, "modelUsage": {model: mu},
|
||||
"total_cost_usd": cost}
|
||||
if scen == "two_models":
|
||||
res["modelUsage"]["claude-haiku-5-5"] = {"inputTokens": 5, "outputTokens": 1,
|
||||
"cacheReadInputTokens": 0, "cacheCreationInputTokens": 0}
|
||||
if scen == "no_cost":
|
||||
del res["total_cost_usd"]
|
||||
if scen == "api_error":
|
||||
res.update(subtype="error_during_execution", is_error=True, api_error_status=429,
|
||||
result="API Error: 429 rate limit")
|
||||
emit(res)
|
||||
sys.exit(1 if scen == "api_error" else 0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user