Skip to content

fix(cloud-agent-next): split assistant unavailability by gateway origin - #6802

Merged
eshurakov merged 3 commits into
mainfrom
eshurakov/quiet-beacon
Sep 28, 2026
Merged

eshurakov merged 3 commits into
mainfrom
eshurakov/quiet-beacon

Conversation

@eshurakov

@eshurakov eshurakov commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Summary

assistant_unavailable on the code-review page collapsed two different outcomes under one label: a real upstream provider failure, and the gateway's own temporarily_unavailable (our over-limit guard or our managed-provider payment failure). The HTTP status code alone cannot tell them apart, so a failed review said nothing about which component actually failed.

The gateway already tags its own non-2xx responses with a bounded error_type in the JSON body. This change reads that tag in the single assistant-failure classifier and maps it to distinct reasons:

  • upstream_disconnect → provider_disconnect
  • temporarily_unavailable → gateway_unavailable

The two reasons flow through the existing taxonomy (packages/worker-utils, the sandbox control-protocol enum, packages/db reason unions) to two new code-review terminal reasons, so "Assistant Unavailable" now splits into "Assistant Provider Disconnect" and "Assistant Gateway Unavailable" in the admin error analysis.

The gateway response contract is unchanged — the error_type these mappings read already existed. This is a classifier-only change, with no apps/web/src/lib/ai-gateway edits.

Design notes for a reviewer:

  • Both reasons stay on the model-serving path (provider responsibility), matching the existing rule that the cloud agent treats the gateway and upstream as one origin. This adds visibility; it does not move the platform share. A comment marks the deliberate follow-up if gateway_unavailable should be attributed to platform.
  • The error body is provider-influenced on the passthrough path. It is read only to select from a fixed set, is length-bounded (≤4096 chars), and is never retained or copied into a message. The prior "does not inspect private fields" test was renamed to "does not retain private fields" and a dedicated test was added.
  • No customer-facing terminal-reason-copy entries: these are transient infrastructure failures with no customer remedy, so the generic path applies.

Verification

No manual tests were run — this affects failure classification on the cloud-agent callback path, which needs a running control plane plus a provider fault to exercise end to end, and the local stack was not started in this worktree. Verification was automated:

  • pnpm run test in services/cloud-agent-next (7759 passed) and packages/worker-utils (788 passed).

  • apps/web jest for src/lib/code-reviews, src/app/api/internal/code-review-status, src/app/admin/components/CloudAgentNextTelemetry, src/lib/ai-gateway, src/tests/openrouterApi.timeout.test.ts (all passing).

  • tsgo --noEmit for apps/web, packages/worker-utils, packages/db, services/cloud-agent-next.

  • oxlint and oxfmt clean on the changed files.

  • Manual end-to-end check of a gateway 503 upstream_disconnect producing assistant_provider_disconnect

Known gap: data.responseBody presence on the client error was inferred from the ingest sanitizer and test fixtures, not captured from a live production error.

Visual Changes

N/A

Reviewer Notes

  • Deploy order matters: the callback schema is .strict(), so an unknown assistantReason discards the whole failure object. Deploy apps/web before cloud-agent-next.
  • The classifier distinguishes the gateway's own temporarily_unavailable from an upstream disconnect. It does not split the upstream sub-cause (headers timeout vs connection reset): that would fragment the admin without a clear owner.
  • The mid-stream interrupt path (rewriteModelResponse) is untouched.

`assistant_unavailable` collapsed two different outcomes: a real upstream provider failure, and the gateway's own `temporarily_unavailable` (our over-limit guard or our managed-provider payment failure). The status code alone cannot tell them apart, so the code-review row said nothing about which component failed.

The gateway already tags its own responses with a bounded `error_type`; read it from the client error body and map it to distinct reasons: `upstream_disconnect` -> `provider_disconnect`, `temporarily_unavailable` -> `gateway_unavailable`. `failure_family` is added to the disconnect body for the sub-cause. Both reasons stay on the model-serving path (`provider`), so this adds visibility without moving the platform share.

