112 lines
3.4 KiB
Python
112 lines
3.4 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
[Agent 入口] Python 独立进程 — JSON-RPC over HTTP
|
||
改监听地址:HOST / PORT
|
||
改业务方法:handle_rpc 内的 method 分支
|
||
协议字段必须与 Go internal/protocol 对齐(protocolVersion=1.0)
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import json
|
||
import uuid
|
||
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||
from typing import Any
|
||
|
||
HOST = "127.0.0.1"
|
||
PORT = 17890
|
||
PROTOCOL_VERSION = "1.0"
|
||
|
||
|
||
def handle_rpc(body: dict[str, Any]) -> dict[str, Any]:
|
||
# ---------- [关键] 所有 Agent method 分发在这里 ----------
|
||
req_id = body.get("id") or str(uuid.uuid4())
|
||
version = body.get("protocolVersion", "")
|
||
method = body.get("method", "")
|
||
params = body.get("params") or {}
|
||
|
||
if version != PROTOCOL_VERSION:
|
||
return {
|
||
"protocolVersion": PROTOCOL_VERSION,
|
||
"id": req_id,
|
||
"error": {
|
||
"code": -32000,
|
||
"message": f"protocol mismatch: got {version}, want {PROTOCOL_VERSION}",
|
||
},
|
||
}
|
||
|
||
if method == "agent.health":
|
||
return {
|
||
"protocolVersion": PROTOCOL_VERSION,
|
||
"id": req_id,
|
||
"result": {"ok": True, "engine": "python-stub"},
|
||
}
|
||
|
||
if method == "agent.chat":
|
||
# TODO[云端 API]: 在此接入 OpenAI / Claude 等
|
||
message = ""
|
||
if isinstance(params, dict):
|
||
message = str(params.get("message") or params.get("userMessage") or "")
|
||
return {
|
||
"protocolVersion": PROTOCOL_VERSION,
|
||
"id": req_id,
|
||
"result": {
|
||
"role": "assistant",
|
||
"content": f"(Python stub)收到:{message}",
|
||
},
|
||
}
|
||
|
||
if method == "agent.plan_next":
|
||
# TODO[多模态]: 解析 frameBase64 + userMessage → actions
|
||
return {
|
||
"protocolVersion": PROTOCOL_VERSION,
|
||
"id": req_id,
|
||
"result": {
|
||
"thought": "骨架:尚未接入视觉模型",
|
||
"actions": [],
|
||
},
|
||
}
|
||
|
||
return {
|
||
"protocolVersion": PROTOCOL_VERSION,
|
||
"id": req_id,
|
||
"error": {"code": -32601, "message": f"method not found: {method}"},
|
||
}
|
||
|
||
|
||
class RPCHandler(BaseHTTPRequestHandler):
|
||
def log_message(self, fmt: str, *args: Any) -> None:
|
||
print(f"[agent] {self.address_string()} - {fmt % args}")
|
||
|
||
def do_POST(self) -> None:
|
||
# [关键] 唯一 RPC 入口路径
|
||
if self.path != "/rpc":
|
||
self.send_error(404)
|
||
return
|
||
length = int(self.headers.get("Content-Length", "0"))
|
||
raw = self.rfile.read(length)
|
||
try:
|
||
body = json.loads(raw.decode("utf-8"))
|
||
except json.JSONDecodeError:
|
||
self._write(400, {"error": {"code": -32700, "message": "parse error"}})
|
||
return
|
||
self._write(200, handle_rpc(body))
|
||
|
||
def _write(self, status: int, payload: dict[str, Any]) -> None:
|
||
data = json.dumps(payload, ensure_ascii=False).encode("utf-8")
|
||
self.send_response(status)
|
||
self.send_header("Content-Type", "application/json; charset=utf-8")
|
||
self.send_header("Content-Length", str(len(data)))
|
||
self.end_headers()
|
||
self.wfile.write(data)
|
||
|
||
|
||
def main() -> None:
|
||
server = HTTPServer((HOST, PORT), RPCHandler)
|
||
print(f"[agent] listening on http://{HOST}:{PORT}/rpc protocol={PROTOCOL_VERSION}")
|
||
server.serve_forever()
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|