Skip to main content
A response handler runs after a successful call and returns whatever the model should actually see. It is the context-economy hook: an API that returns 40KB of envelope for one useful string costs the model its window on every call. Across 536 measured runs the packs’ own handlers were the difference between 33-35KB of payload per run and 7.7-8.4KB reaching the model. See context window for how to find the tool that needs one.

ResponseHandler

An async callable taking the decoded payload and returning the result of the tool call. Passed to Tool(response_handler=...) or to a factory’s builder. Four properties of when it runs:
  • Only on success. HTTP failures and declared envelope failures have already raised, so a handler never sees an error payload.
  • It must be async def. A non-async callable raises DeclarationError at build time, naming the function.
  • It is timed separately. Its cost lands in ToolCall.handler_ms, and what it returns is what context_bytes measures — so the saving is visible.
  • It is per tool. The shape of one endpoint’s response is not the shape of another’s.
Two cautions when trimming a list endpoint: keep whatever a Pagination declaration reads — the object id behind a derived cursor, and has_more even when it is False — and keep whatever the model needs to make the next call, which is usually an id it would otherwise have to guess.

decode_base64url

Decode a base64url string to UTF-8 text, padding it first.
str
required
The encoded string. APIs that hand back base64url almost never pad it — Gmail, JWT segments, Microsoft Graph attachments — and base64.urlsafe_b64decode requires padding, so this adds it back.
str
default:"\"replace\""
Passed to bytes.decode. The default degrades rather than raising, because a handler should not fail a whole call over one malformed part.

html_to_text

Flatten HTML to readable plain text. Drops script, style, head and title content, turns block-level tags into line breaks, decodes character entities, and collapses runs of blank lines. Malformed input degrades to the stripped raw markup rather than raising. Stdlib-only, on purpose: an HTML-to-text pass this shallow does not justify a parser dependency.
Both functions exist because they are the two decodings response handlers keep needing — anything carrying user-authored content: Gmail messages, Notion blocks, Zendesk tickets, Intercom conversations.
  • What a call cost — measuring what a handler saved
  • Packs — handlers written against eleven real APIs