The error body is provider-influenced on the passthrough path, so the read is length-bounded and only selects from a fixed set; nothing is retained or copied into a message.
@kilo-code-bot

kilo-code-bot Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental commit moves classifyGatewayOrigin ahead of the message-text classifier, so a gateway upstream_disconnect body whose wording reads as a provider timeout now classifies as provider_disconnect, and the stale failure_family doc comment is corrected. Both findings from the previous review are resolved and no new issues were found in the changed lines.

Files Reviewed (2 files)
  • services/cloud-agent-next/src/shared/assistant-failure.ts
  • services/cloud-agent-next/src/session/safe-failure-projection.test.ts
Previous Review Summaries (2 snapshots, latest commit 50938b5)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 50938b5)

Status: 2 Issues Found | Recommendation: Address before merge

Executive Summary

The incremental commit reverted the gateway failure_family field, leaving a stale reference in the classifier doc comment, while the earlier unresolved WARNING about gateway-origin classification being shadowed by message-text timeout matching still stands in the same classifier.

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 1
Issue Details (click to expand)

WARNING

File Line Issue
services/cloud-agent-next/src/shared/assistant-failure.ts 98 classifyGatewayOrigin runs after the specificMessageReason short-circuit, so gateway upstream_disconnect bodies whose message contains timeout wording classify as timeout instead of provider_disconnect. Carried forward from the previous review; code unchanged.

SUGGESTION

File Line Issue
services/cloud-agent-next/src/shared/assistant-failure.ts 157 Doc comment still claims upstream disconnects carry failure_family, but the field was removed from the gateway body by commit 50938b5.
Files Reviewed (3 files)
  • apps/web/src/lib/ai-gateway/providers/upstream-request.ts
  • apps/web/src/tests/openrouterApi.timeout.test.ts
  • services/cloud-agent-next/src/shared/assistant-failure.ts - 1 carried WARNING, 1 SUGGESTION

Fix these issues in Kilo Cloud

Previous review (commit d18eff7)

Status: 1 Issue Found | Recommendation: Address before merge

Executive Summary

The gateway-origin branch that splits assistant_unavailable in cloud-agent-next is shadowed by the message-text classifier for timeout-family upstream disconnects, so the new assistant_provider_disconnect split may not fire as intended.

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
services/cloud-agent-next/src/shared/assistant-failure.ts 98 classifyGatewayOrigin runs after the specificMessageReason short-circuit, so gateway upstream_disconnect bodies whose message contains timeout wording classify as timeout instead of provider_disconnect. Add a real-payload fixture or reorder the check.
Files Reviewed (13 files)
  • apps/web/src/app/admin/components/CloudAgentNextTelemetry/health-summary.ts
  • apps/web/src/lib/ai-gateway/providers/upstream-request.ts
  • apps/web/src/lib/code-reviews/terminal-reason-from-failure.test.ts
  • apps/web/src/lib/code-reviews/terminal-reason-from-failure.ts
  • apps/web/src/routers/admin-code-reviews-router.ts
  • apps/web/src/tests/openrouterApi.timeout.test.ts
  • packages/db/src/schema-types.ts
  • packages/db/src/schema.ts
  • packages/worker-utils/src/cloud-agent-failure.test.ts
  • packages/worker-utils/src/cloud-agent-failure.ts
  • services/cloud-agent-next/src/session/safe-failure-projection.test.ts
  • services/cloud-agent-next/src/shared/assistant-failure.ts - 1 issue
  • services/cloud-agent-next/src/shared/sandbox-control-protocol.ts

Fix these issues in Kilo Cloud


Reviewed by deepseek-v4.1-flash · Input: 0 · Output: 0 · Cached: 0

Review guidance: REVIEW.md from base branch main

The classification split only needs the gateway's existing `error_type`; the extra `failure_family` field was optional observability, not a dependency. Drop it so the gateway response contract is untouched and the change is classifier-only.
The gateway APIError's data.message is built from the gateway's own response body, so an upstream_disconnect timeout body matched the text classifier's timeout pattern and never reached the error_type mapping. Read the structured error_type first so the gateway origin decides, and drop the stale failure_family mention from the classifier doc comment.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants