Skip to content

Tool middleware ​

Tool middleware applies cross-cutting controls after a handler returns but before its result goes back to the model. This example replaces oversized text with a compact reference.

ts
import { writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { Agent, createMiddleware } from '@anvia/core'

const outputGate = createMiddleware({
  async onToolOutput({ toolName, result, internalCallId }) {
    if (result.length <= 1_000) {
      return undefined
    }

    const file = join(tmpdir(), `${toolName}-${internalCallId}.txt`)
    await writeFile(file, result, 'utf8')

    return JSON.stringify({
      type: 'file_reference',
      reason: 'tool_output_too_large',
      chars: result.length,
      path: file,
    })
  },
})

const agent = new Agent({
  id: 'analyst',
  model,
  instructions: 'Use tools when useful. Summarize results briefly.',
  middlewares: [outputGate],
  maxTurns: 2,
  tools: [longReportTool],
})

const result = await agent.generate({
    prompt: 'Create a short update from the onboarding report.'
})

Returning undefined preserves the original serialized result. Returning a string replaces what the model receives. Middleware can also redact secrets, normalize output, enforce size limits, or create durable references consistently across tools.

The temporary-file example is only suitable for a local demonstration. In distributed production, write to tenant-scoped storage, return an opaque authorized ID, apply expiry and deletion, and never let the model choose storage paths or fetch arbitrary references.

Continue with tool middleware.

Built for Anvia.