Open-source agentic AI for transaction monitoring. Just ask Jooby.What's Jube? →

Orchestration: models, the plan gate, and prompt caching

This describes the runtime as it stands on top of the agent hierarchy (AgentDefinitions.cs, PageAgentToolBinder): the models each role runs on, the plan gate that sits in front of every delegation, and the prompt-caching layout that keeps a conversation’s preamble from being paid for on every turn.

Models

Role Model Why
Executor DeepSeek V4.1 Flash Every agent turn. Cheap input, so the hierarchy’s narrow toolboxes matter more for attention than for cost.
Critic (Jadek) DeepSeek V4.1 Flash The same locally served model as the executor, chosen for regional availability. This gives up the independence a critic drawn from a different model family would have – a critic sharing a family of weights with the executor shares some of its blind spots – so the critic leans on the thing that does differ: it searches the Pasture itself and judges the reply against retrieved text rather than against its own prior. Low reasoning effort, since the judgement is bounded.

There is no elective reasoner tool and no AskJoobyEnablePlanning switch in the code or the configuration. The critic and graph-directed workflows are what the hierarchy leans on in preference to a reasoning tier.

Thinking is off by default (AskJoobyEnableThinking is False) and is not a substitute for a plan. The orchestrator writes a plan before any handover to a specialist, and the code refuses a handover without one; leaf specialists do not plan. WritePlan (Jube.AskJooby/Tools/Delegation/PlanTool.cs) is offered to the orchestrator beside its spawn tools and records the plan on the turn; SpawnAgent/SpawnAgents refuse at depth 0 until a plan exists, fail closed when the turn has no ledger, and count each refusal in UnplannedHandovers. See docs/AskJooby/OrchestrationTools.md for the tool-level detail.

A mandatory planning stage in front of every request is not run. The retrieval corpus carries the Jube-specific knowledge a plan depends on, and Flash plans well enough against it that forcing a second model through the critical path would buy latency and configuration rather than quality.

DeepSeek’s own thinking (ThinkingOptions, the reasoning_content stream BasicAgentRunnable surfaces) stays off by default, switched on by AskJoobyEnableThinking. The planner reasons natively while it plans.

A plan is validated deterministically, in code, before a single node runs, rather than by trusting the planner to have reasoned its way to a good one.

The critic stays a separate model from the executor; independence is the point of it.

Prompt caching

The inference provider caches a prompt prefix per worker and matches it byte for byte, so two things decide whether a conversation pays for its own preamble once or on every turn.

The first is routing. Every request the inference client makes carries X-Model-Affinity set to the conversation’s Guid (ModelAffinityScope, stamped on by ModelAffinityPolicy), which asks the provider to keep sending that conversation to the worker already holding its prefix. One AsyncLocal set at the top of a turn reaches the Worker, every spawned Joobrik, the validator, the suggestions call and the embeddings, including anything detached onto its own task, so a whole turn pins to one worker without any of those paths knowing the mechanism exists. The live model-coherence test uses the same policy under a fixed value, since its prompts never change between runs.

The second is layout: static first, volatile last, everywhere. InstructionsBuilder sorts the specialist list rather than merely enumerating it, keeping that block static. ResponseValidator.BuildTask and ResponseReviser.BuildTask lead with the static block of unchanging criteria and append the volatile question-and-reply part, with only a one-line format reminder after it, because the instruction immediately before the model answers is the one that gets followed. For the same reason the page a caller happens to be on is appended to their message rather than prepended to it: it changes as they move around Jube within one conversation.

What already exists

Concern Component
Response criticism ResponseValidator, ValidationResult(Approved, Feedback, FailureKind), ResponseReviser, gated by AskJoobyEnableValidation
Bypass signalling None. Every substantive reply is validated, and no tool output is exempt
Chat interception UserQueryGuardChatClient and PersistedChatClient, both IChatClient decorators
Tool interception PersistedAiFunction, SnapshotOnWriteAiFunction
Snapshot gating IAutoSnapshot.Taken / TakeBeforeWriteAsync, enforced per write-capable agent
Snapshot and restore PreservationSnapshot (Write) and PreservationRecover (Delete, Destructive) – real catalogued operations
Run and tool telemetry IRunRecorder.StartRunAsync / CompleteRunAsync / RecordToolCallAsync / RecordModelCallAsync
Delegation and depth AgentDefinition.AllowedDelegates, RunContext.MaxDepth (3), RunContext.MaxFanOut (8)

Every chat client and tool interception point above is a decorator, or a per-turn signal object carried on RunContext, matching the same pattern throughout.