Uh oh!
There was an error while loading. Please reload this page.
fix(providers): pin transport policy and lift the 60s cap on Groq and Cerebras - #6306
Conversation
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview Guardrails now forwards Adds Reviewed by Cursor Bugbot for commit eeb262e. Configure here. |
Greptile SummaryThe PR centralizes timeout and retry settings for OpenAI-compatible provider clients, raising Groq and Cerebras timeouts while explicitly preserving the existing policy elsewhere. It also propagates request cancellation through hallucination guardrail scoring and preserves cancellation as a 499 response.
Confidence Score: 5/5The PR appears safe to merge. The previously reported retry drift test now compares the policy against the vendored OpenAI retry default, and no blocking failure remains.
|
| Filename | Overview |
|---|---|
| apps/sim/providers/transport.ts | Defines the shared 600-second timeout and two-retry transport policy used by OpenAI-compatible clients. |
| apps/sim/providers/transport.test.ts | The revised assertion compares the pinned retry count with the vendored OpenAI default, resolving the prior drift-detection concern. |
| apps/sim/providers/groq/index.ts | Applies the shared transport policy to Groq, replacing its shorter SDK timeout. |
| apps/sim/providers/cerebras/index.ts | Applies the shared transport policy to Cerebras, replacing its shorter SDK timeout. |
| apps/sim/lib/guardrails/validate_hallucination.ts | Threads cancellation into provider scoring and rethrows abort errors instead of converting them into guardrail failures. |
| apps/sim/app/api/guardrails/validate/route.ts | Passes the request signal into hallucination validation and returns 499 for client cancellation. |
Reviews (4): Last reviewed commit: "fix(guardrails): return 499 on a cancell..." | Re-trigger Greptile
Uh oh!
There was an error while loading. Please reload this page.
waleedlatif1
commented
Aug 6, 2026
Final audit — 49 agents, 18 providers, adversarially verifiedVerdict: ship with fixes. Zero dead changes — the failure mode I was most worried about does not occur. All 18 spreads land on constructors that genuinely read Fixed in |
| per attempt | worst case | |
|---|---|---|
| Before | 60s | 181.5s |
| After, real (transport wall ~300s) | ~300s | 901.5s (~15 min), 5.0x |
- Free sync = 300s (
execution-limits/types.ts): a single failing attempt now consumes the whole budget, so free users get "Execution timed out after 5 minutes" instead of a block-level provider error. Sharpest regression. - Pro/team sync = 3000s: two sequential failing agent blocks (3,603s) blow it. Async = 5400s: three (5,404.5s) exceed it, and
trigger.config.ts:53 maxDuration: 5400has zero headroom. - Error classification regresses. At 60s the SDK aborted itself →
APIConnectionTimeoutError. At the transport wall it rewraps intoAPIConnectionError("Connection error"), andisTransportTimeout()inagent-handler.ts:82-88matches onlyAbortError/TimeoutError— so a 15-minute stall is no longer classified as a timeout, undoing part of what shipped in v0.7.57. - Guardrails become unbounded.
lib/guardrails/validate_hallucination.ts:170callsexecuteProviderRequestwith noabortSignal(contrastagent-handler.ts:1274). Previously capped at 181.5s by the SDK; now it can run 15–30 min and keeps running after the workflow aborts. The audit flagged this as promotable to a blocker if Groq/Cerebras are used in guardrails. - Throughput: at
WORKFLOW_EXECUTION_CONCURRENCY_LIMIT = 75, a Groq brownout holds each slot 5–10x longer (~25 runs/min → 2.5–5).
Mitigation available without dropping the fix: maxRetries: 1 for those two so a stall is not tripled, or a per-request timeout at their create() sites.
Doc alignment
Nothing contradicts the policy outright. Worth knowing: Baseten documents a 1200s read timeout — our 600s pin is half their recommendation. Groq documents 1 min and "retried twice"; Mistral's own SDK bounds the same endpoint at 300s. Aligned and clean: deepseek, xai, kimi, nvidia, zai, fireworks, openrouter, litellm (their own example is request_timeout: 600), ollama, ollama-cloud, vllm.
Consistency
Three genuine misses, all one-liners and provably no-op since their SDK defaults are byte-identical to the pinned values: anthropic (index.ts:27) plus the two Azure paths. Leaving google/vertex/bedrock/openai-raw-fetch is correctly deferred — they need different fixes.
waleedlatif1
commented
Aug 6, 2026
Wired the abort signal into hallucination scoring — That closes the side effect the audit flagged as promotable to a blocker: the scoring request previously had no signal at all, so it outlived a cancelled request and kept burning a provider slot until the transport gave up — which the Groq/Cerebras raise would have stretched from ~181s to potentially 15+ minutes. The free-tier budget consequence is being kept as-is by decision: a single failing Groq attempt now consumes the whole 300s sync budget rather than failing at 60s. That makes Groq consistent with every other provider rather than uniquely fast-failing, and the alternative — leaving a 60s cap on any generation — is the bug this PR exists to fix. |
waleedlatif1
commented
Aug 6, 2026
waleedlatif1
commented
Aug 6, 2026
@cursor review |
Uh oh!
There was an error while loading. Please reload this page.
…port-defaults # Conflicts: # apps/sim/app/api/guardrails/validate/route.ts # apps/sim/lib/guardrails/validate_hallucination.ts
… a failed guardrail
waleedlatif1
commented
Aug 6, 2026
waleedlatif1
commented
Aug 6, 2026
@cursor review |
Uh oh!
There was an error while loading. Please reload this page.
waleedlatif1
commented
Aug 6, 2026
waleedlatif1
commented
Aug 6, 2026
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit eeb262e. Configure here.
Summary
Centralises provider transport policy in
providers/transport.tsand applies it across all 18 SDK-backed providers.openai@7. Stamping it explicitly means an SDK bump cannot move production behaviour silently.What this deliberately does NOT do
It does not add retries, and that is the finding — not an omission. My working assumption going in was that Sim's zero-retry OpenAI path should adopt the vendor's
maxRetries: 2. A 25-provider integration audit rejected that, and the reasoning holds: a chat completion is non-idempotent, carries no idempotency key, and on the non-streaming path the response only exists once the generation is already billed. A replay therefore re-bills completed work — multiplied by every turn of the tool loop. The vendor default is kept and pinned; no hand-rolled loop is introduced.Also rejected, each for a specific reason: dropping 409 (discards
x-should-retry: false, which proxies use to shed load — amplifying the outage the header exists to damp); swapping to full jitter (subtractive jitter is a 25% spread vsbackoffWithJitter's 40% — buys nothing); clampingRetry-After(the sleep is insidenode_modules/openai/client.js:580-607and unreachable from Sim); and memoising clients (retains plaintext tenant API keys in a global LRU for 30 idle minutes, andopenai@7uses a process-global connection pool anyway, so it saves no handshake).It also does not raise a number to fix the production stalls, because that cannot work. Bun's ~300s
fetchwall is socket-scoped and reachable from no SDK, undiciAgent, orRequestInitoption — the audit measured that Bun ignores Agent timeouts entirely (Node throwsUND_ERR_HEADERS_TIMEOUTat 1007ms withheadersTimeout: 800; Bun returns OK at 3013ms). The 279s/296s failures are that wall, reduced by however long a pooled socket sat idle before reuse — which is why 279 and not 300. Raising a timeout above it changes nothing.Type of Change
Testing
4 tests pinning policy against the vendored SDK rather than a remembered number —
PROVIDER_HEADERS_TIMEOUT_MSis asserted equal toOpenAI.DEFAULT_TIMEOUT, so an SDK bump fails the test instead of silently drifting. Verified fail-detectable by drifting the constant (2 red).Providers + agent-handler suites: 110 files / 1420 tests passing. Typecheck, lint, and
check:api-validationclean.Follow-up (deliberately not in this PR)
The audit's central conclusion is that keeping bytes on the socket is the only remedy for a long silent generation. That means a stream idle/inter-chunk watchdog in
stream-pump.tsplus abort threading through the three stream helpers, so a stalled stream unwinds its socket instead of leaking it (todayreturn()queues behind the pendingnext()and never runs). That is the highest-value remaining change and the most delicate — it touches every provider's stream path and warrants its own PR and its own review.Checklist