chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Live smoke for the openai_codex (ChatGPT OAuth) provider.
|
||||
|
||||
Gated on the Codex CLI auth file existing (``$CODEX_HOME/auth.json`` or
|
||||
``~/.codex/auth.json``); exits 2 with guidance when it does not. Runs one
|
||||
text turn and one tool-call turn against the real ChatGPT backend and
|
||||
prints a compact JSON verdict. No secrets are printed.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import asyncio
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
from typing import Any
|
||||
|
||||
from opensquilla.provider.codex_auth import CodexAuthError, codex_auth_path, load_codex_credentials
|
||||
from opensquilla.provider.openai_codex import OpenAICodexProvider
|
||||
from opensquilla.provider.types import (
|
||||
ChatConfig,
|
||||
DoneEvent,
|
||||
ErrorEvent,
|
||||
Message,
|
||||
ReasoningDeltaEvent,
|
||||
TextDeltaEvent,
|
||||
ToolDefinition,
|
||||
ToolInputSchema,
|
||||
ToolUseEndEvent,
|
||||
)
|
||||
|
||||
|
||||
async def _run_turn(
|
||||
provider: OpenAICodexProvider,
|
||||
prompt: str,
|
||||
*,
|
||||
tools: list[ToolDefinition] | None = None,
|
||||
timeout: float = 120.0,
|
||||
) -> dict[str, Any]:
|
||||
start = time.perf_counter()
|
||||
text_parts: list[str] = []
|
||||
tool_ends: list[dict[str, Any]] = []
|
||||
reasoning_chars = 0
|
||||
done: DoneEvent | None = None
|
||||
error: ErrorEvent | None = None
|
||||
async for event in provider.chat(
|
||||
[Message(role="user", content=prompt)],
|
||||
tools=tools,
|
||||
config=ChatConfig(max_tokens=512, timeout=timeout),
|
||||
):
|
||||
if isinstance(event, TextDeltaEvent):
|
||||
text_parts.append(event.text)
|
||||
elif isinstance(event, ReasoningDeltaEvent):
|
||||
reasoning_chars += len(event.text)
|
||||
elif isinstance(event, ToolUseEndEvent):
|
||||
tool_ends.append({"name": event.tool_name, "arguments": event.arguments})
|
||||
elif isinstance(event, DoneEvent):
|
||||
done = event
|
||||
elif isinstance(event, ErrorEvent):
|
||||
error = event
|
||||
return {
|
||||
"content": "".join(text_parts),
|
||||
"tool_calls": tool_ends,
|
||||
"reasoning_chars": reasoning_chars,
|
||||
"usage": (
|
||||
{
|
||||
"input_tokens": done.input_tokens,
|
||||
"output_tokens": done.output_tokens,
|
||||
"cached_tokens": done.cached_tokens,
|
||||
"reasoning_tokens": done.reasoning_tokens,
|
||||
"model": done.model,
|
||||
"stop_reason": done.stop_reason,
|
||||
}
|
||||
if done
|
||||
else None
|
||||
),
|
||||
"error": {"code": error.code, "message": error.message[:300]} if error else None,
|
||||
"latency_ms": int((time.perf_counter() - start) * 1000),
|
||||
}
|
||||
|
||||
|
||||
async def main() -> int:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--model", default="gpt-5.5")
|
||||
parser.add_argument("--timeout", type=float, default=120.0)
|
||||
parser.add_argument("--skip-tools", action="store_true")
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
credentials = load_codex_credentials()
|
||||
except CodexAuthError as exc:
|
||||
print(f"SKIP: {exc}", file=sys.stderr)
|
||||
return 2
|
||||
account_hint = credentials.account_id[:8] if credentials.account_id else "(from JWT)"
|
||||
print(f"auth file: {codex_auth_path()} (account {account_hint}...)", file=sys.stderr)
|
||||
|
||||
provider = OpenAICodexProvider(model=args.model)
|
||||
report: dict[str, Any] = {"model": args.model}
|
||||
|
||||
marker = f"codex smoke {int(time.time())}"
|
||||
text = await _run_turn(
|
||||
provider, f"Reply exactly with: {marker}", timeout=args.timeout
|
||||
)
|
||||
text["marker_present"] = marker in text.pop("content", "")
|
||||
report["text_turn"] = text
|
||||
|
||||
if not args.skip_tools:
|
||||
tool = ToolDefinition(
|
||||
name="get_weather",
|
||||
description="Get current weather for a city.",
|
||||
input_schema=ToolInputSchema(
|
||||
properties={"city": {"type": "string"}}, required=["city"]
|
||||
),
|
||||
)
|
||||
tool_turn = await _run_turn(
|
||||
provider,
|
||||
"Use the get_weather tool to check the weather in Tokyo.",
|
||||
tools=[tool],
|
||||
timeout=args.timeout,
|
||||
)
|
||||
tool_turn.pop("content", None)
|
||||
report["tool_turn"] = tool_turn
|
||||
|
||||
print(json.dumps(report, indent=2, ensure_ascii=False))
|
||||
text_ok = bool(report["text_turn"].get("marker_present")) and not report["text_turn"]["error"]
|
||||
tool_ok = args.skip_tools or (
|
||||
bool(report.get("tool_turn", {}).get("tool_calls"))
|
||||
and not report.get("tool_turn", {}).get("error")
|
||||
)
|
||||
return 0 if text_ok and tool_ok else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(asyncio.run(main()))
|
||||
Reference in New Issue
Block a user