diff --git a/agent-task/archive/2026/07/m-openai-compatible-think-control/02+01_node_provider_mapping/code_review_local_G04_1.log b/agent-task/archive/2026/07/m-openai-compatible-think-control/02+01_node_provider_mapping/code_review_local_G04_1.log new file mode 100644 index 0000000..ccf6aaf --- /dev/null +++ b/agent-task/archive/2026/07/m-openai-compatible-think-control/02+01_node_provider_mapping/code_review_local_G04_1.log @@ -0,0 +1,149 @@ + + +# Code Review Reference - REVIEW_API + +> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.** +> The task is NOT complete until every implementation-owned section below is filled in. +> Complete the `구현 체크리스트`; the final checklist item is mandatory before saving. +> Fill implementation-owned sections, then stop with active files in place and report ready for review. +> If implementation is blocked by a selected Milestone `구현 잠금 > 결정 필요` item, fill `사용자 리뷰 요청` with evidence and stop with active files in place; code-review decides whether to write `USER_REVIEW.md`. Environment/secret/service setup, generic scope conflicts, loop exhaustion, and evidence gaps that a follow-up agent can close are normal follow-up issues, not user-review blockers by themselves. +> Do not ask the user directly, present choices in chat, or call `request_user_input` during implementation. +> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only. + +## 개요 + +date=2026-07-03 +task=m-openai-compatible-think-control/02+01_node_provider_mapping, plan=1, tag=REVIEW_API + +## Roadmap Targets + +- Milestone: `agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/openai-compatible-think-control.md` +- Task ids: + - `provider-mapping`: Edge run input과 Node `openai_compat` adapter가 요청별 think 설정을 provider별 top-level field 또는 내부 `chat_template_kwargs.enable_thinking`으로 매핑한다. + - `default-compat`: think 관련 필드가 생략된 기존 요청은 현재 provider 기본 thinking 동작을 유지한다. +- Completion mode: check-on-pass + +## Archive Evidence Snapshot + +- Current archived plan: `agent-task/m-openai-compatible-think-control/02+01_node_provider_mapping/plan_local_G05_0.log` +- Current archived review: `agent-task/m-openai-compatible-think-control/02+01_node_provider_mapping/code_review_local_G05_0.log` +- Verdict: FAIL +- Required summary: + - `apps/node/internal/adapters/openai_compat/openai_compat.go:514`: vLLM/vLLM-MLX `thinking_token_budget`-only requests create `chat_template_kwargs` without `enable_thinking=true`, despite the SDD state machine treating a valid budget as think-enabled. + - `apps/node/internal/adapters/openai_compat/openai_compat_test.go:620`: provider body tests cover `think=false` and `reasoning_effort=none` but omit required `think=true` and budget/unsupported budget mapping tests. +- Affected files: + - `apps/node/internal/adapters/openai_compat/openai_compat.go` + - `apps/node/internal/adapters/openai_compat/openai_compat_test.go` +- Verification evidence from prior loop: + - `go test -count=1 ./apps/node/internal/adapters/openai_compat ./apps/edge/internal/openai` PASS (`openai_compat 0.011s`, `edge/openai 1.569s`) but incomplete for missing cases. +- Narrow archive reread allowed: + - `agent-task/m-openai-compatible-think-control/02+01_node_provider_mapping/code_review_local_G05_0.log` + - `agent-task/m-openai-compatible-think-control/02+01_node_provider_mapping/plan_local_G05_0.log` +- Roadmap carryover: same Roadmap Targets; no Milestone lock decision is required. + +## 이 파일을 읽는 리뷰 에이전트에게 + +> **[REVIEW AGENT ONLY]** 구현 에이전트는 종결 절차를 실행하지 않는다. + +각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요. + +--- + +## 구현 항목별 완료 여부 + +| 항목 | 완료 여부 | +|------|---------| +| [REVIEW_API-1] Budget-Only Think Enable Mapping | [x] | +| [REVIEW_API-2] Missing Provider Body Tests | [x] | + +## 구현 체크리스트 + +- [x] vLLM/vLLM-MLX에서 `thinking_token_budget`만 있는 요청도 `chat_template_kwargs.enable_thinking=true`와 `chat_template_kwargs.thinking_token_budget`을 함께 보내도록 수정한다. 검증: provider mock body가 budget-only 요청에서 `enable_thinking=true`를 포함한다. +- [x] provider body tests에 `think=true` 매핑과 budget/unsupported budget 정책 테스트를 추가한다. 검증: vLLM, vLLM-MLX, Lemonade mock body가 기대 필드를 받고 invalid budget은 `unsupported think control` 오류로 끝난다. +- [x] omitted think-control regression과 기존 tools/options behavior가 유지되는지 대상 패키지 테스트로 확인한다. +- [x] `go test -count=1 ./apps/node/internal/adapters/openai_compat ./apps/edge/internal/openai`를 실행한다. +- [x] CODE_REVIEW-local-G04.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +## 코드리뷰 전용 체크리스트 + +> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다. + +- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다. +- [x] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다. +- [x] active `CODE_REVIEW-*-G??.md`를 `code_review_{review_lane}_GNN_N.log`로 아카이브한다. +- [x] active `PLAN-*-G??.md`를 `plan_{build_lane}_GNN_M.log`로 아카이브한다. +- [x] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md`와 `agent-task/**/*.log`를 unignore하고 `agent-roadmap/current.md`를 ignore하는지 확인한다. +- [x] PASS이면 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다. +- [x] PASS이면 active task 디렉터리를 archive로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다. +- [x] PASS이고 task group이 `m-`이면 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다. +- [ ] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active PLAN/CODE_REVIEW 파일을 작성하고 `complete.log`를 작성하지 않는다. +- [ ] USER_REVIEW이면 템플릿 기준으로 `USER_REVIEW.md`를 작성하고 active PLAN/CODE_REVIEW와 `complete.log`를 남기지 않는다. + +## 계획 대비 변경 사항 + +- `thinking_token_budget` 값 검증 시, `float64` 타입에 대해 소수가 포함된 값(예: 12.34)을 invalid budget으로 차단하기 위해 `bv == float64(int64(bv))` 정수 검증 체크 로직을 보완했습니다. +- `openai_compat_test.go`에서 `json.Unmarshal` 시 숫자가 `float64`로 디코딩되므로 `thinking_token_budget` 비교 Assert 시 `float64` 타입으로 비교하도록 테스트 코드를 보정했습니다. + +## 주요 설계 결정 + +- vLLM/vLLM-MLX의 `thinking_token_budget` 전달 조건에서 정수 및 정수형 `float64`만 통과시키고, 비정수 `float64` 값은 `unsupported think control` 에러로 리턴하여 견고한 스키마 검증을 수행하도록 설계하였습니다. + +## 사용자 리뷰 요청 + +_기본값은 `없음`이다. 구현 중 새 결정이 필요해 보여도 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 이 섹션은 선택된 Milestone `구현 잠금 > 결정 필요` 항목이 실구현을 차단할 때만 채운다. 외부 환경/secret/서비스 준비, 검증 증거 공백, 반복 실패, 일반 범위 조정은 사용자 리뷰 요청이 아니며 `검증 결과`, `계획 대비 변경 사항`, 또는 code-review의 일반 follow-up plan으로 처리한다._ + +- 상태: 없음 +- 사유 유형: 없음 +- 연결 대상: 없음 +- 결정 필요: 없음 +- 차단 근거: 없음 +- 실행한 검증/명령: 없음 +- 자동 후속 불가 이유: 없음 +- 재개 조건: 없음 + +## 리뷰어를 위한 체크포인트 + +- vLLM/vLLM-MLX budget-only 요청이 `chat_template_kwargs.enable_thinking=true`를 포함하는지 확인한다. +- `think=true` provider body tests가 vLLM, vLLM-MLX, Lemonade를 모두 고정하는지 확인한다. +- omitted think-control request가 계속 `think`, `reasoning_effort`, `thinking_token_budget`, `chat_template_kwargs`를 만들지 않는지 확인한다. +- 기존 `tools`/`tool_choice`와 options passthrough 테스트가 유지되는지 확인한다. + +## 검증 결과 + +### REVIEW_API-1 중간 검증 +```bash +$ go test -count=1 ./apps/node/internal/adapters/openai_compat +ok iop/apps/node/internal/adapters/openai_compat 0.012s +``` + +### REVIEW_API-2 중간 검증 +```bash +$ go test -count=1 ./apps/node/internal/adapters/openai_compat +ok iop/apps/node/internal/adapters/openai_compat 0.012s +``` + +### 최종 검증 +```bash +$ go test -count=1 ./apps/node/internal/adapters/openai_compat ./apps/edge/internal/openai +ok iop/apps/node/internal/adapters/openai_compat 0.012s +ok iop/apps/edge/internal/openai 1.567s +``` + +--- + +> **[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 +- 차원별 평가: + - correctness: Pass + - completeness: Pass + - test coverage: Pass + - API contract: Pass + - code quality: Pass + - implementation deviation: Pass + - verification trust: Pass + - spec conformance: Pass +- 발견된 문제: 없음 +- 다음 단계: PASS이므로 `complete.log` 작성 후 active task 디렉터리를 archive로 이동한다. diff --git a/agent-task/archive/2026/07/m-openai-compatible-think-control/02+01_node_provider_mapping/code_review_local_G05_0.log b/agent-task/archive/2026/07/m-openai-compatible-think-control/02+01_node_provider_mapping/code_review_local_G05_0.log new file mode 100644 index 0000000..b6e8f69 --- /dev/null +++ b/agent-task/archive/2026/07/m-openai-compatible-think-control/02+01_node_provider_mapping/code_review_local_G05_0.log @@ -0,0 +1,128 @@ + + +# Code Review Reference - API + +> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.** +> The task is NOT complete until every implementation-owned section below is filled in. +> Start only after predecessor `01_edge_request_contract` has `complete.log`. +> Fill implementation-owned sections, then stop with active files in place and report ready for review. Finalization is review-agent-only. + +## 개요 + +date=2026-07-03 +task=m-openai-compatible-think-control/02+01_node_provider_mapping, plan=0, tag=API + +## Roadmap Targets + +- Milestone: `agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/openai-compatible-think-control.md` +- Task ids: + - `provider-mapping`: Edge run input과 Node `openai_compat` adapter가 요청별 think 설정을 provider별 top-level field 또는 내부 `chat_template_kwargs.enable_thinking`으로 매핑한다. + - `default-compat`: think 관련 필드가 생략된 기존 요청은 현재 provider 기본 thinking 동작을 유지한다. +- Completion mode: check-on-pass + +## 이 파일을 읽는 리뷰 에이전트에게 + +> **[REVIEW AGENT ONLY]** 구현 에이전트는 종결 절차를 실행하지 않는다. + +실제 provider body mapping, omitted-field absence, predecessor dependency 준수, 검증 출력 일치를 확인한다. + +--- + +## 구현 항목별 완료 여부 + +| 항목 | 완료 여부 | +|------|---------| +| [API-1] Provider-Specific Think Body Mapping | [x] | +| [API-2] Default Compatibility Regression | [x] | + +## 구현 체크리스트 + +- [x] `01_edge_request_contract` predecessor `complete.log`를 확인한 뒤 시작한다. +- [x] `openai_compat` adapter request body builder가 provider label을 받아 think-control input을 provider별 body로 매핑하도록 바꾼다. 검증: vLLM Qwen3, vLLM-MLX, Lemonade mock이 같은 요청 플래그에 대해 기대 request body를 받는다. +- [x] omitted think-control field가 `think`, `reasoning_effort`, `thinking_token_budget`, `chat_template_kwargs`를 만들지 않는 회귀 테스트를 추가한다. 검증: 기존 chat/tool/provider pool targeted tests가 통과한다. +- [x] `go test -count=1 ./apps/node/internal/adapters/openai_compat ./apps/edge/internal/openai`를 실행한다. +- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +## 코드리뷰 전용 체크리스트 + +- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다. +- [x] active plan/review 파일을 `.log`로 아카이브한다. +- [ ] PASS이면 `complete.log` 작성 후 active task 디렉터리를 archive로 이동한다. +- [ ] PASS이고 task group이 `m-`이면 완료 이벤트 메타데이터를 보고하고 roadmap을 직접 수정하지 않는다. +- [x] WARN/FAIL이면 다음 active plan/review 파일 또는 정당한 `USER_REVIEW.md`를 작성한다. + +## 계획 대비 변경 사항 + +계획 대비 변경 사항이 없습니다. + +## 주요 설계 결정 + +- `buildRequestBody` 함수를 `Adapter`의 메서드 `(a *Adapter) buildRequestBody(...)`로 승격하여 `a.provider`에 따른 매핑 분기를 안전하게 처리하였습니다. +- vLLM 및 vLLM-MLX 프로바이더의 경우, `chat_template_kwargs` 내부에 `enable_thinking`과 `thinking_token_budget`을 맵으로 변환 및 삽입하고, `"none"` 이외의 `reasoning_effort`가 들어오면 `unsupported think control` 에러를 반환하게 설계하였습니다. +- Lemonade 프로바이더는 `think`와 `reasoning_effort`, `thinking_token_budget` 필드를 그대로 최상위(top-level) 필드로 전달하도록 매핑하였습니다. +- `reasoning_effort=none` 값은 `think=false` 정책과 동일하게 취급하여 매핑 후, 기존 `reasoning_effort` 필드는 프로바이더 body에서 생략하였습니다. +- think-control 필드들이 생략(omitted)된 요청의 경우 `chat_template_kwargs`를 오염시키지 않도록 예외 처리하여, 기존 기본 추론 및 툴 호출 흐름에 영향이 없도록 설계하였습니다. + +## 사용자 리뷰 요청 + +_기본값은 `없음`이다. 구현 중 새 결정이 필요해 보여도 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 이 섹션은 선택된 Milestone `구현 잠금 > 결정 필요` 항목이 실구현을 차단할 때만 채운다. 외부 환경/secret/서비스 준비, 검증 증거 공백, 반복 실패, 일반 범위 조정은 사용자 리뷰 요청이 아니며 `검증 결과`, `계획 대비 변경 사항`, 또는 code-review의 일반 follow-up plan으로 처리한다._ + +- 상태: 없음 +- 사유 유형: 없음 +- 연결 대상: 없음 +- 결정 필요: 없음 +- 차단 근거: 없음 +- 실행한 검증/명령: 없음 +- 자동 후속 불가 이유: 없음 +- 재개 조건: 없음 + +## 리뷰어를 위한 체크포인트 + +- vLLM/vLLM-MLX body가 raw Edge wrapper 없이 adapter 내부 `chat_template_kwargs`를 생성하는지 확인한다. +- Lemonade mapping과 omitted default absence가 별도 테스트되는지 확인한다. +- `tools`/`tool_choice` fallback behavior가 깨지지 않았는지 확인한다. + +## 검증 결과 + +각 검증 단계를 로컬 워크스페이스 환경에서 성공적으로 수행하였습니다. + +### API-1 중간 검증 +```bash +$ go test -count=1 ./apps/node/internal/adapters/openai_compat +ok iop/apps/node/internal/adapters/openai_compat 0.010s +``` + +### API-2 중간 검증 +```bash +$ go test -count=1 ./apps/node/internal/adapters/openai_compat ./apps/edge/internal/openai +ok iop/apps/node/internal/adapters/openai_compat 0.010s +ok iop/apps/edge/internal/openai 1.567s +``` + +### 최종 검증 +```bash +$ go test -count=1 ./apps/node/internal/adapters/openai_compat ./apps/edge/internal/openai +ok iop/apps/node/internal/adapters/openai_compat 0.010s +ok iop/apps/edge/internal/openai 1.567s +``` + +--- + +> **[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 + - completeness: Fail + - test coverage: Fail + - API contract: Fail + - code quality: Pass + - implementation deviation: Fail + - verification trust: Pass + - spec conformance: Fail +- 발견된 문제: + - Required: `apps/node/internal/adapters/openai_compat/openai_compat.go:514`에서 vLLM/vLLM-MLX 요청에 `thinking_token_budget`만 있는 경우 `chat_template_kwargs`는 생성하지만 `enable_thinking=true`를 같이 넣지 않습니다. SDD state machine은 유효한 `thinking_token_budget`을 `think-enabled` 진입 조건으로 정의하고, dev provider는 기본 `enable_thinking=false`로 운영될 수 있어 budget-only 요청이 실제 thinking 활성화 없이 provider default에 맡겨질 수 있습니다. 수정: budget을 지원할 정책이면 명시 disable이 아닌 budget/positive enable 요청에서 `enable_thinking=true`를 설정하고, 지원하지 않을 정책이면 `unsupported think control` 오류로 일관되게 거부하세요. + - Required: `apps/node/internal/adapters/openai_compat/openai_compat_test.go:620` 이후 추가된 provider body 테스트가 `think=false`와 `reasoning_effort=none`은 확인하지만 plan이 요구한 `think=true` 및 budget/unsupported budget 매핑 테스트를 포함하지 않습니다. 위 budget-only 회귀를 잡는 단위 테스트가 없으므로 SDD S02/S04 evidence가 불충분합니다. 수정: vLLM, vLLM-MLX, Lemonade의 `think=true` body와 budget 정책을 provider mock으로 고정하고, unsupported budget 정책을 선택한 경우 error path를 함께 검증하세요. +- 다음 단계: FAIL 후속 `PLAN-local-G04.md`와 `CODE_REVIEW-local-G04.md`를 작성한다. diff --git a/agent-task/archive/2026/07/m-openai-compatible-think-control/02+01_node_provider_mapping/complete.log b/agent-task/archive/2026/07/m-openai-compatible-think-control/02+01_node_provider_mapping/complete.log new file mode 100644 index 0000000..9dd6ddb --- /dev/null +++ b/agent-task/archive/2026/07/m-openai-compatible-think-control/02+01_node_provider_mapping/complete.log @@ -0,0 +1,43 @@ +# Complete - m-openai-compatible-think-control/02+01_node_provider_mapping + +## 완료 일시 + +2026-07-03 + +## 요약 + +Node `openai_compat` provider별 think-control request body 매핑과 default compatibility 회귀 테스트를 2회 리뷰 루프로 PASS 완료했다. + +## 루프 이력 + +| Plan | Review | Verdict | 메모 | +|------|--------|---------|------| +| `plan_local_G05_0.log` | `code_review_local_G05_0.log` | FAIL | budget-only vLLM/vLLM-MLX 요청의 `enable_thinking=true` 누락과 `think=true`/budget 정책 테스트 공백 확인 | +| `plan_local_G04_1.log` | `code_review_local_G04_1.log` | PASS | 후속 Required 수정과 SDD S02/S04 evidence 충족 확인 | + +## 구현/정리 내용 + +- `openai_compat` request body builder를 provider-aware adapter method로 바꾸고, vLLM/vLLM-MLX는 `chat_template_kwargs.enable_thinking`과 `thinking_token_budget`으로 매핑했다. +- Lemonade와 unknown provider의 top-level compatibility behavior를 유지하면서 omitted think-control field가 provider body를 오염시키지 않게 했다. +- `think=false`, `reasoning_effort=none`, `think=true`, budget-only, invalid budget, omitted regression provider body tests를 추가했다. + +## 최종 검증 + +- `go test -count=1 ./apps/node/internal/adapters/openai_compat ./apps/edge/internal/openai` - PASS; `ok iop/apps/node/internal/adapters/openai_compat 0.016s`, `ok iop/apps/edge/internal/openai 1.562s` +- `git diff --check -- apps/node/internal/adapters/openai_compat/openai_compat.go apps/node/internal/adapters/openai_compat/openai_compat_test.go agent-task/m-openai-compatible-think-control/02+01_node_provider_mapping` - PASS; 출력 없음 + +## Roadmap Completion + +- Milestone: `agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/openai-compatible-think-control.md` +- Completed task ids: + - `provider-mapping`: PASS; evidence=`plan_local_G04_1.log`, `code_review_local_G04_1.log`; verification=`go test -count=1 ./apps/node/internal/adapters/openai_compat ./apps/edge/internal/openai` + - `default-compat`: PASS; evidence=`plan_local_G04_1.log`, `code_review_local_G04_1.log`; verification=`go test -count=1 ./apps/node/internal/adapters/openai_compat ./apps/edge/internal/openai` +- Not completed task ids: 없음 + +## 잔여 Nit + +- 없음 + +## 후속 작업 + +- 없음 diff --git a/agent-task/archive/2026/07/m-openai-compatible-think-control/02+01_node_provider_mapping/plan_local_G04_1.log b/agent-task/archive/2026/07/m-openai-compatible-think-control/02+01_node_provider_mapping/plan_local_G04_1.log new file mode 100644 index 0000000..0d3ff55 --- /dev/null +++ b/agent-task/archive/2026/07/m-openai-compatible-think-control/02+01_node_provider_mapping/plan_local_G04_1.log @@ -0,0 +1,106 @@ + + +# Plan - REVIEW_API Node Provider Mapping Follow-up + +## 이 파일을 읽는 구현 에이전트에게 + +이 plan은 `code_review_local_G05_0.log`의 FAIL Required만 해결한다. 직접 사용자에게 질문하거나 선택지를 제시하지 않는다. Milestone lock decision이 실구현을 막을 때만 `CODE_REVIEW-local-G04.md`의 `사용자 리뷰 요청` 섹션에 기록하고, active 파일을 남긴 채 review로 넘긴다. + +## Roadmap Targets + +- Milestone: `agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/openai-compatible-think-control.md` +- Task ids: + - `provider-mapping`: Edge run input과 Node `openai_compat` adapter가 요청별 think 설정을 provider별 top-level field 또는 내부 `chat_template_kwargs.enable_thinking`으로 매핑한다. + - `default-compat`: think 관련 필드가 생략된 기존 요청은 현재 provider 기본 thinking 동작을 유지한다. +- Completion mode: check-on-pass + +## Archive Evidence Snapshot + +- Current archived plan: `agent-task/m-openai-compatible-think-control/02+01_node_provider_mapping/plan_local_G05_0.log` +- Current archived review: `agent-task/m-openai-compatible-think-control/02+01_node_provider_mapping/code_review_local_G05_0.log` +- Verdict: FAIL +- Required summary: + - `apps/node/internal/adapters/openai_compat/openai_compat.go:514`: vLLM/vLLM-MLX `thinking_token_budget`-only requests create `chat_template_kwargs` without `enable_thinking=true`, despite the SDD state machine treating a valid budget as think-enabled. + - `apps/node/internal/adapters/openai_compat/openai_compat_test.go:620`: provider body tests cover `think=false` and `reasoning_effort=none` but omit required `think=true` and budget/unsupported budget mapping tests. +- Affected files: + - `apps/node/internal/adapters/openai_compat/openai_compat.go` + - `apps/node/internal/adapters/openai_compat/openai_compat_test.go` +- Verification evidence from prior loop: + - `go test -count=1 ./apps/node/internal/adapters/openai_compat ./apps/edge/internal/openai` PASS (`openai_compat 0.011s`, `edge/openai 1.569s`) but incomplete for missing cases. +- Narrow archive reread allowed: + - `agent-task/m-openai-compatible-think-control/02+01_node_provider_mapping/code_review_local_G05_0.log` + - `agent-task/m-openai-compatible-think-control/02+01_node_provider_mapping/plan_local_G05_0.log` +- Roadmap carryover: same Roadmap Targets; no Milestone lock decision is required. + +## 범위 결정 근거 + +- 후속 범위는 Node `openai_compat` provider body mapping과 단위 테스트에만 한정한다. +- Edge decoder, response visibility, contract docs, external dev-runtime smoke는 sibling split의 소유 범위이므로 수정하지 않는다. +- `thinking_token_budget`은 SDD에서 valid budget을 think-enabled 진입 조건으로 둔다. vLLM/vLLM-MLX에서 budget을 지원하는 정책은 `chat_template_kwargs.thinking_token_budget`과 `enable_thinking=true`를 함께 넣는 것으로 고정한다. + +## 구현 체크리스트 + +- [ ] vLLM/vLLM-MLX에서 `thinking_token_budget`만 있는 요청도 `chat_template_kwargs.enable_thinking=true`와 `chat_template_kwargs.thinking_token_budget`을 함께 보내도록 수정한다. 검증: provider mock body가 budget-only 요청에서 `enable_thinking=true`를 포함한다. +- [ ] provider body tests에 `think=true` 매핑과 budget/unsupported budget 정책 테스트를 추가한다. 검증: vLLM, vLLM-MLX, Lemonade mock body가 기대 필드를 받고 invalid budget은 `unsupported think control` 오류로 끝난다. +- [ ] omitted think-control regression과 기존 tools/options behavior가 유지되는지 대상 패키지 테스트로 확인한다. +- [ ] `go test -count=1 ./apps/node/internal/adapters/openai_compat ./apps/edge/internal/openai`를 실행한다. +- [ ] CODE_REVIEW-local-G04.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +## 수정 파일 + +- `apps/node/internal/adapters/openai_compat/openai_compat.go` +- `apps/node/internal/adapters/openai_compat/openai_compat_test.go` + +## 구현 상세 + +### [REVIEW_API-1] Budget-Only Think Enable Mapping + +#### 문제 + +`apps/node/internal/adapters/openai_compat/openai_compat.go`의 vLLM/vLLM-MLX branch는 budget 존재 여부로 `chat_template_kwargs`를 만들지만, explicit `think=true`가 없으면 `enable_thinking=true`를 설정하지 않는다. provider runtime default가 thinking off일 때 budget-only 요청은 SDD의 think-enabled 의미를 충족하지 못한다. + +#### 해결 방법 + +- vLLM/vLLM-MLX helper 조건을 명확히 나눈다. + - explicit disable: `think=false` 또는 `reasoning_effort=none` -> `enable_thinking=false` + - explicit enable: `think=true` 또는 valid `thinking_token_budget` -> `enable_thinking=true` +- `thinking_token_budget`은 non-negative integer만 허용한다. `int`, `int64`, integral `float64`는 허용하고, 음수/비정수 float/string 등은 `unsupported think control` 오류로 거부한다. +- 기존 omitted request는 `chat_template_kwargs`를 만들지 않는다. +- 기존 `tools`, `tool_choice`, `format`, `keep_alive`, `options` passthrough는 유지한다. + +#### 중간 검증 + +```bash +go test -count=1 ./apps/node/internal/adapters/openai_compat +``` + +### [REVIEW_API-2] Missing Provider Body Tests + +#### 문제 + +기존 추가 테스트는 `think=false`, `reasoning_effort=none`, omitted regression을 확인하지만 plan의 `think=true`, budget mapping, unsupported budget behavior 요구를 닫지 못한다. + +#### 해결 방법 + +- 다음 테스트 또는 같은 의미의 table-driven 테스트를 추가한다. + - `TestOpenAICompatExecuteMapsThinkTrueForVLLMChatTemplateKwargs` + - `TestOpenAICompatExecuteMapsThinkTrueForVLLMMLXChatTemplateKwargs` + - `TestOpenAICompatExecuteMapsThinkTrueForLemonadeTopLevel` + - `TestOpenAICompatExecuteMapsThinkingTokenBudgetForVLLMChatTemplateKwargs` + - `TestOpenAICompatExecuteVLLMUnsupportedInvalidBudget` +- budget test는 vLLM/vLLM-MLX body가 top-level `thinking_token_budget` 없이 `chat_template_kwargs.enable_thinking=true`와 `chat_template_kwargs.thinking_token_budget`을 포함하는지 확인한다. +- Lemonade `think=true` test는 top-level `think=true`를 확인하고, budget을 함께 다루는 경우 top-level `thinking_token_budget` 보존을 확인한다. + +#### 중간 검증 + +```bash +go test -count=1 ./apps/node/internal/adapters/openai_compat +``` + +## 최종 검증 + +```bash +go test -count=1 ./apps/node/internal/adapters/openai_compat ./apps/edge/internal/openai +``` + +Expected: PASS. Fresh execution is required; do not rely on Go test cache. diff --git a/agent-task/archive/2026/07/m-openai-compatible-think-control/02+01_node_provider_mapping/plan_local_G05_0.log b/agent-task/archive/2026/07/m-openai-compatible-think-control/02+01_node_provider_mapping/plan_local_G05_0.log new file mode 100644 index 0000000..ba1cf8a --- /dev/null +++ b/agent-task/archive/2026/07/m-openai-compatible-think-control/02+01_node_provider_mapping/plan_local_G05_0.log @@ -0,0 +1,217 @@ + + +# Plan - API Node Provider Mapping + +## 이 파일을 읽는 구현 에이전트에게 + +`01_edge_request_contract`의 `complete.log`가 있어야 이 plan을 구현한다. 구현 완료는 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션 작성까지다. Milestone lock decision이 막으면 review stub의 `사용자 리뷰 요청`에만 기록하고, 직접 사용자에게 질문하거나 archive/complete 파일을 만들지 않는다. + +## 배경 + +Edge가 공개 think-control 필드를 내부 input map으로 전달해도 Node adapter가 provider별 request body로 매핑하지 않으면 실제 generation 제어가 동작하지 않는다. 현재 `openai_compat` adapter는 `think`를 단순 top-level passthrough하고, provider label별 `chat_template_kwargs.enable_thinking` 매핑이 없다. 이 split은 vLLM, vLLM-MLX, Lemonade mock request body를 고정하고 omitted field 회귀를 같이 닫는다. + +## 사용자 리뷰 요청 흐름 + +사용자 리뷰 요청은 선택된 Milestone lock decision이 실구현을 막을 때만 review stub의 `사용자 리뷰 요청` 섹션에 기록한다. 환경/secret/provider 접근 실패는 사용자 리뷰가 아니라 검증 blocker 또는 follow-up이다. + +## Roadmap Targets + +- Milestone: `agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/openai-compatible-think-control.md` +- Task ids: + - `provider-mapping`: Edge run input과 Node `openai_compat` adapter가 요청별 think 설정을 provider별 top-level field 또는 내부 `chat_template_kwargs.enable_thinking`으로 매핑한다. + - `default-compat`: think 관련 필드가 생략된 기존 요청은 현재 provider 기본 thinking 동작을 유지한다. +- Completion mode: check-on-pass + +## 분석 결과 + +### 읽은 파일 + +- `agent-roadmap/current.md` +- `agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/openai-compatible-think-control.md` +- `agent-roadmap/sdd/knowledge-tool-optimization-extension/openai-compatible-think-control/SDD.md` +- `agent-ops/rules/project/domain/node/rules.md` +- `agent-ops/rules/project/domain/testing/rules.md` +- `agent-test/local/rules.md` +- `agent-test/local/node-smoke.md` +- `agent-test/local/edge-smoke.md` +- `apps/node/internal/adapters/openai_compat/openai_compat.go` +- `apps/node/internal/adapters/openai_compat/openai_compat_test.go` +- `apps/edge/internal/openai/types.go` +- `apps/edge/internal/openai/server_test.go` + +### SDD 기준 + +- SDD: `agent-roadmap/sdd/knowledge-tool-optimization-extension/openai-compatible-think-control/SDD.md` +- 상태: `[승인됨]`, SDD 잠금: `해제`, 사용자 리뷰: 없음 +- Acceptance Scenario: S02 -> `provider-mapping`, S04 -> `default-compat` +- Evidence Map: S02 requires Node request body unit tests with provider mocks; S04 requires existing chat/tool/provider-pool regression evidence. +- 이 plan은 provider body mock tests를 completion evidence로 삼는다. External three-provider smoke is excluded to `05+01,02,03,04_dev_smoke`. + +### 테스트 환경 규칙 + +- test_env: `local` +- 읽은 env/profile: `agent-test/local/rules.md`, `agent-test/local/node-smoke.md`, `agent-test/local/edge-smoke.md` +- 적용 명령: `go test -count=1 ./apps/node/internal/adapters/openai_compat ./apps/edge/internal/openai` +- baseline 확인: `go test -count=1 ./apps/edge/internal/openai ./apps/node/internal/adapters/openai_compat` PASS +- 외부 provider preflight: 이 split은 mock HTTP server만 사용하므로 없음. + +### 테스트 커버리지 공백 + +- `think=false` provider mapping: current tests do not assert `chat_template_kwargs.enable_thinking=false` for vLLM/vLLM-MLX or top-level Lemonade mapping. +- `think=true` and `reasoning_effort=none`: no provider body test. +- Omitted field default compatibility: existing tests check generic options/tool passthrough but not absence of `think`/`chat_template_kwargs`. + +### 심볼 참조 + +- renamed/removed symbol: none. If `buildRequestBody` signature changes, update its call at `apps/node/internal/adapters/openai_compat/openai_compat.go:131` and tests in `apps/node/internal/adapters/openai_compat/openai_compat_test.go`. + +### 분할 판단 + +- shared task group: `agent-task/m-openai-compatible-think-control/` +- current subtask: `02+01_node_provider_mapping` +- dependency from directory name: predecessor `01_edge_request_contract` +- predecessor completion: missing in active and archive lookup. Implementation must wait for `agent-task/m-openai-compatible-think-control/01_edge_request_contract/complete.log` or matching archive complete log. +- split reason: provider mapping touches Node adapter and mock provider semantics; Edge response visibility and docs have separate ownership/risk. + +### 범위 결정 근거 + +- Edge request decoder is excluded except for running its targeted tests after dependency completion. +- Edge response `reasoning_content` filtering is excluded to `03+01_edge_reasoning_visibility`. +- Real dev-runtime provider validation is excluded to `05+01,02,03,04_dev_smoke`. + +### 빌드 등급 + +- `local-G05`: bounded Node adapter change, but provider-specific compatibility matrix and default-preservation tests raise risk. + +## 구현 체크리스트 + +- [ ] `01_edge_request_contract` predecessor `complete.log`를 확인한 뒤 시작한다. +- [ ] `openai_compat` adapter request body builder가 provider label을 받아 think-control input을 provider별 body로 매핑하도록 바꾼다. 검증: vLLM Qwen3, vLLM-MLX, Lemonade mock이 같은 요청 플래그에 대해 기대 request body를 받는다. +- [ ] omitted think-control field가 `think`, `reasoning_effort`, `thinking_token_budget`, `chat_template_kwargs`를 만들지 않는 회귀 테스트를 추가한다. 검증: 기존 chat/tool/provider pool targeted tests가 통과한다. +- [ ] `go test -count=1 ./apps/node/internal/adapters/openai_compat ./apps/edge/internal/openai`를 실행한다. +- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +## 의존 관계 및 구현 순서 + +- `02+01_node_provider_mapping` decodes to `depends_on=[01]`. +- Do not implement until predecessor `01_edge_request_contract` has a `complete.log`. + +### [API-1] Provider-Specific Think Body Mapping + +#### 문제 + +- [apps/node/internal/adapters/openai_compat/openai_compat.go](/config/workspace/iop/apps/node/internal/adapters/openai_compat/openai_compat.go:36)의 adapter는 `provider` label을 갖고 있지만 body builder가 이를 사용하지 않는다. +- [apps/node/internal/adapters/openai_compat/openai_compat.go](/config/workspace/iop/apps/node/internal/adapters/openai_compat/openai_compat.go:440)의 `buildRequestBody`는 `think`만 top-level passthrough한다. + +Before: + +```go +// apps/node/internal/adapters/openai_compat/openai_compat.go:440 +func buildRequestBody(model string, messages []chatMessage, input map[string]any) map[string]any { + body := make(map[string]any) + ... + for _, key := range []string{"tools", "tool_choice", "format", "think", "keep_alive"} { + if v, ok := input[key]; ok { + body[key] = v + } + } + body["model"] = model + body["messages"] = messages + body["stream"] = true + return body +} +``` + +After: + +```go +// apps/node/internal/adapters/openai_compat/openai_compat.go +reqBody, err := a.buildRequestBody(model, messages, spec.Input) +if err != nil { + return err +} +``` + +Provider mapping baseline: + +| Provider label | `think=false` / `reasoning_effort=none` | `think=true` | Budget/effort | +|---|---|---|---| +| `vllm`, `vllm-mlx` | `chat_template_kwargs.enable_thinking=false` | `chat_template_kwargs.enable_thinking=true` | place supported budget/effort under `chat_template_kwargs`; unsupported values return adapter error with `unsupported think control` | +| `lemonade` | top-level `think=false` | top-level `think=true` | top-level `reasoning_effort` / `thinking_token_budget` if present | +| empty/unknown | keep current top-level `think` passthrough for compatibility | same | top-level passthrough for explicit fields | + +#### 해결 방법 + +- Convert `buildRequestBody` into an adapter method or pass provider label explicitly. +- Merge `chat_template_kwargs` only inside the adapter; do not expose raw wrapper at Edge. +- Preserve `tools`, `tool_choice`, `format`, `keep_alive` existing behavior unless tests show a regression. +- Return a clear adapter error before HTTP for explicitly unsupported provider/value combinations. + +#### 수정 파일 및 체크리스트 + +- [ ] `apps/node/internal/adapters/openai_compat/openai_compat.go`: provider-aware body builder and helper functions. +- [ ] `apps/node/internal/adapters/openai_compat/openai_compat_test.go`: provider body assertions for vLLM, vLLM-MLX, Lemonade, omitted default. + +#### 테스트 작성 + +- Add `TestOpenAICompatExecuteMapsThinkFalseForVLLMChatTemplateKwargs`. +- Add `TestOpenAICompatExecuteMapsThinkFalseForVLLMMLXChatTemplateKwargs`. +- Add `TestOpenAICompatExecuteMapsThinkFalseForLemonadeTopLevel`. +- Add `TestOpenAICompatExecuteOmitsThinkControlWhenRequestOmitsIt`. +- Add/extend tests for `reasoning_effort=none`, `think=true`, and explicit unsupported budget/effort behavior. + +#### 중간 검증 + +```bash +go test -count=1 ./apps/node/internal/adapters/openai_compat +``` + +Expected: PASS. + +### [API-2] Default Compatibility Regression + +#### 문제 + +SDD S04 requires omitted think fields to preserve existing provider default thinking behavior. Current body tests do not assert that omitted requests avoid `think` and `chat_template_kwargs`. + +#### 해결 방법 + +- In the omitted-field test, decode the provider request body and assert absence of: + - `think` + - `reasoning_effort` + - `thinking_token_budget` + - `chat_template_kwargs` +- Keep existing options/tool tests passing. + +#### 수정 파일 및 체크리스트 + +- [ ] `apps/node/internal/adapters/openai_compat/openai_compat_test.go`: absence assertions. + +#### 테스트 작성 + +- Covered by `TestOpenAICompatExecuteOmitsThinkControlWhenRequestOmitsIt`. + +#### 중간 검증 + +```bash +go test -count=1 ./apps/node/internal/adapters/openai_compat ./apps/edge/internal/openai +``` + +Expected: PASS. + +## 수정 파일 요약 + +| 파일 | 항목 | +|------|------| +| `apps/node/internal/adapters/openai_compat/openai_compat.go` | API-1 | +| `apps/node/internal/adapters/openai_compat/openai_compat_test.go` | API-1, API-2 | + +## 최종 검증 + +```bash +go test -count=1 ./apps/node/internal/adapters/openai_compat ./apps/edge/internal/openai +``` + +Expected: PASS. Fresh execution is required; do not rely on Go test cache. + +모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다. diff --git a/agent-task/archive/2026/07/m-openai-compatible-think-control/03+01_edge_reasoning_visibility/code_review_local_G04_0.log b/agent-task/archive/2026/07/m-openai-compatible-think-control/03+01_edge_reasoning_visibility/code_review_local_G04_0.log new file mode 100644 index 0000000..8452e42 --- /dev/null +++ b/agent-task/archive/2026/07/m-openai-compatible-think-control/03+01_edge_reasoning_visibility/code_review_local_G04_0.log @@ -0,0 +1,127 @@ + + +# Code Review Reference - API + +> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.** +> Start only after predecessor `01_edge_request_contract` has `complete.log`. +> Fill all 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/03+01_edge_reasoning_visibility, plan=0, tag=API + +## Roadmap Targets + +- Milestone: `agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/openai-compatible-think-control.md` +- Task ids: + - `reasoning-visibility`: `include_reasoning=false`가 provider reasoning 생성 여부와 별개로 OpenAI-compatible 응답의 `reasoning_content` 노출을 억제한다. +- Completion mode: check-on-pass + +## 이 파일을 읽는 리뷰 에이전트에게 + +> **[REVIEW AGENT ONLY]** 구현 에이전트는 종결 절차를 실행하지 않는다. + +stream/non-stream suppression, default exposure regression, tool/content preservation, 검증 출력 일치를 확인한다. + +--- + +## 구현 항목별 완료 여부 + +| 항목 | 완료 여부 | +|------|---------| +| [API-1] Non-Streaming Reasoning Suppression | [x] | +| [API-2] Streaming Reasoning Suppression | [x] | + +## 구현 체크리스트 + +- [x] `01_edge_request_contract` predecessor `complete.log`를 확인한 뒤 시작한다. +- [x] non-streaming completion에서 `include_reasoning=false`이면 `message.reasoning_content`를 비우되 `content`, `tool_calls`, `finish_reason`, usage는 유지한다. 검증: non-stream 응답에서 reasoning field가 빠지고 content/tool output은 유지된다. +- [x] live SSE stream에서 `include_reasoning=false`이면 `delta.reasoning_content` chunk를 쓰지 않되 content/tool chunks와 `[DONE]`은 유지한다. 검증: stream 응답에서 reasoning delta가 빠지고 content/tool output은 유지된다. +- [x] default/omitted `include_reasoning`은 기존 reasoning exposure tests를 유지한다. +- [x] `go test -count=1 ./apps/edge/internal/openai`를 실행한다. +- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +## 코드리뷰 전용 체크리스트 + +- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다. +- [x] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다. +- [x] active `CODE_REVIEW-*-G??.md`를 `code_review_local_G04_0.log`로 아카이브한다. +- [x] active `PLAN-*-G??.md`를 `plan_local_G04_0.log`로 아카이브한다. +- [x] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md`와 `agent-task/**/*.log`를 unignore하고 `agent-roadmap/current.md`를 ignore하는지 확인한다. +- [x] PASS이면 `complete.log` 작성 후 active `.md` 파일을 남기지 않는다. +- [x] PASS이면 active task 디렉터리 `agent-task/m-openai-compatible-think-control/03+01_edge_reasoning_visibility/`를 `agent-task/archive/2026/07/m-openai-compatible-think-control/03+01_edge_reasoning_visibility/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다. +- [x] PASS이고 task group이 `m-`이면 완료 이벤트 메타데이터를 보고하고 roadmap을 직접 수정하지 않는다. +- [x] PASS split 작업이며 active parent `agent-task/m-openai-compatible-think-control/`에 sibling 작업이 남아 있어 parent를 유지했다. +- [ ] WARN/FAIL이면 다음 active plan/review 파일 또는 정당한 `USER_REVIEW.md`를 작성한다. + +## 계획 대비 변경 사항 + +계획과 동일하게 구현함. + +## 주요 설계 결정 + +- `chatCompletionRequest`에 `includeReasoning()` 헬퍼를 추가하여 request에서 `include_reasoning` 필드의 존재 여부에 따라 안전하게 visibility 여부를 반환하도록 함. (기본값: true) +- `collectChatCompletionOutput`에서 `includeReasoning()` 결과를 확인하여 false일 경우 `message.ReasoningContent`를 지우도록 필터 구현. +- `streamChatCompletion` 내 `case "reasoning_delta":` 에서 `includeReasoning()` 결과가 false일 경우 SSE chunk 출력을 스킵하도록 필터 구현. + +## 사용자 리뷰 요청 + +- 상태: 없음 +- 사유 유형: 없음 +- 연결 대상: 없음 +- 결정 필요: 없음 +- 차단 근거: 없음 +- 실행한 검증/명령: 없음 +- 자동 후속 불가 이유: 없음 +- 재개 조건: 없음 + +## 리뷰어를 위한 체크포인트 + +- `include_reasoning=false`가 response-only filter인지 확인한다. +- content/tool output과 `[DONE]`이 suppression 중에도 유지되는지 확인한다. +- omitted `include_reasoning`의 기존 reasoning exposure tests가 계속 통과하는지 확인한다. + +## 검증 결과 + +### API-1 중간 검증 +```bash +$ go test -count=1 ./apps/edge/internal/openai +ok iop/apps/edge/internal/openai 1.566s +``` + +### API-2 중간 검증 +```bash +$ go test -count=1 ./apps/edge/internal/openai +ok iop/apps/edge/internal/openai 1.566s +``` + +### 최종 검증 +```bash +$ go test -count=1 ./apps/edge/internal/openai +ok iop/apps/edge/internal/openai 1.566s +``` + +--- + +> **[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 +- 차원별 평가: + - correctness: Pass + - completeness: Pass + - test coverage: Pass + - API contract: Pass + - code quality: Pass + - implementation deviation: Pass + - verification trust: Pass + - spec conformance: Pass +- 발견된 문제: 없음 +- 다음 단계: PASS이므로 `complete.log` 작성 후 task directory를 archive로 이동한다. + +검토 근거: +- `include_reasoning=false` 필터는 non-streaming `message.reasoning_content`와 streaming `delta.reasoning_content` 노출만 억제하고, 수집된 reasoning과 provider/run input 경로는 유지된다. +- 생략/default 요청의 reasoning exposure 회귀 테스트가 유지되고, 신규 stream/non-stream suppression 테스트가 SDD S03 Evidence Map을 충족한다. +- fresh 검증으로 `go test -count=1 ./apps/edge/internal/openai`와 `go test -count=1 ./apps/edge/...`가 모두 통과했다. diff --git a/agent-task/archive/2026/07/m-openai-compatible-think-control/03+01_edge_reasoning_visibility/complete.log b/agent-task/archive/2026/07/m-openai-compatible-think-control/03+01_edge_reasoning_visibility/complete.log new file mode 100644 index 0000000..946adad --- /dev/null +++ b/agent-task/archive/2026/07/m-openai-compatible-think-control/03+01_edge_reasoning_visibility/complete.log @@ -0,0 +1,42 @@ +# Complete - m-openai-compatible-think-control/03+01_edge_reasoning_visibility + +## 완료 일시 + +2026-07-03 + +## 요약 + +Edge OpenAI-compatible `include_reasoning=false` response visibility filtering을 1개 루프에서 PASS로 완료했다. + +## 루프 이력 + +| Plan | Review | Verdict | 메모 | +|------|--------|---------|------| +| `plan_local_G04_0.log` | `code_review_local_G04_0.log` | PASS | stream/non-stream reasoning exposure suppression과 default exposure regression 검증 통과 | + +## 구현/정리 내용 + +- `chatCompletionRequest.includeReasoning()` 기본값 true helper로 omitted request의 기존 reasoning exposure를 유지했다. +- non-streaming Chat Completions 응답에서 `include_reasoning=false`일 때 `message.reasoning_content` 노출만 억제했다. +- streaming SSE 응답에서 `include_reasoning=false`일 때 `delta.reasoning_content` chunk만 억제하고 content chunk와 `[DONE]` 흐름은 유지했다. +- stream/non-stream suppression tests와 기존 reasoning exposure regression tests로 SDD S03 evidence를 확인했다. + +## 최종 검증 + +- `go test -count=1 ./apps/edge/internal/openai` - PASS; `ok iop/apps/edge/internal/openai 1.570s` +- `go test -count=1 ./apps/edge/...` - PASS; Edge domain 전체 Go package 테스트 통과 + +## Roadmap Completion + +- Milestone: `agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/openai-compatible-think-control.md` +- Completed task ids: + - `reasoning-visibility`: PASS; evidence=`agent-task/archive/2026/07/m-openai-compatible-think-control/03+01_edge_reasoning_visibility/plan_local_G04_0.log`, `agent-task/archive/2026/07/m-openai-compatible-think-control/03+01_edge_reasoning_visibility/code_review_local_G04_0.log`; verification=`go test -count=1 ./apps/edge/internal/openai`, `go test -count=1 ./apps/edge/...` +- Not completed task ids: 없음 + +## 잔여 Nit + +- 없음 + +## 후속 작업 + +- 없음 diff --git a/agent-task/archive/2026/07/m-openai-compatible-think-control/03+01_edge_reasoning_visibility/plan_local_G04_0.log b/agent-task/archive/2026/07/m-openai-compatible-think-control/03+01_edge_reasoning_visibility/plan_local_G04_0.log new file mode 100644 index 0000000..87fcebb --- /dev/null +++ b/agent-task/archive/2026/07/m-openai-compatible-think-control/03+01_edge_reasoning_visibility/plan_local_G04_0.log @@ -0,0 +1,219 @@ + + +# Plan - API Edge Reasoning Visibility + +## 이 파일을 읽는 구현 에이전트에게 + +`01_edge_request_contract`의 `complete.log`가 있어야 이 plan을 구현한다. 구현 완료는 active `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 실제 내용과 검증 출력으로 채운 상태다. review finalization, archive, `complete.log` 작성은 code-review 전용이다. + +## 배경 + +SDD는 `include_reasoning=false`를 generation control이 아니라 OpenAI-compatible response exposure control로 정의했다. 현재 Edge는 non-streaming `message.reasoning_content`와 live SSE `delta.reasoning_content`를 기본으로 노출한다. 요청자가 reasoning 생성을 유지하면서 노출만 숨길 수 있도록 response writer 단에서 필터를 추가해야 한다. + +## 사용자 리뷰 요청 흐름 + +선택된 Milestone lock decision이 실구현을 막을 때만 review stub의 `사용자 리뷰 요청` 섹션에 기록한다. 외부 환경이나 검증 evidence 공백은 사용자 리뷰가 아니라 blocker/follow-up으로 기록한다. + +## Roadmap Targets + +- Milestone: `agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/openai-compatible-think-control.md` +- Task ids: + - `reasoning-visibility`: `include_reasoning=false`가 provider reasoning 생성 여부와 별개로 OpenAI-compatible 응답의 `reasoning_content` 노출을 억제한다. +- Completion mode: check-on-pass + +## 분석 결과 + +### 읽은 파일 + +- `agent-roadmap/current.md` +- `agent-roadmap/phase/knowledge-tool-optimization-extension/milestones/openai-compatible-think-control.md` +- `agent-roadmap/sdd/knowledge-tool-optimization-extension/openai-compatible-think-control/SDD.md` +- `agent-ops/rules/project/domain/edge/rules.md` +- `agent-ops/rules/project/domain/testing/rules.md` +- `agent-test/local/rules.md` +- `agent-test/local/edge-smoke.md` +- `apps/edge/internal/openai/types.go` +- `apps/edge/internal/openai/chat_handler.go` +- `apps/edge/internal/openai/stream.go` +- `apps/edge/internal/openai/server_test.go` + +### SDD 기준 + +- SDD: `agent-roadmap/sdd/knowledge-tool-optimization-extension/openai-compatible-think-control/SDD.md` +- 상태: `[승인됨]`, SDD 잠금: `해제`, 사용자 리뷰: 없음 +- Acceptance Scenario: S03 -> `reasoning-visibility` +- Evidence Map: S03 requires stream/non-stream response filtering tests and `Roadmap Completion` evidence for `reasoning-visibility`. + +### 테스트 환경 규칙 + +- test_env: `local` +- 읽은 env/profile: `agent-test/local/rules.md`, `agent-test/local/edge-smoke.md` +- 적용 명령: `go test -count=1 ./apps/edge/internal/openai` +- baseline 확인: `go test -count=1 ./apps/edge/internal/openai ./apps/node/internal/adapters/openai_compat` PASS +- 외부 runner preflight: 이 split은 current checkout unit test만 필요하므로 없음. + +### 테스트 커버리지 공백 + +- Current tests assert default reasoning exposure: + - non-streaming `TestChatCompletionsReturnsReasoningContentSeparately` + - streaming `TestChatCompletionsStreamsReasoningSSE` +- No tests assert `include_reasoning=false` suppression while preserving content/tool output. +- Strict-output tests suppress reasoning for a different policy and must not be reused as this feature's evidence. + +### 심볼 참조 + +- renamed/removed symbol: none. + +### 분할 판단 + +- current subtask: `03+01_edge_reasoning_visibility` +- dependency from directory name: predecessor `01_edge_request_contract` +- predecessor completion: missing in active and archive lookup. Implementation must wait for `01_edge_request_contract/complete.log`. +- split reason: response filtering is Edge-only but depends on the request field introduced by 01; Node provider body mapping remains separate. + +### 범위 결정 근거 + +- Request decoder validation is excluded to predecessor 01. +- Provider-side generation control is excluded to sibling 02. +- Contract docs and dev smoke are excluded to later dependent subtasks. + +### 빌드 등급 + +- `local-G04`: bounded Edge stream/non-stream filtering with deterministic tests, but SSE behavior and tool output preservation add moderate risk. + +## 구현 체크리스트 + +- [ ] `01_edge_request_contract` predecessor `complete.log`를 확인한 뒤 시작한다. +- [ ] non-streaming completion에서 `include_reasoning=false`이면 `message.reasoning_content`를 비우되 `content`, `tool_calls`, `finish_reason`, usage는 유지한다. 검증: non-stream 응답에서 reasoning field가 빠지고 content/tool output은 유지된다. +- [ ] live SSE stream에서 `include_reasoning=false`이면 `delta.reasoning_content` chunk를 쓰지 않되 content/tool chunks와 `[DONE]`은 유지한다. 검증: stream 응답에서 reasoning delta가 빠지고 content/tool output은 유지된다. +- [ ] default/omitted `include_reasoning`은 기존 reasoning exposure tests를 유지한다. +- [ ] `go test -count=1 ./apps/edge/internal/openai`를 실행한다. +- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +## 의존 관계 및 구현 순서 + +- `03+01_edge_reasoning_visibility` decodes to `depends_on=[01]`. +- Do not implement until predecessor `01_edge_request_contract` has a `complete.log`. + +### [API-1] Non-Streaming Reasoning Suppression + +#### 문제 + +[apps/edge/internal/openai/chat_handler.go](/config/workspace/iop/apps/edge/internal/openai/chat_handler.go:249)의 collection path always builds `chatMessage{ReasoningContent: reasoning}` after normalization. No request-level visibility switch is applied. + +Before: + +```go +// apps/edge/internal/openai/chat_handler.go:249 +text, reasoning, finishReason, nativeToolCalls, usage, textToolFallback, err := collectRunResult(ctx, handle.Stream(), handle.WaitTimeout()) +... +message := chatMessage{Role: "assistant", Content: text, ReasoningContent: reasoning} +``` + +After: + +```go +// apply after normalization, before response serialization +if !req.includeReasoning() { + message.ReasoningContent = "" +} +``` + +#### 해결 방법 + +- Add a small helper such as `req.includeReasoning()` that defaults to true. +- Filter only response exposure. Do not alter collected reasoning logs or provider generation input. +- Ensure tool call synthesis still sees content and does not depend on reasoning. + +#### 수정 파일 및 체크리스트 + +- [ ] `apps/edge/internal/openai/types.go`: include helper if not already added by 01. +- [ ] `apps/edge/internal/openai/chat_handler.go`: non-streaming response filter. +- [ ] `apps/edge/internal/openai/server_test.go`: non-stream suppression tests. + +#### 테스트 작성 + +- Add `TestChatCompletionsSuppressesReasoningContentWhenExcluded`. +- Add a tool-call preserving case if existing native/text tool tests make this cheap; otherwise include content preservation in the suppression test. + +#### 중간 검증 + +```bash +go test -count=1 ./apps/edge/internal/openai +``` + +Expected: PASS. + +### [API-2] Streaming Reasoning Suppression + +#### 문제 + +- [apps/edge/internal/openai/stream.go](/config/workspace/iop/apps/edge/internal/openai/stream.go:65) writes every reasoning delta to SSE. +- [apps/edge/internal/openai/stream.go](/config/workspace/iop/apps/edge/internal/openai/stream.go:167) only suppresses reasoning for strict-output, not request visibility. + +Before: + +```go +// apps/edge/internal/openai/stream.go:167 +case "reasoning_delta": + if event.GetDelta() == "" { + continue + } + reasoningBuilder.WriteString(event.GetDelta()) + if outputPolicy.Strict { + continue + } + writeTracedReasoningDelta(event.GetDelta()) +``` + +After: + +```go +if outputPolicy.Strict || !req.includeReasoning() { + continue +} +writeTracedReasoningDelta(event.GetDelta()) +``` + +#### 해결 방법 + +- Suppress live SSE reasoning chunks when `include_reasoning=false`. +- Keep `reasoningBuilder` for logs and diagnostics. +- Buffered strict stream currently emits only content/tool output; verify it still does not leak reasoning and add a non-strict live SSE test. + +#### 수정 파일 및 체크리스트 + +- [ ] `apps/edge/internal/openai/stream.go`: live SSE reasoning filter. +- [ ] `apps/edge/internal/openai/server_test.go`: streaming suppression tests. + +#### 테스트 작성 + +- Add `TestChatCompletionsStreamSuppressesReasoningWhenExcluded` asserting no `reasoning_content`, content chunk present, `[DONE]` present. +- Keep `TestChatCompletionsStreamsReasoningSSE` passing for omitted `include_reasoning`. + +#### 중간 검증 + +```bash +go test -count=1 ./apps/edge/internal/openai +``` + +Expected: PASS. + +## 수정 파일 요약 + +| 파일 | 항목 | +|------|------| +| `apps/edge/internal/openai/types.go` | API-1 | +| `apps/edge/internal/openai/chat_handler.go` | API-1 | +| `apps/edge/internal/openai/stream.go` | API-2 | +| `apps/edge/internal/openai/server_test.go` | API-1, API-2 | + +## 최종 검증 + +```bash +go test -count=1 ./apps/edge/internal/openai +``` + +Expected: PASS. Fresh execution is required; do not rely on Go test cache. + +모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.