/** * Agent validators — pure helper functions extracted from Agent.ts. * * These run at Agent construction time (eagerly, so misconfiguration * fails fast at `.build()`) and during stage execution (safeStringify * for tool-result formatting). * * Pure functions, no class state — extracted for readability and * isolated testability. The Agent class imports + invokes these in * its constructor and stage handlers. */ import type { MemoryDefinition } from '../../memory/define.types.js'; import type { Injection } from '../../lib/injection-engine/types.js'; import type { ToolRegistryEntry } from '../tools.js'; /** * Validate that every memory definition has a unique id. Each memory * writes to its own scope key (`memoryInjection_${id}`); duplicates * silently overwrite, leading to data loss that's hard to debug. * * Throws on collision so `Agent.build()` fails fast at construction. */ export declare function validateMemoryIdUniqueness(memories: readonly MemoryDefinition[]): void; /** * Validate `maxIterations`. The historical silent clamp to 50 existed because * footprintjs's recursive traversal hit its depth wall around iteration 71 — * footprintjs 9.0.0's trampoline removed that wall (loops run on a flat * stack), so the cap is gone. The lower bound (1) still prevents a * 0-iteration agent; large values are the consumer's COST choice (each * iteration is an LLM call) — a dev-mode warning flags budgets above 100. * The Agent passes matching headroom to the engine's own loop-iteration * limit so it can never fire below the agent's budget. */ export declare function clampIterations(n: number): number; /** * Validate tool-name uniqueness across `.tool()`-registered tools + * every Skill's `inject.tools[]`. The LLM dispatches by `tool.schema.name` * (the wire format), so any collision silently shadows execution. * * Called eagerly in the Agent constructor so `Agent.build()` throws * immediately, not on first `run()`. * * `read_skill` is reserved when ≥1 Skill is registered — collisions * with consumer tools throw. */ export declare function validateToolNameUniqueness(registry: readonly ToolRegistryEntry[], injections: readonly Injection[]): void; /** * What a tool that returned nothing puts in the conversation. * * Self-describing on purpose: the model reads this string as the tool's * result, and it has to be able to tell "this tool does not report a value" * apart from "this tool returned the word undefined". `''` would say neither. */ export declare const NO_TOOL_VALUE = "(this tool returned no value)"; /** * JSON.stringify with circular-ref protection. Tool results are untrusted — * a hostile/buggy tool returning a cyclic object must not crash the run. * Falls back to '[unstringifiable: ]' so the LLM still sees that * the tool ran and produced something unusable. * * **Total, since 8.18.0.** `JSON.stringify` returns `undefined` — not a * string — for `undefined`, a function and a symbol, so the old body's * `: string` was a promise it could not keep. An `async execute()` that did * its work and forgot to `return` produced a `role: 'tool'` message with * `content: undefined`, which crashed the next turn's messages slot with an * anonymous `TypeError` five frames inside the engine. A tool is allowed to * do something and report nothing; the conversation just has to say so. * * The truth is unaffected: `agentfootprint.stream.tool_end` still carries * the tool's REAL return value, `undefined` included. */ export declare function safeStringify(value: unknown): string;