How to Build a Harness

14. Tool Argument Validation

Validate LLM-provided arguments against your JSON schema.

The LLM generates JSON arguments. They might be malformed. Validate before executing.

File: packages/ai/src/utils/validation.ts L64-93

export function validateToolArguments(tool: Tool, toolCall: ToolCall): any {
  const validate = ajv.compile(tool.parameters);
  const args = structuredClone(toolCall.arguments);

  if (validate(args)) {
    return args; // Valid -- AJV may have coerced types
  }

  const errors = validate.errors?.map((err) => `  - ${err.instancePath || "root"}: ${err.message}`).join("\n");

  throw new Error(
    `Validation failed for tool "${toolCall.name}":\n${errors}\n\n` + `Received arguments:\n${JSON.stringify(toolCall.arguments, null, 2)}`
  );
}

pi uses AJV to compile TypeBox schemas into validators. When validation fails, the error message is sent back to the LLM as a ToolResultMessage with isError: true, so Claude can try again.

File: packages/agent/src/agent-loop.ts L491-493

const preparedToolCall = prepareToolCallArguments(tool, toolCall);
const validatedArgs = validateToolArguments(tool, preparedToolCall);

Open this chapter inside the full course