@luan.sh/pi-thinking-binding
Drop Anthropic thinking blocks that a system prompt or tool change has already invalidated
Package details
Install @luan.sh/pi-thinking-binding from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@luan.sh/pi-thinking-binding- Package
@luan.sh/pi-thinking-binding- Version
0.3.2- Published
- Sep 11, 2026
- Downloads
- not available
- Author
- cfcluan
- License
- MIT
- Types
- extension
- Size
- 18.8 KB
- Dependencies
- 0 dependencies · 2 peers
Pi manifest JSON
{
"extensions": [
"./src/extension.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
@luan.sh/pi-thinking-binding
A Pi extension that drops Anthropic thinking blocks a system prompt or tool
change has already invalidated, so the prefix_binding_mismatch warning
appears once instead of on every turn.
Install
pi install npm:@luan.sh/pi-thinking-binding
Nothing else is needed. The extension registers no tools, commands, settings, or keybindings, and it has no companion packages.
The problem
Anthropic binds every thinking block signature to the request prefix that
produced it: the system prompt, the tools set, and the messages before the
block. When that prefix changes, typically because an extension's tool
description or the system prompt changed and Pi was restarted into an existing
session, every earlier block is invalid. The API then drops each one on every
later turn and Pi reports
Anthropic dropped N thinking blocks: prefix_binding_mismatch for the rest of
the session.
What it does
The extension does the drop itself, once. It only acts on models whose API is
anthropic-messages; other providers are untouched.
- On each
before_provider_request, it fingerprints the request'ssystemandtools(a SHA-256 over their JSON) and compares it with the fingerprint recorded on the current session branch. - If the fingerprint is new for this branch, it records it. The first sighting in a session invalidates nothing.
- If the fingerprint differs from the recorded one, it strips
thinkingandredacted_thinkingblocks from the assistant messages in that request body and records the newest assistant message timestamp as the stale cutoff. - On later turns, the
contexthook removes thinking from assistant messages at or before the cutoff before they reach the provider. Newer reasoning is left alone. - For sessions that were already broken before a fingerprint was recorded,
the
message_endhook trusts Anthropic's ownthinking_dropped/prefix_binding_mismatchdiagnostic once and records the cutoff from it.
A message whose only content is thinking is never emptied; it is left as is.
State
State lives in the session as custom entries of type @luan.sh/pi-thinking-binding,
one per prefix change on the branch:
{ "version": 1, "fingerprint": "<sha256 hex>", "staleThrough": 1712345678901 }
staleThrough is the assistant message timestamp at or before which thinking
is dead; it is absent until the first prefix change. The newest valid entry on
the branch wins.
The session file keeps the original thinking blocks. Only the messages handed to the provider are changed, which is what the API would have done anyway.
Configuration
There is none. Behaviour is fixed in source; there are no settings, keybindings, or environment variables.
Programmatic use
@luan.sh/pi-thinking-binding exports the core functions for reuse or
testing: BINDING_ENTRY_TYPE, BindingState, fingerprintPrefix,
newestAssistantTimestamp, parseAnthropicPayload, readBindingState,
reportsPrefixMismatch, stripPayloadThinking, stripStaleThinking.
Layout
| Responsibility | File |
|---|---|
Pi registration; context, before_provider_request, message_end hooks |
src/extension.ts |
| Payload narrowing, fingerprint, state read, stale cutoff, stripping | src/core/binding.ts |
| Public exports | src/index.ts |
Develop
Source: https://github.com/luan/agents, directory
harnesses/pi/agent/packages/pi-thinking-binding. Run bun run typecheck and
bun test test in that directory.