Summary
defineAgent modifies the object passed in by the caller: it reassigns def.steps when folding an agent-level inputSchema, and attaches AGENT_DEFINITION_BRAND via Object.defineProperty directly on def. Both mutations are visible on the caller's original reference.
Root Cause
packages/agent/src/agent.ts:
// Mutation 1: reassigns def.steps on the CALLER'S object
(def as { steps: ... }).steps = {
...def.steps,
[def.entry]: { ...entryStep, inputSchema: def.inputSchema },
};
// Mutation 2: brand attached to caller's object
Object.defineProperty(def, AGENT_DEFINITION_BRAND, { value: 1, enumerable: false });
Reproduction
const myDef = {
name: 'x', entry: 'start',
inputSchema: z.object({ name: z.string() }),
steps: { start: myStep },
};
const originalSteps = myDef.steps;
defineAgent(myDef);
console.log(myDef.steps === originalSteps); // false mutated
console.log(isAgentDefinition(myDef)); // true brand on original object
Fix
Operate on a shallow copy instead of mutating the input:
const result = { ...def };
result.steps = { ...def.steps, [def.entry]: { ...entryStep, inputSchema: ... } };
Object.defineProperty(result, AGENT_DEFINITION_BRAND, { value: 1, enumerable: false });
return result;
Summary
defineAgentmodifies the object passed in by the caller: it reassignsdef.stepswhen folding an agent-levelinputSchema, and attachesAGENT_DEFINITION_BRANDviaObject.definePropertydirectly ondef. Both mutations are visible on the caller's original reference.Root Cause
packages/agent/src/agent.ts:Reproduction
Fix
Operate on a shallow copy instead of mutating the input: