# Server tools and modalities

> Field reference for governed web_search/web_fetch tools, context-window compression, document ingestion, and the audio/image/realtime-voice input gates.

Every block on this page is off by default (strict opt-in) and each governs one specific extension to the standard chat path: tool execution, prompt compression, or a non-text input modality.

## Server tools

The Server Tools block lets the gateway itself execute Web Search and Web Fetch tool calls inside the request, so the model can pull in live information without your application having to implement or govern that tool call itself. The model emits a tool call, the gateway runs it under OPA, per-surface domain policy, the SSRF guard, metering, and governance, injects the result, and re-invokes the model. A model-initiated fetch is no less controlled than any other request.

- Turn on Web Search when the model needs to look things up; turn on Web Fetch when it needs to retrieve a specific known URL. Dropping either node onto the canvas is what turns it on; there’s no separate master switch.

- Pick a Domain Policy based on which list is shorter for your use case: Allow all (block-list) when you mostly trust the open web and just want to exclude a few domains; Block all (allow-list) when the model should only ever reach a small, known set of domains.

- Choose a search engine based on what you already have an account with; Tavily is the default if you don’t have a preference.

| Field | What it does | Default |
| Max Tool Iterations | Maximum model⇄tool round-trips before the loop stops, bounding cost and latency. Dashboard label: “Max tool iterations”. Shown only on the Web Search node’s panel (not on Web Fetch); its value is what’s saved for this field regardless of which tool node set it. | 3 |
| Web Search | Web Search tool configuration (below). Represented on the canvas by the “Web Search” node (dropping it on enables the tool). | Not set |
| Web Fetch | Web Fetch tool configuration (below). Represented on the canvas by the “Web Fetch” node (dropping it on enables the tool). | Not set |

Web Search fields:

| Field | What it does | Default |
| Enabled | Per-tool switch. Dashboard label: “Enabled”. | Off |
| Search Engine | Search engine, picked from a dropdown: Tavily, Brave, or Google. Dashboard label: “Search engine”. | Tavily |
| Engine API Key | Secret id holding the engine API key. Dashboard label: “Engine API key” (a secret picker, not a text field). Tavily, Brave, and Google each issue this from their own separate developer console. Create an account and an API key with whichever engine you select here, then create a secret on the Secrets page holding it before referencing it from this picker. | Not set |
| Max Results | Maximum results returned. Dashboard label: “Max results”. | 5 |
| Google Programmable Search ID (cx) | Google Programmable Search Engine id (cx). Required when the search engine is Google. Dashboard label: “Google Programmable Search id (cx)”. Created in Google’s Programmable Search Engine console, separately from the API key above. | Not set |
| Domain Policy | Domain-policy baseline, chosen between radio options (below) under a card headed “Baseline”. | Allow all |
| Domain Exceptions | Exception domains read against the domain policy, suffix-matched (example.com also covers docs.example.com). Not a field with a fixed label in the dashboard. It’s a list editor under a heading that switches between “Blocked domains” (allow-all baseline) and “Allowed domains” (block-all baseline). | None added |

Web Fetch fields:

| Field | What it does | Default |
| Enabled | Per-tool switch. Needs no external API key. Dashboard label: “Enabled”. | Off |
| Max Content Size (KB) | Cap on fetched page content passed back to the model. Dashboard label: “Max content size (KB)”. The field is entered and displayed in KB in the UI, then stored as bytes. | 60 KB |
| Domain Policy | Domain-policy baseline, chosen between radio options. Dashboard label: “Domain policy”. | Allow all |
| Domain Exceptions | Exception domains, suffix-matched. Not a field with a fixed label in the dashboard. Same dynamic “Blocked domains” / “Allowed domains” list editor as the Web Search tool. | None added |

Domain policy values:

| Value | Meaning |
| allow_all (default) | Allow every domain except those in the exceptions list (a block-list). |
| block_all | Block every domain except those in the exceptions list (an allow-list). |

## Context management

The Context Management block guards against an over-long conversation failing once it exceeds the model’s context window: instead of an error, older messages are trimmed to make room before the upstream call, while the most recent turns and every system message are preserved.

