from __future__ import annotations import asyncio from typing import Iterable from api import Request, Response from secret_stream_socket import wrap_connection_socket SERVER_HOST = "127.0.0.1" SERVER_PORT = 9000 SHARED_SECRET = "change-me" def build_chat_request(request_id: int, role: str, content: str) -> bytes: return Request.build( { "request_id": request_id, "kind": "chat", "payload": { "messages": [ { "role": role, "content": content, } ] }, } ) def describe_response(response: object) -> str: kind = response.kind if kind == "chat": return f"chat piece: {response.payload.piece!r}" if kind == "cancel": return "cancel" if kind == "end": return "end" return f"unknown {kind!r}" def is_terminal_response(response: object) -> bool: return response.kind in ("cancel", "end") async def read_responses(transport, pending: set[int]) -> None: while pending: frame = await transport.recv_frame() if frame is None: print("[disconnected]") return response = Response.parse(frame) print(f"[recv] request_id={response.request_id} {describe_response(response)}") if is_terminal_response(response): pending.discard(response.request_id) async def main() -> None: reader, writer = await asyncio.open_connection(SERVER_HOST, SERVER_PORT) transport = await wrap_connection_socket(reader, writer, SHARED_SECRET) requests: Iterable[bytes] = [ build_chat_request(1, "user", "hello from client one"), build_chat_request(2, "user", "second request with more words"), ] for payload in requests: await transport.send_frame(payload) await read_responses(transport, {1, 2}) await transport.close() if __name__ == "__main__": asyncio.run(main())