diff --git a/agent-contract/outer/anthropic-compatible-api.md b/agent-contract/outer/anthropic-compatible-api.md index f5fd4e6c..84798aa8 100644 --- a/agent-contract/outer/anthropic-compatible-api.md +++ b/agent-contract/outer/anthropic-compatible-api.md @@ -284,6 +284,7 @@ anthropic-version: 2023-06-01 지원하는 `Anthropic-Beta` 값: - `advanced-tool-use-2025-11-20` +- `advisor-tool-2026-03-01` - `claude-code-20250219` - `context-management-2025-06-27` - `effort-2025-11-24` @@ -298,7 +299,7 @@ anthropic-version: 2023-06-01 지원하지 않는 beta 값을 보내면 `400 invalid_request_error`를 반환한다. Native Messages 경로는 지원 beta 헤더를 upstream으로 전달한다. Chat bridge 경로는 지원 beta 헤더를 upstream으로 전달하지 않고, 아래에 명시한 대응 field만 Chat Completions 형식으로 변환한다. -`prompt-caching-scope-2026-01-05`, `advanced-tool-use-2025-11-20`, `redact-thinking-2026-02-12`, `thinking-token-count-2026-05-13` 수용은 Claude Code 호출 호환성만 제공한다. 이 beta들은 Chat bridge에서 cache, route, stage, provider, workspace 또는 authorization 권한을 만들지 않으며 normalized Chat provider 요청으로 전달되지 않는다. +`prompt-caching-scope-2026-01-05`, `advanced-tool-use-2025-11-20`, `advisor-tool-2026-03-01`, `redact-thinking-2026-02-12`, `thinking-token-count-2026-05-13` 수용은 Claude Code 호출 호환성만 제공한다. 이 beta들은 Chat bridge에서 cache, route, stage, provider, workspace 또는 authorization 권한을 만들지 않으며 normalized Chat provider 요청으로 전달되지 않는다. ## Routes diff --git a/agent-spec/input/openai-compatible-surface.md b/agent-spec/input/openai-compatible-surface.md index 55497095..b8a45779 100644 --- a/agent-spec/input/openai-compatible-surface.md +++ b/agent-spec/input/openai-compatible-surface.md @@ -265,7 +265,7 @@ sequenceDiagram - Marked single-request Plan/Review templates are Edge-owned internal artifact shapes, not part of this input surface. The operator configures them in `execution_presets[].single_request.templates`; admission freezes the effective pair, so a config refresh reaches only requests admitted after it and an already running request keeps its pair. The Plan stage requests a closed strict JSON object containing only `goal`, `steps`, and `verification`, enforces the single-line goal, 2-6 step bullets, and 1-3 verification bullets, and lets Edge render the frozen Plan template deterministically. The Review template shapes the private `review.md` artifact rendered from the model's `checks`/`verification`/`summary` fields. No caller field, header, or metadata value can supply, name, select, or override a template, and no template path, content, or digest appears in a response, an error message, a log projection, or a metric label. Changing a template changes neither the Messages request schema nor the response schema: the buffered/SSE terminal projection is unchanged and the final caller-visible text remains the model's `decision.output`. - Marked single-request observation evidence links ingress=1, request-total=1, terminal=1, stage/tool/cleanup counts, and raw-free correlation for one real POST. `iop_anthropic_single_request_ingress_total` is strictly unlabeled: no request_id, stage_id, provider identity, content, or workspace reference appears as a metric label. Internal tool names (`workspace_read`, `workspace_write`, etc.), raw arguments, private results, and workspace references are absent from the public terminal JSON and from log projections. Stage-pure timing, cardinality-bounded labels, and privacy semantics are documented here. SDD S12 qualifies the external Claude path on an approved IOP Node with one accepted ingress, the expected stage sequence, one terminal, exact output, timing, cleanup, and redacted evidence. - Internal workspace calls use a service-owned schema independent of caller-facing tool codecs. The five closed operation names decode into typed Node requests only after request/stage/tool identity, canonical relative path, approved operation/command/environment capability, and immutable budget checks. The loop opens once, preserves the admitted connection generation, executes one pending call at a time, accepts only correlated typed results, and returns a deep-copied raw-free result to the same executor continuation. Repeated IDs, stale responses, malformed or denied input, timeout, output/iteration exhaustion, and cancellation never become public Anthropic tool protocol or trigger a second ingress. -- Claude Code Messages requests may use adaptive thinking, `output_config.effort`, structured output, cache-control annotations, and supported beta headers. The Chat bridge consumes those headers, maps supported fields, and requires callers to replay opaque `tool_use.id` values unchanged so Gemini thought signatures can be restored on tool-result turns. +- Claude Code Messages requests may use adaptive thinking, `output_config.effort`, structured output, cache-control annotations, and supported beta headers, including the compatibility-only `advisor-tool-2026-03-01` marker emitted by the pinned official caller. The Chat bridge consumes rather than forwards those headers, maps supported fields, and requires callers to replay opaque `tool_use.id` values unchanged so Gemini thought signatures can be restored on tool-result turns. - provider capacity와 long-context slot은 model alias별이 아니라 `node_id + provider_id`별로 공유한다. queue pending 상한과 timeout은 Edge root `provider_pool` policy이며, lease 반환·refresh·disconnect/reconnect가 모든 model group waiter를 global enqueue 순서로 재평가한다. - provider가 full이면 queue policy에 따라 대기하지만 live candidate가 모두 사라지면 즉시 unavailable로 수렴한다. Chat Completions와 Responses provider-pool 표면은 새 public status/field 없이 HTTP 502 `node_dispatch_error`를 유지한다. - In legacy mode, `openai.provider_auth` stores only a forwarding rule and reads raw provider material from its request-time header; inbound IOP authorization is never reused. Managed mode rejects that rule and the caller header and uses only the sealed slot lease. @@ -326,6 +326,7 @@ sequenceDiagram ## 변경 기록 +- 2026-08-12: Admitted Claude Code's `advisor-tool-2026-03-01` beta as a consumed compatibility marker for both direct and marked-preset Messages ingress. It grants no internal capability and is not forwarded through the Chat bridge (`apps/edge/internal/openai/anthropic_types.go`). - 2026-08-12: Replaced free-form PlanMD generation with a stage-owned strict `goal`/`steps`/`verification` JSON response and deterministic Edge rendering of the frozen Plan template. Internal artifact customization and all caller-visible Messages schemas remain unchanged (`apps/edge/internal/openai/single_request_plan_stage.go`, `packages/go/singlerequesttemplate/template.go`). - 2026-08-09: Separated Edge-owned internal Plan/Review stage templates from caller-visible I/O. Operator-configured `execution_presets[].single_request.templates` is frozen at admission, supplies the private Plan prompt/PlanMD grammar and the private `review.md` artifact shape, and is not selectable, supplyable, or observable by callers. The Messages request/response schema, terminal projection, and final `decision.output` text are unchanged (`apps/edge/internal/openai/single_request_preset_binding.go`, `apps/edge/internal/openai/single_request_review_stage.go`, `agent-contract/outer/anthropic-compatible-api.md`). - 2026-08-09: Qualified S12 `claude-smoke` with one supervised external Claude task on an approved IOP Node: ingress `0→1`, Gemini → ornith-fast → Gemini, one `end_turn`, exact 42-byte workspace output, timing, cleanup, and redacted evidence. diff --git a/agent-task/m-iop-one-shot-agent-model-comparison/08+07_comparison_rerun/CODE_REVIEW-cloud-G10.md b/agent-task/m-iop-one-shot-agent-model-comparison/08+07_comparison_rerun/CODE_REVIEW-cloud-G10.md index e27bb539..2e305115 100644 --- a/agent-task/m-iop-one-shot-agent-model-comparison/08+07_comparison_rerun/CODE_REVIEW-cloud-G10.md +++ b/agent-task/m-iop-one-shot-agent-model-comparison/08+07_comparison_rerun/CODE_REVIEW-cloud-G10.md @@ -22,10 +22,11 @@ task=m-iop-one-shot-agent-model-comparison/08+07_comparison_rerun, plan=3, tag=R | REVIEW_REVIEW_TEST-2 agy request/error compatibility | [x] | | REVIEW_REVIEW_TEST-3 lifecycle exit coherence | [x] | | REVIEW_REVIEW_TEST-4 deterministic Plan rendering | [x] | -| REVIEW_REVIEW_TEST-5 complete local verification | [ ] | -| REVIEW_REVIEW_TEST-6 clean release deployment | [ ] | -| REVIEW_REVIEW_TEST-7 public smokes/preflight | [ ] | -| REVIEW_REVIEW_TEST-8 scored run/report | [ ] | +| REVIEW_REVIEW_TEST-5 pinned Claude beta compatibility | [x] | +| REVIEW_REVIEW_TEST-6 complete local verification | [ ] | +| REVIEW_REVIEW_TEST-7 clean release deployment | [ ] | +| REVIEW_REVIEW_TEST-8 public smokes/preflight | [ ] | +| REVIEW_REVIEW_TEST-9 scored run/report | [ ] | ## Implementation Evidence @@ -37,10 +38,12 @@ task=m-iop-one-shot-agent-model-comparison/08+07_comparison_rerun, plan=3, tag=R - Post-deploy official agy direct and `gemini-hybrid` smokes reached `result.status=SUCCESS`; Claude direct reached `result/subtype=success`. The first Claude hybrid smoke did not repeat the immediate API error, but raw-free Edge metrics exposed three Plan validation failures and the call exceeded the 180-second non-scored boundary, creating R4 before scored execution. - R4 replaces free-form PlanMD generation with a strict stage-owned `goal`/`steps`/`verification` JSON schema, exact closed-object decoding (including duplicate-key rejection), bounded field validation, and deterministic rendering of the frozen operator template. Focused Plan/template/executor regressions and the complete `apps/edge/internal/openai` package pass. - The current feature tree passes all 437 Python benchmark tests, every relevant Go package under Control Plane/Edge/Node/shared runtime (excluding only the declared `agenttask` boundary), `git diff --check`, and manifest validation. Clean release-tree repetition remains pending commit/merge. +- After deploying release `1f748bd9bd7fcc843074847a57ed523a28db75fd`, official Claude Code `2.1.228` direct smoke exposed R5 before any scored run: its nominal `result/subtype=success` carried `is_error=true` and a sanitized unsupported-beta 400 for `advisor-tool-2026-03-01`. The scored-run allowance remains unused. +- R5 adds the exact pinned-caller beta to the closed admission inventory and consumes it at the Chat bridge without forwarding it or creating capability authority. Direct Claude Code mapping, marked single-request admission, and unknown-beta rejection regressions pass. ## Review-Only Checklist -- [ ] Verify every R1-R4 regression exercises the exact production lifecycle path and remains fail-closed for unknown data. +- [ ] Verify every R1-R5 regression exercises the exact production lifecycle path and remains fail-closed for unknown data. - [ ] Verify no credential value, ambient caller config, direct provider call, manifest change, hidden retry, or provider reselection was introduced. - [ ] Verify the prior run is immutable, exactly one plan-3 scored run exists, and all nine attempts plus web gates succeed. - [ ] Verify clean build/deployment identities, 4/4 node and 8/8 provider health, ready=9, and report pointer consistency. diff --git a/agent-task/m-iop-one-shot-agent-model-comparison/08+07_comparison_rerun/PLAN-cloud-G10.md b/agent-task/m-iop-one-shot-agent-model-comparison/08+07_comparison_rerun/PLAN-cloud-G10.md index 90eee61e..79c201c1 100644 --- a/agent-task/m-iop-one-shot-agent-model-comparison/08+07_comparison_rerun/PLAN-cloud-G10.md +++ b/agent-task/m-iop-one-shot-agent-model-comparison/08+07_comparison_rerun/PLAN-cloud-G10.md @@ -4,7 +4,7 @@ ## For the Implementing Agent -Implement R1-R4 exactly as selected below. Do not alter benchmark inputs, route aliases, credentials, scoring, or retained run evidence. Use only the public benchmark CLI for live caller/provider execution. Run deterministic local qualification first, then clean-build and deploy the release, run non-scored direct/hybrid smokes, require ready=9, and execute exactly one fresh scored run. Fill the implementation-owned sections of `CODE_REVIEW-cloud-G10.md` with sanitized actual evidence and leave both active files in place for review. +Implement R1-R5 exactly as selected below. Do not alter benchmark inputs, route aliases, credentials, scoring, or retained run evidence. Use only the public benchmark CLI for live caller/provider execution. Run deterministic local qualification first, then clean-build and deploy the release, run non-scored direct/hybrid smokes, require ready=9, and execute exactly one fresh scored run. Fill the implementation-owned sections of `CODE_REVIEW-cloud-G10.md` with sanitized actual evidence and leave both active files in place for review. ## Background @@ -25,6 +25,7 @@ Plan 2 fixed the first live compatibility set and deployed clean release `04f7c3 | R2 | C03's structurally redacted evidence initially showed only top-level keys, but the retained raw stream and caller log prove the payload is nested and the model request first failed with Edge `400 INVALID_ARGUMENT: request body is invalid` | Edge's pinned Gemini request decoder lacks the official agy planner's structured-output request fields; the adapter then maps the caller's nested `result.status=ERROR` to `malformed_event` instead of preserving the upstream/process failure | extend the Gemini bridge's exact structured-output request contract and tests; treat a valid agy ERROR result as non-success terminal evidence without parser failure | direct-fix | Gemini bridge structured-output regression and agy error lifecycle regression pass; non-scored official agy direct smoke succeeds | | R3 | C01 result exit `143` differs from authenticated receipt exit `null` | supervisor snapshots returncode before joining the concurrent exit watcher | join watcher/IO, refresh the authoritative child returncode, then write the one receipt; add deterministic race/recovery regression | direct-fix | timeout/recovery test proves result and receipt exit/signal equality and public resume can reconcile | | R4 | Post-deploy raw-free metrics recorded three `plan/validation` failures among six marked single-request calls; Claude hybrid did not complete before the non-scored 180-second boundary | Plan stage asks the provider for free-form PlanMD and rejects harmless format drift after the model call | request a stage-owned strict JSON object (`goal`, `steps`, `verification`), validate the bounded fields, and render the configured PlanMD template deterministically inside Edge | direct-fix | repeated plan-stage fixtures cannot create malformed PlanMD; official Claude hybrid smoke reaches a success terminal within the scored timeout budget | +| R5 | After the R4 release deployment, pinned Claude Code `2.1.228` returned `result/subtype=success` with `is_error=true` and `API Error: 400 unsupported anthropic-beta "advisor-tool-2026-03-01"` before either direct or hybrid model execution | the exact official caller now emits a compatibility beta absent from Edge's closed admission set | admit and consume `advisor-tool-2026-03-01` without forwarding it or granting any route/tool/workspace authority; retain rejection for every unknown beta | direct-fix | direct and marked-preset header regressions pass; official Claude direct and both hybrid smokes terminate with `is_error=false` | ## Modified Files Summary @@ -41,6 +42,9 @@ Plan 2 fixed the first live compatibility set and deployed clean release `04f7c3 - `apps/edge/internal/openai/single_request_plan_stage_test.go` - `packages/go/singlerequesttemplate/template.go` - `packages/go/singlerequesttemplate/template_test.go` +- `apps/edge/internal/openai/anthropic_types.go` +- `apps/edge/internal/openai/anthropic_bridge_test.go` +- `apps/edge/internal/openai/single_request_handler_test.go` - this active review plus existing run/preflight/report pointer files after successful fresh execution ## Implementation Checklist @@ -49,10 +53,11 @@ Plan 2 fixed the first live compatibility set and deployed clean release `04f7c3 - [x] [REVIEW_REVIEW_TEST-2] Implement R2 official agy structured-output request compatibility and error-terminal classification regressions. - [x] [REVIEW_REVIEW_TEST-3] Implement R3 authoritative supervisor exit snapshot and timeout/recovery regression. - [x] [REVIEW_REVIEW_TEST-4] Implement R4 schema-bound Plan fields and deterministic configured-template rendering. -- [ ] [REVIEW_REVIEW_TEST-5] Run the complete Python benchmark suite and relevant Go/runtime regressions from a clean tree. -- [ ] [REVIEW_REVIEW_TEST-6] Commit/push, merge the clean release branch, rebuild/deploy Edge and every Node, and verify 4/4 nodes plus 8/8 healthy providers. -- [ ] [REVIEW_REVIEW_TEST-7] Run public non-scored direct and hybrid smoke coverage and a fresh ready=9 preflight. -- [ ] [REVIEW_REVIEW_TEST-8] Execute exactly one fresh scored run, require success=9 and all web gates, update existing id pointers, and generate the human-readable Markdown report. +- [x] [REVIEW_REVIEW_TEST-5] Implement R5 pinned Claude beta compatibility without forwarding or widening internal authority. +- [ ] [REVIEW_REVIEW_TEST-6] Run the complete Python benchmark suite and relevant Go/runtime regressions from a clean tree. +- [ ] [REVIEW_REVIEW_TEST-7] Commit/push, merge the clean release branch, rebuild/deploy Edge and every Node, and verify 4/4 nodes plus 8/8 healthy providers. +- [ ] [REVIEW_REVIEW_TEST-8] Run public non-scored direct and hybrid smoke coverage and a fresh ready=9 preflight. +- [ ] [REVIEW_REVIEW_TEST-9] Execute exactly one fresh scored run, require success=9 and all web gates, update existing id pointers, and generate the human-readable Markdown report. - [ ] Fill `CODE_REVIEW-cloud-G10.md` with exact sanitized commands, release identities, deployment health, run id, terminal summary, and report path. ## Verification @@ -76,7 +81,7 @@ Plan 2 fixed the first live compatibility set and deployed clean release `04f7c3 ### Outcome and Acceptance -The task is complete only when deterministic regressions prove the four boundary corrections, the clean release is deployed across the managed dev runtime, public readiness is 9/9, and one fresh immutable scored run is 9/9 with a generated Markdown report. +The task is complete only when deterministic regressions prove the five boundary corrections, the clean release is deployed across the managed dev runtime, public readiness is 9/9, and one fresh immutable scored run is 9/9 with a generated Markdown report. ### Scope and Ownership @@ -95,7 +100,7 @@ Keep one plan because the scored-run acceptance depends on one indivisible evide ## Dependencies and Execution Order -R1-R4 are independent code fixes but must all pass local regressions before one clean release is built. Deployment must finish before non-scored smokes; smokes and ready=9 must pass before the only fresh scored run. +R1-R5 are independent code fixes but must all pass local regressions before one clean release is built. Deployment must finish before non-scored smokes; smokes and ready=9 must pass before the only fresh scored run. ## Final Routing diff --git a/apps/edge/internal/openai/anthropic_bridge_test.go b/apps/edge/internal/openai/anthropic_bridge_test.go index 4b2777e0..975e237f 100644 --- a/apps/edge/internal/openai/anthropic_bridge_test.go +++ b/apps/edge/internal/openai/anthropic_bridge_test.go @@ -400,6 +400,7 @@ func TestAnthropicChatBridgeClaudeCodeRequest(t *testing.T) { req := newAnthropicRequest(http.MethodPost, "/v1/messages", body) req.Header.Set(anthropicBetaHeader, strings.Join([]string{ "advanced-tool-use-2025-11-20", + "advisor-tool-2026-03-01", "claude-code-20250219", "context-management-2025-06-27", "interleaved-thinking-2025-05-14", diff --git a/apps/edge/internal/openai/anthropic_types.go b/apps/edge/internal/openai/anthropic_types.go index 80d6bf73..b2439270 100644 --- a/apps/edge/internal/openai/anthropic_types.go +++ b/apps/edge/internal/openai/anthropic_types.go @@ -18,6 +18,7 @@ const ( var supportedAnthropicBetas = map[string]struct{}{ "advanced-tool-use-2025-11-20": {}, + "advisor-tool-2026-03-01": {}, "claude-code-20250219": {}, "context-management-2025-06-27": {}, "effort-2025-11-24": {}, diff --git a/apps/edge/internal/openai/single_request_handler_test.go b/apps/edge/internal/openai/single_request_handler_test.go index 18319ffd..332489b8 100644 --- a/apps/edge/internal/openai/single_request_handler_test.go +++ b/apps/edge/internal/openai/single_request_handler_test.go @@ -281,7 +281,7 @@ func TestAnthropicSingleRequestUsesOnePost(t *testing.T) { defer cancel() body := `{"model":"` + testSingleRequestModel + `","max_tokens":128,"messages":[{"role":"user","content":"` + privatePrompt + `"}],"tools":[{"name":"caller_tool","input_schema":{"type":"object"}}]}` req := newAnthropicSingleRequestHTTPReq(t, ctx, httpServer.URL, "/v1/messages", body) - req.Header.Set(anthropicBetaHeader, "thinking-token-count-2026-05-13") + req.Header.Set(anthropicBetaHeader, "advisor-tool-2026-03-01,thinking-token-count-2026-05-13") response, err := httpServer.Client().Do(req) if err != nil { t.Fatalf("POST /v1/messages: %v", err)