A ceiling that was a schedule, and a reply that ended in silence
Reported: an ordinary chat with a small local model researching a question well -- six searches, each one informed by the last -- stopped at the round limit and produced no answer at all. Two separate faults, and the second is the serious one. The limit was 5 and it should not have been a working number. It was 1 once, and the note beside it already said why that was wrong: a count low enough to be reached by ordinary work is a schedule, not a ceiling, and it overrides the model's judgement on every turn instead of catching a runaway. Five was the same mistake with a larger number. It is 0 now -- no ceiling, falling back to MAX_TOOL_ROUNDS as a runaway backstop, which is the shape `Limits.steps` already had for an agent chat. What bounds an ordinary chat is the context window, which is a real limit rather than a guess at how much looking-up a question deserves. An administrator who wants a ceiling can still set one. The worse fault: *every* budget ended the reply where it was noticed. That is survivable for a model that narrates as it works and produces nothing at all for one that goes straight to tool calls -- an empty bubble with a red line under it, and everything it had gathered thrown away. `_wrap_up` withdraws the tools and asks once more instead. What it found is in the transcript either way; one request turns it into an answer. Same move `plan_submit` makes, and the reason the loop now runs to `budget + 2`: the round at the budget notices, the one after it answers. The event stays, because an answer the model chose to give and one it gave because it ran out of room read identically otherwise. `_too_big` is the one exception and stays a hard stop. It *is* the finding that there is no room for another request, so a wrap-up round would be the same overflow with an upstream error in place of an explanation. `core.keep_working` was gated on the agent family and is now gated on `unbounded`, the exact complement of `round_budget` -- so an ordinary chat with no ceiling is told to work until the job is done rather than being told nothing, and is never told it has a budget of two hundred, which it would ration. The regression test asserts the reply is not empty, and fails with `'' == 'Here is what I found.'` against the old code -- which is exactly what was seen. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -131,9 +131,20 @@ VARIABLES: tuple[Variable, ...] = (
|
||||
Variable(
|
||||
"round_budget",
|
||||
"Round budget applies",
|
||||
"Set in an ordinary chat and blank in an agent chat. Nothing renders it; "
|
||||
"it exists so a fragment can say `requires=('round_budget',)` and appear "
|
||||
"for one and not the other.",
|
||||
"Set when an administrator has put a ceiling on an ordinary chat's tool "
|
||||
"rounds, and blank otherwise — including in every agent chat. Nothing "
|
||||
"renders it; it exists so a fragment can say "
|
||||
"`requires=('round_budget',)` and appear only where there is a budget "
|
||||
"worth planning within.",
|
||||
),
|
||||
Variable(
|
||||
"unbounded",
|
||||
"No round budget",
|
||||
"The exact complement of the one above: set whenever `round_budget` is "
|
||||
"blank. Nothing renders this either. Two gates rather than one because "
|
||||
"what is worth telling a model with a budget and what is worth telling "
|
||||
"one that should work until the job is done are different sentences, "
|
||||
"not the same sentence with a different number in it.",
|
||||
),
|
||||
Variable(
|
||||
"memory_limit",
|
||||
@@ -656,18 +667,22 @@ BUILTIN: tuple[Fragment, ...] = (
|
||||
label="Working until it is done",
|
||||
group=GROUP_CORE,
|
||||
order=111,
|
||||
families=("agent",),
|
||||
hint="An agent chat only, and the counterpart to the round budget above. "
|
||||
"A model told it has a budget rations it and stops early to report "
|
||||
"progress; the step count here is a runaway backstop, not an "
|
||||
"allowance, and saying so is what makes a long piece of work run.",
|
||||
when_tools=True,
|
||||
requires=("unbounded",),
|
||||
hint="The counterpart to the round budget above, and exactly one of the "
|
||||
"two ever appears: `unbounded` is set precisely when `round_budget` is "
|
||||
"not. A model told it has a budget rations it and stops early to report "
|
||||
"progress; where the number is a runaway backstop rather than an "
|
||||
"allowance, saying so is what makes a long piece of work run. An agent "
|
||||
"chat always gets this one; an ordinary chat gets it whenever an "
|
||||
"administrator has set no ceiling, which is now the default.",
|
||||
default=(
|
||||
"Keep working until the task is actually done. You are not rationing a "
|
||||
"round budget: call tools as many times as the work needs, one step "
|
||||
"informing the next. What ends a reply is finishing it, being stopped, or "
|
||||
"running past the time and output an administrator allowed — and if that "
|
||||
"happens you are told so and can be asked to carry on. Do not stop halfway "
|
||||
"to report progress and wait to be told to continue."
|
||||
"running out of room — and if you run out you are told so, asked for an "
|
||||
"answer from what you have, and can be asked to carry on afterwards. Do "
|
||||
"not stop halfway to report progress and wait to be told to continue."
|
||||
),
|
||||
),
|
||||
Fragment(
|
||||
|
||||
Reference in New Issue
Block a user