# Milestone: Tool Call Runtime 검증 재시도 MVP

## 위치

- Roadmap: `agent-roadmap/ROADMAP.md`
- Phase: `agent-roadmap/phase/knowledge-tool-optimization-extension/PHASE.md`

## 목표

명시적 `tools[]`와 `tool_choice` 계약이 있는 OpenAI-compatible 요청에서 IOP가 provider 응답의 마지막 tool call을 반환 직전에 검증한다.
tool name 또는 `function.arguments`가 요청 schema와 맞지 않으면 caller agent에 실패를 노출하기 전에 IOP 내부에서 같은 요청을 bounded exact replay로 재시도한다.
이 Milestone은 validator 모델 없이 runtime이 결정적으로 판단할 수 있는 케이스만 다룬다.

## 상태

[완료]

## 승격 조건

- 없음

## 구현 잠금

- 상태: 해제
- SDD: 불필요
- SDD 문서: 없음
- SDD 사유: 기존 OpenAI-compatible 요청/응답 계약 안에서 명시적 `tools[]` schema를 검증하고 같은 요청을 내부 재제출하는 bounded MVP로 제한하며, 새 proto/config/API field나 외부 계약 확장은 만들지 않는다.
- 잠금 해제 조건: 없음
- 결정 필요: 없음

## 범위

- OpenAI-compatible Chat Completions 요청의 `tools[]`, `tool_choice` 기반 runtime validation contract 판정
- native OpenAI `tool_calls`와 IOP text tool-call fallback 결과를 공통 `ToolCallCandidate` 형태로 해석
- 요청 `tools[].function.parameters`를 기준으로 tool name, arguments JSON, required/type/object/array/enum/additionalProperties 중심의 JSON Schema subset 검증
- 검증 실패 시 caller에게 응답을 내보내기 전 같은 `SubmitRunRequest`를 bounded exact replay로 재제출
- non-stream 또는 buffered stream처럼 아직 caller에게 malformed 응답을 흘리지 않은 경로 우선 적용
- retry attempt와 validation failure reason을 run metadata 또는 로그로 구분 가능하게 남기는 최소 추적

## 기능

### Epic: [runtime-validate] Runtime Tool Call Validation

명시적 schema가 있는 요청에서 모델 응답의 tool call shape를 runtime이 결정적으로 검증하고 재시도하는 capability를 묶는다.

- [x] [contract-detect] `tools[]`가 있는 OpenAI-compatible 요청을 runtime validation 대상으로 판정하고 `tool_choice: none` 등 검증 제외 조건을 정리한다.
- [x] [candidate-normalize] native `tool_calls`와 IOP text fallback 결과를 tool name, arguments, origin, raw payload를 가진 공통 후보로 정규화한다.
- [x] [schema-validate] 요청 tool schema를 기준으로 tool name, arguments JSON parse, required/type/object/array/enum/additionalProperties subset을 검증한다.
- [x] [exact-retry] validation 실패가 응답 방출 전 발견되면 같은 요청을 bounded exact replay로 재제출하고, 새 attempt run과 원 요청의 상관관계를 남긴다.
- [x] [failure-surface] retry 한도 초과 또는 재시도 불가 경로에서는 malformed tool call을 그대로 성공 응답으로 내보내지 않고 OpenAI-compatible 실패로 구분한다.
- [x] [validation-tests] runtime validation, retry 성공, retry 한도 초과, stream 제외 또는 buffer 경로를 테스트한다. 검증: `go test ./apps/edge/internal/openai`

## 완료 리뷰

- 상태: 통과
- 요청일: 2026-07-03
- 완료 근거: `agent-task/archive/2026/07/m-tool-call-runtime-validation-retry/complete.log`의 Roadmap Completion에서 `contract-detect`, `candidate-normalize`, `schema-validate`, `exact-retry`, `failure-surface`, `validation-tests`가 모두 PASS로 기록되었다.
- 검토 항목: 2026-07-03 현재 `go test -count=1 ./apps/edge/internal/openai`, `go test -count=1 ./apps/edge/...` 재실행 PASS. 구현 잠금은 해제이며 남은 결정 필요와 SDD gate는 없다.
- agent-ui 상태 반영: 해당 없음
- 리뷰 코멘트: 코드 레벨 종료 검토 통과로 완료 archive 처리했다.

## 범위 제외

- `tools[]`가 없는 요청에서 tool 사용 필요 여부를 추론하는 validator 모델
- agent-specific 자연어 또는 임의 텍스트를 tool call로 추정하는 휴리스틱 확장
- caller agent까지 실패를 되돌려 repair instruction을 넣는 외부 loop
- live SSE로 이미 content를 방출한 뒤의 투명 재시도
- 새 public API/config/proto field와 장기 ledger schema 확정

## 작업 컨텍스트

- 관련 경로: `apps/edge/internal/openai`, `apps/edge/internal/service`, `apps/node/internal/adapters/openai_compat`, `apps/node/internal/adapters/vllm`, `agent-contract/outer/openai-compatible-api.md`
- 표준선(선택): 명시적 `tools[]`가 있는 요청은 별도 validator 모델 없이 요청 schema를 source of truth로 삼는다.
- 표준선(선택): 재시도는 작업 전체 재실행이 아니라 IOP 내부 provider 응답 sampling의 bounded exact replay로 제한한다.
- 선행 작업: OpenAI-compatible tool call passthrough와 text fallback
- 후속 작업: Tool Call 판정 모델 Gate 리뷰, 요청 실행 로그와 Usage Ledger 기반
- 확인 필요: 없음