- Set Context Window (Tokens) to your upstream model’s real window size. Without it, compression is a no-op even when requested, since there’s no budget to compress against.

- Turn on Auto-Compress Over-Window Prompts if you want this to happen automatically for any request that would exceed the window; leave it off if you’d rather have callers opt in explicitly via their own transforms field.

- Raise Keep Recent Messages if your use case depends on more than the last few turns staying verbatim. The rest of the budget is still filled from the middle of the conversation outward.

| Field | What it does | Default |
| Auto-Compress Over-Window Prompts | Auto-apply “middle-out” compression when a request would exceed the window, even if the caller did not ask for it. A request’s explicit transforms field always overrides this (an empty list disables compression for that request). Dashboard label: “Auto-compress over-window prompts (middle-out)” (this dashboard block is under LLM configuration → “Context Window Management”). | Off |
| Context Window (Tokens) | The upstream model’s context window, in tokens. Operator-provided. There is no universal per-model catalogue for this. The compression budget is this minus the reserved output tokens (below). Dashboard label: “Context window (tokens)”. | Not set |
| Keep Recent Messages | Always preserve the last N messages (the most recent turns). Dashboard label: “Keep recent messages”. | 4 messages |
| Reserve Output Tokens | Tokens reserved for the completion when the request does not name a max-tokens value, so the prompt budget leaves room for the reply. Dashboard label: “Reserve output tokens”. | 1,024 tokens |

When compression runs, messages are dropped from the middle of the conversation (expanding outward from the centre) until the prompt fits the budget, preserving every system/developer message and the configured number of most-recent messages, matching OpenRouter’s middle-out semantics.

## Document ingestion

The Document Ingestion block recognizes inline document parts a caller attaches to a chat message and, when the gateway can parse the type locally, extracts the text and injects it as ordinary prompt content, routed through the same PII masking, guardrails, and context-window guard as any other prompt text. The surface itself never has to be document-aware.

- auto, the default, extracts whatever types the gateway can parse locally and forwards the rest untouched; it stays the safest choice as new parsing engines land over time.

- extract requires every allowed type to parse successfully: an unparseable document becomes an error instead of silently passing through.

- Use passthrough when you’re forwarding to a document-native upstream that should receive the file as-is; the allow-list and size cap still apply.

| Field | What it does | Default |
| Accept And Extract Attached Documents | Master switch. When off, document parts pass through untouched. Dashboard label: “Accept and extract attached documents”. | Off |
| Allowed Document Types | Allow-list of document types accepted, picked from a list. An inline document of any other type is rejected (fail-closed). PDF is a recognized type but not yet a local-parse engine. Dashboard label: “Allowed document types”. | Text, Markdown, CSV, JSON, DOCX |
| Max File Size (MB) | Maximum decoded size of a single inline document. Dashboard label: “Max file size (MB)”. Entered in MB, stored as bytes. | 5 MiB |
| Max Extracted Characters | Maximum extracted characters injected per document; longer text is truncated with a marker. Dashboard label: “Max extracted characters”. | 100,000 characters |
| Mode | Extraction strategy, picked from a dropdown (below). Dashboard label: “Mode”. | Auto |

Extraction strategies:

| Value | Behaviour |
| auto (default) | Extract types the gateway can parse locally; forward the rest untouched. Forward-compatible as new parsing engines land. |
| extract | Extract every allowed type; error if a type cannot be parsed locally. |
| passthrough | Never extract; leave file parts as-is (forward to a document-native upstream). Still enforces the allow-list and size cap. |

A DOCX file is itself a ZIP archive of XML parts, so the DOCX engine applies entry-count, declared-size, and compression-ratio guards against ZIP-bomb inputs.

## Audio input

The Audio Input block is off by default, strict opt-in. When absent or disabled, the surface rejects inline audio parts.

| Field | What it does | Default |
| Accept Audio Files | Master switch. Dashboard label: “Accept audio files”. | Off |
| Accepted Formats | Accepted audio container formats, picked from a list. Dashboard label: “Accepted formats”. | The backend-published audio format set |
| Max Total Audio (MB) | Cap on total decoded audio in a single request, mirroring the audio-input ceiling of the major providers. Dashboard label: “Max total audio (MB)”. Entered in MB, stored as bytes. | 25 MiB |

