Running every turn on your most capable model is the safe choice and the expensive one. Running on a mid-tier model is cheap until the agent hits the one decision in the task that needed more judgment, and by then it has committed. The usual fix is to build your own escalation: detect the hard case, package the context, call a bigger model, splice the answer back in.
An advisor does that inside the session. You name a second, more capable model in the agent's multiagent roster as an {"type": "advisor", "model": ...} entry. The primary thread then has an advisor tool it can call mid-turn: the platform puts the conversation so far in front of the advisor model, returns its guidance to the working model, and sampling continues. Each consultation runs as a short-lived platform thread with its own token usage, so you can see when it happened and price exactly what it cost.
reading a consultation off the event stream and its cost off the thread
what changes when the advisor's output comes back redacted
1. Set up the client
lient = juglow.Juglow()
2. Give a Sonnet agent an Opus advisor
api_designer: agent_staging_018FvRjvrM6ASGuXXcDTAvdH v1 roster: [{'model': 'haijun-opus-5', 'type': 'advisor'}] 3. Hand it a task with a hard call inside An idempotency scheme for a money-moving endpoint is the kind of decision the prompt told the agent to escalate: cheap to write, expensive to change after clients ship against it. The rest of the design is routine, so a well-calibrated agent consults on that and drafts the remainder itself.
e, 1));font-weight:533.3" aria-hidden="true">
--- consulting advisor #1 (sthr_staging_01PnQEQPc1nLxUK4S2vcVbCL) --- [redacted advice: content withheld by the advisor model's policy] --- advice received, primary thread resumes --- Incorporated the advisor's feedback directly into the design — the most consequential changes were: - Idempotency became a stored resource with a claim→execute→finalize lifecycle, not a simple header check. This closes the "processor succeeded but our server died before recording it" window, which a naive check-then-execute design leaves open. - Added a second, independent safety layer: a server-side invariant (sum(active refunds) + new_amount <= captured_amount) enforced under a row lock, so the system is safe even if a client reuses/loses its idempotency key. - Made refund creation explicitly asynchronous (201 + status: pending, terminal states succeeded|failed|canceled) instead of implying synchronous success. - Added a recovery path (GET /refunds?idempotency_key=...) for clients that lose the response to a request that actually succeeded — critical for flaky mobile networks. - Switched list pagination to opaque cursor-based instead of offset, since refunds are append-heavy and offset pagination skips/duplicates rows under concurrent inserts. - Made the retry policy part of the documented contract (which codes are safe to retry, and that retries must reuse the same idempotency key), not just implicit. - Resolved the nesting question: creation under /payments/{id}/refunds for natural scoping and clean 404s; retrieve/list stay top-level at /refunds. Full design written below. The design is written to /mnt/session/outputs/design.md. Summary of the approach: - Endpoints: POST /v1/payments/{payment_id}/refunds (create, scoped to parent), GET /v1/refunds/{id} (retrieve), GET /v1/refunds (list) — top-level for retrieve/list per advisor guidance. - Idempotency — the centerpiece: Idempotency-Key header is required and persisted as its own resource with a claim → execute → finalize lifecycle (claim written in the same transaction as the pending refund), so a crash after the processor succeeds but before we record it can't produce a silent duplicate on retry. Replay rules are explicit: same key+body replays the original response, same key+different body is a 422, same key still in-flight is a 409. - Second safety net, independent of the header: a server-enforced invariant (sum(active refunds) + new_amount <= captured_amount) under a row lock, protecting against buggy clients that regenerate keys or omit them. - Async-first status model: 201 means "accepted," not "money moved" — pending → succeeded|failed|canceled. - Recovery path: GET /v1/refunds?idempotency_key=... so a client that lost the response never needs to guess by retrying a write. - Pagination: opaque cursor on (created_at DESC, id DESC), not offset, since refunds are append-only and growing. - Errors: one envelope (type, code, message, param, request_id), plus an explicit table of which codes are safe to retry with the same key — documented as part of the API contract, not left to client guesswork. All of this reflects the advisor's review — the biggest change from my initial draft was moving idempotency from "check a header" to "a durably-claimed resource," and adding the amount-conservation invariant as a belt-and-suspenders check that holds even when the idempotency layer is bypassed. [idle] stop_reason=end_turn consultations this turn: 1 5. Price the consultations Because every consultation is a real session thread, its cost is on the thread rather than folded invisibly into the primary thread's numbers. Pull each advisor thread by the id from its session.thread_created event and read its usage. The token counts are there, and so is usage.list_cost: the thread's tokens priced at the advisor model's public list price, as an integer string in minor units of USD ("131" is $1.31), so the cost comes off the API instead of a rate card you maintain. Those tokens are billed in addition to the primary thread's, and they are already counted in the session-level usage aggregate, which carries a list_cost of its own.