Skip to content

Commit c32e4a6

Browse files
committed
api: add json-verbose output format support + test
1 parent 03a7569 commit c32e4a6

File tree

2 files changed

+33
-2
lines changed

2 files changed

+33
-2
lines changed

api_server.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
from fastapi.responses import FileResponse, Response
1212
from pydantic import BaseModel, ConfigDict, Field
1313

14+
from jsonverbose import assemble # noqa: E402
15+
1416
app = FastAPI()
1517

1618

@@ -98,6 +100,7 @@ class RunRequest(BaseModel):
98100
append_system_prompt: Optional[str] = Field(None, alias="appendSystemPrompt")
99101
json_schema: Optional[str] = Field(None, alias="jsonSchema")
100102
effort: Optional[str] = None
103+
output_format: Optional[str] = Field(None, alias="outputFormat")
101104
no_continue: bool = Field(False, alias="noContinue")
102105
resume: Optional[str] = None
103106
fire_and_forget: bool = Field(False, alias="fireAndForget")
@@ -109,7 +112,10 @@ def _build_args(req: RunRequest, with_continue: bool = False):
109112
args += ["--resume", req.resume]
110113
elif with_continue and not req.no_continue:
111114
args.append("--continue")
112-
args += ["-p", req.prompt, "--output-format", "json"]
115+
if req.output_format == "json-verbose":
116+
args += ["-p", req.prompt, "--output-format", "stream-json", "--verbose"]
117+
else:
118+
args += ["-p", req.prompt, "--output-format", "json"]
113119
if req.model:
114120
args += ["--model", req.model]
115121
if req.system_prompt:
@@ -242,7 +248,14 @@ async def _disconnect_watcher():
242248
if not req.fire_and_forget and await request.is_disconnected():
243249
return Response(status_code=499)
244250

245-
return Response(content=_normalize_response(output), media_type="application/json")
251+
if req.output_format == "json-verbose":
252+
lines = output.decode().splitlines()
253+
assembled = assemble(lines)
254+
content = json.dumps(assembled).encode()
255+
else:
256+
content = _normalize_response(output)
257+
258+
return Response(content=content, media_type="application/json")
246259

247260

248261
@app.get("/files/{path:path}")

tests/test_api.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,23 @@ test_api_continue_fallback() {
243243
_api_stop "${API_CONTAINER}-cont"
244244
}
245245

246+
# ── json-verbose output format ──────────────────────────────────────────────
247+
248+
test_api_json_verbose() {
249+
_api_start "${API_CONTAINER}-jv" || return 1
250+
251+
local out
252+
out=$(post "$API_BASE/run" \
253+
"{\"prompt\": \"read the file /etc/hostname and tell me what it says\", \"model\": \"$TEST_MODEL\", \"noContinue\": true, \"outputFormat\": \"json-verbose\"}")
254+
assert_contains "$out" '"turns"' "json-verbose has turns array" || { _api_stop "${API_CONTAINER}-jv"; return 1; }
255+
assert_contains "$out" '"tool_use"' "json-verbose has tool_use in turns" || { _api_stop "${API_CONTAINER}-jv"; return 1; }
256+
assert_contains "$out" '"tool_result"' "json-verbose has tool_result in turns" || { _api_stop "${API_CONTAINER}-jv"; return 1; }
257+
assert_contains "$out" '"system"' "json-verbose has system init" || { _api_stop "${API_CONTAINER}-jv"; return 1; }
258+
259+
echo "OK: api_json_verbose"
260+
_api_stop "${API_CONTAINER}-jv"
261+
}
262+
246263
ALL_TESTS+=(
247264
test_api_endpoints
248265
test_api_run
@@ -254,4 +271,5 @@ ALL_TESTS+=(
254271
test_api_no_continue
255272
test_api_append_system_prompt
256273
test_api_continue_fallback
274+
test_api_json_verbose
257275
)

0 commit comments

Comments
 (0)