From 791a707eb6eec5539fb87f2e5f565a25d9cbf229 Mon Sep 17 00:00:00 2001 From: agent_coder Date: Sat, 11 Jul 2026 09:11:32 +0300 Subject: [PATCH] =?UTF-8?q?docs(ai-chat):=20=D0=B7=D0=B0=D0=B4=D0=BE=D0=BA?= =?UTF-8?q?=D1=83=D0=BC=D0=B5=D0=BD=D1=82=D0=B8=D1=80=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D1=82=D1=8C=20=D0=BF=D0=BE=D0=B2=D0=B5=D1=80=D1=85=D0=BD=D0=BE?= =?UTF-8?q?=D1=81=D1=82=D1=8C=20#489=20=E2=80=94=20env-var,=20=D1=83=D1=81?= =?UTF-8?q?=D1=82=D0=B0=D1=80=D0=B5=D0=B2=D1=88=D0=B0=D1=8F=20=D0=B7=D0=B0?= =?UTF-8?q?=D0=BC=D0=B5=D1=82=D0=BA=D0=B0,=20CHANGELOG?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit F1 (ревью #508): - .env.example: новая AI_MCP_SSE_BODY_TIMEOUT_MS (дефолт 600000, 10 мин) — bodyTimeout SSE-транспорта external-MCP; idle между тул-вызовами легитимен. - .env.example: поправлена ставшая ложной заметка про AI_MCP_STREAM_TIMEOUT_MS (SSE-idle-между-вызовами больше не режется им — с #489 это отдельная var; 1-мин silence остаётся только для HTTP/headers и одиночного залипшего вызова). - CHANGELOG [Unreleased]/Fixed: битый part больше не 500-ит каждый ход + не плодит дубль user-строки; MCP-транспорт-дропы восстанавливаются in-run (readOnly ретраится раз, write никогда) + новая env-var. Co-Authored-By: Claude Opus 4.8 (1M context) --- .env.example | 21 ++++++++++++++++++--- CHANGELOG.md | 17 +++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/.env.example b/.env.example index f3acb7ba..6d7dec43 100644 --- a/.env.example +++ b/.env.example @@ -225,11 +225,26 @@ MCP_DOCMOST_PASSWORD= # Silence timeout (ms) for EXTERNAL-MCP transport ONLY (not the chat provider). # Tighter than AI_STREAM_TIMEOUT_MS so a byte-silent/hung MCP server is broken in -# ~1 min instead of 15. Note it also cuts a legitimately long but byte-silent -# single tool call (a slow crawl that emits nothing until done) and an SSE -# transport idling >1 min BETWEEN tool calls. Default 60000 (1 min). +# ~1 min instead of 15. It cuts a legitimately long but byte-silent single tool +# call (a slow crawl that emits nothing until done) on the HTTP (streamable) +# transport, which opens a fresh request per call. The SSE transport — one +# long-lived body across many calls — is NO LONGER governed by this timeout +# (as of #489): its idle-BETWEEN-calls window has its own, raised bodyTimeout, +# AI_MCP_SSE_BODY_TIMEOUT_MS below. Default 60000 (1 min). # AI_MCP_STREAM_TIMEOUT_MS=60000 +# bodyTimeout (ms) for the EXTERNAL-MCP SSE transport ONLY (#489). The SSE +# transport holds ONE response body open across many tool calls, so undici's +# bodyTimeout (time between body bytes) counts the LEGITIMATE silence BETWEEN the +# model's tool calls, not just a hung single call. At the tight 1-min silence +# timeout above, a normal >1-min gap between calls would break the SSE socket and +# the cache would serve a dead client until TTL — so the SSE transport gets its +# OWN, RAISED bodyTimeout. A single stuck call is still bounded by the per-call +# cap (AI_MCP_CALL_TIMEOUT_MS), and a socket that does break is healed by the +# in-run transport-error retry. The HTTP (streamable) transport keeps the tight +# timeout. Default 600000 (10 min). +# AI_MCP_SSE_BODY_TIMEOUT_MS=600000 + # Total wall-clock cap (ms) for ONE external MCP tool call (app-level, not # transport). Aborts a tool that keeps the socket warm (SSE heartbeats / trickle) # but never returns a result — which the silence timeout above never breaks. diff --git a/CHANGELOG.md b/CHANGELOG.md index 30d27413..adecf01f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -336,6 +336,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- **A chat with one malformed message part no longer 500s on every turn, and a + failed send no longer duplicates the user's message.** Incoming client parts + are now whitelisted to `text` (a forged tool-result part can no longer reach + the persisted history or the model context), and the turn is converted BEFORE + the user row is inserted, so a mid-flight failure cannot leave a duplicate + user row that a retry then compounds. A single part that still fails to convert + degrades to a `[tool context omitted]` marker on that one row instead of + bricking the whole chat. (#489) +- **A transport drop to an external MCP server now heals within the same turn.** + On an undici transport error, a read-only MCP tool reconnects its server and + retries once within the run; a write is never auto-retried (it may already have + applied). One flapping server no longer nulls the shared client cache, so other + servers' cached clients are untouched. The SSE transport also gets a raised + body-timeout so a legitimate >1-min idle between the model's tool calls no + longer breaks a long-lived SSE socket (new `AI_MCP_SSE_BODY_TIMEOUT_MS`, default + 10 min; see `.env.example`). (#489) + - **The server no longer runs out of heap during long autonomous agent runs.** A new pnpm patch on `ai@6.0.134` stops the SDK from building a cumulative snapshot of the ENTIRE turn text on every streamed text-delta when no output