inspect_swarm
Swarms and members
swarm
A swarm of agents working on one sample.
Each member gets a timeline in the sample named after it, so member names must be unique across the swarm runs and other timelines in a sample. To run swarms more than once in one sample, build them with distinct member names. A member may not be named init, solvers or scorers: Inspect’s timelines read spans with those names as the sample’s phases.
@agent
def swarm(
members: Member | Agent | Sequence[Member | Agent],
*,
controller: str | Controller = "leaderless",
channels: str | Channel | Sequence[str | Channel] = ("filesystem",),
budget: Budget = Budget(), # noqa: B008
) -> AgentmembersMember | Agent | Sequence[Member | Agent]-
The roster: built agents or member() records. A bare agent is
member(agent). A factory-form member() may stand for several members (count). controllerstr | Controller-
How the swarm runs: who starts, when and with what input, and when the swarm is done. A name resolves to a registered controller with its default parameters.
channelsstr | Channel | Sequence[str | Channel]-
How members share information. A name resolves to a registered channel with its default parameters.
[]means none: members get no channel instructions, though a shared sandbox is still shared. budgetBudget-
The swarm-wide cap.
member
A swarm member, with a name, role, limits or count.
A member is a built agent, member(react(prompt=...)), or a registered @agent factory and its arguments, member(deepagent, args={"tools": [bash()]}, count=4). Both must be registered with @agent, so that the log can name them and replay can find them. A built agent can also be passed to swarm(members=...) without member().
No agent object runs twice at the same time in one sample. A built agent is one member: it is built once, when the task is built, and shared by concurrent samples, as any Inspect solver is. The same agent object cannot be in two members. Several copies of one configuration (count above 1) need the factory form: the swarm calls factory(**args) once for each member in each sample, so each copy gets its own agent and whatever the factory builds. member() checks the arguments against the factory’s signature but does not call it, so the factory’s own checks run when the member is built.
Names. Members left on their default name are numbered across the whole roster, not per record, so one member with different arguments takes two records: [member(react, args={"prompt": a}, count=6), member(react, args={"prompt": b, "model": m})] is react-1 to react-7. When every copy differs, give each its own record, as in [member(react, args={"prompt": p}) for p in prompts]. Names given with name are not numbered across records, so give each record its own.
Objects given to an agent are shared. Every member built from one record receives the same objects from args, and two built agents given the same tool object share it, across members and samples. Inspect’s built-in tools keep their state in the sample store or the sandbox, so this matters only for a custom tool or helper that keeps state in its Python object (a counter, a cache, a client). To give each member its own, construct it inside a member builder, an @agent factory that builds the configured agent, and use the factory form.
Tool state. Each member runs in its own tool-state scope, named after the member. Built-in tools that keep state in the sample store (memory(), bash_session(), web_browser(), the skill tool) give each member its own state when their instance is left at the default, so the default memory() is private to each member. An explicit instance is used as given: members, or the copies of one counted member, that name the same instance share its state, so a board shared on purpose is memory(instance="board"). The sample store itself is shared. State that custom tools or agent code keep in the store with no instance is shared unless they resolve their instance with tool_state_instance(). Built-in tool state that a setup solver prepared at the default instance before the swarm runs is not visible to the members.
Submissions. A member that returns normally has submitted, and its output is its answer, unless the output’s stop reason is content_filter or model_length. That is how react() returns after three refusals or a context overflow it could not recover from, so the member ends unsubmitted and the swarm never chooses its output as the answer. Other agents keep the rule that a normal return is a submission: an agent that gives up in some other way and returns is treated as having answered.
Stopping itself. An agent that raises LimitExceededError("custom", ...) with no source to stop itself ends only its member, with status member_limit:custom; the other members continue and the swarm never chooses its output as the answer. This holds when the error is raised in a task group inside the agent, too.
Sandboxes. Members share the sample’s sandbox by default. With sandbox, a member works in its own: the swarm makes that environment the member’s default, so sandbox() in its tools returns it, and hides the sample’s other environments from the member except those in visible_sandboxes, such as a shared service. Tools that choose a sandbox without a name, such as text_editor(), bash_session() and the agent bridge, use the member’s own; a visible service is reached only by name. sandbox="{member}" gives each copy of a counted member the environment named after it: member(factory, name="agent", count=2, sandbox="{member}") runs agent-1 and agent-2 in the environments of those names. The sample’s sandbox configuration provides the environments (for Docker, a compose service for each), and the swarm checks that they exist when it starts. When one member has its own sandbox, every member must have one, no two the same, and the filesystem channel, which describes a shared sandbox, can be used only as filesystem(shared_volume=True), for sandboxes that each mount one shared volume. A service in visible_sandboxes is reachable from any of the member’s tools that take a sandbox name, so list only services every member may use.
Scoring with member sandboxes. The task’s scorers run after the swarm, outside every member, where sandbox() is default. A scorer that grades the members’ work names each member’s sandbox itself, as in sandbox("agent-1"), and the sandbox field of each member in the swarm’s result record says which member used which.
Background work belongs to the member. Work its agent starts with background(), such as deepagent(background=...) subagents, spends through the member’s limits and share, and is the member’s in the ledger. When the member’s agent returns, the swarm stops the background work from starting model calls, gives it the swarm’s grace period to finish calls and tool calls in flight, and cancels what is left. The member ends after that, with the status its agent ended with; Budget.grace=0 cancels background work at once. A member time limit bounds its agent only: after the agent returns, its background work gets the grace period too, and the cancelled work’s cleanup is awaited. Background work must be started by the agent while it runs; a factory that starts it while building the agent makes the member errored. A sourceless custom limit error raised in background work ends only the task that raised it; the member’s agent and its other background work continue. Work started outside background() (an asyncio task, a process left running in the sandbox) is not stopped. Bridged members cannot have background work: background() raises in a member declared or found bridged, and a member that uses the agent bridge after starting background work (through a bridged subagent, for example) is cancelled and ends errored.
ACP agents, which wait for their caller to drive them rather than returning, are refused: a built one when member() is called, and a factory’s when the member is built.
def member(
agent: Agent | AgentFactory,
args: Mapping[str, Any] | None = None,
*,
name: str | None = None,
role: str | None = None,
count: int = 1,
limits: Sequence[Limit] | None = None,
bridged: bool | None = None,
delivery: Literal["notify", "poll"] | None = None,
sandbox: str | None = None,
visible_sandboxes: Sequence[str] = (),
) -> MemberagentAgent | AgentFactory-
A built, registered agent, or a registered
@agentfactory. argsMapping[str, Any] | None-
The factory’s keyword arguments. Only for a factory.
namestr | None-
The member’s name. Defaults to the agent’s or factory’s registry name, without its package; a default name that more than one member has is numbered across the roster. With
countabove 1 the members arename-1toname-k. It names the member’s tool-state scope, so it cannot be empty or contain “/” or “#”. rolestr | None-
The member’s role, given to the controller and in the member’s preamble.
countint-
How many members this record stands for. Above 1 needs a factory.
limitsSequence[Limit] | None-
The member’s own token, cost, turn, message or time limits.
bridgedbool | None-
Whether the agent is bridged (runs a CLI in the sandbox through Inspect’s agent bridge).
Nonecounts inspect_swe’s agents as bridged and others as native. PassTruefor any other bridged agent: the swarm stops a bridged member by cancelling it, because a limit error raised inside the bridge would end the sample, and it must know before the member’s first model request. Bridged members cannot use channels with tools and records yet, and swarm() refuses one beside such a channel. A bridged agent that is not declared and not in theinspect_swe/namespace is not refused: it cannot reach those channels’ tools, so it runs without them. PassTrueto have it refused instead. deliveryLiteral['notify', 'poll'] | None-
The member’s configured delivery mode:
notifyorpoll.Noneselectsnotify. Innotifymode, swarm_on_continue() adds notices to the member’s conversation; inpollmode it adds none, and the member learns of changes from the status line that ends a shared memory result and fromswarm_waitresults. A member declared or identified as bridged before it starts has effective modepoll. Bridge use detected later leaves its configured mode unchanged. sandboxstr | None-
The name of the member’s own sandbox environment.
{member}stands for the member’s name.Noneshares the sample’s sandbox. visible_sandboxesSequence[str]-
Other sandbox environments the member can reach by name, such as a shared service. Only with
sandbox. It cannot includedefault, which inside the member is the member’s own sandbox.
Controllers
leaderless
Start every member with the swarm’s input; stop at the first submission, or when all have ended.
By default the swarm stops when the first member submits. The swarm’s answer is the first submission, so nothing the other members do after it can change the answer. The members still running are stopped: they finish the calls they have in flight, within Budget.grace, and the ones still running after it are cancelled.
Pass stop_on_submission=False to let every member run to its end when the other members’ work still matters: tasks whose scorer reads a shared artifact (such as the sandbox) after the members end, where members still working change what is scored; arms that measure each member’s result (team@k); and agents for which any normal return counts as a submission, so that a member that gives up would end the swarm. Add final="last" to make the latest submission the answer, for a team whose members build on each other’s work.
@swarm_controller
def leaderless(
stop_on_submission: bool = True, *, final: FinalName | None = None
) -> Controllerstop_on_submissionbool-
Stop the swarm when the first member ends with a submission.
finalFinalName | None-
How the swarm chooses its answer from the submissions:
first, the earliest, orlast, the latest. A tie goes to the member listed first.Noneis the default,first.lastneedsstop_on_submission=False.
swarm_controller
Decorator for registering swarm controllers.
The factory’s arguments are recorded with the controller, so they appear in the log and the controller can be rebuilt from it. A factory in a package is registered as <package>/<name>.
def swarm_controller(
func: Callable[P, Controller] | None = None, /, *, name: str | None = None
) -> (
Callable[P, Controller]
| Callable[[Callable[P, Controller]], Callable[P, Controller]]
)funcCallable[P, Controller] | None-
A function returning a Controller.
namestr | None-
The registered name, in place of the function’s name.
Controller
How a swarm runs: which members start, when and with what input, and when the swarm is done.
A Controller holds configuration only: one object serves every sample, so per-sample state belongs in run’s local variables. Return one from a factory decorated with @swarm_controller.
class ControllerMethods
- __init__
-
Create a controller.
def __init__( self, run: Callable[[SwarmControl], Awaitable[StopReason]], *, final: FinalName | None = None, check: Callable[[Sequence[MemberInfo]], None] | None = None, ) -> NonerunCallable[[SwarmControl], Awaitable[StopReason]]-
Called once per sample. Starts members and waits for their events through the SwarmControl, and returns the stop reason. Returning requests the stop.
finalFinalName | None-
How the swarm chooses its answer from the submissions, for the provisional answer and when the swarm ends:
first, the earliest submission, orlast, the latest.Noneis the default,first. Whenrunnames the answer withSwarmControl.choose_answer(), that choice is the answer instead. checkCallable[[Sequence[MemberInfo]], None] | None-
Called with the roster when the swarm is built. Raise
ValueErrorfor a roster the controller cannot run.
SwarmControl
What a controller’s run works through: the swarm’s members and their events, for one sample.
class SwarmControl(Protocol)Attributes
membersSequence[MemberHandle]-
The members, in roster order.
Methods
- member
-
The member with this name.
def member(self, name: str) -> MemberHandlenamestr-
The member’s name.
- start
-
Start a member, and return at once.
The member runs in its own task, span and tool-state scope, with its limits. Its input is
input, or the swarm’s input wheninputisNone, followed by the member’s preamble: its name, role and roster size, how the budget is split, and each channel’s instructions.def start( self, member: str | MemberHandle, input: str | list[ChatMessage] | None = None ) -> Nonememberstr | MemberHandle-
The member, or its name.
inputstr | list[ChatMessage] | None-
The member’s input.
Nonegives it the swarm’s input.
- events
-
The swarm’s events, in order from the swarm’s start.
Each event is yielded once. The iterator ends when no member is running and no event is waiting; a member started later is reported by a new
events()call. Use one iterator at a time: an iterator holds the events from its first step until it ends or is closed (aclose(), or leaving acontextlib.aclosing()block).def events(self) -> AsyncGenerator[SwarmEvent, None] - choose_answer
-
Make this member’s submission the swarm’s answer, in place of the controller’s
finalrule.The choice is the provisional answer from now on and the final answer when the swarm ends. The result record and the
finalevent give the modecontroller, the member andreason. Choose once, from a member that has ended with a submission.def choose_answer( self, member: str | MemberHandle, reason: str | None = None ) -> Nonememberstr | MemberHandle-
The member, or its name.
reasonstr | None-
Why the controller chose it, for the record.
MemberHandle
A member as a controller sees it: its name, role, state and status, never its text.
class MemberHandle(Protocol)Attributes
namestr-
The member’s name.
rolestr | None-
The member’s role, if it has one.
stateMemberState-
The member’s lifecycle state.
statusstr | None-
How the member ended, once it has:
submitted,unsubmitted,stopped,share,member_limit:<type>,swarm_cap,cancelledorerrored. submittedbool-
Whether the member ended with a submission (status
submitted).
MemberEnded
A member ended.
@dataclass(frozen=True)
class MemberEndedAttributes
memberstr-
The member’s name.
statusstr-
How it ended, as
MemberHandle.status. submittedbool-
Whether it ended with a submission.
SwarmEvent
An event a controller receives from SwarmControl.events(). Later versions add kinds, so test an event’s type before reading its fields.
SwarmEvent = MemberEndedMemberInfo
A member as the controller’s check and a channel’s instructions() see it.
@dataclass(frozen=True)
class MemberInfoAttributes
namestr-
The member’s name.
rolestr | None-
The member’s role, if it has one.
MemberState
A member’s lifecycle: not started, running, or ended.
MemberState = Literal["pending", "running", "ended"]StopReason
Why a controller’s run returned: a topology reason such as all_done, or the controller’s own, recorded as controller:<reason>.
StopReason = strFinalName
How the swarm chooses its answer from the submissions: first, the earliest, or last, the latest. A tie goes to the member listed first in the roster.
FinalName = Literal["first", "last"]Channels
filesystem
A shared directory, with a convention for using it, stated in each member’s preamble.
By default the channel describes the sample’s sandbox, which the members share: a directory for shared files, a notes file members append to, and a scratch directory for each member.
With shared_volume=True it describes members with their own sandboxes (member(sandbox=...)) that each mount one shared volume at shared: shared and the notes file in it are the same directory in every member’s sandbox. There is no scratch directory, since each member’s sandbox is already its own. The swarm cannot check that the volume is mounted in every member’s sandbox; it takes your word for it.
The channel adds no tools and does not create the directories.
@swarm_channel
def filesystem(
shared: str = "/shared",
notes: str = "notes.md",
scratch: str = _SCRATCH,
shared_volume: bool = False,
) -> Channelsharedstr-
The directory for files members share. With
shared_volume=True, an absolute path where the volume is mounted. notesstr-
The notes file members read and append to, relative to
shared(or an absolute path). Withshared_volume=Trueit must be insideshared. scratchstr-
Each member’s own directory.
{member}is replaced by the member’s name. Not used withshared_volume=True. shared_volumebool-
Whether members have their own sandboxes that each mount one shared volume at
shared. swarm() accepts the channel beside per-member sandboxes only withTrue, and refusesTruewhen members share the sample’s sandbox.
swarm_tools
The tools of the swarm’s channels, for a member’s agent.
Pass it in the member’s tools, react(tools=[bash(), swarm_tools()]). The member’s own loop gets the tools of every channel of the swarm that has them; its nested loops, such as a deepagent() member’s subagents, get only those of channels whose reach is "member". A loop also gets swarm_wait, which waits for other members’ work, when one of the channels it reaches wakes waits, as shared_memory() does. The member’s own loop is the first in which the tools are resolved, which for react() and deepagent() members is their top-level loop. Each tool acts as the member, whichever loop calls it.
The same member definition serves swarms with different channels, and one with none. Outside a swarm it gives no tools.
def swarm_tools() -> ToolSourceswarm_on_continue
Notices for a swarm member, as its agent’s on_continue hook.
Pass it as the member’s hook, react(on_continue=swarm_on_continue()), or around the hook the member would otherwise have, swarm_on_continue(inner). The member then continues or stops exactly as it would without it. At each of its turn boundaries, unless it is stopping, a member in notify mode gets a notice of what changed in the swarm’s channels since its last notice, such as shared memory files other agents wrote. A notice is a user message with fixed text: counts, ids such as f-3 and member names, never what a member wrote.
Only the member’s own loop gets notices, not its subagents. Outside a swarm, or for a member in poll mode, it adds nothing.
def swarm_on_continue(
inner: str | AgentContinue | None = None,
*,
no_tool_calls: Literal["continue", "stop"] = "continue",
) -> AgentContinueinnerstr | AgentContinue | None-
The hook the member would otherwise have. A string continues the member with that message after a turn without tool calls, as it does as
on_continueof react() with a submit tool. A function is called and its result kept. no_tool_callsLiteral['continue', 'stop']-
Without
inner, what the member does after a turn without tool calls, which must be what its agent does with no hook:"continue"for react() with a submit tool and for deepagent(),"stop"forreact(submit=False). Ignored wheninneris given.
swarm_channel
Decorator for registering swarm channels.
The factory’s arguments are recorded with the channel, so they appear in the log and the channel can be rebuilt from it. A factory in a package is registered as <package>/<name>.
def swarm_channel(
func: Callable[P, Channel] | None = None, /, *, name: str | None = None
) -> Callable[P, Channel] | Callable[[Callable[P, Channel]], Callable[P, Channel]]Channel
A sanctioned way for members to share information.
Subclass it and override instructions(), and return an instance from a factory decorated with @swarm_channel. A Channel holds configuration only: one object serves every sample.
A channel with tools and records also sets name and prefix and overrides open(), which gives each run of the swarm its own ChannelState. A channel that only adds instructions, such as filesystem(), leaves them unset.
class ChannelAttributes
namestr | None-
The name of the channel’s records (
Record.channel), orNonefor a channel with no records. No two channels of a swarm may share it. prefixstr | None-
The prefix of the channel’s record ids (
"w"givesw-1), set exactly whennameis. No two channels of a swarm may share it. reachLiteral['loop', 'member']-
Which of a member’s agent loops get the channel’s tools from swarm_tools().
"loop"(the default): only the member’s own loop, the first in which it resolves swarm_tools()."member": also the member’s nested loops, such as a deepagent() member’s subagents, which then act as the member. stormStormControls-
The storm controls the bus applies to the channel’s records. By default there are none.
max_waitint | None-
This channel’s contribution to the longest
swarm_wait, in seconds, orNone(the default) for a channel whose records wake no waits. A channel that sets it opens a state that implements WaitingState. The bus’s effective maximum is the largestmax_waitof the run’s open channels that set it.
Methods
- check
-
Check the roster when swarm() is called.
def check(self, roster: Sequence[MemberInfo]) -> NonerosterSequence[MemberInfo]-
The swarm’s members.
- open
-
Open the channel’s state for one run of the swarm, before any member starts.
def open(self, run: "ChannelRun") -> "ChannelState | None"runChannelRun-
The run’s bus and roster.
- instructions
-
Text for the member’s preamble.
def instructions(self, member: MemberInfo) -> str | NonememberMemberInfo-
The member the text is for.
ChannelRun
What Channel.open() gets for one run of the swarm.
@dataclass(frozen=True)
class ChannelRunAttributes
busBus-
The run’s bus, which the channel’s tools deliver records through.
rosterSequence[MemberInfo]-
The swarm’s members.
ChannelState
A channel’s state in one run of the swarm, which only the bus changes.
The bus calls validate(), admit() and apply() with no await between them, so admit() sees the state that apply() changes.
class ChannelState(Protocol)Methods
- tools
-
The channel’s tools, which deliver records through the run’s bus.
def tools(self) -> list[Tool] - validate
-
Check a record’s payload and operation data, before the record gets an id.
def validate(self, record: Record) -> NonerecordRecord-
The record.
- admit
-
Check a record against the state as it is now, after the storm controls.
def admit(self, record: Record) -> NonerecordRecord-
The record.
- apply
-
Apply an admitted record to the state. It cannot fail.
def apply(self, record: Record) -> tuple[list[str], Mapping[str, JsonValue] | None]recordRecord-
The record.
- notice_lines
-
The lines of the member’s next notice, which they then cover.
Called at the member’s turn boundary, only when the notice will be added, so a line covers what it names: the next call leaves it out until it changes again.
def notice_lines(self, member: str) -> list[NoticeLine]memberstr-
The member the notice is for.
WaitingState
The state of a channel whose records wake waits (one that sets Channel.max_wait).
The bus calls these methods with no await around them. None of them marks anything: a loop acknowledges what a wait names by reading it with the channel’s own tool.
class WaitingState(ChannelState, Protocol)Methods
- tools
-
The channel’s tools, which deliver records through the run’s bus.
def tools(self) -> list[Tool] - validate
-
Check a record’s payload and operation data, before the record gets an id.
def validate(self, record: Record) -> NonerecordRecord-
The record.
- admit
-
Check a record against the state as it is now, after the storm controls.
def admit(self, record: Record) -> NonerecordRecord-
The record.
- apply
-
Apply an admitted record to the state. It cannot fail.
def apply(self, record: Record) -> tuple[list[str], Mapping[str, JsonValue] | None]recordRecord-
The record.
- notice_lines
-
The lines of the member’s next notice, which they then cover.
Called at the member’s turn boundary, only when the notice will be added, so a line covers what it names: the next call leaves it out until it changes again.
def notice_lines(self, member: str) -> list[NoticeLine]memberstr-
The member the notice is for.
- wait_check
-
Check a wait’s filter when the wait is called.
def wait_check(self, spec: WaitSpec) -> NonespecWaitSpec-
The wait.
- wakes
-
Whether a record the channel has just applied made something reportable to a wait.
def wakes(self, spec: WaitSpec, record: Record) -> bool - news
-
What is reportable to a wait now.
def news(self, spec: WaitSpec) -> WaitNews | NonespecWaitSpec-
The wait.
WaitSpec
One call of swarm_wait, as the bus asks a WaitingState about it.
@dataclass(frozen=True)
class WaitSpecAttributes
idstr-
The wait’s id (
"x-4"), numbered per run. memberstr-
The waiting member’s name.
loopstr | None-
The agent span of the loop that waits.
ownbool-
Whether that loop is the member’s own, not one of its subagents’.
pathstr | None-
The shared memory’s filter as the model gave it, or
Nonefor the whole board. Later channels add filters of their own.
WaitNews
What a channel has for a waiting loop to look at.
@dataclass(frozen=True)
class WaitNewsAttributes
lineslist[str]-
The channel’s lines for the wait’s result. Fixed templates with ids and member names, never content.
fileslist[dict[str, JsonValue]]-
What
linesname, for thewaitedevidence.
NoticeLine
A line of a member’s notice, which swarm_on_continue() adds at the member’s turn boundary.
@dataclass(frozen=True)
class NoticeLineAttributes
textstr-
The line: a fixed template whose only variables are counts, swarm-assigned ids and roster names, never anything a member wrote or chose.
idsMapping[str, JsonValue]-
The swarm ids the line names, such as
{"files": [{"file": "f-2", "version": 3, "record": "w-7"}]}, given asidsin the notice’s metadata and in itsnotifiedevidence.
Record
One communication through the bus: a message, a write, a claim.
A channel’s tool hands the bus a Draft; the bus makes the record, binding the sender and resolving the addresses, and gives it to the channel.
@dataclass(frozen=True)
class RecordAttributes
idstr-
The record’s id, the channel’s prefix and a per-channel number (
"w-14"). Every attempt that passes the bus’s first checks gets one, refused or not, so the ids of delivered records can skip numbers;seqin thedeliveredevidence numbers what the run delivered, across its channels. channelstr-
The name of the channel the record is for.
kindstr-
What the record does, in the channel’s terms (
"message","create"). senderstr-
The sending member’s name, bound by the runtime, never taken from model output.
totuple[str, ...]-
The addresses as written.
()for an unaddressed record, such as a write to shared state, which reaches nobody directly. recipientstuple[str, ...]-
The member names the addresses resolved to.
routed_outtuple[str, ...]-
Resolved names the channel’s routes dropped.
payloadstr-
The text the record carries.
opMapping[str, FrozenJson] | None-
The channel’s operation data, if any, as JSON that cannot be changed: objects are read-only mappings and arrays are tuples. A record is shared by the channel and the sender’s tool, so neither can change what the other sees.
wakebool-
Whether the record can end a member’s wait (
swarm_wait). reply_tostr | None-
The id of a record this one answers.
sender_span_idstr | None-
The sender’s agent span.
tool_span_idstr | None-
The tool span the call ran in.
Budget view
swarm_resources
A tool that reports the swarm’s budget to the member that calls it.
It shows the caps that will stop the swarm, how much all members have used, the member’s own share when the budget is split, and the time cap. Use it in place of a tool that reads sample_limits(), which shows the sample’s limits rather than the swarm’s caps.
@tool
def swarm_resources() -> Toolswarm_budget
The budget of the swarm the caller runs in.
Reports the swarm’s cap per kind and how much of it the whole swarm has used, and, when the budget is split and the caller is a member, the member’s share and its usage. The caps are the ones that stop the swarm, which sample_limits() does not show: the swarm holds back part of each sample limit.
def swarm_budget() -> SwarmBudgetSwarmBudget
The swarm’s budget as a member sees it, from swarm_budget().
@dataclass(frozen=True)
class SwarmBudgetAttributes
splitLiteral['pool', 'equal'] | tuple[float, ...]-
How the cost and token caps are divided between members, as
Budget.split. costBudgetUsage | None-
The cost cap in dollars, or
Nonewhen the swarm has none. tokensBudgetUsage | None-
The token cap, or
Nonewhen the swarm has none. token_typestr-
The tokens the token cap meters:
all, or a metering type such asoutput. timeBudgetUsage | None-
The time cap, and the seconds since the swarm started, or
Nonewhen the swarm has none.
BudgetUsage
One capped kind of the swarm’s budget, and what has been used of it.
@dataclass(frozen=True)
class BudgetUsageAttributes
capfloat-
The swarm’s cap: dollars, tokens or seconds.
usedfloat-
What the whole swarm has used of the cap so far.
sharefloat | None-
The member’s own share of the cap when the budget is split, else
None. Time is never split. share_usedfloat | None-
What the member has used of its share, when it has one.