When enabled, audio is additionally gated on the target model being audio-capable (resolved from the catalogue); every declared format must be in the accepted-formats list. Governance records never store the raw base64 audio, only a digest plus the text-extracted prompt.

## Image input

The Image Input block is off by default, strict opt-in. When absent or disabled, the surface rejects inline image parts.

| Field | What it does | Default |
| Accept Image Files | Master switch. Dashboard label: “Accept image files”. | Off |
| Accepted Inline Formats | Accepted inline (data:) image formats, picked from a list. Dashboard label: “Accepted inline formats”. | The backend-published image format set |
| Max Total Inline Images (MB) | Cap on total decoded inline-image bytes in a single request. Dashboard label: “Max total inline images (MB)”. Entered in MB, stored as bytes. | 20 MiB |

Format and size checks apply only to inline data: images the gateway can inspect; a remote image URL is forwarded as-is once image input is enabled, since it cannot be inspected without fetching it.

## Realtime voice (Mode C)

The Realtime block is off by default. When absent or disabled, the surface refuses a realtime WebSocket upgrade. Enabling it turns a surface into a live, bidirectional voice session instead of a request/response chat call. Every turn is still authenticated and authorized exactly like the chat path, and each committed exchange is written to the surface’s governance hash chain the same way a text call would be.

- A voice surface that needs the same Judge/Jury protection as text should turn on Review realtime model replies (the Safety sub-section); it reuses your existing Judge/Jury configuration rather than a separate one.

- Set Max Session Length based on how long a legitimate session should realistically run; it’s a hard ceiling so a stuck socket can’t pin resources indefinitely.

- Configure Audio Streams if you want callers to hear something during a safety hold or on a blocked/failed turn, rather than dead air.

| Field | What it does | Default |
| Enable Realtime Voice | Master switch. A surface accepts a realtime upgrade only when this is set, and only for a realtime-capable model. Dashboard label: the Audio Stream node’s sidebar switch reads “Enable realtime voice”; the same field’s switch inside the full-page editor reads “Realtime voice (streaming)”. | Off |
| Max Session Length (Seconds) | Hard ceiling on session wall-clock duration, so a stuck socket cannot pin resources indefinitely. Clamped to a sane band at connection open. Dashboard label: “Max session length (seconds)”. | 600 seconds (10 minutes) |
| Voice (Optional) | Optional default voice hint forwarded to the provider session. Dashboard label: “Voice (optional)”. | Not set |
| Safety | Per-turn voice safety (Judge on input + Jury on output); reuses the surface’s own Judge/Jury configuration. Not a single labeled field in the dashboard. It’s a sub-section headed “Realtime response safety”, whose own enable switch reads “Review realtime model replies”, with an “Enforcement” mode selector and a “Refusal message” text field nested inside. | Off |
| Audio Streams | Pre-recorded clip playback: escalating filler audio during a safety hold, a refusal clip on a blocked turn, and an “on fail” clip on an upstream error. Clip ids reference the shared audio-stream catalogue. Dashboard label: “Audio streams” (section heading in the full-page editor). | Not set |

A realtime session is authenticated and authorized exactly like the chat path (source auth + OPA), then segmented into attestable turns: one committed user input → one assistant response, each written as a signed governance record on the surface’s existing hash chain, with the user audio persisted to a content-addressed multimedia store (a hash-only reference is kept in the record).

## Related

- [Core configuration](/products/affinidi-trust-fabric/agent-stream/reference/surfaces/surface-reference.md): Where these blocks sit on a surface, and the reasoning-token governor, the sibling limit for reasoning-token spend.

- [Routing and variants](/products/affinidi-trust-fabric/agent-stream/reference/surfaces/routing-and-variants.md): The modality routing-rule match kind, which routes on the same modalities gated here.

- [Guardrails](/products/affinidi-trust-fabric/agent-stream/reference/surfaces/guardrails.md): The Judge/Jury configuration a realtime voice surface reuses for turn-by-turn review.
