Repository navigation
Conversation
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
✅ Deterministic PR hygiene checks passed. |
⏳ DRAFT
What to do
Review readiness checklist
0/4 boxes ticked. This PR stays in draft until every box above is ticked. |
|
Scoped review at |
입력 정규화는 호출 쌍을 유지하고 미지원 part를 성공 문자열로 바꾸지 않는다. 빈 완료 검사는 원본 바이트를 넘긴 뒤 참조를 놓고, terminal/cancel에서만 upstream read를 취소한다. 재작성 응답은 도구 소유권과 시도별 usage를 유지하며 물리 재시도는 한 번이다.
|
Scoped follow-up at Input normalization and empty-completion recovery are now separately testable: Tool-result projection aligns call/output pairs before placing image messages, so those messages stay after the tool-result group instead of splitting a pair. Image-only results keep a Empty-response inspection releases held byte references after forwarding the original chunk on hold/size expiry and does not cancel a healthy upstream there. True terminal and consumer-cancel paths cancel the owned upstream read without awaiting a hanging cancel. Rewritten responses carry tool-ownership metadata. Each consumed attempt records its own usage once, and the guard makes at most one physical retry. Exact-head receipts cover SSE/JSON failure heads, reason-only versus empty output, max-output incomplete, stalled and cancelled reads, and replay-unsafe pass-through. Local focused tests, typecheck, structure check, and the docs build passed. This remains a draft: no OpenGateway call was made, and this rollup still has no functional CI execution. |
|
Intake/scoped review at The new receipt separates tool-output normalization from empty-completion recovery, including image placement after complete tool pairs, unsupported media refusal and a non-replayable cancellation after body ownership commits. Keep the off-provider, retry-limit and cancellation controls visible. The new author-reported tests are acknowledged; I did not run this branch locally and its Draft/CI requirements remain. Current-head functional workflows are awaiting fork approval; that is pending execution, not a passing test result. No local suite was run for this branch in this intake. No workflow approval, new scan, live configuration change or merge was performed. Required review/readiness gates remain in force. |
Carry the input-normalization slice of draft #7281 (16263b7). Preserve call/result identities and image content while projecting text arrays; reject unsupported or malformed parts explicitly instead of forwarding them. Keep the normalizer independently covered by mocked, immutable-input tests. Co-authored-by: HeiTuz <79418013+HeiTuz@users.noreply.github.com>
Carry the independent completion guard and replay-safety tests from draft #7281 (16263b7). Inspect SSE/JSON only before meaningful output, release the held prefix on time/size expiry, and permit at most one eligible retry callback. Release the owned reader lock on cancellation and remove a redundant counter. Co-authored-by: HeiTuz <79418013+HeiTuz@users.noreply.github.com>
Port the remaining adapter/dispatch integration from draft #7281 (16263b7) onto current dev. Map input incompatibility to HTTP 400 before any send; cap empty-completion recovery at one physical send, including HTTP 503 and connection-reset failures, while preserving existing admission and accounting. Cover the actual handler with mocked fetches and keep English/Korean guidance consistent. Split the OpenGateway structure contract to stay within document budgets and distinguish native recovery from the translated opt-in guard. Verification: typecheck, 118 focused tests, 27 layout tests, 9 size-ratchet tests, structure and privacy checks, and the docs build passed. Changed-mode rerun passed 19780 tests with 34 skips (30s timeout, two workers); the first run had one unrelated package-tree subprocess timeout, which also passed standalone. Co-authored-by: HeiTuz <79418013+HeiTuz@users.noreply.github.com>
…l-result handling for 2.90 (#7395) * fix(opengateway): normalize paired tool result inputs Carry the input-normalization slice of draft #7281 (16263b7). Preserve call/result identities and image content while projecting text arrays; reject unsupported or malformed parts explicitly instead of forwarding them. Keep the normalizer independently covered by mocked, immutable-input tests. Co-authored-by: HeiTuz <79418013+HeiTuz@users.noreply.github.com> * fix(opengateway): inspect empty completions with bounded replay Carry the independent completion guard and replay-safety tests from draft #7281 (16263b7). Inspect SSE/JSON only before meaningful output, release the held prefix on time/size expiry, and permit at most one eligible retry callback. Release the owned reader lock on cancellation and remove a redundant counter. Co-authored-by: HeiTuz <79418013+HeiTuz@users.noreply.github.com> * fix(opengateway): integrate completion recovery with the send budget Port the remaining adapter/dispatch integration from draft #7281 (16263b7) onto current dev. Map input incompatibility to HTTP 400 before any send; cap empty-completion recovery at one physical send, including HTTP 503 and connection-reset failures, while preserving existing admission and accounting. Cover the actual handler with mocked fetches and keep English/Korean guidance consistent. Split the OpenGateway structure contract to stay within document budgets and distinguish native recovery from the translated opt-in guard. Verification: typecheck, 118 focused tests, 27 layout tests, 9 size-ratchet tests, structure and privacy checks, and the docs build passed. Changed-mode rerun passed 19780 tests with 34 skips (30s timeout, two workers); the first run had one unrelated package-tree subprocess timeout, which also passed standalone. Co-authored-by: HeiTuz <79418013+HeiTuz@users.noreply.github.com> * fix(mistral): preserve cache keys and recover from rate limits Canonical key-auth Mistral Chat now sends prompt-cache keys, paces each credential/model pair from measured refusal headers with bounded, abortable waits outside the upstream header deadline, and retries 429s with a slower default budget. A server delay beyond the retry budget is kept non-replayable and its Retry-After reaches the caller. Relays, other adapters, OAuth credentials and xAI are unchanged. Co-authored-by: adaurban <31841049+adaurban@users.noreply.github.com> * fix(mistral): pace native Chat sends through the Mistral transport A single-key native Chat route never re-resolved its transport, so the new Mistral retry default replayed an over-budget Retry-After after 60 seconds instead of returning the refusal. Co-authored-by: adaurban <31841049+adaurban@users.noreply.github.com> * fix(opengateway): share the exact-URL boundary between normalization and recovery Co-authored-by: HeiTuz <79418013+HeiTuz@users.noreply.github.com> * test(responses): inventory the OpenGateway completion owners Co-authored-by: HeiTuz <79418013+HeiTuz@users.noreply.github.com> * fix(mistral): keep evicted pacing deadlines in force At 128 live identities the pacer dropped the oldest deadline, so that credential/model pair could send before its Retry-After. Remember the latest evicted deadline and make identities without an entry wait it out; memory stays bounded and the only cost is conservative pacing under extreme fan-out. Co-authored-by: adaurban <31841049+adaurban@users.noreply.github.com> * test(layout): keep B4b registrations within the layout file budget Merged with #7397, the three new rows pushed layout.json to 2001 lines. Fold them onto neighboring rows; the file stays at dev's 1998. Co-authored-by: adaurban <31841049+adaurban@users.noreply.github.com> Co-authored-by: HeiTuz <79418013+HeiTuz@users.noreply.github.com> * fix(mistral): hold only same-key replays on an over-budget Retry-After Marking the refusal non-replayable also blocked key-pool rotation and sanitized the upstream body. Use a same-target retry hold that only the same-key 429 loops check (native Chat, adapter dispatch and continuation, image and web-search loops), carried across response rewraps, so another pooled key can still serve and the original status, body and Retry-After reach the caller. Also keep an evicted identity's live deadline in force when it re-enters with a shorter delay. Co-authored-by: adaurban <31841049+adaurban@users.noreply.github.com> --------- Co-authored-by: HeiTuz <79418013+HeiTuz@users.noreply.github.com> Co-authored-by: adaurban <31841049+adaurban@users.noreply.github.com>
Summary
Codex의 OpenGateway 대화가 도구 결과 전송 시 400으로 중단되거나, 공급자가 텍스트 없이
completed를 보내 조용히 끝나는 문제를 처리합니다. 요청의 결과 배열을 호환 형식으로 변환하고, 응답에서는 출력 전의 확실한 빈 완료만 검사합니다.https://apis.opengateway.ai/v1/responses입니다. 텍스트 결과 배열을 문자열로 변환하고call_id와 텍스트 순서를 유지합니다.B → A도 분리하지 않습니다.detail: original을 지원되는high로 변환합니다. 이미지 바이트는 바꾸지 않습니다.output배열을 그대로 남겼습니다. 이 PR은 최종 outbound 직렬화 직전에 빠진 변환을 수행합니다.incomplete / max_output_tokens로 알립니다. 예산을 임의로 늘리지 않습니다. 예산이 남았고 명시적store:false·완전한 입력·client-only 도구인 경우에만 기존 전송 한도 안에서 한 번 복구합니다. 재시도 실패의 원래 HTTP 상태·본문·헤더를 유지하고, 두 번째 빈 200은 명시적 실패로 끝냅니다.최소 재현
2026-10-18 KST, 정식 v2.88.0(
6936d988)과 실제 OpenGateway 키로 확인했습니다. 아래 합성 요청에는 개인 대화나 자격 증명이 없습니다.deepseek/deepseek-v4.1-flash-ultrafast와z-ai/glm-5.3-flash-ultrafast모두 같은 결과입니다.payload.json:{ "model": "deepseek/deepseek-v4.1-flash-ultrafast", "input": [ {"role": "user", "content": "Reply exactly OK."}, {"type": "function_call", "call_id": "call_probe", "name": "echo", "arguments": "{\"value\":\"OK\"}"}, {"type": "function_call_output", "call_id": "call_probe", "output": [{"type": "input_text", "text": "OK"}]} ], "tools": [{"type": "function", "name": "echo", "description": "Return a value.", "parameters": {"type": "object", "properties": {"value": {"type": "string"}}, "required": ["value"], "additionalProperties": false}}], "reasoning": {"effort": "low"}, "max_output_tokens": 128, "stream": false }curl --silent --show-error --include \ https://apis.opengateway.ai/v1/responses \ -H "Authorization: Bearer ${OPENGATEWAY_API_KEY}" \ --json @payload.json수정 전에는 다음 오류를 반환합니다.
{"error":{"message":"The request was malformed or contained invalid parameters.","type":"invalid_request_error"}}같은 요청의 마지막
output만"OK"문자열로 바꾸면 두 모델 모두 HTTP 200과OK를 반환합니다. OCX 경유 재현은 URL을http://127.0.0.1:10100/v1/responses로, 모델을opengateway/deepseek-deepseek-v4.1-flash-ultrafast또는opengateway/z-ai-glm-5.3-flash-ultrafast로 바꾸면 됩니다. 로컬 인증이 설정된 환경은 해당 로컬 자격 증명을 사용합니다.추가 대조: GLM에 같은 PNG를
input_image로 보내되detail: original을 지정하면Input should be 'auto', 'low' or 'high'로 400을 반환했습니다.high로 바꾼 수정본은 HTTP 200과 실제 이미지 내용 설명을 반환했습니다.빈 완료의 공급자·OCX 비교 재현
다음 요청을 위
/v1/responsescurl로 보내면 두 모델에서 텍스트가 없는response.completed가 재현됐습니다.{ "model": "z-ai/glm-5.3-flash-ultrafast", "input": [{"role": "user", "content": "83476319 곱하기 34839727을 정확하게 계산하세요. 최종 숫자만 답하세요."}], "reasoning": {"effort": "high"}, "max_output_tokens": 16, "stream": true }messages,reasoning_effort: high,max_tokens: 16)finish_reason: lengthfinish_reason: length동일 물리 요청의 upstream
Response.clone()과 productionhandleResponses출력을 함께 수집해 비교했습니다. 이 재현에서는 OCX가 텍스트를 잃은 것이 아니라 공급자 원본부터 비었고 종료 상태가 잘못됐으며, native passthrough가 이를 그대로 성공 처리했습니다. 기존 translated empty-completion guard는 이 경로에서 실행되지 않았습니다. 공식 Responses 문서는incomplete상태와store/previous_response_id를 지원하지만,store생략을false라고 보장하지 않으므로 생략된 경우 자동 재생하지 않습니다.Verification
실제 호출 결과
OKOKOCX_REPRO_OKOCX_REPRO_OKmax결과 배열 재생OKOK실제 Desktop 번들 Codex CLI 0.163.0-alpha.10.2의
exec --ephemeral로printf OCX_REPRO_OK를 실행했습니다. 수정 전 DeepSeek에서는 셸 실행이 exit 0으로 끝난 뒤 모델 후속 요청이 400 /turn.failed/ CLI exit 1이었습니다. 수정 후 두 모델 모두 도구 결과를 읽고OCX_REPRO_OK를 반환했으며turn.completed와 0이 아닌 사용량을 확인했습니다. SSE 검증은 모델이 선택한 echo 인자를 로컬에서 실행한 뒤_EXECUTED를 붙인 결과를 배열로 반환하고, 최종 응답이 실제 실행 결과와 일치하는지 검사했습니다.DeepSeek
max첫 진단은 30초 클라이언트 제한으로 취소(499)됐습니다. 시간 제한을 120초, 출력 예산을 1024로 조정한 별도 검사에서 HTTP 200 /OK를 확인했습니다. 취소된 실행을 성공으로 집계하지 않았습니다.추가 실제 텍스트·복구 검증
2908292164924913을 텍스트로 반환했습니다. GLM의 예산 1024 검사는 추론에 전부 사용돼 미완료였으며 성공으로 집계하지 않았습니다.store:false·client-only 요청에서 두 번째 시도를 실제 API로 보냈습니다. 두 모델 모두 정확히 1회 재시도 후 한국어 텍스트를 반환했습니다. 이것을 해당 순간 자연발생한 빈 응답의 회복으로 표현하지 않습니다. 두 시도의 usage 합산과 sendCount=2도 확인했습니다.printf OCX_TEXT_READY실행 → 결과 확인 → 한국어 설명을 요청했습니다. GLM·DeepSeek 모두 exit 0 / turn.completed / 실제 한국어 최종 답변을 확인했습니다. 단순 HTTP 200을 성공 기준으로 삼지 않았습니다.store:false이지만web_search같은 hosted tool이 outbound에 남을 수 있습니다. 해당 요청은 빈 완료 시 명시적 실패만 하고 자동 재생하지 않습니다. 서버 실행을 중복시킬 수 있는 조건을 완화하지 않았습니다.자동 검증과 기준 커밋
bun scripts/test.ts --changed=HEAD실행: 19,352 pass / 34 skip / 0 fail, 813개 파일, 207.34초. 기준 HEAD는6936d988입니다.dev의2a10a2bc위에 올렸습니다. 위 검증 기준과 이 dev의 차이는 package/desktop 버전 번호 4개뿐이고, 구현·테스트·의존성 lockfile은 동일합니다. 리베이스로 수정 내용이 바뀌지 않았습니다.bb41ac3에서bun test tests/providers/opengateway-provider.test.ts: 17 pass / 0 fail / 53 assertions.bb41ac3)에서 Bun 1.4.3bun scripts/test.ts --changed=HEAD: 15,648 pass / 34 skip / 0 fail, 625개 파일, 165.59초. 저장한 검사 시작 파일 해시와 최종 8개 변경 파일이 모두 일치합니다. 두 실행의 수치는 겹치는 테스트를 포함하므로 합산하지 않습니다. 전체 2,468개 파일 실행은 아니며 기존 opt-in/플랫폼 skip을 변경하지 않았습니다.bun run typecheck,bun run structure:check,bun scripts/file-size-ratchet.ts,bun run privacy:scan, diff whitespace 검사 통과.cd docs-site && bun run build성공, 577페이지 / 81,423개 내부 링크 검사.검증 한계
Checklist
기여자 정책에 따라 Draft로 제출합니다. GitHub 검토 및 maintainer CI는 아직 대기 중입니다.
Review readiness checklist
This PR stays in draft until every box below is ticked. Tick all four boxes once the requirements are met:
Required local validation passed; commands, results, and any full-suite exception are documented.
I pushed my PR to a recent dev commit (at most 10 behind; a maintainer may still ask for the exact tip before merge).
I resolved all correct Codex and CodeRabbit findings.
My PR is ready for review.