v2.2.0: agent persona selector, Command Code backend, per-provider identity
This commit is contained in:
@@ -30,7 +30,7 @@ def load_config():
|
||||
p = argparse.ArgumentParser(description="Responses API translation proxy")
|
||||
p.add_argument("--config", help="JSON config file path")
|
||||
p.add_argument("--port", type=int, default=None)
|
||||
p.add_argument("--backend", default=None, choices=["openai-compat", "anthropic"])
|
||||
p.add_argument("--backend", default=None, choices=["openai-compat", "anthropic", "command-code"])
|
||||
p.add_argument("--target-url", default=None)
|
||||
p.add_argument("--api-key", default=None)
|
||||
p.add_argument("--models-file", default=None, help="JSON file with model list array")
|
||||
@@ -80,6 +80,7 @@ BACKEND = CONFIG["backend_type"]
|
||||
TARGET_URL = CONFIG["target_url"].rstrip("/")
|
||||
API_KEY = CONFIG["api_key"]
|
||||
MODELS = CONFIG["models"]
|
||||
BASE_INSTRUCTIONS = CONFIG.get("base_instructions", "")
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════
|
||||
# Shared helpers
|
||||
@@ -500,6 +501,119 @@ def an_stream_to_sse(stream, model, req_id):
|
||||
"response": {"id": resp_id, "object": "response", "model": model,
|
||||
"status": status, "created": int(time.time()), "output": completed}})
|
||||
|
||||
_DEFAULT_CC_CONFIG = {
|
||||
"workingDir": "/tmp",
|
||||
"date": "",
|
||||
"environment": "linux",
|
||||
"shell": "bash",
|
||||
"files": [],
|
||||
"structure": [],
|
||||
"isGitRepo": False,
|
||||
"currentBranch": "",
|
||||
"mainBranch": "",
|
||||
"gitStatus": "",
|
||||
"recentCommits": [],
|
||||
}
|
||||
|
||||
def _cc_config():
|
||||
cfg = dict(_DEFAULT_CC_CONFIG)
|
||||
cfg["date"] = time.strftime("%Y-%m-%d")
|
||||
return cfg
|
||||
|
||||
def cc_input_to_messages(input_data):
|
||||
return oa_input_to_messages(input_data)
|
||||
|
||||
def cc_convert_tools(tools):
|
||||
return oa_convert_tools(tools)
|
||||
|
||||
def cc_resp_to_responses(cc_lines, model, resp_id=None):
|
||||
text = ""
|
||||
usage = {}
|
||||
for line in cc_lines:
|
||||
try:
|
||||
d = json.loads(line)
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
continue
|
||||
t = d.get("type", "")
|
||||
if t == "text-delta":
|
||||
text += d.get("text", "")
|
||||
elif t == "finish-step":
|
||||
u = d.get("usage", {})
|
||||
usage = {
|
||||
"input_tokens": u.get("inputTokens", 0),
|
||||
"output_tokens": u.get("outputTokens", 0),
|
||||
"total_tokens": u.get("inputTokens", 0) + u.get("outputTokens", 0),
|
||||
}
|
||||
outputs = []
|
||||
if text:
|
||||
outputs.append({"type": "message", "id": uid("msg"), "role": "assistant",
|
||||
"status": "completed",
|
||||
"content": [{"type": "output_text", "text": text, "annotations": []}]})
|
||||
return {"id": resp_id or uid("resp"), "object": "response", "created": int(time.time()),
|
||||
"model": model, "status": "completed", "output": outputs,
|
||||
"usage": {"input_tokens": usage.get("input_tokens", 0),
|
||||
"output_tokens": usage.get("output_tokens", 0),
|
||||
"total_tokens": usage.get("total_tokens", 0),
|
||||
"input_tokens_details": {"cached_tokens": 0}}}
|
||||
|
||||
def cc_stream_to_sse(cc_stream, model, req_id):
|
||||
resp_id = req_id or uid("resp")
|
||||
msg_id = uid("msg")
|
||||
text_buf = ""
|
||||
|
||||
yield emit("response.created", {"type": "response.created",
|
||||
"response": {"id": resp_id, "object": "response", "model": model,
|
||||
"status": "in_progress", "created": int(time.time()), "output": []}})
|
||||
yield emit("response.in_progress", {"type": "response.in_progress", "response": {"id": resp_id}})
|
||||
yield emit("response.output_item.added", {"type": "response.output_item.added",
|
||||
"item": {"type": "message", "id": msg_id, "role": "assistant", "status": "in_progress", "content": []}})
|
||||
yield emit("response.content_part.added", {"type": "response.content_part.added",
|
||||
"part": {"type": "output_text", "text": "", "annotations": []}, "item_id": msg_id})
|
||||
|
||||
total_usage = {}
|
||||
for raw in cc_stream:
|
||||
line = raw.decode("utf-8", errors="replace").strip()
|
||||
if not line:
|
||||
continue
|
||||
try:
|
||||
d = json.loads(line)
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
t = d.get("type", "")
|
||||
|
||||
if t == "text-delta":
|
||||
txt = d.get("text", "")
|
||||
if txt:
|
||||
text_buf += txt
|
||||
yield emit("response.output_text.delta", {"type": "response.output_text.delta",
|
||||
"delta": txt, "item_id": msg_id, "content_index": 0})
|
||||
|
||||
elif t == "finish-step":
|
||||
u = d.get("usage", {})
|
||||
total_usage = {
|
||||
"input_tokens": u.get("inputTokens", 0),
|
||||
"output_tokens": u.get("outputTokens", 0),
|
||||
"total_tokens": u.get("inputTokens", 0) + u.get("outputTokens", 0),
|
||||
}
|
||||
|
||||
if text_buf:
|
||||
yield emit("response.output_text.done", {"type": "response.output_text.done",
|
||||
"text": text_buf, "item_id": msg_id, "content_index": 0})
|
||||
yield emit("response.content_part.done", {"type": "response.content_part.done",
|
||||
"part": {"type": "output_text", "text": text_buf, "annotations": []}, "item_id": msg_id})
|
||||
yield emit("response.output_item.done", {"type": "response.output_item.done",
|
||||
"item": {"type": "message", "id": msg_id, "role": "assistant", "status": "completed",
|
||||
"content": [{"type": "output_text", "text": text_buf, "annotations": []}]}})
|
||||
|
||||
final_out = []
|
||||
if text_buf:
|
||||
final_out.append({"type": "message", "id": msg_id, "role": "assistant", "status": "completed",
|
||||
"content": [{"type": "output_text", "text": text_buf, "annotations": []}]})
|
||||
yield emit("response.completed", {"type": "response.completed",
|
||||
"response": {"id": resp_id, "object": "response", "model": model,
|
||||
"status": "completed", "created": int(time.time()), "output": final_out,
|
||||
"usage": total_usage}})
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════
|
||||
# HTTP Server
|
||||
# ═══════════════════════════════════════════════════════════════════
|
||||
@@ -531,6 +645,8 @@ class Handler(http.server.BaseHTTPRequestHandler):
|
||||
|
||||
if BACKEND == "anthropic":
|
||||
self._handle_anthropic(body, model, stream)
|
||||
elif BACKEND == "command-code":
|
||||
self._handle_command_code(body, model, stream)
|
||||
else:
|
||||
self._handle_openai_compat(body, model, stream)
|
||||
|
||||
@@ -538,6 +654,8 @@ class Handler(http.server.BaseHTTPRequestHandler):
|
||||
input_data = body.get("input", "")
|
||||
messages = oa_input_to_messages(input_data)
|
||||
instructions = body.get("instructions", "").strip()
|
||||
if not instructions and BASE_INSTRUCTIONS:
|
||||
instructions = BASE_INSTRUCTIONS
|
||||
if instructions:
|
||||
messages.insert(0, {"role": "system", "content": instructions})
|
||||
chat_body = {"model": model, "messages": messages}
|
||||
@@ -571,6 +689,8 @@ class Handler(http.server.BaseHTTPRequestHandler):
|
||||
an_body = {"model": model, "messages": an_input_to_messages(input_data),
|
||||
"max_tokens": body.get("max_output_tokens", 8192)}
|
||||
instructions = body.get("instructions", "").strip()
|
||||
if not instructions and BASE_INSTRUCTIONS:
|
||||
instructions = BASE_INSTRUCTIONS
|
||||
if instructions:
|
||||
an_body["system"] = instructions
|
||||
for k in ("temperature", "top_p"):
|
||||
@@ -601,6 +721,76 @@ class Handler(http.server.BaseHTTPRequestHandler):
|
||||
lambda r: an_resp_to_responses(json.loads(r.read()), model),
|
||||
lambda s: an_stream_to_sse(s, model, body.get("request_id") or body.get("id")))
|
||||
|
||||
def _handle_command_code(self, body, model, stream):
|
||||
input_data = body.get("input", "")
|
||||
instructions = body.get("instructions", "").strip()
|
||||
messages = cc_input_to_messages(input_data)
|
||||
if not instructions and BASE_INSTRUCTIONS:
|
||||
instructions = BASE_INSTRUCTIONS
|
||||
if instructions:
|
||||
sys_msg = {"role": "system", "content": instructions}
|
||||
messages.insert(0, sys_msg)
|
||||
|
||||
cc_body = {
|
||||
"config": _cc_config(),
|
||||
"memory": "",
|
||||
"taste": "",
|
||||
"skills": "",
|
||||
"params": {
|
||||
"stream": True,
|
||||
"max_tokens": body.get("max_output_tokens", 64000),
|
||||
"temperature": body.get("temperature", 0.3),
|
||||
"messages": messages,
|
||||
"model": model,
|
||||
"tools": cc_convert_tools(body.get("tools")) or [],
|
||||
},
|
||||
"threadId": body.get("request_id") or uid("thread"),
|
||||
}
|
||||
|
||||
target = upstream_target(TARGET_URL, "/alpha/generate")
|
||||
fwd = forwarded_headers(self.headers, {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {API_KEY}",
|
||||
"Accept": "text/event-stream, application/json",
|
||||
}, browser_ua=True)
|
||||
print(f"[translate-proxy] POST {target} model={model} stream={stream} [command-code]", file=sys.stderr)
|
||||
req = urllib.request.Request(
|
||||
target,
|
||||
data=json.dumps(cc_body).encode(),
|
||||
headers=fwd,
|
||||
)
|
||||
|
||||
if stream:
|
||||
try:
|
||||
upstream = urllib.request.urlopen(req)
|
||||
except urllib.error.HTTPError as e:
|
||||
err = e.read().decode()
|
||||
return self.send_json(e.code, {"error": {"type": "upstream_error", "message": err}})
|
||||
except Exception as e:
|
||||
return self.send_json(500, {"error": {"type": "proxy_error", "message": str(e)}})
|
||||
|
||||
self.send_response(200)
|
||||
self.send_header("Content-Type", "text/event-stream")
|
||||
self.send_header("Cache-Control", "no-cache")
|
||||
self.send_header("Connection", "keep-alive")
|
||||
self.end_headers()
|
||||
for event in cc_stream_to_sse(upstream, model, body.get("request_id") or body.get("id")):
|
||||
self.wfile.write(event.encode("utf-8"))
|
||||
self.wfile.flush()
|
||||
else:
|
||||
try:
|
||||
upstream = urllib.request.urlopen(req)
|
||||
except urllib.error.HTTPError as e:
|
||||
err = e.read().decode()
|
||||
return self.send_json(e.code, {"error": {"type": "upstream_error", "message": err}})
|
||||
except Exception as e:
|
||||
return self.send_json(500, {"error": {"type": "proxy_error", "message": str(e)}})
|
||||
|
||||
raw = upstream.read().decode()
|
||||
lines = raw.strip().split("\n")
|
||||
result = cc_resp_to_responses(lines, model)
|
||||
self.send_json(200, result)
|
||||
|
||||
def _forward(self, req, stream, model, nonstream_fn, stream_fn):
|
||||
try:
|
||||
upstream = urllib.request.urlopen(req)
|
||||
|
||||
Reference in New Issue
Block a user