Skip to content

Routing with Select

Select groups flows so an upstream agent picks one by id:

go
brain := router.Next(bb.Select(talk, remember, house)).Next(bb.Respond)
  • Each Select member must set an id with WithId; a member without one is ignored (with a warning).
  • An agent picks a member with turn.Select(id). An unknown id is a loud error at request time, never a silent misroute.
  • Declaring an agent's exits with Selects(id…) adds a startup check (bb.Serve/bb.Handler verifies every declared exit is a group member) before any request runs. It is optional — declare it when you want the boot-time guarantee.
  • Within one agent, the last Select wins (program order). Across concurrent agents, two different selects is a loud error, not a race; the same id is fine.

A typical intent router

The pattern behind both reference brains: classify with a model + typed schema, then dispatch.

go
type intent struct {
    Intent string `json:"intent" enum:"talk,house,remember" doc:"the chosen capability"`
    Reason string `json:"reason"`
}

router := bb.NewAgent().
    WithModel(bb.NewModel("cheap")).
    WithSchema(bb.Schema[intent]()).
    Selects("talk", "house", "remember").
    OnMessage(func(ctx context.Context, turn bb.Turn, chat bb.ModelChat) error {
        chat.Add(turn.Last())
        reply, err := chat.Ask()
        if err != nil {
            return err
        }
        it := bb.Extract[intent](reply)
        turn.Select(it.Intent)
        return nil
    })

brain := bb.NewFlow().WithAgent(router).
    Next(bb.Select(talkFlow, houseFlow, rememberFlow)).
    Next(bb.Respond)

Selects(...) is worth adding here: a typo in it.Intent, or a capability you forgot to add to the Select group, fails at bb.Serve startup instead of the first time a live classification happens to pick it.

See Concurrency for what happens when multiple flows in a Select group's siblings (All/One/Group) run at once.

A tree of flows and agents, disguised as a model.