Erinaldordso's picture
Route Naldo brain through OpenCode free models
69f9cd1 verified
Raw History Blame Contribute Delete
8.14 kB
"""Checklist de aceite do endpoint Programa.
Cobre, nesta ordem: /v1/models, chat simples, stream, system, multi-turn,
tools + tool_choice=auto, tool result + continuacao, max_tokens, temperature,
stop, /v1/responses e /v1/messages (somente se o servidor expuser de verdade).
Uso:
BASE=https://erinaldordso-programa.hf.space/v1 python3 tests/test_agent.py
BASE=... MODEL=... APIKEY=... python3 tests/test_agent.py
Nao declara sucesso parcial: qualquer FAIL aborta com exit 1.
"""
import json
import os
import sys
import urllib.request
import tiktoken
BASE = os.environ.get("BASE", "https://erinaldordso-minecraft-friends-ai-zerogpu.hf.space/v1").rstrip("/")
MODEL = os.environ.get("MODEL", "granite-4.0-h-tiny")
APIKEY = os.environ.get("APIKEY", "")
PASS, FAIL = "PASS", "FAIL"
results = []
def req(method, path, body=None, stream=False):
url = BASE + path
data = json.dumps(body).encode() if body is not None else None
headers = {"Content-Type": "application/json"}
if APIKEY:
headers["Authorization"] = f"Bearer {APIKEY}"
r = urllib.request.Request(url, data=data, headers=headers, method=method)
if not stream:
with urllib.request.urlopen(r, timeout=300) as resp:
return resp.status, json.loads(resp.read().decode())
out = []
with urllib.request.urlopen(r, timeout=300) as resp:
for line in resp:
s = line.decode(errors="replace").strip()
if s.startswith("data:"):
s = s[5:].strip()
if s == "[DONE]":
break
try:
out.append(json.loads(s))
except json.JSONDecodeError:
pass
return 200, out
def check(name, cond, extra=""):
results.append((name, bool(cond)))
print(f"[{PASS if cond else FAIL}] {name} {extra}")
if not cond:
raise SystemExit(f"FAIL em {name}: {extra}")
TOOLS = [{"type": "function", "function": {
"name": "read_file",
"description": "Read a file from the project",
"parameters": {"type": "object",
"properties": {"path": {"type": "string"}},
"required": ["path"]}}},
{"type": "function", "function": {
"name": "list_directory",
"description": "List a directory",
"parameters": {"type": "object",
"properties": {"path": {"type": "string"}},
"required": ["path"]}}},
{"type": "function", "function": {
"name": "execute_command",
"description": "Run a shell command",
"parameters": {"type": "object",
"properties": {"command": {"type": "string"}},
"required": ["command"]}}}]
def main():
print(f"BASE={BASE} MODEL={MODEL}")
st, models = req("GET", "/models")
ids = [m.get("id", "") for m in models.get("data", [])]
check("models", st == 200 and any(MODEL in i or "granite" in i.lower() for i in ids), f"ids={ids[:4]}")
st, emb = req("POST", "/embeddings", {"model": "text-embedding-ada-002", "input": ["mine wood", "craft pickaxe"]})
vecs = emb.get("data", [])
check("embeddings Voyager", st == 200 and len(vecs) == 2 and all(isinstance(x.get("embedding"), list) and len(x.get("embedding")) > 0 for x in vecs), f"vectors={len(vecs)}")
enc = tiktoken.get_encoding("cl100k_base")
st, emb = req("POST", "/embeddings", {"model": "text-embedding-ada-002", "input": [enc.encode("mine wood"), enc.encode("craft pickaxe")]})
vecs = emb.get("data", [])
check("embeddings token input", st == 200 and len(vecs) == 2 and all(isinstance(x.get("embedding"), list) and len(x.get("embedding")) > 0 for x in vecs), f"vectors={len(vecs)}")
st, r = req("POST", "/chat/completions", {
"model": MODEL, "messages": [{"role": "user", "content": "diga ok"}],
"max_tokens": 16, "temperature": 0})
txt = r["choices"][0]["message"].get("content", "")
check("chat stream=false", st == 200 and isinstance(txt, str), f"len={len(txt)}")
st, chunks = req("POST", "/chat/completions", {
"model": MODEL, "messages": [{"role": "user", "content": "conte ate 3"}],
"max_tokens": 32, "temperature": 0, "stream": True}, stream=True)
joined = "".join((c.get("choices", [{}])[0].get("delta", {}) or {}).get("content") or "" for c in chunks)
check("chat stream=true", st == 200 and len(chunks) > 0, f"chunks={len(chunks)} chars={len(joined)}")
st, r = req("POST", "/chat/completions", {
"model": MODEL,
"messages": [{"role": "system", "content": "You are an autonomous software engineering agent."},
{"role": "user", "content": "diga ok"}],
"max_tokens": 16, "temperature": 0})
check("system message", st == 200, "")
st, r = req("POST", "/chat/completions", {
"model": MODEL,
"messages": [{"role": "user", "content": "meu projeto usa npm"},
{"role": "assistant", "content": "anotado"},
{"role": "user", "content": "qual gerenciador citei?"}],
"max_tokens": 32, "temperature": 0})
check("multi-turn", st == 200 and "npm" in json.dumps(r).lower(), "")
st, r = req("POST", "/chat/completions", {
"model": MODEL,
"messages": [
{"role": "system", "content": "You are an autonomous software engineering agent. Use tools instead of describing hypothetical actions. Inspect files before modifying them."},
{"role": "user", "content": "Leia package.json e diga qual comando executa os testes."}],
"tools": TOOLS[:1], "tool_choice": "auto",
"max_tokens": 256, "temperature": 0})
msg = r["choices"][0]["message"]
tcs = msg.get("tool_calls") or []
ok = (r["choices"][0].get("finish_reason") == "tool_calls" and tcs
and tcs[0]["function"]["name"] == "read_file"
and "package.json" in tcs[0]["function"].get("arguments", ""))
check("tools read_file", ok, f"finish={r['choices'][0].get('finish_reason')} calls={json.dumps(tcs)[:200]}")
tc = tcs[0]
st, r = req("POST", "/chat/completions", {
"model": MODEL,
"messages": [
{"role": "system", "content": "You are an autonomous software engineering agent."},
{"role": "user", "content": "Leia package.json e diga qual comando executa os testes."},
{"role": "assistant", "tool_calls": [{
"id": tc.get("id", "call_1"), "type": "function",
"function": {"name": "read_file", "arguments": tc["function"]["arguments"]}}]},
{"role": "tool", "tool_call_id": tc.get("id", "call_1"),
"content": "{\"name\": \"demo\", \"scripts\": {\"test\": \"npm test\"}}"}],
"max_tokens": 128, "temperature": 0})
txt2 = r["choices"][0]["message"].get("content", "")
check("tool result + continuacao", st == 200 and "npm test" in txt2, f"resp={txt2[:160]}")
st, r = req("POST", "/chat/completions", {
"model": MODEL, "messages": [{"role": "user", "content": "fale muito"}],
"max_tokens": 8, "temperature": 0})
check("max_tokens respeitado", st == 200, "")
st, r = req("POST", "/chat/completions", {
"model": MODEL, "messages": [{"role": "user", "content": "diga ok"}],
"max_tokens": 16, "temperature": 0.7, "stop": ["<|im_end|>"]})
check("temperature+stop", st == 200, "")
for path, label in [("/responses", "responses"), ("/messages", "messages")]:
try:
if label == "responses":
st, r = req("POST", path, {"model": MODEL, "input": "diga ok", "max_output_tokens": 16})
else:
st, r = req("POST", path, {"model": MODEL, "max_tokens": 16,
"messages": [{"role": "user", "content": "diga ok"}]})
check(label, st in (200, 201), f"status={st}")
except Exception as e: # noqa: BLE001
print(f"[SKIP] {label} ausente neste build ({str(e)[:120]})")
print(f"\nTodos os checks obrigatorios passaram ({len(results)}).")
if __name__ == "__main__":
main()