Skip to content

Commit 4f5bd77

Browse files
committed
docs(changelog): scope fail-closed notes to chat/messages/responses, document collector settled-set
1 parent 44e1e4f commit 4f5bd77

1 file changed

Lines changed: 2 additions & 1 deletion

File tree

‎CHANGELOG.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3838
- **同族错误路径查漏**:responses 串流 idleTimeout 补 poll 失败检查(不再静默回空 `completed`);messages 非串流改用 transformed `status/type/code`(不再硬编码 `502/api_error`);messages 串流检查 `collected.error` 与 poll 失败(失败即抛正規化错误走 SSE error 事件,不再静默 200);`isTransientUpstreamError` 纳入 `name/code/type` 参与签名匹配(无 message 纯对象不再必判 false)。
3939
- **Docker six-way symmetry (Stage 1)**: `Dockerfile` adds the missing empty `ENV OPENCODE_PROXY_BIND_HOST=` plus the five legacy `ENV EXTERNAL_TOOL_*=` aliases so image defaults stay empty and never shadow a mounted `config.json` or legacy alias; behavior is value-identical (empty == unset).
4040
- **Stream tool-error surface unification (Stage 2 + final)**: `/v1/chat/completions`, `/v1/messages`, and `/v1/responses` `stream:true` fail-closed tool errors (`parallel_external_tool_calls`, `external_tool_choice_*`, `invalid_external_tool_call`, `external_tool_policy_blocked`, `duplicate_external_tool_call_id`, `malformed_external_tool_call`) now return the same stable `code` as non-stream (chat: 502 JSON before headers / SSE `data: {error}` after; messages: 502 JSON / SSE `error` event, `api_error`; responses: 502 JSON / `response.failed` + `[DONE]`, `server_error`) instead of falling through to 500 `internal_error` via `transformUpstreamError`.
41-
- **Collector ID-less tool tracking (Stage 2)**: `activeToolWithoutId` boolean becomes a counter so two concurrent ID-less backend tool parts no longer clear each other and truncate the stream via early idle/`stop` resolution.
41+
- **Collector ID-less tool tracking (Stage 2, review fix)**: counter becomes a per-tool-name `Set` (`noid:<tool>` / `noid:unknown`) so two concurrent ID-less backend tool parts no longer clear each other, while repeated `message.part.updated` snapshots of the same logical tool no longer inflate and pin the idle exemption until `REQUEST_TIMEOUT_MS`. Replayed terminal snapshots are ignored via a settled set (they must not delete a still-running bucket); name-mismatch fuzzy clearing applies to the single-bucket case only, multi-bucket ambiguity waits for the real terminal (waiting beats truncating). Locked by `tests/stream-hardening.test.js` (repeat, distinct-parallel, replay, mismatch both directions, same-name limitation).
42+
- **Review confirmations (no behavior change)**: `stream:true` with any external tool contract intentionally buffers visible text until completion to avoid leaking `<function_calls>` markup incrementally (pure-text turns also batch — documented in route comments); non-stream `if (error != null)` intentionally fails even with partial content rather than returning partial as success on chat/messages/responses (retry still covers the no-output transient case; interactions is the deliberate exception — it only throws when there is no content at all, otherwise returns partial as `interaction.completed`); verified-empty tool discovery (`[]`) intentionally stays 503 fail-closed under `DISABLE_TOOLS=true` (a real backend always exposes tools; empty means unverifiable — locked by `tests/tool-alias.test.js`).
4243
- **Explicit external-tool policy semantics (Stage 2, breaking note)**: `REQUIRE_CONFIRMATION` now fires only for proxy-authored `requiresConfirmation===true` or `EXTERNAL_TOOL_REQUIRE_CONFIRMATION_FOR` hits (plus `report-only` bypass); the old implicit `WRITE/HIGH/CRITICAL`/`DELETE` inference is removed, so a `delete_*` tool with an empty allowlist now returns `ALLOW` instead of being blocked. Operators relying on default-deny for destructive tools should set `EXTERNAL_TOOL_REQUIRE_CONFIRMATION_FOR=delete_*,write_*` explicitly. Parser stays fail-closed by design (`valid plus malformed` still rejects the batch with `malformed_external_tool_call`, locked by `tests/app.test.js`).
4344
- **Wire-compat confirmations (Stage 3)**: upstream 503 now passes through as 503 `server_error` (was coerced to 502; `tool_discovery_unavailable` stays proxy-originated only, locked by `tests/backend-error-surface.test.js`); `/v1/messages` bare `{type:tool}` without `name` is 400 via `validateAnthropicToolChoice` (direct converter calls degrade to auto, locked by `tests/messages-anthropic.test.js`); empty `tool_result` is preserved as `TOOL_RESULT content:""` to keep turn alignment (prompt breaking: previously dropped, now one extra prompt line); chat/messages/responses empty-stream stays 500 `Upstream returned no assistant data` (fail-closed, non-stream empty stays 200 — documented inconsistency, unify later); interactions `storeResponseState` intentionally omits tool calls (text+grounding only); native discovery 30s cooldown fail-closed is by design (no second `tool.ids()` probe inside the window).
4445

0 commit comments

Comments
 (0)