Skip to content

feat(workflows): add model fallbacks to Agent, Evaluator, and Router - #7972

Merged
icecrasher321 merged 17 commits into
stagingfrom
feat/agent-fallback-models
Sep 18, 2026
Merged

icecrasher321 merged 17 commits into
stagingfrom
feat/agent-fallback-models

Conversation

@mzxchandra

@mzxchandra mzxchandra commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds ordered fallback models to Agent, Evaluator, and Router, including legacy Router blocks. When a provider request fails, the block can try another model while preserving its prompts, inputs, and output contract.

  • Expose up to five fallback choices under Additional fields using shared model options, permission filtering, and canonical Chip controls.
  • Exhaust the primary model's configured retries before trying each fallback once. Cancellation and explicitly non-retryable failures stop the chain.
  • Share fallback credential, tuning, and diagnostic rules across all three blocks. Router and Evaluator share a request runner; Agent retains its streaming, attachment, tool, and memory handling.
  • Resolve BYOK through the existing provider path. Same-provider fallbacks reuse the primary key, cross-provider keys use secret references, and hidden row keys cannot override current credential rules.
  • Keep Router NO_MATCH and response parsing outside model failover. A completed routing decision cannot trigger another model request.
  • Record failed models in execution traces, report the model that answered, and document the behavior on all three block pages.

Behavior and limits

  • Agent streaming startup failures can retry or fall back before the first chunk. Failures after output begins remain stream failures.
  • Stored conversation history and configured memory windows carry into fallbacks without duplicate memory writes. Deep-research follow-up interactions stay on their original provider.
  • Agent attempts can repeat tool effects. Conversation memory does not checkpoint the generated tool-call/result transcript.
  • Failed attempts' usage is not aggregated into the successful block result, matching existing block retry behavior.

Testing

  • 750 tests passed across 15 suites, covering handlers, retry integration, memory, credential resolution, BYOK cost handling, validation, export sanitization, search, and UI behavior.
  • Type-check passed.
  • All 46 repository audits and docs-manifest check passed.
  • Full lint and block-registry checks passed.
  • Local editor visually checked. Current regression tests mock provider responses; no new live-provider failover run was performed for this update.
  • Local cleanup, runtime, and credential reviews found no actionable issues.

Checklist

  • Code follows project style guidelines
  • Self-reviewed changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

Adds the type to the shared SubBlockType union, the block registry test
allowlist, the tool-input exclusion set, and the docs generator's semantic
type map.
The Agent block gains an ordered list of fallback models as an advanced
field. The helpers normalize stored rows into execution candidates, decide
which models a row may offer (credentials the block can actually supply),
whether a row needs its own env-var key, and how the primary's tuning
carries over: graded knobs only when the fallback declares the value,
temperature and max output tokens clamped to the fallback's caps.
…t fails

One handler invocation tries the primary then each fallback in order, so
block retry wraps the whole chain. Falling through is as indiscriminate as
retry: only a stop or a non-retryable failure ends it early. Messages are
built once; hydration is cached per provider; a fallback that is
blacklisted, not permitted, or cannot take the attachments is skipped. The
models that failed are recorded on the block log and rendered in the trace
as a Fell back from row.
…rows

Copilot and YAML writes are refused when a row names an unknown model,
sim-auto, a raw key instead of a {{ENV_VAR}} reference, or a tuning value
the model does not declare. Export keeps only reference keys, search never
rewrites a row key, and the canvas card summarizes the models.
Ordered rows (2nd choice, 3rd choice, ...) directly above Retry on fail.
Each row picks a model the block can supply credentials for, an env-var
reference for its key when a different provider needs one, and a tuning
value only for the knobs the primary's setting cannot fill.
Executor: hydrate the primary before the secret registries settle and fork
again, re-forking per fallback provider, so file provenance stays in the
result registry; project the fall-through warn against the failed attempt's
error registry and reinstate it before a post-skip rethrow; prime a
streaming candidate's first chunk when another candidate follows, so a
tool-loop startup failure still falls back; never fall back on a
deep-research follow-up turn; strip the sim-auto identity preamble from a
named fallback's messages; treat a row key still in {{VAR}} form as no key;
stop starting candidates after an abort; record failed models on every exit,
clearing them when a retry succeeds, and only when the names project safely.

Helpers: row tuning applies only while its field is shown; the editor's row
transforms are pure functions; changing a row's model to another provider
drops the key reference; Bedrock honors NEXT_PUBLIC_BEDROCK_DEFAULT_CREDENTIALS.

Editor: legacy Combobox to match the block editor, a row's own model is never
disabled in its own picker, move controls only for two or more rows, the
shared dashed add-row button, Create Secret wording, non-reference keys never
rendered. Trace: one Failed model row per fallback. Export sanitizer uses the
strict whole-reference check.
Retry on fail used to wrap the whole fallback chain, so tries 3 with
fallbacks B and C ran A, B, C three times over. A builder who lists
fallbacks wants the selected model retried and the fallbacks tried once
each after its last try fails, which is also how LiteLLM orders retries
and fallbacks and how OpenRouter treats each model in its list.

