What happened?
TexeraAgent caps its ReAct loop with stopWhen: stepCountIs(this.settings.maxSteps) (texera-agent.ts:529). In ai@7.0.48 that predicate is an equality test, not a ceiling:
// node_modules/ai/dist/index.js:4655
function isStepCount(stepCount) {
return ({ steps }) => steps.length === stepCount;
}
It is evaluated after a step has run, so steps.length is always at least 1. With maxSteps: 0 the predicate is therefore never satisfied and the cap is silently disabled — a model that keeps emitting tool calls is never stopped by it. (A model that returns a plain text answer still terminates, because the loop ends on its own when there are no tool calls to service. The failure needs a tool-calling model, which is the normal case here.)
Nothing rejects the value. updateSettings assigns it unchecked:
// texera-agent.ts:379
if (updates.maxSteps !== undefined) {
this.settings.maxSteps = updates.maxSteps;
}
and the HTTP settings endpoint declares it as maxSteps: t.Optional(t.Number()) (server.ts:244) with no minimum, so any client can turn the cap off. The default is 100, so this only bites when a value is supplied.
Negative values have the same problem for the same reason.
How to reproduce?
- Start the agent service and connect a client.
- Update the agent settings with
maxSteps: 0 (accepted — no validation rejects it).
- Send a message that leads the model to keep calling tools.
- The loop is never stopped by the step cap.
Reproducing it in a unit test is possible but do not add one: because the run never ends, the test hangs the suite rather than failing it. This surfaced while writing coverage for sendMessage, and it is noted in that spec so nobody tries.
Version/Branch
1.3.0-incubating-SNAPSHOT (main)
Expected behavior
maxSteps should be validated at both boundaries — rejected at the API schema (t.Number({ minimum: 1 })) and clamped or rejected in updateSettings — so the cap cannot be disabled by configuration. Alternatively stopWhen should use a >= comparison rather than the SDK's equality predicate, which would also make the cap robust to a step count that overshoots.
Additional context
Found while raising texera-agent.ts coverage from 51% to 99.8%. The reachable-but-untestable nature of this path is the reason no regression test accompanies the report.
What happened?
TexeraAgentcaps its ReAct loop withstopWhen: stepCountIs(this.settings.maxSteps)(texera-agent.ts:529). Inai@7.0.48that predicate is an equality test, not a ceiling:It is evaluated after a step has run, so
steps.lengthis always at least 1. WithmaxSteps: 0the predicate is therefore never satisfied and the cap is silently disabled — a model that keeps emitting tool calls is never stopped by it. (A model that returns a plain text answer still terminates, because the loop ends on its own when there are no tool calls to service. The failure needs a tool-calling model, which is the normal case here.)Nothing rejects the value.
updateSettingsassigns it unchecked:and the HTTP settings endpoint declares it as
maxSteps: t.Optional(t.Number())(server.ts:244) with no minimum, so any client can turn the cap off. The default is 100, so this only bites when a value is supplied.Negative values have the same problem for the same reason.
How to reproduce?
maxSteps: 0(accepted — no validation rejects it).Reproducing it in a unit test is possible but do not add one: because the run never ends, the test hangs the suite rather than failing it. This surfaced while writing coverage for
sendMessage, and it is noted in that spec so nobody tries.Version/Branch
1.3.0-incubating-SNAPSHOT (main)
Expected behavior
maxStepsshould be validated at both boundaries — rejected at the API schema (t.Number({ minimum: 1 })) and clamped or rejected inupdateSettings— so the cap cannot be disabled by configuration. AlternativelystopWhenshould use a>=comparison rather than the SDK's equality predicate, which would also make the cap robust to a step count that overshoots.Additional context
Found while raising
texera-agent.tscoverage from 51% to 99.8%. The reachable-but-untestable nature of this path is the reason no regression test accompanies the report.