bindClientTools() is the main helper from @threadplane/middleware/langgraph. It binds your server tools plus the current run's client-tool catalog onto a LangChain chat model.
import { bindClientTools, clientToolsChannel, clientToolsRouter,} from '@threadplane/middleware/langgraph';
There is no root JavaScript entry point for @threadplane/middleware; import from the /langgraph subpath. The Python package exposes equivalent snake_case helpers from threadplane.middleware.langgraph.
The routing helpers in the same entry point include clientToolsChannel(), clientToolsRouter(), clientToolSpecs(), clientToolNames(), hasClientToolCall(), hasServerToolCall(), routeAfterAgent(), and lastMessage(). The entry point also exports client-tool execution stores; Introduction lists the supported surface and explains the breaking removal of the receipt helpers.
bindClientToolsfunction
Bind server tools + the client catalog stubs onto `llm`. Call this INSIDE the
agent node (per-run) — the client catalog arrives in state and may differ per run.
bindClientTools(llm: M, serverTools: unknown[], state: ClientToolsState): ReturnType<M["bindTools"]>
Parameters
Parameter
Type
Description
llm
M
serverTools
unknown[]
state
ClientToolsState
Returns
ReturnType<M["bindTools"]>
clientToolsChannelfunction
State channels for the client-tools catalog. Spread into Annotation.Root so a graph
declares the `tools` (primary) and `client_tools` (fallback) slices in one line:
const State = Annotation.Root({ ...MessagesAnnotation.spec, ...clientToolsChannel() });
Both are last-value-wins channels (the catalog is replaced per run, not accumulated).
clientToolsChannel(): object
Returns
object
clientToolsRouterfunction
A prebuilt conditional-edge callback. serverToolNames is bound once at construction;
the returned function takes only state.
graph.addConditionalEdges('agent', clientToolsRouter(names), ['server_tools', END]);
`opts.toolsNode` defaults to `'server_tools'`; a graph carrying the client-tool
channels cannot name a node `tools`, because clientToolsChannel already
claims that name as a state channel.
True if the last message calls at least one server (non-client) tool.
A call is server-side when its name is in serverToolNames OR is not a known
client tool (unknown tools are assumed server-side).
Routing helper for a LangGraph conditional edge. Returns `toolsNode` when the last
message has a server tool call (dispatch to the server ToolNode); otherwise `end`
(client-only calls — the browser executes them — and no-tool-call turns both end).
`toolsNode` defaults to `'server_tools'`. It cannot default to `'tools'`, because
clientToolsChannel declares a `tools` state channel and LangGraph.js shares
one namespace between channel names and node names — `addNode('tools', …)` throws
"tools is already being used as a state attribute".