Skip to content

[feature] Consider request groups for completion candidates #1124

Open

Description

@afourniernv

Problem

While reviewing #1042, we ran into a case where completion candidates need different versions of the same request:

Cloud model    → request containing the handoff note
Local fallback → original request

RoutingOutcome now has an ordered candidate list, request, fallback_request, and a candidate_requests map. #1042 added the fallback override, #1176 added per-candidate requests, and #1299 exposed the map in Go.

A candidate-specific request takes precedence. Otherwise, later candidates use fallback_request when present. The default is outcome.request, which may already contain routing changes.

Those fields handle the immediate cases, but hosts must apply the same selection rules. Adding public Rust fields breaks callers that construct the struct directly. Hosts using constructors may keep compiling while ignoring a new override.

The question here is whether grouping requests and candidates would make that contract simpler. Per-candidate requests are already supported.

Proposed solution

Consider an ordered completion plan that groups each request with the models that should receive it:

// Design sketch, not existing code.
struct RequestGroup {
    request: Request,
    models: Vec<ModelId>,
}

struct CompletionPlan {
    groups: Vec<RequestGroup>,
}

Ordinary routing would produce one group:

Original request → [selected model, fallback models]

VGR could produce two:

Handoff request  → [cloud]
Original request → [local]

The host would try candidates in order under its existing fallback rules. It would not need to know which router produced the plan.

Each group would own one request. Iteration could borrow the model/request pairs rather than copy the request for every candidate. Keeping the original and rewritten versions still requires retaining both; this does not remove that cost.

Alternatives considered

  • Keep fallback_request and candidate_requests: the current implementation already handles these cases. A grouped plan needs enough benefit to justify migration.
  • Add a candidate iterator over the existing fields: centralizes request selection, but existing hosts could still ignore it.
  • Introduce router-specific outcome types: makes hosts handle router details instead of a common execution format.

Scope notes

This is a design discussion, not a committed rewrite or a claim that the existing fields are inherently wrong.

A completion plan would itself be a broader breaking change. Replacing the old execution fields could force Rust hosts to update; merely adding another accessor would not. Python bindings and custom hosts would need an explicit migration too.

Keep this focused on associating candidates with requests. It does not require a request graph, new routing policy, or moving target preparation, retries or streaming into libsy.

Additional context

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions