You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
For more details on accessing state, context, and long-term memory from tools, see [Access context](#access-context).
830
830
831
+
## Headless tools
832
+
833
+
Some tools should run **where your user's app runs** (typically the browser), not inside the process. **Headless tools** are tool definitions, e.g. name, description, and argument schema, that you register on the **server** with your agent, while the **implementation** is registered only on the **client** and executed after a short interrupt/resume handshake.
834
+
835
+
This is different from ordinary tools whose function body runs on the server, and from [server-side tool use](#server-side-tool-use) where the model provider executes built-in tools remotely.
836
+
837
+
### When to use headless tools
838
+
839
+
Use them when the work depends on **environment, device, or UI** that only exists on the client:
-**Privacy and locality:** Data stays on the device (for example local “memory” in IndexedDB).
843
+
-**Latency:** No extra server round trip for purely local operations.
844
+
-**Structured, safe effects:** Prefer many small, typed tools (for example one tool per canvas primitive) instead of sending arbitrary code to `eval`.
845
+
846
+
### How the pattern works
847
+
848
+
1.**Define** the tool with `tool({ name, description, schema })` from `langchain`, metadata and validation only, no server-side runner.
849
+
2.**Implement** the real behavior with `.implement(async (args) => { ... })`, which returns a **headless tool implementation** (definition + `execute` function).
850
+
851
+
:::python
852
+
<Info>
853
+
There is no `.implement()` API for this pattern in Python. If your agent is defined in Python, you must **redefine** each headless tool on the **frontend**.
854
+
</Info>
855
+
:::
856
+
:::js
857
+
<Info>
858
+
Put **tool definitions** (`tool({ name, description, schema })`) and **implementations** (`.implement(...)`) in **separate modules**. Import the shared definition file from your server agent and from your frontend so names and schemas stay aligned; keep client-only execute logic in implementation modules the server never loads.
859
+
</Info>
860
+
:::
861
+
862
+
3.**Server agent:** Pass the **definitions** (the objects from step 1) to `createAgent` / your graph so the model sees the tools in its usual tool-calling loop.
863
+
4.**Client:** Pass the **implementations** from step 2 to your streaming hook's `tools` option (for example `useStream` from `@langchain/react`, `@langchain/svelte`, `@langchain/vue` or `@langchain/angular`).
864
+
865
+
When the model issues a tool call for one of these tools, the run **interrupts** with a small payload the SDK recognizes. The client finds the matching implementation, runs it (for example calling `navigator.geolocation` or drawing on a canvas), then **resumes** the graph with the tool result so the agent can continue. You do not need to wire that resume manually when using the supported SDK hooks—they detect headless-tool interrupts, execute the client code, and submit the resume command for you.
866
+
867
+
Use the optional **`onTool`** callback to observe lifecycle events (`start`, `success`, `error`) for UI feedback such as spinners or toasts.
868
+
869
+
### Example
870
+
871
+
Split **definitions** (shared between server and UI) from **implementations** (client-only). The server agent registers the tool so the model can call it; `useStream` registers `.implement(...)` handlers that run when the headless-tool interrupt fires.
872
+
873
+
<CodeGroup>
874
+
875
+
:::python
876
+
```python agent.py
877
+
from langchain.agents import create_agent
878
+
from langchain.tools import tool
879
+
from langchain_openai import ChatOpenAI
880
+
from langgraph.checkpoint.memory import MemorySaver
881
+
882
+
883
+
@tool
884
+
defsave_note(key: str, text: str) -> str:
885
+
"""Persist a short note in the user's browser (local only)."""
886
+
# Body is not used when the client handles the tool call; keep name, description,
887
+
# and parameters aligned with `tools.ts`.
888
+
return""
889
+
890
+
891
+
agent = create_agent(
892
+
model=ChatOpenAI(model="gpt-4o-mini"),
893
+
tools=[save_note],
894
+
checkpointer=MemorySaver(),
895
+
)
896
+
```
897
+
898
+
```ts tools.ts
899
+
import*aszfrom"zod";
900
+
import { tool } from"langchain";
901
+
902
+
/** Mirror the Python tool’s name, description, and fields for the client SDK. */
903
+
exportconst saveNote =tool({
904
+
name: "save_note",
905
+
description: "Persist a short note in the user's browser (local only).",
End-to-end demos in the LangGraph.js repo show two contrasting styles:
1001
+
1002
+
-**[Browser tools](https://github.com/langchain-ai/langgraphjs/tree/main/examples/ui-react/src/examples/browser-tools)** — IndexedDB-backed memory tools plus geolocation; geolocation is wrapped with human-in-the-loop while other tools run automatically on the client.
1003
+
-**[Canvas drawing](https://github.com/langchain-ai/langgraphjs/tree/main/examples/ui-react/src/examples/canvas-drawing)** — Many small canvas tools mapping to safe Canvas 2D operations (no arbitrary code execution).
1004
+
</Info>
1005
+
831
1006
## Prebuilt tools
832
1007
833
1008
LangChain provides a large collection of prebuilt tools and toolkits for common tasks like web search, code interpretation, database access, and more. These ready-to-use tools can be directly integrated into your agents without writing custom code.
0 commit comments