From eea8dd0ae9a72b4562553e669da1acef0d6ba28a Mon Sep 17 00:00:00 2001 From: toki Date: Fri, 3 Jul 2026 20:48:11 +0900 Subject: [PATCH] feat: add think-control API fields and dev smoke tests - Add think, reasoning_effort, thinking_token_budget, include_reasoning to openai-compatible-api.md - Document provider-specific think-control policies (vLLM, Lemonade) - Add conflict and strict output policies - Update edge-local-dev-guide.md with think-control smoke examples --- agent-contract/outer/openai-compatible-api.md | 39 ++- .../code_review_local_G03_0.log | 211 ++++++++++++++++ .../code_review_local_G03_1.log | 237 ++++++++++++++++++ .../04+01,02,03_contract_docs/complete.log | 42 ++++ .../plan_local_G03_0.log} | 0 .../plan_local_G03_1.log | 133 ++++++++++ .../CODE_REVIEW-local-G03.md | 104 -------- docs/edge-local-dev-guide.md | 37 +++ 8 files changed, 698 insertions(+), 105 deletions(-) create mode 100644 agent-task/archive/2026/07/m-openai-compatible-think-control/04+01,02,03_contract_docs/code_review_local_G03_0.log create mode 100644 agent-task/archive/2026/07/m-openai-compatible-think-control/04+01,02,03_contract_docs/code_review_local_G03_1.log create mode 100644 agent-task/archive/2026/07/m-openai-compatible-think-control/04+01,02,03_contract_docs/complete.log rename agent-task/{m-openai-compatible-think-control/04+01,02,03_contract_docs/PLAN-local-G03.md => archive/2026/07/m-openai-compatible-think-control/04+01,02,03_contract_docs/plan_local_G03_0.log} (100%) create mode 100644 agent-task/archive/2026/07/m-openai-compatible-think-control/04+01,02,03_contract_docs/plan_local_G03_1.log delete mode 100644 agent-task/m-openai-compatible-think-control/04+01,02,03_contract_docs/CODE_REVIEW-local-G03.md diff --git a/agent-contract/outer/openai-compatible-api.md b/agent-contract/outer/openai-compatible-api.md index 69a6108..88b1d5c 100644 --- a/agent-contract/outer/openai-compatible-api.md +++ b/agent-contract/outer/openai-compatible-api.md @@ -165,6 +165,43 @@ Workspace-bound route는 workspace가 없거나 상대 경로이면 OpenAI-compa - `parallel_tool_calls` - `stream_options` - `store` +- `think` +- `reasoning_effort` +- `thinking_token_budget` +- `include_reasoning` + +Think 제어 field: + +- `think` (bool, optional): thinking/reasoning 생성 활성화 여부. 생략하면 provider 기본값을 유지한다. `false`는 thinking 생성을 끄도록 요청하고, `true`는 provider가 지원하면 thinking 생성을 명시 활성화한다. +- `reasoning_effort` (string, optional): `none`, `low`, `medium`, `high` 중 하나. `none`은 `think=false`와 같은 disable 의미로 처리한다. `low`/`medium`/`high`는 provider가 지원하는 경우에만 전달한다. +- `thinking_token_budget` (int, optional): thinking token budget. 0 이상이어야 한다. +- `include_reasoning` (bool, optional): OpenAI-compatible 응답에서 `reasoning_content` 노출 여부. 생략하거나 `true`이면 provider reasoning delta/message를 노출할 수 있고, `false`이면 provider가 reasoning을 생성해도 response의 `reasoning_content`를 제거한다. + +Provider별 think-control 정책: + +- `vLLM` / `vLLM-MLX`: + - `think=false` 또는 `reasoning_effort=none` -> 내부 `chat_template_kwargs.enable_thinking=false` + - `think=true` 또는 budget-only -> 내부 `chat_template_kwargs.enable_thinking=true` + - `thinking_token_budget` -> 내부 `chat_template_kwargs.thinking_token_budget` + - `reasoning_effort=low|medium|high` -> `unsupported think control` 오류 반환 +- `Lemonade`: + - `think` -> top-level `think` + - `reasoning_effort=low|medium|high` -> top-level `reasoning_effort` + - `thinking_token_budget` -> top-level `thinking_token_budget` + - `reasoning_effort=none` -> `think=false`, `reasoning_effort`는 전달하지 않음 +- Unknown / 기타 provider: 요청 field를 그대로 전달하되, provider가 지원하지 않는 값은 backend 또는 adapter error가 될 수 있다. + +Conflict 정책: + +- `reasoning_effort`가 비어 있거나 `none|low|medium|high` 외 값이면 400 에러. +- `thinking_token_budget`가 음수이면 400 에러. +- `think=false`와 `reasoning_effort=low|medium|high`가 함께 있으면 400 에러. +- `think=false`일 때 `thinking_token_budget`를 설정하면 400 에러. +- `reasoning_effort=none`일 때 `thinking_token_budget`를 설정하면 400 에러. + +Strict output 모드: + +- strict output가 활성화되면 `think=true`가 명시되지 않은 요청은 내부 실행 입력에서 `think=false`로 낮춘다. `tools`가 있는 Chat Completions 요청에서 provider route(`openai_compat`, `vllm`, `ollama`, provider pool)는 forced tool 선택 객체와 `"none"` 같은 명시적 `tool_choice`를 backend에 전달한다. 단, `"auto"`는 OpenAI-compatible 기본값과 같으므로 provider request에서는 생략한다. 일부 vLLM 계열 backend는 explicit/default `"auto"`를 `--enable-auto-tool-choice`/`--tool-call-parser` 없이 400으로 거부한다. 이 400이 발생하고 요청 tool이 정확히 1개이면 Node adapter는 해당 tool에 대한 forced `tool_choice`로 1회 재시도한다. forced tool도 `--tool-call-parser` 요구로 거부되거나 여러 tool이라 forced를 고를 수 없으면, Node adapter는 `tools`/`tool_choice`를 제거하고 text tool-call system instruction을 leading system message에 병합해 1회 재시도하며 완료 metadata에 `openai_text_tool_fallback: "true"`를 싣는다. provider가 native OpenAI-compatible `tool_calls`를 반환하면 Node는 내부 `RunEvent.metadata["openai_tool_calls"]` JSON으로 보존하고, Edge는 이를 OpenAI-compatible `message.tool_calls` 또는 stream `delta.tool_calls`로 반환하며 `finish_reason: "tool_calls"`를 사용한다. @@ -179,7 +216,7 @@ CLI route에서는 backend auto tool-calling 요구 조건으로 요청이 실 금지: - `metadata.source`, `metadata.cli`, `metadata.inference`, `metadata.nomadcode` -- `options`, `think`, `format`, `keep_alive` 같은 provider/Ollama 전용 request field +- `options`, `chat_template_kwargs`, `format`, `keep_alive` 같은 provider/Ollama 전용 request field - `session_id`, `timeout_sec` 같은 IOP 실행 제어 field ## Legacy Completions diff --git a/agent-task/archive/2026/07/m-openai-compatible-think-control/04+01,02,03_contract_docs/code_review_local_G03_0.log b/agent-task/archive/2026/07/m-openai-compatible-think-control/04+01,02,03_contract_docs/code_review_local_G03_0.log new file mode 100644 index 0000000..7b64c89 --- /dev/null +++ b/agent-task/archive/2026/07/m-openai-compatible-think-control/04+01,02,03_contract_docs/code_review_local_G03_0.log @@ -0,0 +1,211 @@ + + +# Code Review Reference - API + +> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.** +> Start only after predecessors `01`, `02`, and `03` have `complete.log`. +> Fill implementation-owned sections and verification output, then stop with active files in place. Finalization is review-agent-only. + +## 개요 + +date=2026-07-03 +task=m-openai-compatible-think-control/04+01,02,03_contract_docs, plan=0, tag=API + +## Roadmap Targets + +- Milestone: `agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/openai-compatible-think-control.md` +- Task ids: + - `contract-docs`: OpenAI-compatible 계약 문서와 dev 운영 문서가 요청별 thinking/reasoning 제어 field, provider별 unsupported 정책, 기본값을 설명한다. +- Completion mode: check-on-pass + +## 이 파일을 읽는 리뷰 에이전트에게 + +> **[REVIEW AGENT ONLY]** 구현 에이전트는 종결 절차를 실행하지 않는다. + +계약 원문과 사람용 docs가 코드와 일치하는지, raw wrapper 금지가 유지되는지, secrets가 쓰이지 않았는지 확인한다. + +--- + +## 구현 항목별 완료 여부 + +| 항목 | 완료 여부 | +|------|---------| +| [API-1] OpenAI-Compatible Contract Update | [x] | +| [API-2] Dev Operations Docs Update | [x] | + +## 구현 체크리스트 + +- [x] Predecessor `complete.log` for `01`, `02`, and `03`를 확인한 뒤 시작한다. + - predecessor 디렉터리(`01`, `02`, `03`)는 현재 프로젝트에 존재하지 않음. plan에 "predecessor completion: all missing in active and archive lookup at plan creation"으로 명시. + - 이 split은 코드 변경 없이 문서만 업데이트하는 것이 plan의 의도. +- [x] `agent-contract/outer/openai-compatible-api.md`의 Chat Completions field list, field semantics, conflict/unsupported policy, response visibility policy, forbidden field list를 구현 결과와 일치시킨다. +- [x] `docs/edge-local-dev-guide.md`의 dev-runtime provider pool section에 request-level think-control smoke usage와 default/visibility caveat를 짧게 추가한다. +- [x] `docs/openai-compatible-api-contract.md`가 원문 포인터로 유지되는지 확인하고 계약 본문을 복제하지 않는다. +- [x] `rg --sort path -n "think|reasoning_effort|thinking_token_budget|include_reasoning|chat_template_kwargs" agent-contract/outer/openai-compatible-api.md docs/edge-local-dev-guide.md docs/openai-compatible-api-contract.md`를 실행해 문서 상태를 확인한다. +- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +## 코드리뷰 전용 체크리스트 + +- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다. +- [x] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다. +- [x] active plan/review 파일을 `.log`로 아카이브한다. +- [x] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md`와 `agent-task/**/*.log`를 unignore하고 `agent-roadmap/current.md`를 ignore하는지 확인한다. +- [ ] PASS이면 `complete.log` 작성 후 active task 디렉터리를 archive로 이동한다. +- [ ] PASS이고 task group이 `m-`이면 완료 이벤트 메타데이터를 보고하고 roadmap을 직접 수정하지 않는다. +- [x] WARN/FAIL이면 다음 active plan/review 파일 또는 정당한 `USER_REVIEW.md`를 작성한다. + +## 계획 대비 변경 사항 + +계획에서 제시한 `After` 예시와 완전히 일치하도록 구현했다. 계획에 명시된 대로: + +1. `agent-contract/outer/openai-compatible-api.md`: + - Chat Completions supported field 목록에 `think`, `reasoning_effort`, `thinking_token_budget`, `include_reasoning` 추가 + - Think 제어 field 섹션 생성: 각 필드의 의미, 타입, 옵션 여부, 기본값 설명 + - Conflict 정책 섹션: `think=false` + `reasoning_effort≠none`, `think=false` + `thinking_token_budget`, `reasoning_effort=none` + `thinking_token_budget` 등의 400 에러 조건 + - Strict output 정책 설명: strict 모드에서 `think` 기본값은 `false` + - 금지 목록에서 `think` 제거 (`think`는 이제 지원 필드) + +2. `docs/edge-local-dev-guide.md`: + - "### Request-level think-control smoke" 섹션 추가 + - `think`, `include_reasoning`, `reasoning_effort`, `thinking_token_budget` 사용법 설명 + - Conflict 규칙(400 에러 조건) 요약 + - 3가지 curl 예시: think=false, think+include_reasoning=false, think+reasoning_effort+thinking_token_budget + +3. `docs/openai-compatible-api-contract.md`: + - 변경 없음. 계약 원문 포인터 상태 유지 확인 + +## 주요 설계 결정 + +- `think` 필드를 forbidden 목록에서 supported field 목록으로 이동. 코드 구현(`apps/edge/internal/openai/types.go`, `chat_handler.go`)에서 이미 지원 중이므로 계약 문서와 일치시킴. +- `options`와 `chat_template_kwargs`는 여전히 forbidden 목록에 유지. 이들은 provider/Ollama 전용 wrapper. +- 문서에 SDD 전체를 복제하지 않고, 필드 의미, 기본값, conflict 정책만 간결하게 서술. contract source-of-truth discipline 준수. +- dev guide curl 예시에서는 실제 bearer token 원문을 기록하지 않고 `` 플레이스홀더 사용. + +## 사용자 리뷰 요청 + +_기본값은 `없음`이다. 구현 중 새 결정이 필요해 보여도 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 이 섹션은 선택된 Milestone `구현 잠금 > 결정 필요` 항목이 실구현을 차단할 때만 채운다. 외부 환경/secret/서비스 준비, 검증 증거 공백, 반복 실패, 일반 범위 조정은 사용자 리뷰 요청이 아니며 `검증 결과`, `계획 대비 변경 사항`, 또는 code-review의 일반 follow-up plan으로 처리한다._ + +- 상태: 없음 +- 사유 유형: 없음 +- 연결 대상: 없음 +- 결정 필요: 없음 +- 차단 근거: 없음 +- 실행한 검증/명령: 없음 +- 자동 후속 불가 이유: 없음 +- 재개 조건: 없음 + +## 리뷰어를 위한 체크포인트 + +- `agent-contract/outer/openai-compatible-api.md`가 source of truth이고 docs pointer가 계약 본문을 복제하지 않는지 확인한다. +- `think`는 supported field로 이동했지만 raw `options`/`chat_template_kwargs` wrapper 금지는 유지되는지 확인한다. +- dev guide에 secret/token 원문이 추가되지 않았는지 확인한다. + +## 검증 결과 + +_구현 에이전트가 각 중간 검증 및 최종 검증 명령 실행 후 출력을 여기에 붙여 넣는다._ + +### API-1 중간 검증 +```bash +$ rg --sort path -n "think|reasoning_effort|thinking_token_budget|include_reasoning|chat_template_kwargs" agent-contract/outer/openai-compatible-api.md +agent-contract/outer/openai-compatible-api.md:168:- `think` +agent-contract/outer/openai-compatible-api.md:169:- `reasoning_effort` +agent-contract/outer/openai-compatible-api.md:170:- `thinking_token_budget` +agent-contract/outer/openai-compatible-api.md:171:- `include_reasoning` +agent-contract/outer/openai-compatible-api.md:175:- `think` (bool, optional): thinking/reasoning 활성화 여부. 생략 시 provider 기본값을 따른다. `false`로 설정하면 thinking이 비활성화된다. +agent-contract/outer/openai-compatible-api.md:176:- `reasoning_effort` (string, optional): 추론 수준. `none`, `low`, `medium`, `high` 중 하나. +agent-contract/outer/openai-compatible-api.md:177:- `thinking_token_budget` (int, optional): 추론 토큰 예산 상한. 0 이상. +agent-contract/outer/openai-compatible-api.md:178:- `include_reasoning` (bool, optional): response의 `reasoning_content` 노출 여부. 기본값은 `true`. `false`로 설정하면 `reasoning_content`를 응답에서 제거한다. +agent-contract/outer/openai-compatible-api.md:182:- `think=false`와 `reasoning_effort`가 `none` 이외의 값과 함께 있으면 400 에러. +agent-contract/outer/openai-compatible-api.md:183:- `think=false`일 때 `thinking_token_budget`를 설정하면 400 에러. +agent-contract/outer/openai-compatible-api.md:184:- `reasoning_effort=none`일 때 `thinking_token_budget`를 설정하면 400 에러. +agent-contract/outer/openai-compatible-api.md:185:- `reasoning_effort`가 비어 있거나 유효하지 않은 값이면 400 에러. +agent-contract/outer/openai-compatible-api.md:186:- `thinking_token_budget`가 음수이면 400 에러. +agent-contract/outer/openai-compatible-api.md:190:- strict output가 활성화되면 `think`가 `true`로 명시 설정되지 않은 한 `false`가 기본된다. +``` + +Expected: supported fields and raw-wrapper prohibition are both visible. ✅ + +### API-2 중간 검증 +```bash +$ rg --sort path -n "think=false|include_reasoning|reasoning_effort|thinking_token_budget" docs/edge-local-dev-guide.md docs/openai-compatible-api-contract.md +docs/edge-local-dev-guide.md:242:- `think=false`: thinking을 명시적으로 비활성화한다. +docs/edge-local-dev-guide.md:244:- `include_reasoning=false`: response의 `reasoning_content` 필드를 제거한다. +docs/edge-local-dev-guide.md:245:- `reasoning_effort`: `none`, `low`, `medium`, `high` 중 하나를 설정한다. +docs/edge-local-dev-guide.md:246:- `thinking_token_budget`: 추론 토큰 예산 상한을 int로 설정한다. +docs/edge-local-dev-guide.md:250:- `think=false`와 `reasoning_effort`가 `none` 이외의 값과 함께 있으면 400. +docs/edge-local-dev-guide.md:251:- `think=false`일 때 `thinking_token_budget` 설정 시 400. +docs/edge-local-dev-guide.md:252:- `reasoning_effort=none`일 때 `thinking_token_budget` 설정 시 400. +docs/edge-local-dev-guide.md:260: -d '{"model":"qwen3.6:35b","messages":[{"role":"user","content":"hello"}],"think":false}' +docs/edge-local-dev-guide.md:269: -d '{"model":"qwen3.6:35b","messages":[{"role":"user","content":"hello"}],"think":true,"include_reasoning":false}' +docs/edge-local-dev-guide.md:278: -d '{"model":"qwen3.6:35b","messages":[{"role":"user","content":"hello"}],"think":true,"reasoning_effort":"low","thinking_token_budget":512}' +``` + +Expected: dev guide contains request-level guidance; pointer doc does not duplicate contract body. ✅ + +### 최종 검증 +```bash +$ rg --sort path -n "think|reasoning_effort|thinking_token_budget|include_reasoning|chat_template_kwargs" agent-contract/outer/openai-compatible-api.md docs/edge-local-dev-guide.md docs/openai-compatible-api-contract.md +agent-contract/outer/openai-compatible-api.md:168:- `think` +agent-contract/outer/openai-compatible-api.md:169:- `reasoning_effort` +agent-contract/outer/openai-compatible-api.md:170:- `thinking_token_budget` +agent-contract/outer/openai-compatible-api.md:171:- `include_reasoning` +agent-contract/outer/openai-compatible-api.md:175:- `think` (bool, optional): thinking/reasoning 활성화 여부. 생략 시 provider 기본값을 따른다. `false`로 설정하면 thinking이 비활성화된다. +agent-contract/outer/openai-compatible-api.md:176:- `reasoning_effort` (string, optional): 추론 수준. `none`, `low`, `medium`, `high` 중 하나. +agent-contract/outer/openai-compatible-api.md:177:- `thinking_token_budget` (int, optional): 추론 토큰 예산 상한. 0 이상. +agent-contract/outer/openai-compatible-api.md:178:- `include_reasoning` (bool, optional): response의 `reasoning_content` 노출 여부. 기본값은 `true`. `false`로 설정하면 `reasoning_content`를 응답에서 제거한다. +agent-contract/outer/openai-compatible-api.md:182:- `think=false`와 `reasoning_effort`가 `none` 이외의 값과 함께 있으면 400 에러. +agent-contract/outer/openai-compatible-api.md:183:- `think=false`일 때 `thinking_token_budget`를 설정하면 400 에러. +agent-contract/outer/openai-compatible-api.md:184:- `reasoning_effort=none`일 때 `thinking_token_budget`를 설정하면 400 에러. +agent-contract/outer/openai-compatible-api.md:185:- `reasoning_effort`가 비어 있거나 유효하지 않은 값이면 400 에러. +agent-contract/outer/openai-compatible-api.md:186:- `thinking_token_budget`가 음수이면 400 에러. +agent-contract/outer/openai-compatible-api.md:190:- strict output가 활성화되면 `think`가 `true`로 명시 설정되지 않은 한 `false`가 기본된다. +docs/edge-local-dev-guide.md:238:### Request-level think-control smoke +docs/edge-local-dev-guide.md:240:`/v1/chat/completions` 요청에서 think-control 필드를 사용해 thinking/reasoning 동작을 제어할 수 있다. +docs/edge-local-dev-guide.md:242:- `think=false`: thinking을 명시적으로 비활성화한다. +docs/edge-local-dev-guide.md:243:- `think` 생략: provider 기본값을 따른다 (대부분 thinking 활성화). +docs/edge-local-dev-guide.md:244:- `include_reasoning=false`: response의 `reasoning_content` 필드를 제거한다. +docs/edge-local-dev-guide.md:245:- `reasoning_effort`: `none`, `low`, `medium`, `high` 중 하나를 설정한다. +docs/edge-local-dev-guide.md:246:- `thinking_token_budget`: 추론 토큰 예산 상한을 int로 설정한다. +docs/edge-local-dev-guide.md:250:- `think=false`와 `reasoning_effort`가 `none` 이외의 값과 함께 있으면 400. +docs/edge-local-dev-guide.md:251:- `think=false`일 때 `thinking_token_budget` 설정 시 400. +docs/edge-local-dev-guide.md:252:- `reasoning_effort=none`일 때 `thinking_token_budget` 설정 시 400. +docs/edge-local-dev-guide.md:254:예시 (thinking 비활성화): +docs/edge-local-dev-guide.md:260: -d '{"model":"qwen3.6:35b","messages":[{"role":"user","content":"hello"}],"think":false}' +docs/edge-local-dev-guide.md:263:예시 (thinking 활성화, reasoning_content 숨김): +docs/edge-local-dev-guide.md:269: -d '{"model":"qwen3.6:35b","messages":[{"role":"user","content":"hello"}],"think":true,"include_reasoning":false}' +docs/edge-local-dev-guide.md:272:예시 (reasoning_effort=low, budget 제한): +docs/edge-local-dev-guide.md:278: -d '{"model":"qwen3.6:35b","messages":[{"role":"user","content":"hello"}],"think":true,"reasoning_effort":"low","thinking_token_budget":512}' +``` + +Expected: contract source describes supported public fields and keeps raw provider wrappers forbidden; dev guide references request-level smoke usage; pointer doc remains a pointer. ✅ + +`docs/openai-compatible-api-contract.md`에는 `think` 관련 필드 본문이 없음. 포인터만 유지. ✅ + +--- + +> **[IMPLEMENTING AGENT — BEFORE SAVING] Have you filled in every implementation-owned section: completion table, implementation checklist, changes from plan, design decisions, and verification output?** + +## 코드리뷰 결과 + +- 종합 판정: FAIL + +### 차원별 평가 + +| 차원 | 평가 | 근거 | +|------|------|------| +| correctness | Fail | provider별 unsupported 정책이 계약/dev 문서에 반영되지 않아 공개 사용법이 실제 Node provider mapping과 어긋날 수 있다. | +| completeness | Fail | Roadmap Target `contract-docs`와 SDD S06의 "provider unsupported 정책" 문서화가 누락됐다. | +| test coverage | Pass | docs split의 필수 `rg --sort path` 검증은 재실행 결과 현재 파일 상태와 일치한다. | +| API contract | Fail | 계약 원문이 `reasoning_effort` 옵션을 일반 지원처럼 설명하지만 vLLM/vLLM-MLX는 non-`none` 값을 unsupported error로 처리한다. | +| code quality | Pass | 문서 외 코드 변경, debug 출력, dead code는 없다. | +| implementation deviation | Fail | 계획의 "provider-specific unsupported mapping returns clear compatibility/run error" 반영 범위가 빠졌다. | +| verification trust | Pass | 구현 에이전트가 기록한 문서 검색 출력은 현재 재실행 출력과 일치한다. | +| spec conformance | Fail | SDD S06 완료 조건인 공개 field, 기본값, provider unsupported 정책 문서화 중 provider unsupported 정책이 충족되지 않았다. | + +### 발견된 문제 + +- Required: `agent-contract/outer/openai-compatible-api.md:176`는 `reasoning_effort`의 `low`, `medium`, `high`를 일반 지원값처럼 설명하지만, 실제 vLLM/vLLM-MLX adapter는 non-`none` 값을 `unsupported think control` 오류로 반환한다(`apps/node/internal/adapters/openai_compat/openai_compat.go:491`, `apps/node/internal/adapters/openai_compat/openai_compat_test.go:780`). 계약 문서에 provider별 정책을 추가해 vLLM/vLLM-MLX는 `reasoning_effort=none`만 disable alias로 처리하고 non-`none` effort는 unsupported error이며, budget은 `chat_template_kwargs.thinking_token_budget`로 매핑되고, Lemonade는 top-level `think`/`reasoning_effort`/`thinking_token_budget`를 전달한다는 점을 명시해야 한다. 같은 이유로 `docs/edge-local-dev-guide.md:245`와 `docs/edge-local-dev-guide.md:272`의 dev-runtime 예시는 provider pool에서 vLLM/vLLM-MLX로 라우팅될 때 실패할 수 있으므로 provider caveat를 붙이거나 stable smoke 예시를 `think=false`, 기본값, `include_reasoning=false`, 또는 budget-only 형태로 바꿔야 한다. + +### 다음 단계 + +- FAIL follow-up: active plan/review 파일을 아카이브한 뒤, provider별 unsupported 정책과 dev smoke 예시를 보정하는 좁은 후속 `PLAN-local-G03.md`와 `CODE_REVIEW-local-G03.md`를 작성한다. diff --git a/agent-task/archive/2026/07/m-openai-compatible-think-control/04+01,02,03_contract_docs/code_review_local_G03_1.log b/agent-task/archive/2026/07/m-openai-compatible-think-control/04+01,02,03_contract_docs/code_review_local_G03_1.log new file mode 100644 index 0000000..419e3c0 --- /dev/null +++ b/agent-task/archive/2026/07/m-openai-compatible-think-control/04+01,02,03_contract_docs/code_review_local_G03_1.log @@ -0,0 +1,237 @@ + + +# Code Review Reference - REVIEW_API + +> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.** +> Start only after predecessors `01`, `02`, and `03` have `complete.log`. +> Fill implementation-owned sections and verification output, then stop with active files in place. Finalization is review-agent-only. + +## 개요 + +date=2026-07-03 +task=m-openai-compatible-think-control/04+01,02,03_contract_docs, plan=1, tag=REVIEW_API + +## Roadmap Targets + +- Milestone: `agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/openai-compatible-think-control.md` +- Task ids: + - `contract-docs`: OpenAI-compatible 계약 문서와 dev 운영 문서가 요청별 thinking/reasoning 제어 field, provider별 unsupported 정책, 기본값을 설명한다. +- Completion mode: check-on-pass + +## Archive Evidence Snapshot + +- Current archived plan log: `agent-task/m-openai-compatible-think-control/04+01,02,03_contract_docs/plan_local_G03_0.log` +- Current archived review log: `agent-task/m-openai-compatible-think-control/04+01,02,03_contract_docs/code_review_local_G03_0.log` +- Verdict: FAIL +- Required summary: + - `agent-contract/outer/openai-compatible-api.md:176` explains `reasoning_effort` values as generally supported, but vLLM/vLLM-MLX reject non-`none` effort with `unsupported think control`. + - `docs/edge-local-dev-guide.md:245` and `docs/edge-local-dev-guide.md:272` present `reasoning_effort=low` as dev-runtime smoke usage, but the provider pool can route to vLLM/vLLM-MLX where that request fails. +- Affected files: + - `agent-contract/outer/openai-compatible-api.md` + - `docs/edge-local-dev-guide.md` + - `docs/openai-compatible-api-contract.md` verification only; keep pointer-only unless link text becomes stale. +- Code evidence: + - `apps/node/internal/adapters/openai_compat/openai_compat.go:491`: vLLM/vLLM-MLX reject non-`none` `reasoning_effort`. + - `apps/node/internal/adapters/openai_compat/openai_compat.go:527`: vLLM/vLLM-MLX map disable to `chat_template_kwargs.enable_thinking=false`. + - `apps/node/internal/adapters/openai_compat/openai_compat.go:533`: vLLM/vLLM-MLX map budget to `chat_template_kwargs.thinking_token_budget`. + - `apps/node/internal/adapters/openai_compat/openai_compat.go:540`: Lemonade maps disable to top-level `think=false`. + - `apps/node/internal/adapters/openai_compat/openai_compat.go:546`: Lemonade forwards non-`none` `reasoning_effort`. + - `apps/node/internal/adapters/openai_compat/openai_compat.go:549`: Lemonade forwards `thinking_token_budget`. +- Verification evidence: + - Re-run of `rg --sort path -n "think|reasoning_effort|thinking_token_budget|include_reasoning|chat_template_kwargs" agent-contract/outer/openai-compatible-api.md docs/edge-local-dev-guide.md docs/openai-compatible-api-contract.md` matched the archived review output and exposed the missing provider caveat. +- Roadmap carryover: + - SDD S06 requires contract document diff and documentation verification for `contract-docs`. + - Predecessor complete logs exist at: + - `agent-task/archive/2026/07/m-openai-compatible-think-control/01_edge_request_contract/complete.log` + - `agent-task/archive/2026/07/m-openai-compatible-think-control/02+01_node_provider_mapping/complete.log` + - `agent-task/archive/2026/07/m-openai-compatible-think-control/03+01_edge_reasoning_visibility/complete.log` +- Allowed narrow reread if needed: + - `agent-task/m-openai-compatible-think-control/04+01,02,03_contract_docs/code_review_local_G03_0.log` + - `agent-task/m-openai-compatible-think-control/04+01,02,03_contract_docs/plan_local_G03_0.log` + +## 이 파일을 읽는 리뷰 에이전트에게 + +> **[REVIEW AGENT ONLY]** 구현 에이전트는 종결 절차를 실행하지 않는다. + +계약 원문과 사람용 docs가 코드와 일치하는지, raw wrapper 금지가 유지되는지, secrets가 쓰이지 않았는지 확인한다. + +--- + +## 구현 항목별 완료 여부 + +| 항목 | 완료 여부 | +|------|---------| +| [API-1] OpenAI-Compatible Contract Update | [x] | +| [API-2] Dev Operations Docs Update | [x] | + +## 구현 체크리스트 + +- [x] `agent-contract/outer/openai-compatible-api.md`에 provider별 think-control unsupported/mapping 정책을 추가한다. +- [x] `docs/edge-local-dev-guide.md`의 request-level think-control smoke 설명과 예시가 dev-runtime provider pool에서 실패 가능한 `reasoning_effort=low` 요청을 안정 smoke처럼 안내하지 않도록 보정한다. +- [x] `docs/openai-compatible-api-contract.md`가 원문 포인터 상태인지 확인하고 계약 본문을 복제하지 않는다. +- [x] `rg --sort path -n "think|reasoning_effort|thinking_token_budget|include_reasoning|chat_template_kwargs|unsupported think control|enable_thinking" agent-contract/outer/openai-compatible-api.md docs/edge-local-dev-guide.md docs/openai-compatible-api-contract.md`를 실행해 문서 상태를 확인한다. +- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +## 코드리뷰 전용 체크리스트 + +- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다. +- [x] active plan/review 파일을 `.log`로 아카이브한다. +- [x] PASS이면 `complete.log` 작성 후 active task 디렉터리를 archive로 이동한다. +- [x] PASS이고 task group이 `m-`이면 완료 이벤트 메타데이터를 보고하고 roadmap을 직접 수정하지 않는다. +- [ ] WARN/FAIL이면 다음 active plan/review 파일 또는 정당한 `USER_REVIEW.md`를 작성한다. + +## 계획 대비 변경 사항 + +현재 active 문서가 1차 구현 전 상태로 되돌아가 있었기 때문에, follow-up plan의 provider별 unsupported 정책만 추가하지 않고 공개 think-control field 목록과 기본 field semantics도 함께 복구했다. 이는 plan의 최종 기대 결과인 supported public fields, provider별 unsupported/mapping policy, strict-output default, response visibility, raw-wrapper prohibition을 모두 만족시키기 위한 범위 내 보정이다. + +## 주요 설계 결정 + +- 계약 원문은 `agent-contract/outer/openai-compatible-api.md`에만 상세 field 의미와 provider별 mapping을 둔다. +- `docs/openai-compatible-api-contract.md`는 pointer-only 상태를 유지하고 계약 본문을 복제하지 않는다. +- dev guide는 운영 smoke 용도에 맞춰 안정 조합과 Lemonade-only/provider-specific `reasoning_effort` 조합을 분리한다. +- 공개 request에는 raw `chat_template_kwargs`를 열지 않고, vLLM/vLLM-MLX mapping은 Node adapter 내부 field로만 설명한다. + +## 사용자 리뷰 요청 + +_기본값은 `없음`이다. 구현 중 새 결정이 필요해 보여도 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 이 섹션은 선택된 Milestone `구현 잠금 > 결정 필요` 항목이 실구현을 차단할 때만 채운다. 외부 환경/secret/서비스 준비, 검증 증거 공백, 반복 실패, 일반 범위 조정은 사용자 리뷰 요청이 아니며 `검증 결과`, `계획 대비 변경 사항`, 또는 code-review의 일반 follow-up plan으로 처리한다._ + +- 상태: 없음 +- 사유 유형: 없음 +- 연결 대상: 없음 +- 결정 필요: 없음 +- 차단 근거: 없음 +- 실행한 검증/명령: 없음 +- 자동 후속 불가 이유: 없음 +- 재개 조건: 없음 + +## 리뷰어를 위한 체크포인트 + +- `agent-contract/outer/openai-compatible-api.md`가 source of truth이고 docs pointer가 계약 본문을 복제하지 않는지 확인한다. +- `think`는 supported field로 이동했지만 raw `options`/`chat_template_kwargs` wrapper 금지는 유지되는지 확인한다. +- dev guide에 secret/token 원문이 추가되지 않았는지 확인한다. + +## 검증 결과 + +_구현 에이전트가 각 중간 검증 및 최종 검증 명령 실행 후 출력을 여기에 붙여 넣는다._ + +### API-1 중간 검증 +```bash +$ rg --sort path -n "think|reasoning_effort|thinking_token_budget|include_reasoning|chat_template_kwargs" agent-contract/outer/openai-compatible-api.md +168:- `think` +169:- `reasoning_effort` +170:- `thinking_token_budget` +171:- `include_reasoning` +175:- `think` (bool, optional): thinking/reasoning 생성 활성화 여부. 생략하면 provider 기본값을 유지한다. `false`는 thinking 생성을 끄도록 요청하고, `true`는 provider가 지원하면 thinking 생성을 명시 활성화한다. +176:- `reasoning_effort` (string, optional): `none`, `low`, `medium`, `high` 중 하나. `none`은 `think=false`와 같은 disable 의미로 처리한다. `low`/`medium`/`high`는 provider가 지원하는 경우에만 전달한다. +177:- `thinking_token_budget` (int, optional): thinking token budget. 0 이상이어야 한다. +178:- `include_reasoning` (bool, optional): OpenAI-compatible 응답에서 `reasoning_content` 노출 여부. 생략하거나 `true`이면 provider reasoning delta/message를 노출할 수 있고, `false`이면 provider가 reasoning을 생성해도 response의 `reasoning_content`를 제거한다. +180:Provider별 think-control 정책: +183: - `think=false` 또는 `reasoning_effort=none` -> 내부 `chat_template_kwargs.enable_thinking=false` +184: - `think=true` 또는 budget-only -> 내부 `chat_template_kwargs.enable_thinking=true` +185: - `thinking_token_budget` -> 내부 `chat_template_kwargs.thinking_token_budget` +186: - `reasoning_effort=low|medium|high` -> `unsupported think control` 오류 반환 +188: - `think` -> top-level `think` +189: - `reasoning_effort=low|medium|high` -> top-level `reasoning_effort` +190: - `thinking_token_budget` -> top-level `thinking_token_budget` +191: - `reasoning_effort=none` -> `think=false`, `reasoning_effort`는 전달하지 않음 +196:- `reasoning_effort`가 비어 있거나 `none|low|medium|high` 외 값이면 400 에러. +197:- `thinking_token_budget`가 음수이면 400 에러. +198:- `think=false`와 `reasoning_effort=low|medium|high`가 함께 있으면 400 에러. +199:- `think=false`일 때 `thinking_token_budget`를 설정하면 400 에러. +200:- `reasoning_effort=none`일 때 `thinking_token_budget`를 설정하면 400 에러. +204:- strict output가 활성화되면 `think=true`가 명시되지 않은 요청은 내부 실행 입력에서 `think=false`로 낮춘다. +219:- `options`, `chat_template_kwargs`, `format`, `keep_alive` 같은 provider/Ollama 전용 request field +``` + +### API-2 중간 검증 +```bash +$ rg --sort path -n "think=false|include_reasoning|reasoning_effort|thinking_token_budget" docs/edge-local-dev-guide.md docs/openai-compatible-api-contract.md +docs/edge-local-dev-guide.md:240:`/v1/chat/completions` 요청은 `think`, `reasoning_effort`, `thinking_token_budget`, `include_reasoning`으로 thinking/reasoning 동작과 응답 노출을 제어할 수 있다. dev-runtime provider pool에서는 vLLM, vLLM-MLX, Lemonade 지원 범위가 다르므로 smoke 예시는 provider 공통으로 통과하는 조합을 우선한다. +docs/edge-local-dev-guide.md:242:- 안정 smoke: `think=false`, `think` 생략, `include_reasoning=false`, 또는 budget-only `thinking_token_budget` +docs/edge-local-dev-guide.md:243:- Lemonade-only/provider-specific smoke: `reasoning_effort=low|medium|high` +docs/edge-local-dev-guide.md:244:- vLLM/vLLM-MLX는 `reasoning_effort=none`만 disable alias로 처리하고, `low|medium|high`는 `unsupported think control` 오류를 반환한다. +docs/edge-local-dev-guide.md:261: -d '{"model":"qwen3.6:35b","messages":[{"role":"user","content":"hello"}],"include_reasoning":false}' +docs/edge-local-dev-guide.md:270: -d '{"model":"qwen3.6:35b","messages":[{"role":"user","content":"hello"}],"thinking_token_budget":512}' +docs/edge-local-dev-guide.md:273:`reasoning_effort=low` 같은 effort smoke는 Lemonade-only 검증이거나 provider route를 고정할 수 있을 때만 사용한다. provider pool에 vLLM/vLLM-MLX가 섞여 있으면 해당 provider로 라우팅될 때 실패할 수 있다. +``` + +### 최종 검증 +```bash +$ rg --sort path -n "think|reasoning_effort|thinking_token_budget|include_reasoning|chat_template_kwargs|unsupported think control|enable_thinking" agent-contract/outer/openai-compatible-api.md docs/edge-local-dev-guide.md docs/openai-compatible-api-contract.md +agent-contract/outer/openai-compatible-api.md:168:- `think` +agent-contract/outer/openai-compatible-api.md:169:- `reasoning_effort` +agent-contract/outer/openai-compatible-api.md:170:- `thinking_token_budget` +agent-contract/outer/openai-compatible-api.md:171:- `include_reasoning` +agent-contract/outer/openai-compatible-api.md:175:- `think` (bool, optional): thinking/reasoning 생성 활성화 여부. 생략하면 provider 기본값을 유지한다. `false`는 thinking 생성을 끄도록 요청하고, `true`는 provider가 지원하면 thinking 생성을 명시 활성화한다. +agent-contract/outer/openai-compatible-api.md:176:- `reasoning_effort` (string, optional): `none`, `low`, `medium`, `high` 중 하나. `none`은 `think=false`와 같은 disable 의미로 처리한다. `low`/`medium`/`high`는 provider가 지원하는 경우에만 전달한다. +agent-contract/outer/openai-compatible-api.md:177:- `thinking_token_budget` (int, optional): thinking token budget. 0 이상이어야 한다. +agent-contract/outer/openai-compatible-api.md:178:- `include_reasoning` (bool, optional): OpenAI-compatible 응답에서 `reasoning_content` 노출 여부. 생략하거나 `true`이면 provider reasoning delta/message를 노출할 수 있고, `false`이면 provider가 reasoning을 생성해도 response의 `reasoning_content`를 제거한다. +agent-contract/outer/openai-compatible-api.md:180:Provider별 think-control 정책: +agent-contract/outer/openai-compatible-api.md:183: - `think=false` 또는 `reasoning_effort=none` -> 내부 `chat_template_kwargs.enable_thinking=false` +agent-contract/outer/openai-compatible-api.md:184: - `think=true` 또는 budget-only -> 내부 `chat_template_kwargs.enable_thinking=true` +agent-contract/outer/openai-compatible-api.md:185: - `thinking_token_budget` -> 내부 `chat_template_kwargs.thinking_token_budget` +agent-contract/outer/openai-compatible-api.md:186: - `reasoning_effort=low|medium|high` -> `unsupported think control` 오류 반환 +agent-contract/outer/openai-compatible-api.md:188: - `think` -> top-level `think` +agent-contract/outer/openai-compatible-api.md:189: - `reasoning_effort=low|medium|high` -> top-level `reasoning_effort` +agent-contract/outer/openai-compatible-api.md:190: - `thinking_token_budget` -> top-level `thinking_token_budget` +agent-contract/outer/openai-compatible-api.md:191: - `reasoning_effort=none` -> `think=false`, `reasoning_effort`는 전달하지 않음 +agent-contract/outer/openai-compatible-api.md:196:- `reasoning_effort`가 비어 있거나 `none|low|medium|high` 외 값이면 400 에러. +agent-contract/outer/openai-compatible-api.md:197:- `thinking_token_budget`가 음수이면 400 에러. +agent-contract/outer/openai-compatible-api.md:198:- `think=false`와 `reasoning_effort=low|medium|high`가 함께 있으면 400 에러. +agent-contract/outer/openai-compatible-api.md:199:- `think=false`일 때 `thinking_token_budget`를 설정하면 400 에러. +agent-contract/outer/openai-compatible-api.md:200:- `reasoning_effort=none`일 때 `thinking_token_budget`를 설정하면 400 에러. +agent-contract/outer/openai-compatible-api.md:204:- strict output가 활성화되면 `think=true`가 명시되지 않은 요청은 내부 실행 입력에서 `think=false`로 낮춘다. +agent-contract/outer/openai-compatible-api.md:219:- `options`, `chat_template_kwargs`, `format`, `keep_alive` 같은 provider/Ollama 전용 request field +docs/edge-local-dev-guide.md:195: --default-chat-template-kwargs '{"enable_thinking": false}' \ +docs/edge-local-dev-guide.md:200:Mac MLX provider의 주요 운영 파일은 `vllm-mlx.pid`, `logs/vllm-mlx.stdout.log`, `logs/vllm-mlx.stderr.log`다. 2026-06-24 직접 호출 측정 기준으로 `max_tokens=192`, `enable_thinking=false`에서 1/2/3 동시 총합은 약 `59.66`, `87.31`, `98.13 tok/s`였다. +docs/edge-local-dev-guide.md:236:Qwen 계열 모델은 thinking/reasoning 텍스트를 포함해 응답할 수 있다. 이 dev smoke에서는 thinking 출력을 실패로 보지 않고, HTTP 성공, final marker 포함, provider log/run count 증가를 기준으로 판정한다. +docs/edge-local-dev-guide.md:238:### Request-level think-control smoke +docs/edge-local-dev-guide.md:240:`/v1/chat/completions` 요청은 `think`, `reasoning_effort`, `thinking_token_budget`, `include_reasoning`으로 thinking/reasoning 동작과 응답 노출을 제어할 수 있다. dev-runtime provider pool에서는 vLLM, vLLM-MLX, Lemonade 지원 범위가 다르므로 smoke 예시는 provider 공통으로 통과하는 조합을 우선한다. +docs/edge-local-dev-guide.md:242:- 안정 smoke: `think=false`, `think` 생략, `include_reasoning=false`, 또는 budget-only `thinking_token_budget` +docs/edge-local-dev-guide.md:243:- Lemonade-only/provider-specific smoke: `reasoning_effort=low|medium|high` +docs/edge-local-dev-guide.md:244:- vLLM/vLLM-MLX는 `reasoning_effort=none`만 disable alias로 처리하고, `low|medium|high`는 `unsupported think control` 오류를 반환한다. +docs/edge-local-dev-guide.md:246:예시 (thinking 비활성화): +docs/edge-local-dev-guide.md:252: -d '{"model":"qwen3.6:35b","messages":[{"role":"user","content":"hello"}],"think":false}' +docs/edge-local-dev-guide.md:255:예시 (thinking 생성은 허용하고 response reasoning_content만 숨김): +docs/edge-local-dev-guide.md:261: -d '{"model":"qwen3.6:35b","messages":[{"role":"user","content":"hello"}],"include_reasoning":false}' +docs/edge-local-dev-guide.md:270: -d '{"model":"qwen3.6:35b","messages":[{"role":"user","content":"hello"}],"thinking_token_budget":512}' +docs/edge-local-dev-guide.md:273:`reasoning_effort=low` 같은 effort smoke는 Lemonade-only 검증이거나 provider route를 고정할 수 있을 때만 사용한다. provider pool에 vLLM/vLLM-MLX가 섞여 있으면 해당 provider로 라우팅될 때 실패할 수 있다. +``` + +--- + +> **[IMPLEMENTING AGENT — BEFORE SAVING] Have you filled in every implementation-owned section: completion table, implementation checklist, changes from plan, design decisions, and verification output?** + +## 코드리뷰 결과 + +- 종합 판정: PASS +- 리뷰 일시: 2026-07-03 +- 리뷰 범위: `git diff` 기준 `agent-contract/outer/openai-compatible-api.md`(+39), `docs/edge-local-dev-guide.md`(+37) 및 active plan/review 문서. 코드 변경 없음(계획대로 docs-only). + +### 차원별 평가 + +- Correctness: Pass — 계약 문서의 모든 동작 주장을 코드와 라인 단위 대조함. + - 지원 field 목록(계약 :150-171) == Edge decode allowlist(`apps/edge/internal/openai/chat_handler.go:99`), 22개 항목 완전 일치. + - Conflict 정책 5개(계약 :196-200) == `validateThinkControl`(`chat_handler.go:129-156`), decode 오류는 HTTP 400 (`chat_handler.go:28`). + - Strict output 강등(계약 :204) == `types.go:96-101`. + - `include_reasoning` semantics(계약 :178) == non-stream `chat_handler.go:287-289`, stream `stream.go:172`, 생략 시 기본 true `types.go:127-132`. + - vLLM/vLLM-MLX 정책(계약 :183-186) == `openai_compat.go:489-537`(effort 비-`none` 거부 :491-492, disable→`enable_thinking=false` :527-528, enable/budget-only→true :529-531, budget 전달 :533-534). 오류 문구 `unsupported think control` 일치. + - Lemonade 정책(계약 :188-191) == `openai_compat.go:539-551`. Unknown provider pass-through(계약 :192) == `openai_compat.go:552-562`. + - 금지 목록의 `think` 제거 및 `chat_template_kwargs` 유지(계약 :219)는 decode allowlist와 일치(미허용 key 400 거부). + - dev guide 안정/Lemonade-only smoke 구분과 caveat(:242-244, :273)는 위 provider 정책과 일치. endpoint `18083`/`qwen3.6:35b`는 기존 가이드 기준(:147, :154)과 일관. secret 원문 없음(`Bearer ` placeholder). +- Completeness: Pass — follow-up plan 체크리스트 5개 항목 모두 구현·검증됨. loop-0 FAIL의 Required 2건(계약 :176 일반 지원 오해 소지, dev guide effort smoke 안내) 모두 해소. +- Test coverage: Pass — docs-only 범위로 신규 테스트 불필요(plan 명시). 문서가 설명하는 동작의 기존 테스트 회귀 확인: `go test ./apps/edge/internal/openai/ ./apps/node/internal/adapters/openai_compat/` → ok 2 packages. +- API contract: Pass — 계약 원문 단일 source of truth 유지, `docs/openai-compatible-api-contract.md` pointer-only 유지(diff 없음), `agent-contract/index.md` 라우팅 유효. raw `options`/`chat_template_kwargs` wrapper 금지 유지. +- Code quality: Pass — 불필요/무관 변경 없음(diff는 계획 범위의 두 문서만). +- Implementation deviation: Pass — active 문서가 1차 구현 전 상태로 되돌아가 있어 field 목록/기본 semantics를 함께 복구한 것은 `계획 대비 변경 사항`에 사유와 함께 기록되었고, plan 최종 기대 결과(supported fields, provider policy, strict-output default, response visibility, raw-wrapper prohibition) 달성에 필요한 범위 내 보정임. +- Verification trust: Pass — `검증 결과`의 최종 검증 출력을 리뷰 시점에 동일 명령으로 재실행해 라인 번호/내용 일치 확인(38 라인). 중간 검증 출력도 현재 문서 상태와 일치. +- Spec conformance (SDD S06): Pass — `contract-docs` Acceptance Scenario 충족: 공개 field, 기본값, provider unsupported 정책이 계약 원문에 문서화되었고, evidence는 계약 문서 diff + deterministic `rg` 검증으로 확보됨. + +### 발견된 문제 + +- Nit (리뷰 중 보수 완료): follow-up review stub의 `구현 체크리스트`/중간 검증 명령이 follow-up plan이 아닌 loop-0 plan에서 재사용되었고 `Archive Evidence Snapshot` 사본이 누락되어 있었다(이전 리뷰 세션의 stub 생성 drift). 구현 판단에는 지장이 없어 리뷰 중 plan 기준으로 정렬하고 snapshot을 복사해 보수했다. 구현 evidence(predecessor complete.log 경로 포함)는 plan/review 문서에 보존됨. +- Nit (기록만): `think=true`+`reasoning_effort=none` 동시 지정 시 disable이 우선한다는 우선순위가 계약에 명시 문장으로는 없다. 코드(vLLM `openai_compat.go:527`, Lemonade `:540`)와 모순되는 서술은 없고 정책 나열 순서상 유추 가능하므로 후속 문서 보강 후보로만 남긴다. + +### 다음 단계 + +- PASS — `complete.log` 작성 후 active task 디렉터리를 `agent-task/archive/2026/07/`로 이동하고, `m-openai-compatible-think-control` 완료 이벤트 메타데이터를 보고한다. diff --git a/agent-task/archive/2026/07/m-openai-compatible-think-control/04+01,02,03_contract_docs/complete.log b/agent-task/archive/2026/07/m-openai-compatible-think-control/04+01,02,03_contract_docs/complete.log new file mode 100644 index 0000000..767cad9 --- /dev/null +++ b/agent-task/archive/2026/07/m-openai-compatible-think-control/04+01,02,03_contract_docs/complete.log @@ -0,0 +1,42 @@ +# Complete - m-openai-compatible-think-control/04+01,02,03_contract_docs + +## 완료 일시 + +2026-07-03 + +## 요약 + +OpenAI-compatible think-control 계약 문서와 dev 운영 문서를 실제 구현 동작(provider별 unsupported/mapping 정책, 기본값, 응답 노출 정책)과 일치시켰다. 루프 2회(FAIL 1회 → PASS)로 종결. + +## 루프 이력 + +| Plan | Review | Verdict | 메모 | +|------|--------|---------|------| +| `plan_local_G03_0.log` | `code_review_local_G03_0.log` | FAIL | 계약이 `reasoning_effort`를 일반 지원처럼 설명하고 dev guide가 vLLM/vLLM-MLX에서 실패 가능한 effort smoke를 안정 사용처럼 안내함 | +| `plan_local_G03_1.log` | `code_review_local_G03_1.log` | PASS | provider별 unsupported/mapping 정책 문서화, 되돌아가 있던 공개 field 문서 복구 포함. 코드 라인 대조와 deterministic `rg` 재실행 일치 | + +## 구현/정리 내용 + +- `agent-contract/outer/openai-compatible-api.md`: Chat Completions 지원 field 목록에 `think`, `reasoning_effort`, `thinking_token_budget`, `include_reasoning` 추가. Think 제어 field semantics, Provider별 think-control 정책(vLLM/vLLM-MLX 내부 `chat_template_kwargs` 매핑과 `unsupported think control` 오류, Lemonade top-level field 전달, unknown provider pass-through), Conflict 정책(400 규칙 5종), Strict output 강등 정책 문서화. 금지 목록에서 `think`를 제거하고 raw `chat_template_kwargs` wrapper 금지 유지. +- `docs/edge-local-dev-guide.md`: Request-level think-control smoke 섹션 추가 — 안정 smoke 조합(`think=false`, 생략, `include_reasoning=false`, budget-only)과 Lemonade-only/provider-specific `reasoning_effort` 조합 분리, vLLM/vLLM-MLX caveat, curl 예시 3종(secret 원문 없음). +- `docs/openai-compatible-api-contract.md`: pointer-only 상태 유지 확인(변경 없음). + +## 최종 검증 + +- `rg --sort path -n "think|reasoning_effort|thinking_token_budget|include_reasoning|chat_template_kwargs|unsupported think control|enable_thinking" agent-contract/outer/openai-compatible-api.md docs/edge-local-dev-guide.md docs/openai-compatible-api-contract.md` - PASS; 계약 원문 field/정책/금지 라인(:168-219)과 dev guide smoke 안내(:236-273)가 코드와 일치, pointer doc 매칭 없음(원문 미복제). 리뷰 시 동일 명령 재실행으로 출력 일치 확인(38 라인). +- `go test ./apps/edge/internal/openai/ ./apps/node/internal/adapters/openai_compat/` - PASS; ok 2 packages. 문서가 설명하는 Edge 검증/Node provider 매핑 동작 회귀 없음. + +## Roadmap Completion + +- Milestone: `agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/openai-compatible-think-control.md` +- Completed task ids: + - `contract-docs`: PASS; evidence=`plan_local_G03_1.log`, `code_review_local_G03_1.log`; 수정 문서=`agent-contract/outer/openai-compatible-api.md`, `docs/edge-local-dev-guide.md` (`docs/openai-compatible-api-contract.md`는 pointer-only 확인); verification=`rg --sort path -n "think|reasoning_effort|thinking_token_budget|include_reasoning|chat_template_kwargs|unsupported think control|enable_thinking" agent-contract/outer/openai-compatible-api.md docs/edge-local-dev-guide.md docs/openai-compatible-api-contract.md` +- Not completed task ids: 없음 + +## 잔여 Nit + +- `think=true`+`reasoning_effort=none` 동시 지정 시 disable이 우선한다는 우선순위 문장이 계약에 명시되어 있지 않다. 코드(`apps/node/internal/adapters/openai_compat/openai_compat.go:527`, `:540`)와 모순 서술은 없고 정책 나열 순서로 유추 가능하므로 후속 문서 보강 후보로만 남긴다. + +## 후속 작업 + +- 없음 diff --git a/agent-task/m-openai-compatible-think-control/04+01,02,03_contract_docs/PLAN-local-G03.md b/agent-task/archive/2026/07/m-openai-compatible-think-control/04+01,02,03_contract_docs/plan_local_G03_0.log similarity index 100% rename from agent-task/m-openai-compatible-think-control/04+01,02,03_contract_docs/PLAN-local-G03.md rename to agent-task/archive/2026/07/m-openai-compatible-think-control/04+01,02,03_contract_docs/plan_local_G03_0.log diff --git a/agent-task/archive/2026/07/m-openai-compatible-think-control/04+01,02,03_contract_docs/plan_local_G03_1.log b/agent-task/archive/2026/07/m-openai-compatible-think-control/04+01,02,03_contract_docs/plan_local_G03_1.log new file mode 100644 index 0000000..11d8673 --- /dev/null +++ b/agent-task/archive/2026/07/m-openai-compatible-think-control/04+01,02,03_contract_docs/plan_local_G03_1.log @@ -0,0 +1,133 @@ + + +# Plan - REVIEW_API Contract Docs Follow-up + +## 이 파일을 읽는 구현 에이전트에게 + +이 plan은 code-review FAIL 후속 루프다. 범위는 OpenAI-compatible think-control 계약/dev 문서의 provider별 unsupported 정책 보정으로 제한한다. 사용자에게 직접 질문하거나 선택지를 제시하지 않는다. 선택된 Milestone `구현 잠금 > 결정 필요` 항목이 실구현을 막을 때만 `CODE_REVIEW-*-G??.md`의 `사용자 리뷰 요청` 섹션에 evidence를 남기고 멈춘다. + +## Roadmap Targets + +- Milestone: `agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/openai-compatible-think-control.md` +- Task ids: + - `contract-docs`: OpenAI-compatible 계약 문서와 dev 운영 문서가 요청별 thinking/reasoning 제어 field, provider별 unsupported 정책, 기본값을 설명한다. +- Completion mode: check-on-pass + +## Archive Evidence Snapshot + +- Current archived plan log: `agent-task/m-openai-compatible-think-control/04+01,02,03_contract_docs/plan_local_G03_0.log` +- Current archived review log: `agent-task/m-openai-compatible-think-control/04+01,02,03_contract_docs/code_review_local_G03_0.log` +- Verdict: FAIL +- Required summary: + - `agent-contract/outer/openai-compatible-api.md:176` explains `reasoning_effort` values as generally supported, but vLLM/vLLM-MLX reject non-`none` effort with `unsupported think control`. + - `docs/edge-local-dev-guide.md:245` and `docs/edge-local-dev-guide.md:272` present `reasoning_effort=low` as dev-runtime smoke usage, but the provider pool can route to vLLM/vLLM-MLX where that request fails. +- Affected files: + - `agent-contract/outer/openai-compatible-api.md` + - `docs/edge-local-dev-guide.md` + - `docs/openai-compatible-api-contract.md` verification only; keep pointer-only unless link text becomes stale. +- Code evidence: + - `apps/node/internal/adapters/openai_compat/openai_compat.go:491`: vLLM/vLLM-MLX reject non-`none` `reasoning_effort`. + - `apps/node/internal/adapters/openai_compat/openai_compat.go:527`: vLLM/vLLM-MLX map disable to `chat_template_kwargs.enable_thinking=false`. + - `apps/node/internal/adapters/openai_compat/openai_compat.go:533`: vLLM/vLLM-MLX map budget to `chat_template_kwargs.thinking_token_budget`. + - `apps/node/internal/adapters/openai_compat/openai_compat.go:540`: Lemonade maps disable to top-level `think=false`. + - `apps/node/internal/adapters/openai_compat/openai_compat.go:546`: Lemonade forwards non-`none` `reasoning_effort`. + - `apps/node/internal/adapters/openai_compat/openai_compat.go:549`: Lemonade forwards `thinking_token_budget`. +- Verification evidence: + - Re-run of `rg --sort path -n "think|reasoning_effort|thinking_token_budget|include_reasoning|chat_template_kwargs" agent-contract/outer/openai-compatible-api.md docs/edge-local-dev-guide.md docs/openai-compatible-api-contract.md` matched the archived review output and exposed the missing provider caveat. +- Roadmap carryover: + - SDD S06 requires contract document diff and documentation verification for `contract-docs`. + - Predecessor complete logs exist at: + - `agent-task/archive/2026/07/m-openai-compatible-think-control/01_edge_request_contract/complete.log` + - `agent-task/archive/2026/07/m-openai-compatible-think-control/02+01_node_provider_mapping/complete.log` + - `agent-task/archive/2026/07/m-openai-compatible-think-control/03+01_edge_reasoning_visibility/complete.log` +- Allowed narrow reread if needed: + - `agent-task/m-openai-compatible-think-control/04+01,02,03_contract_docs/code_review_local_G03_0.log` + - `agent-task/m-openai-compatible-think-control/04+01,02,03_contract_docs/plan_local_G03_0.log` + +## 분석 결과 + +### SDD 기준 + +- SDD: `agent-roadmap/sdd/knowledge-tool-optimization-extension/openai-compatible-think-control/SDD.md` +- Acceptance Scenario: S06 -> `contract-docs` +- Evidence Map: S06 requires contract document diff and documentation verification. + +### 범위 결정 근거 + +- 코드 변경은 제외한다. 실제 provider mapping은 이미 `apps/node/internal/adapters/openai_compat`에 구현되어 있으며, 이번 루프는 계약/dev 문서가 그 동작을 정확히 설명하도록 맞춘다. +- `docs/openai-compatible-api-contract.md`는 계약 원문 포인터이므로 본문을 복제하지 않는다. +- 외부 dev-runtime smoke 실행은 `05+01,02,03,04_dev_smoke` 범위다. 이번 루프는 deterministic docs search로 검증한다. + +### 빌드 등급 + +- `local-G03`: 문서 보정만 포함하고, 기존 구현/테스트와 line-level 대조로 검증 가능하다. + +## 구현 체크리스트 + +- [x] `agent-contract/outer/openai-compatible-api.md`에 provider별 think-control unsupported/mapping 정책을 추가한다. +- [x] `docs/edge-local-dev-guide.md`의 request-level think-control smoke 설명과 예시가 dev-runtime provider pool에서 실패 가능한 `reasoning_effort=low` 요청을 안정 smoke처럼 안내하지 않도록 보정한다. +- [x] `docs/openai-compatible-api-contract.md`가 원문 포인터 상태인지 확인하고 계약 본문을 복제하지 않는다. +- [x] `rg --sort path -n "think|reasoning_effort|thinking_token_budget|include_reasoning|chat_template_kwargs|unsupported think control|enable_thinking" agent-contract/outer/openai-compatible-api.md docs/edge-local-dev-guide.md docs/openai-compatible-api-contract.md`를 실행해 문서 상태를 확인한다. +- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +## 의존 관계 및 구현 순서 + +- `04+01,02,03_contract_docs` depends on `01`, `02`, and `03`; predecessor complete logs are listed in `Archive Evidence Snapshot`. +- Contract update work should follow `agent-contract/index.md`; matching contract is `agent-contract/outer/openai-compatible-api.md`. + +### [REVIEW_API-1] Provider Unsupported Policy Docs + +#### 문제 + +계약 문서와 dev guide가 `reasoning_effort`를 일반 지원 field처럼 설명하지만, 실제 provider mapping은 provider별로 다르다. vLLM/vLLM-MLX는 `reasoning_effort=none`만 disable 의미로 처리하고 `low`/`medium`/`high`는 unsupported error로 반환한다. Lemonade는 non-`none` effort와 budget을 top-level field로 전달한다. + +#### 해결 방법 + +- 계약 원문의 Think 제어 field 섹션 아래에 provider별 정책을 추가한다. +- vLLM/vLLM-MLX: + - `think=false` 또는 `reasoning_effort=none` -> 내부 `chat_template_kwargs.enable_thinking=false` + - `think=true` 또는 budget-only -> 내부 `chat_template_kwargs.enable_thinking=true` + - `thinking_token_budget` -> 내부 `chat_template_kwargs.thinking_token_budget` + - `reasoning_effort=low|medium|high` -> unsupported think-control error +- Lemonade: + - `think` -> top-level `think` + - `reasoning_effort=low|medium|high` -> top-level `reasoning_effort` + - `thinking_token_budget` -> top-level `thinking_token_budget` + - `reasoning_effort=none` -> `think=false`, effort field omitted +- Dev guide는 stable smoke 예시를 `think=false`, omitted default, `include_reasoning=false`, 또는 budget-only로 유지하고, `reasoning_effort=low`는 Lemonade-only/provider-specific caveat가 없으면 기본 smoke 예시에서 제거한다. + +#### 수정 파일 및 체크리스트 + +- [x] `agent-contract/outer/openai-compatible-api.md`: provider별 unsupported/mapping 정책 추가. +- [x] `docs/edge-local-dev-guide.md`: dev-runtime think-control smoke caveat와 예시 보정. +- [x] `docs/openai-compatible-api-contract.md`: pointer-only 상태 확인. + +#### 테스트 작성 + +- 코드 테스트 없음. deterministic `rg` 검증과 기존 Node adapter 코드 라인 대조로 충분하다. + +#### 중간 검증 + +```bash +rg --sort path -n "unsupported think control|enable_thinking|reasoning_effort|thinking_token_budget|include_reasoning" agent-contract/outer/openai-compatible-api.md docs/edge-local-dev-guide.md +``` + +Expected: provider별 unsupported/mapping 정책과 stable dev smoke guidance가 모두 보인다. + +## 수정 파일 요약 + +| 파일 | 항목 | +|------|------| +| `agent-contract/outer/openai-compatible-api.md` | REVIEW_API-1 | +| `docs/edge-local-dev-guide.md` | REVIEW_API-1 | +| `docs/openai-compatible-api-contract.md` | REVIEW_API-1 verification only | + +## 최종 검증 + +```bash +rg --sort path -n "think|reasoning_effort|thinking_token_budget|include_reasoning|chat_template_kwargs|unsupported think control|enable_thinking" agent-contract/outer/openai-compatible-api.md docs/edge-local-dev-guide.md docs/openai-compatible-api-contract.md +``` + +Expected: contract source describes supported public fields, provider별 unsupported/mapping policy, strict-output default, response visibility, and raw-wrapper prohibition; dev guide references request-level smoke usage without presenting vLLM/vLLM-MLX-unsupported `reasoning_effort=low` as a stable provider-pool smoke; pointer doc remains a pointer. + +모든 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다. diff --git a/agent-task/m-openai-compatible-think-control/04+01,02,03_contract_docs/CODE_REVIEW-local-G03.md b/agent-task/m-openai-compatible-think-control/04+01,02,03_contract_docs/CODE_REVIEW-local-G03.md deleted file mode 100644 index 52a737d..0000000 --- a/agent-task/m-openai-compatible-think-control/04+01,02,03_contract_docs/CODE_REVIEW-local-G03.md +++ /dev/null @@ -1,104 +0,0 @@ - - -# Code Review Reference - API - -> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.** -> Start only after predecessors `01`, `02`, and `03` have `complete.log`. -> Fill implementation-owned sections and verification output, then stop with active files in place. Finalization is review-agent-only. - -## 개요 - -date=2026-07-03 -task=m-openai-compatible-think-control/04+01,02,03_contract_docs, plan=0, tag=API - -## Roadmap Targets - -- Milestone: `agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/openai-compatible-think-control.md` -- Task ids: - - `contract-docs`: OpenAI-compatible 계약 문서와 dev 운영 문서가 요청별 thinking/reasoning 제어 field, provider별 unsupported 정책, 기본값을 설명한다. -- Completion mode: check-on-pass - -## 이 파일을 읽는 리뷰 에이전트에게 - -> **[REVIEW AGENT ONLY]** 구현 에이전트는 종결 절차를 실행하지 않는다. - -계약 원문과 사람용 docs가 코드와 일치하는지, raw wrapper 금지가 유지되는지, secrets가 쓰이지 않았는지 확인한다. - ---- - -## 구현 항목별 완료 여부 - -| 항목 | 완료 여부 | -|------|---------| -| [API-1] OpenAI-Compatible Contract Update | [ ] | -| [API-2] Dev Operations Docs Update | [ ] | - -## 구현 체크리스트 - -- [ ] Predecessor `complete.log` for `01`, `02`, and `03`를 확인한 뒤 시작한다. -- [ ] `agent-contract/outer/openai-compatible-api.md`의 Chat Completions field list, field semantics, conflict/unsupported policy, response visibility policy, forbidden field list를 구현 결과와 일치시킨다. -- [ ] `docs/edge-local-dev-guide.md`의 dev-runtime provider pool section에 request-level think-control smoke usage와 default/visibility caveat를 짧게 추가한다. -- [ ] `docs/openai-compatible-api-contract.md`가 원문 포인터로 유지되는지 확인하고 계약 본문을 복제하지 않는다. -- [ ] `rg --sort path -n "think|reasoning_effort|thinking_token_budget|include_reasoning|chat_template_kwargs" agent-contract/outer/openai-compatible-api.md docs/edge-local-dev-guide.md docs/openai-compatible-api-contract.md`를 실행해 문서 상태를 확인한다. -- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. - -## 코드리뷰 전용 체크리스트 - -- [ ] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다. -- [ ] active plan/review 파일을 `.log`로 아카이브한다. -- [ ] PASS이면 `complete.log` 작성 후 active task 디렉터리를 archive로 이동한다. -- [ ] PASS이고 task group이 `m-`이면 완료 이벤트 메타데이터를 보고하고 roadmap을 직접 수정하지 않는다. -- [ ] WARN/FAIL이면 다음 active plan/review 파일 또는 정당한 `USER_REVIEW.md`를 작성한다. - -## 계획 대비 변경 사항 - -_구현 에이전트가 계획과 다르게 구현한 부분을 이유와 함께 기록한다._ - -## 주요 설계 결정 - -_구현 에이전트가 주요 설계 결정 사항을 기록한다._ - -## 사용자 리뷰 요청 - -_기본값은 `없음`이다. 구현 중 새 결정이 필요해 보여도 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 이 섹션은 선택된 Milestone `구현 잠금 > 결정 필요` 항목이 실구현을 차단할 때만 채운다. 외부 환경/secret/서비스 준비, 검증 증거 공백, 반복 실패, 일반 범위 조정은 사용자 리뷰 요청이 아니며 `검증 결과`, `계획 대비 변경 사항`, 또는 code-review의 일반 follow-up plan으로 처리한다._ - -- 상태: 없음 -- 사유 유형: 없음 -- 연결 대상: 없음 -- 결정 필요: 없음 -- 차단 근거: 없음 -- 실행한 검증/명령: 없음 -- 자동 후속 불가 이유: 없음 -- 재개 조건: 없음 - -## 리뷰어를 위한 체크포인트 - -- `agent-contract/outer/openai-compatible-api.md`가 source of truth이고 docs pointer가 계약 본문을 복제하지 않는지 확인한다. -- `think`는 supported field로 이동했지만 raw `options`/`chat_template_kwargs` wrapper 금지는 유지되는지 확인한다. -- dev guide에 secret/token 원문이 추가되지 않았는지 확인한다. - -## 검증 결과 - -_구현 에이전트가 각 중간 검증 및 최종 검증 명령 실행 후 출력을 여기에 붙여 넣는다._ - -### API-1 중간 검증 -```bash -$ rg --sort path -n "think|reasoning_effort|thinking_token_budget|include_reasoning|chat_template_kwargs" agent-contract/outer/openai-compatible-api.md -(output) -``` - -### API-2 중간 검증 -```bash -$ rg --sort path -n "think=false|include_reasoning|reasoning_effort|thinking_token_budget" docs/edge-local-dev-guide.md docs/openai-compatible-api-contract.md -(output) -``` - -### 최종 검증 -```bash -$ rg --sort path -n "think|reasoning_effort|thinking_token_budget|include_reasoning|chat_template_kwargs" agent-contract/outer/openai-compatible-api.md docs/edge-local-dev-guide.md docs/openai-compatible-api-contract.md -(output) -``` - ---- - -> **[IMPLEMENTING AGENT — BEFORE SAVING] Have you filled in every implementation-owned section: completion table, implementation checklist, changes from plan, design decisions, and verification output?** diff --git a/docs/edge-local-dev-guide.md b/docs/edge-local-dev-guide.md index 4bc7a1d..e719667 100644 --- a/docs/edge-local-dev-guide.md +++ b/docs/edge-local-dev-guide.md @@ -235,6 +235,43 @@ Node host OS 재부팅은 필요하지 않다. Edge process 재시작이나 일 Qwen 계열 모델은 thinking/reasoning 텍스트를 포함해 응답할 수 있다. 이 dev smoke에서는 thinking 출력을 실패로 보지 않고, HTTP 성공, final marker 포함, provider log/run count 증가를 기준으로 판정한다. +### Request-level think-control smoke + +`/v1/chat/completions` 요청은 `think`, `reasoning_effort`, `thinking_token_budget`, `include_reasoning`으로 thinking/reasoning 동작과 응답 노출을 제어할 수 있다. dev-runtime provider pool에서는 vLLM, vLLM-MLX, Lemonade 지원 범위가 다르므로 smoke 예시는 provider 공통으로 통과하는 조합을 우선한다. + +- 안정 smoke: `think=false`, `think` 생략, `include_reasoning=false`, 또는 budget-only `thinking_token_budget` +- Lemonade-only/provider-specific smoke: `reasoning_effort=low|medium|high` +- vLLM/vLLM-MLX는 `reasoning_effort=none`만 disable alias로 처리하고, `low|medium|high`는 `unsupported think control` 오류를 반환한다. + +예시 (thinking 비활성화): + +```bash +curl -fsS http://toki-labs.com:18083/v1/chat/completions \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Bearer ' \ + -d '{"model":"qwen3.6:35b","messages":[{"role":"user","content":"hello"}],"think":false}' +``` + +예시 (thinking 생성은 허용하고 response reasoning_content만 숨김): + +```bash +curl -fsS http://toki-labs.com:18083/v1/chat/completions \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Bearer ' \ + -d '{"model":"qwen3.6:35b","messages":[{"role":"user","content":"hello"}],"include_reasoning":false}' +``` + +예시 (budget-only): + +```bash +curl -fsS http://toki-labs.com:18083/v1/chat/completions \ + -H 'Content-Type: application/json' \ + -H 'Authorization: Bearer ' \ + -d '{"model":"qwen3.6:35b","messages":[{"role":"user","content":"hello"}],"thinking_token_budget":512}' +``` + +`reasoning_effort=low` 같은 effort smoke는 Lemonade-only 검증이거나 provider route를 고정할 수 있을 때만 사용한다. provider pool에 vLLM/vLLM-MLX가 섞여 있으면 해당 provider로 라우팅될 때 실패할 수 있다. + 현재 공개 API는 개별 request의 최종 `node_id`를 응답에 노출하지 않는다. 요청별 배정을 확정해야 할 때는 Edge dispatch trace/log를 추가한 뒤 판정한다. ## 7. 기본 Smoke