The executor keeps the retry policy. Each try is now told where it sits
in it through the node metadata (`BlockNodeMetadata.retry`, with the
executor's own `isFinalTry` judgment), and the Agent handler keeps the
fallbacks out of the candidate list until the final try. Every earlier
try runs the primary alone and lets the failure escape for the policy to
replay. Blocks without fallbacks, and blocks with retry off, behave as
before; other handlers ignore the field.
Review fixes: the executor judges the final try once per iteration; the
skip-warn is one helper; the fallback warn names the candidate position
rather than reusing `attempt`; the BlockLog.modelFallbacks doc matches the
final-try semantics; the viability check resolves a provider once through
the new providerRequiresFamilyCredentials; editor handlers read rows via a
ref so a keystroke in one row no longer re-renders every row, and tuning
options keep their identity across renders.

Two consistency fixes from the red-team pass: a sim-auto fallback takes
the projected system prompt rather than the raw input, and a row key is
honoured at runtime only when the block stored it as a whole {{NAME}}
reference, the one form the editor, the validator, and an export agree on.

Tests now cover the composed executor-plus-handler sequence (three tries on
the selected model, then each fallback once), the node-taking handler
signature, a fallback whose provider cannot take the attachments, the
per-provider hydration cache, a stop during a skipped candidate, the
un-primed stream when no candidate follows, a non-retryable failure on a
non-final try, a numeric tuning value, and an unresolved temperature.
A routed sim-auto primary that fails now shows in the trace as the auto
identity rather than the pool model, which is the name applyAutoModelLabel
exists to hide. Per-row tuning resolves against the model the builder
configured, the one the editor showed the fields for, so a row's value
applies under sim-auto whatever pool model was routed. A fallback on
another provider no longer receives the primary's Azure, Vertex, or
Bedrock fields, which only that family reads.
@vercel

vercel Bot commented Sep 18, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
docs Ready Ready Preview Sep 18, 2026 10:36pm UTC

Request Review

@greptile-apps

greptile-apps Bot commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

The PR appears safe to merge; no actionable correctness, security, or repository-rule violations remain.

Summary

Adds ordered fallback-model execution to Agent, Evaluator, and Router blocks, including retry composition, provider and credential gating, model-specific tuning, editor configuration, trace visibility, validation, sanitization, and documentation.

  • Executes the primary model first and reserves fallbacks for the final block retry.
  • Skips unavailable, unauthorized, incompatible, or provider-family-ineligible fallback candidates.
  • Restricts row credentials to stored environment-variable references and prevents inappropriate cross-provider credential reuse.
  • Adds fallback configuration and display support throughout the workflow editor and preview surfaces.
  • Records failed candidates in execution traces and documents fallback behavior for all supported blocks.
Diagram
sequenceDiagram
  participant E as Block Executor
  participant H as Model Block Handler
  participant P as Primary Model
  participant F as Fallback Models
  E->>H: Execute attempt with retry metadata
  H->>P: Send primary request
  alt Primary succeeds
    P-->>H: Response
    H-->>E: Block output
  else Primary fails before final retry
    P-->>H: Retryable error
    H-->>E: Error for executor retry
  else Primary fails on final retry
    P-->>H: Retryable error
    loop Ordered viable fallbacks
      H->>F: Send adapted request
      alt Candidate succeeds
        F-->>H: Response
        H-->>E: Output and failed-model trace
      else Candidate fails
        F-->>H: Error
      end
    end
  end
Loading

Reviews (4) · Last reviewed commit: "feat(workflows): share model fallbacks a..."

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 36 files

Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Fix all with cubic | Re-trigger cubic

Comment thread apps/sim/executor/handlers/agent/agent-handler.ts Outdated
Comment thread apps/sim/lib/workflows/editing/validation.ts
Comment thread apps/sim/lib/workflows/blocks/fallback-models.ts Outdated
A candidate stream that closes before its first chunk is a startup
failure to fall through from, not an empty answer. The provider-decides
tuning entry is stored as absence on the copilot path too, and a row key
survives a same-provider model change only when it is a reference. The
preview of a fallback list now gates its rows against the previewed
version's selected model and settings rather than the live block's, and
the preview value is typed instead of cast to any.
@mzxchandra

Copy link
Copy Markdown
Contributor Author

@greptile

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@mzxchandra I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 36 files

Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Fix all with cubic | Re-trigger cubic

Comment thread apps/sim/lib/workflows/blocks/fallback-models.ts
The tuning doc read as if an unknown primary's values passed through. They
do not: the block never shows a graded knob for a model outside the
catalog, so a value stored under one is stale and the row's own field
decides. A test now pins that.
@mzxchandra

Copy link
Copy Markdown
Contributor Author

@greptile

@mzxchandra

Copy link
Copy Markdown
Contributor Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@mzxchandra I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 36 files

Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Fix all with cubic | Re-trigger cubic

Comment thread apps/sim/lib/workflows/blocks/fallback-models.ts
@icecrasher321 icecrasher321 changed the title feat(agent): fallback models on the Agent block feat(workflows): add model fallbacks to Agent, Evaluator, and Router Sep 18, 2026
@icecrasher321

Copy link
Copy Markdown
Collaborator

@greptile

@icecrasher321

Copy link
Copy Markdown
Collaborator

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@icecrasher321 I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 48 files

Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Fix all with cubic | Re-trigger cubic

Comment thread apps/sim/executor/utils/model-fallbacks.ts
@icecrasher321
icecrasher321 merged commit 2d87824 into staging Sep 18, 2026
34 of 35 checks passed
@icecrasher321
icecrasher321 deleted the feat/agent-fallback-models branch September 18, 2026 22:52
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