1import json2import threading3import unittest4from http.client import HTTPConnection5from pathlib import Path6import importlib.util789MODULE_PATH = Path(__file__).with_name("model.py")10SPEC = importlib.util.spec_from_file_location("tiny_agent_lab_model", MODULE_PATH)11model = importlib.util.module_from_spec(SPEC)12assert SPEC.loader is not None13SPEC.loader.exec_module(model)141516class ModelFixtureTests(unittest.TestCase):17 def test_hello_uses_latest_user_marker(self):18 result = model.complete({"model": "tiny-lab", "messages": [19 {"role": "user", "content": "old LAB_HELLO_old"},20 {"role": "assistant", "content": "done"},21 {"role": "user", "content": "LAB_HELLO_new"},22 ]})23 self.assertEqual(result["choices"][0]["message"]["content"], "LAB_DONE LAB_HELLO_new")2425 def test_question_requires_advertised_tool_and_returns_canonical_batch(self):26 body = {"messages": [{"role": "user", "content": "LAB_QUESTION_123"}], "tools": [{"type": "function", "function": {"name": "clarify"}}]}27 call = model.complete(body)["choices"][0]["message"]["tool_calls"][0]28 self.assertEqual(call["function"]["name"], "clarify")29 args = json.loads(call["function"]["arguments"])30 self.assertEqual(args["questions"][0]["choices"], ["Continue", "Stop"])31 self.assertFalse(args["questions"][0]["multi_select"])32 error = model.complete({"messages": body["messages"]})["choices"][0]["message"]["content"]33 self.assertIn("clarify tool is unavailable", error)3435 def test_multi_and_approval_tool_results_complete_turn(self):36 multi = model.complete({"messages": [{"role": "user", "content": "LAB_MULTI_123"}], "tools": [{"type": "function", "function": {"name": "clarify"}}]})37 args = json.loads(multi["choices"][0]["message"]["tool_calls"][0]["function"]["arguments"])38 self.assertTrue(args["questions"][0]["multi_select"])39 approval = model.complete({"messages": [{"role": "user", "content": "LAB_APPROVAL_123"}], "tools": [{"type": "function", "function": {"name": "execute_code"}}]})40 approval_call = approval["choices"][0]["message"]["tool_calls"][0]41 self.assertEqual(json.loads(approval_call["function"]["arguments"])["code"], "print('tinyagent-lab')")42 done = model.complete({"messages": [43 {"role": "user", "content": "LAB_APPROVAL_123"},44 {"role": "assistant", "content": None, "tool_calls": [approval_call]},45 {"role": "tool", "tool_call_id": approval_call["id"], "content": '{"stdout":"tinyagent-lab\\n"}'},46 ]})47 self.assertIn("tinyagent-lab", done["choices"][0]["message"]["content"])4849 def test_mention_requires_explicit_operator_hex_and_media_is_visible(self):50 operator = "a" * 6451 mentioned = model.complete({"messages": [{"role": "user", "content": f"LAB_MENTION_123 @{operator}"}]})52 self.assertEqual(mentioned["choices"][0]["message"]["content"], f"LAB_DONE LAB_MENTION_123 @{operator}")53 absent = model.complete({"messages": [{"role": "user", "content": "LAB_MENTION_124 @operator"}]})54 self.assertEqual(absent["choices"][0]["message"]["content"], "LAB_DONE LAB_MENTION_124")55 media = model.complete({"messages": [{"role": "user", "content": "LAB_MEDIA_123 [file: tinyagent-attachment-notes.txt]"}]})56 self.assertEqual(media["choices"][0]["message"]["content"], "LAB_DONE LAB_MEDIA_123 MEDIA_RECEIVED tinyagent-attachment-notes.txt")5758 def test_http_health_models_and_sse(self):59 server = model.ThreadingHTTPServer(("127.0.0.1", 0), model.Handler)60 threading.Thread(target=server.serve_forever, daemon=True).start()61 try:62 conn = HTTPConnection("127.0.0.1", server.server_port)63 conn.request("GET", "/healthz")64 self.assertEqual(conn.getresponse().status, 200)65 conn.close()66 conn = HTTPConnection("127.0.0.1", server.server_port)67 body = json.dumps({"model": "tiny-lab", "stream": True, "messages": [{"role": "user", "content": "LAB_HELLO_sse"}]}).encode()68 conn.request("POST", "/v1/chat/completions", body, {"Content-Type": "application/json"})69 response = conn.getresponse()70 payload = response.read().decode()71 self.assertEqual(response.status, 200)72 self.assertIn('LAB_DONE LAB_HELLO_sse', payload)73 self.assertIn("data: [DONE]", payload)74 conn.close()75 finally:76 server.shutdown()77 server.server_close()787980if __name__ == "__main__":81 unittest.main()