agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
52 lines • 2.73 kB
TypeScript
/**
* AnthropicThinkingHandler — normalizes Anthropic's extended-thinking
* response shape into the framework's `ThinkingBlock[]` contract.
*
* Anthropic emits thinking via blocks in `response.content`:
*
* ```ts
* { type: 'thinking', thinking: 'reasoning text', signature: 'opaque-base64' }
* { type: 'redacted_thinking', data: 'opaque-encrypted' }
* { type: 'text', text: 'visible content' }
* { type: 'tool_use', id, name, input }
* ```
*
* The handler filters for `'thinking'` + `'redacted_thinking'` blocks,
* preserves the `signature` field BYTE-EXACT (Anthropic validates
* signatures server-side on the next turn — any modification = HTTP 400),
* and ignores other block types (visible text + tool calls flow through
* the existing `LLMResponse.content` / `LLMResponse.toolCalls` paths).
*
* The same shapes in both thinking modes (budget and adaptive). Two
* adaptive-mode facts the echo already honours: a turn may carry NO
* thinking block (the model chose not to think), and a block's `thinking`
* text may be EMPTY — `display: 'omitted'`, the default on Claude 4.7 and
* later when the request does not ask to think (`.thinking()` asks for
* `'summarized'`), and the progress notes some models write between tool
* calls. An empty block is still complete — its `signature` carries the
* reasoning — so it is kept and echoed like any other, never dropped.
*
* **Critical invariant:** signature pass-through is byte-exact. The
* handler MUST NOT trim, normalize encoding, JSON-roundtrip, or
* otherwise touch the signature string. Tests verify this explicitly.
*
* **Three input shapes** Anthropic produces (per Phase 4a panel review):
* 1. Non-streaming response: full `response.content` array
* 2. Streaming aggregated: AnthropicProvider accumulates chunks +
* calls handler with the same array shape
* 3. Bedrock-via-Anthropic: deferred to Phase 5+ (separate handler
* or extension of this one)
*
* Streaming + non-streaming converge on shape #1 because the provider
* handles the distinction — handler only sees the assembled content
* array.
*
* **`parseChunk` is OPTIONAL** — Phase 3's framework path populates
* `LLMChunk.thinkingDelta` from inside AnthropicProvider's `stream()`
* directly, bypassing handler.parseChunk. We still implement it for
* consumer integrations that want to use the handler on raw Anthropic
* chunks directly (e.g., custom transports).
*/
import type { ThinkingHandler } from './types.js';
export declare const anthropicThinkingHandler: ThinkingHandler;
//# sourceMappingURL=AnthropicThinkingHandler.d.ts.map