langchain-claude-cli 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- langchain_claude_cli-0.1.0/.gitignore +7 -0
- langchain_claude_cli-0.1.0/LICENSE +21 -0
- langchain_claude_cli-0.1.0/PKG-INFO +211 -0
- langchain_claude_cli-0.1.0/README.md +187 -0
- langchain_claude_cli-0.1.0/langchain_claude_cli/__init__.py +27 -0
- langchain_claude_cli-0.1.0/langchain_claude_cli/_compat.py +20 -0
- langchain_claude_cli-0.1.0/langchain_claude_cli/_convert.py +394 -0
- langchain_claude_cli-0.1.0/langchain_claude_cli/_sessions.py +106 -0
- langchain_claude_cli-0.1.0/langchain_claude_cli/chat_models.py +1109 -0
- langchain_claude_cli-0.1.0/langchain_claude_cli/tools.py +46 -0
- langchain_claude_cli-0.1.0/pyproject.toml +82 -0
- langchain_claude_cli-0.1.0/tests/__init__.py +0 -0
- langchain_claude_cli-0.1.0/tests/integration_tests/__init__.py +0 -0
- langchain_claude_cli-0.1.0/tests/integration_tests/test_e2e.py +305 -0
- langchain_claude_cli-0.1.0/tests/unit_tests/__init__.py +0 -0
- langchain_claude_cli-0.1.0/tests/unit_tests/test_chat_models.py +220 -0
- langchain_claude_cli-0.1.0/tests/unit_tests/test_convert.py +248 -0
- langchain_claude_cli-0.1.0/tests/unit_tests/test_sessions.py +81 -0
- langchain_claude_cli-0.1.0/tests/unit_tests/test_standard.py +23 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Charly López (clriesco@gmail.com)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: langchain-claude-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Drop-in ChatAnthropic replacement backed by the Claude Code CLI — use your Claude Pro/Max subscription, no API key needed
|
|
5
|
+
Project-URL: Homepage, https://github.com/clriesco/langchain-claude-cli
|
|
6
|
+
Project-URL: Issues, https://github.com/clriesco/langchain-claude-cli/issues
|
|
7
|
+
Author-email: Charly López <clriesco@gmail.com>
|
|
8
|
+
License: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: anthropic,claude,claude-agent-sdk,claude-code,langchain
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Requires-Dist: claude-agent-sdk<0.3,>=0.2.115
|
|
22
|
+
Requires-Dist: langchain-core<2.0.0,>=1.0.0
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# langchain-claude-cli
|
|
26
|
+
|
|
27
|
+
**Drop-in replacement for `ChatAnthropic`** that runs on the Claude Code CLI — use your Claude Pro/Max subscription, **no API key needed**.
|
|
28
|
+
|
|
29
|
+
Built on the official [`claude-agent-sdk`](https://pypi.org/project/claude-agent-sdk/) (≥ 0.2.115). Real tool calling via in-process MCP, native structured output, native extended thinking, real token usage — no prompt-injection hacks.
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install langchain-claude-cli
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Quick Start
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
from langchain_claude_cli import ChatClaudeCli
|
|
39
|
+
|
|
40
|
+
# Just like ChatAnthropic, but no API key
|
|
41
|
+
llm = ChatClaudeCli(model="claude-sonnet-4-5")
|
|
42
|
+
response = llm.invoke("What is the capital of France?")
|
|
43
|
+
print(response.content)
|
|
44
|
+
print(response.usage_metadata) # real token usage, including cache tokens
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Prerequisites
|
|
48
|
+
|
|
49
|
+
- **Claude Code CLI** installed and authenticated: `npm install -g @anthropic-ai/claude-code`, then `claude` → log in
|
|
50
|
+
- **Claude Pro or Max subscription**
|
|
51
|
+
- Python ≥ 3.10, Node.js ≥ 18
|
|
52
|
+
|
|
53
|
+
## Feature parity with ChatAnthropic
|
|
54
|
+
|
|
55
|
+
Every `ChatAnthropic` constructor parameter is accepted — nothing breaks on migration. Parity comes in three levels:
|
|
56
|
+
|
|
57
|
+
### 🟢 Level A — Native
|
|
58
|
+
|
|
59
|
+
| Feature | Notes |
|
|
60
|
+
|---|---|
|
|
61
|
+
| `invoke` / `ainvoke` / `stream` / `astream` / `batch` | Real token-by-token streaming |
|
|
62
|
+
| Tool calling (`bind_tools`) | **Classic LangChain pattern**: model returns `AIMessage.tool_calls` without executing. Parallel tool calls supported |
|
|
63
|
+
| `with_structured_output` | CLI-native JSON-schema enforcement (`output_format`) |
|
|
64
|
+
| Extended thinking | Same config dict as ChatAnthropic: `thinking={"type": "enabled", "budget_tokens": N}` — plus `{"type": "adaptive"}` |
|
|
65
|
+
| `effort` | All five levels (`max/xhigh/high/medium/low`), passthrough |
|
|
66
|
+
| Token usage | `usage_metadata` incl. `cache_read`/`cache_creation` details, plus `total_cost_usd` in `response_metadata` |
|
|
67
|
+
| `stop_reason` | In `response_metadata`, like ChatAnthropic |
|
|
68
|
+
| Images (base64 + URL) | |
|
|
69
|
+
| PDFs (`document` blocks) | |
|
|
70
|
+
| System messages | |
|
|
71
|
+
| MCP servers | Both ChatAnthropic API-connector format and CLI-native (stdio/SSE/HTTP) |
|
|
72
|
+
| Server tools `web_search` / `web_fetch` | Mapped to the CLI's built-in WebSearch/WebFetch |
|
|
73
|
+
| `max_retries` / `timeout` | Client-side retry on 429/5xx; plus `fallback_model` |
|
|
74
|
+
| LangGraph agents | `create_agent` / `create_react_agent` work end-to-end |
|
|
75
|
+
|
|
76
|
+
### 🟡 Level B — Client-side workaround
|
|
77
|
+
|
|
78
|
+
| Feature | How |
|
|
79
|
+
|---|---|
|
|
80
|
+
| `stop_sequences` | Output scanned client-side; stream is cut and truncated at the sequence |
|
|
81
|
+
| `max_tokens` | Client-side truncation (~4 chars/token) with synthetic `stop_reason="max_tokens"` |
|
|
82
|
+
| `tool_choice="any"` / specific tool | System-prompt instruction + validation + one retry; explicit error if not satisfied |
|
|
83
|
+
| `get_num_tokens_from_messages` | Heuristic estimate (no count-tokens endpoint without an API key) |
|
|
84
|
+
| Arbitrary message histories | See [How conversations work](#how-conversations-work) below |
|
|
85
|
+
|
|
86
|
+
### 🔴 Level C — Accepted no-op (warns once)
|
|
87
|
+
|
|
88
|
+
`temperature`, `top_k`, `top_p`, `anthropic_api_url`, `anthropic_proxy`, `default_headers`, `inference_geo`, `context_management`, `cache_control` blocks (the CLI caches automatically — you still get cache token counts), citations, computer use, `strict` tool use.
|
|
89
|
+
|
|
90
|
+
## Tool calling — the classic LangChain pattern
|
|
91
|
+
|
|
92
|
+
Tools are registered as an in-process MCP server; a `PreToolUse` hook defers execution back to you. The model **never executes your tools** — it returns `tool_calls`, your code (or your LangGraph) executes them:
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
from langchain_core.tools import tool
|
|
96
|
+
|
|
97
|
+
@tool
|
|
98
|
+
def get_weather(city: str) -> str:
|
|
99
|
+
"""Get the current weather for a city."""
|
|
100
|
+
return f"25°C, sunny in {city}"
|
|
101
|
+
|
|
102
|
+
llm = ChatClaudeCli(model="claude-sonnet-4-5")
|
|
103
|
+
llm_with_tools = llm.bind_tools([get_weather])
|
|
104
|
+
|
|
105
|
+
response = llm_with_tools.invoke("What's the weather in Tokyo?")
|
|
106
|
+
response.tool_calls
|
|
107
|
+
# [{'name': 'get_weather', 'args': {'city': 'Tokyo'}, 'id': 'toolu_...'}]
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Works out of the box with LangGraph:
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
from langgraph.prebuilt import create_react_agent
|
|
114
|
+
|
|
115
|
+
agent = create_react_agent(model=llm, tools=[get_weather])
|
|
116
|
+
agent.invoke({"messages": [{"role": "user", "content": "Weather in Colombo?"}]})
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Structured output
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
from pydantic import BaseModel
|
|
123
|
+
|
|
124
|
+
class Answer(BaseModel):
|
|
125
|
+
answer: str
|
|
126
|
+
confidence: float
|
|
127
|
+
|
|
128
|
+
structured = llm.with_structured_output(Answer)
|
|
129
|
+
structured.invoke("What is the capital of France?")
|
|
130
|
+
# Answer(answer='Paris', confidence=0.99)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Uses the CLI's native `output_format` (JSON-schema enforced by the model runtime, not by prompt begging). `include_raw=True` and dict/TypedDict schemas are supported.
|
|
134
|
+
|
|
135
|
+
## How conversations work
|
|
136
|
+
|
|
137
|
+
`BaseChatModel` is stateless; the CLI is a stateful session. The bridge is a **session prefix-cache**:
|
|
138
|
+
|
|
139
|
+
- A conversation that grows by appending (chatbots, agent loops, tool cycles) **resumes its CLI session** and sends only the new messages — full fidelity, and the CLI's automatic prompt caching keeps input tokens cheap.
|
|
140
|
+
- An arbitrary history with no known prefix (e.g. trimmed or hand-built) is **flattened into a single user message** — role-labelled text, with image/document blocks preserved. A `ClaudeCliCompatWarning` tells you when this happens.
|
|
141
|
+
- You can pin a CLI session explicitly: `llm.invoke(..., config={"configurable": {"session_id": "<uuid>"}})`.
|
|
142
|
+
|
|
143
|
+
## Agentic mode (opt-in)
|
|
144
|
+
|
|
145
|
+
By default the model runs with **no built-in tools** — pure-LLM semantics, same risk profile as an API call. Opt in to Claude Code's agentic capabilities:
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
from langchain_claude_cli import ChatClaudeCli, READ_ONLY_TOOLS
|
|
149
|
+
|
|
150
|
+
# Read-only code analyst
|
|
151
|
+
analyst = ChatClaudeCli(
|
|
152
|
+
model="claude-sonnet-4-5",
|
|
153
|
+
builtin_tools=READ_ONLY_TOOLS, # Read, Glob, Grep
|
|
154
|
+
max_turns=10,
|
|
155
|
+
permission_mode="bypassPermissions",
|
|
156
|
+
cwd="/path/to/project",
|
|
157
|
+
)
|
|
158
|
+
analyst.invoke("Find all TODO comments and summarize them")
|
|
159
|
+
|
|
160
|
+
# Full agent (filesystem + bash) — trusted prompts only!
|
|
161
|
+
agent = ChatClaudeCli(
|
|
162
|
+
model="claude-sonnet-4-5",
|
|
163
|
+
builtin_tools="claude_code", # everything
|
|
164
|
+
permission_mode="bypassPermissions",
|
|
165
|
+
max_budget_usd=1.0, # hard cost cap
|
|
166
|
+
cwd="/path/to/project",
|
|
167
|
+
)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
`builtin_tools` accepts a list of tool names / `ClaudeTool` enum values, or the `"claude_code"` preset. `allowed_tools`, `disallowed_tools`, `add_dirs`, `sandbox` and `max_budget_usd` map straight to the CLI. LangChain tools (deferred) and built-in tools (executed in-run) can be combined.
|
|
171
|
+
|
|
172
|
+
Agentic runs stream too: each built-in tool call the CLI executes is emitted as a `tool_use` content block in the stream, so you can render live activity ("→ Read data.txt") alongside the text tokens.
|
|
173
|
+
|
|
174
|
+
### Security
|
|
175
|
+
|
|
176
|
+
With `builtin_tools` + `bypassPermissions` the CLI subprocess runs as **your OS user**: prompt injection becomes code execution, and `cwd` does **not** sandbox file access. Never enable agentic mode on untrusted input; prefer `READ_ONLY_TOOLS`, `disallowed_tools=["Bash"]`, `sandbox`, and containers for production. Pure-LLM mode (the default) has none of these risks.
|
|
177
|
+
|
|
178
|
+
## Migration
|
|
179
|
+
|
|
180
|
+
### From ChatAnthropic
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
# Before
|
|
184
|
+
from langchain_anthropic import ChatAnthropic
|
|
185
|
+
llm = ChatAnthropic(model="claude-sonnet-4-5", api_key="sk-ant-...")
|
|
186
|
+
|
|
187
|
+
# After — everything else stays the same
|
|
188
|
+
from langchain_claude_cli import ChatClaudeCli
|
|
189
|
+
llm = ChatClaudeCli(model="claude-sonnet-4-5")
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### From langchain-claude-code (the old library)
|
|
193
|
+
|
|
194
|
+
| Old (`ChatClaudeCode`) | New (`ChatClaudeCli`) |
|
|
195
|
+
|---|---|
|
|
196
|
+
| `ChatClaudeCode(...)` | `ChatClaudeCli(...)` |
|
|
197
|
+
| `bind_tools` via prompt injection | Real MCP-based tool calling |
|
|
198
|
+
| `thinking` (prompt text hack) | Native extended thinking |
|
|
199
|
+
| Token usage unavailable | Full `usage_metadata` |
|
|
200
|
+
| `max_turns=5` to enable tools | `builtin_tools=[...]` (explicit opt-in) |
|
|
201
|
+
| History flattened to text | Session resume with full fidelity |
|
|
202
|
+
|
|
203
|
+
## ⚖️ Legal & Terms of Service
|
|
204
|
+
|
|
205
|
+
> **Disclaimer:** community project, **not affiliated with or endorsed by Anthropic**. You are responsible for complying with Anthropic's terms.
|
|
206
|
+
|
|
207
|
+
This package uses the official, MIT-licensed `claude-agent-sdk` published by Anthropic — no reverse engineering, no credential extraction. Your usage is governed by Anthropic's [Consumer Terms](https://www.anthropic.com/legal/consumer-terms) (Pro/Max) or [Commercial Terms](https://www.anthropic.com/legal/commercial-terms) (API), and the [Acceptable Use Policy](https://www.anthropic.com/legal/aup). Notably: consumer subscriptions are for individual use, may not be resold or used to power products for end users, and heavy automated usage counts against your subscription's rate limits. **For anything beyond personal/internal use, use an Anthropic API key under the Commercial Terms** (and then you likely want `langchain-anthropic` directly).
|
|
208
|
+
|
|
209
|
+
## License
|
|
210
|
+
|
|
211
|
+
MIT
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# langchain-claude-cli
|
|
2
|
+
|
|
3
|
+
**Drop-in replacement for `ChatAnthropic`** that runs on the Claude Code CLI — use your Claude Pro/Max subscription, **no API key needed**.
|
|
4
|
+
|
|
5
|
+
Built on the official [`claude-agent-sdk`](https://pypi.org/project/claude-agent-sdk/) (≥ 0.2.115). Real tool calling via in-process MCP, native structured output, native extended thinking, real token usage — no prompt-injection hacks.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install langchain-claude-cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from langchain_claude_cli import ChatClaudeCli
|
|
15
|
+
|
|
16
|
+
# Just like ChatAnthropic, but no API key
|
|
17
|
+
llm = ChatClaudeCli(model="claude-sonnet-4-5")
|
|
18
|
+
response = llm.invoke("What is the capital of France?")
|
|
19
|
+
print(response.content)
|
|
20
|
+
print(response.usage_metadata) # real token usage, including cache tokens
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Prerequisites
|
|
24
|
+
|
|
25
|
+
- **Claude Code CLI** installed and authenticated: `npm install -g @anthropic-ai/claude-code`, then `claude` → log in
|
|
26
|
+
- **Claude Pro or Max subscription**
|
|
27
|
+
- Python ≥ 3.10, Node.js ≥ 18
|
|
28
|
+
|
|
29
|
+
## Feature parity with ChatAnthropic
|
|
30
|
+
|
|
31
|
+
Every `ChatAnthropic` constructor parameter is accepted — nothing breaks on migration. Parity comes in three levels:
|
|
32
|
+
|
|
33
|
+
### 🟢 Level A — Native
|
|
34
|
+
|
|
35
|
+
| Feature | Notes |
|
|
36
|
+
|---|---|
|
|
37
|
+
| `invoke` / `ainvoke` / `stream` / `astream` / `batch` | Real token-by-token streaming |
|
|
38
|
+
| Tool calling (`bind_tools`) | **Classic LangChain pattern**: model returns `AIMessage.tool_calls` without executing. Parallel tool calls supported |
|
|
39
|
+
| `with_structured_output` | CLI-native JSON-schema enforcement (`output_format`) |
|
|
40
|
+
| Extended thinking | Same config dict as ChatAnthropic: `thinking={"type": "enabled", "budget_tokens": N}` — plus `{"type": "adaptive"}` |
|
|
41
|
+
| `effort` | All five levels (`max/xhigh/high/medium/low`), passthrough |
|
|
42
|
+
| Token usage | `usage_metadata` incl. `cache_read`/`cache_creation` details, plus `total_cost_usd` in `response_metadata` |
|
|
43
|
+
| `stop_reason` | In `response_metadata`, like ChatAnthropic |
|
|
44
|
+
| Images (base64 + URL) | |
|
|
45
|
+
| PDFs (`document` blocks) | |
|
|
46
|
+
| System messages | |
|
|
47
|
+
| MCP servers | Both ChatAnthropic API-connector format and CLI-native (stdio/SSE/HTTP) |
|
|
48
|
+
| Server tools `web_search` / `web_fetch` | Mapped to the CLI's built-in WebSearch/WebFetch |
|
|
49
|
+
| `max_retries` / `timeout` | Client-side retry on 429/5xx; plus `fallback_model` |
|
|
50
|
+
| LangGraph agents | `create_agent` / `create_react_agent` work end-to-end |
|
|
51
|
+
|
|
52
|
+
### 🟡 Level B — Client-side workaround
|
|
53
|
+
|
|
54
|
+
| Feature | How |
|
|
55
|
+
|---|---|
|
|
56
|
+
| `stop_sequences` | Output scanned client-side; stream is cut and truncated at the sequence |
|
|
57
|
+
| `max_tokens` | Client-side truncation (~4 chars/token) with synthetic `stop_reason="max_tokens"` |
|
|
58
|
+
| `tool_choice="any"` / specific tool | System-prompt instruction + validation + one retry; explicit error if not satisfied |
|
|
59
|
+
| `get_num_tokens_from_messages` | Heuristic estimate (no count-tokens endpoint without an API key) |
|
|
60
|
+
| Arbitrary message histories | See [How conversations work](#how-conversations-work) below |
|
|
61
|
+
|
|
62
|
+
### 🔴 Level C — Accepted no-op (warns once)
|
|
63
|
+
|
|
64
|
+
`temperature`, `top_k`, `top_p`, `anthropic_api_url`, `anthropic_proxy`, `default_headers`, `inference_geo`, `context_management`, `cache_control` blocks (the CLI caches automatically — you still get cache token counts), citations, computer use, `strict` tool use.
|
|
65
|
+
|
|
66
|
+
## Tool calling — the classic LangChain pattern
|
|
67
|
+
|
|
68
|
+
Tools are registered as an in-process MCP server; a `PreToolUse` hook defers execution back to you. The model **never executes your tools** — it returns `tool_calls`, your code (or your LangGraph) executes them:
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
from langchain_core.tools import tool
|
|
72
|
+
|
|
73
|
+
@tool
|
|
74
|
+
def get_weather(city: str) -> str:
|
|
75
|
+
"""Get the current weather for a city."""
|
|
76
|
+
return f"25°C, sunny in {city}"
|
|
77
|
+
|
|
78
|
+
llm = ChatClaudeCli(model="claude-sonnet-4-5")
|
|
79
|
+
llm_with_tools = llm.bind_tools([get_weather])
|
|
80
|
+
|
|
81
|
+
response = llm_with_tools.invoke("What's the weather in Tokyo?")
|
|
82
|
+
response.tool_calls
|
|
83
|
+
# [{'name': 'get_weather', 'args': {'city': 'Tokyo'}, 'id': 'toolu_...'}]
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Works out of the box with LangGraph:
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from langgraph.prebuilt import create_react_agent
|
|
90
|
+
|
|
91
|
+
agent = create_react_agent(model=llm, tools=[get_weather])
|
|
92
|
+
agent.invoke({"messages": [{"role": "user", "content": "Weather in Colombo?"}]})
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Structured output
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
from pydantic import BaseModel
|
|
99
|
+
|
|
100
|
+
class Answer(BaseModel):
|
|
101
|
+
answer: str
|
|
102
|
+
confidence: float
|
|
103
|
+
|
|
104
|
+
structured = llm.with_structured_output(Answer)
|
|
105
|
+
structured.invoke("What is the capital of France?")
|
|
106
|
+
# Answer(answer='Paris', confidence=0.99)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Uses the CLI's native `output_format` (JSON-schema enforced by the model runtime, not by prompt begging). `include_raw=True` and dict/TypedDict schemas are supported.
|
|
110
|
+
|
|
111
|
+
## How conversations work
|
|
112
|
+
|
|
113
|
+
`BaseChatModel` is stateless; the CLI is a stateful session. The bridge is a **session prefix-cache**:
|
|
114
|
+
|
|
115
|
+
- A conversation that grows by appending (chatbots, agent loops, tool cycles) **resumes its CLI session** and sends only the new messages — full fidelity, and the CLI's automatic prompt caching keeps input tokens cheap.
|
|
116
|
+
- An arbitrary history with no known prefix (e.g. trimmed or hand-built) is **flattened into a single user message** — role-labelled text, with image/document blocks preserved. A `ClaudeCliCompatWarning` tells you when this happens.
|
|
117
|
+
- You can pin a CLI session explicitly: `llm.invoke(..., config={"configurable": {"session_id": "<uuid>"}})`.
|
|
118
|
+
|
|
119
|
+
## Agentic mode (opt-in)
|
|
120
|
+
|
|
121
|
+
By default the model runs with **no built-in tools** — pure-LLM semantics, same risk profile as an API call. Opt in to Claude Code's agentic capabilities:
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
from langchain_claude_cli import ChatClaudeCli, READ_ONLY_TOOLS
|
|
125
|
+
|
|
126
|
+
# Read-only code analyst
|
|
127
|
+
analyst = ChatClaudeCli(
|
|
128
|
+
model="claude-sonnet-4-5",
|
|
129
|
+
builtin_tools=READ_ONLY_TOOLS, # Read, Glob, Grep
|
|
130
|
+
max_turns=10,
|
|
131
|
+
permission_mode="bypassPermissions",
|
|
132
|
+
cwd="/path/to/project",
|
|
133
|
+
)
|
|
134
|
+
analyst.invoke("Find all TODO comments and summarize them")
|
|
135
|
+
|
|
136
|
+
# Full agent (filesystem + bash) — trusted prompts only!
|
|
137
|
+
agent = ChatClaudeCli(
|
|
138
|
+
model="claude-sonnet-4-5",
|
|
139
|
+
builtin_tools="claude_code", # everything
|
|
140
|
+
permission_mode="bypassPermissions",
|
|
141
|
+
max_budget_usd=1.0, # hard cost cap
|
|
142
|
+
cwd="/path/to/project",
|
|
143
|
+
)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
`builtin_tools` accepts a list of tool names / `ClaudeTool` enum values, or the `"claude_code"` preset. `allowed_tools`, `disallowed_tools`, `add_dirs`, `sandbox` and `max_budget_usd` map straight to the CLI. LangChain tools (deferred) and built-in tools (executed in-run) can be combined.
|
|
147
|
+
|
|
148
|
+
Agentic runs stream too: each built-in tool call the CLI executes is emitted as a `tool_use` content block in the stream, so you can render live activity ("→ Read data.txt") alongside the text tokens.
|
|
149
|
+
|
|
150
|
+
### Security
|
|
151
|
+
|
|
152
|
+
With `builtin_tools` + `bypassPermissions` the CLI subprocess runs as **your OS user**: prompt injection becomes code execution, and `cwd` does **not** sandbox file access. Never enable agentic mode on untrusted input; prefer `READ_ONLY_TOOLS`, `disallowed_tools=["Bash"]`, `sandbox`, and containers for production. Pure-LLM mode (the default) has none of these risks.
|
|
153
|
+
|
|
154
|
+
## Migration
|
|
155
|
+
|
|
156
|
+
### From ChatAnthropic
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
# Before
|
|
160
|
+
from langchain_anthropic import ChatAnthropic
|
|
161
|
+
llm = ChatAnthropic(model="claude-sonnet-4-5", api_key="sk-ant-...")
|
|
162
|
+
|
|
163
|
+
# After — everything else stays the same
|
|
164
|
+
from langchain_claude_cli import ChatClaudeCli
|
|
165
|
+
llm = ChatClaudeCli(model="claude-sonnet-4-5")
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### From langchain-claude-code (the old library)
|
|
169
|
+
|
|
170
|
+
| Old (`ChatClaudeCode`) | New (`ChatClaudeCli`) |
|
|
171
|
+
|---|---|
|
|
172
|
+
| `ChatClaudeCode(...)` | `ChatClaudeCli(...)` |
|
|
173
|
+
| `bind_tools` via prompt injection | Real MCP-based tool calling |
|
|
174
|
+
| `thinking` (prompt text hack) | Native extended thinking |
|
|
175
|
+
| Token usage unavailable | Full `usage_metadata` |
|
|
176
|
+
| `max_turns=5` to enable tools | `builtin_tools=[...]` (explicit opt-in) |
|
|
177
|
+
| History flattened to text | Session resume with full fidelity |
|
|
178
|
+
|
|
179
|
+
## ⚖️ Legal & Terms of Service
|
|
180
|
+
|
|
181
|
+
> **Disclaimer:** community project, **not affiliated with or endorsed by Anthropic**. You are responsible for complying with Anthropic's terms.
|
|
182
|
+
|
|
183
|
+
This package uses the official, MIT-licensed `claude-agent-sdk` published by Anthropic — no reverse engineering, no credential extraction. Your usage is governed by Anthropic's [Consumer Terms](https://www.anthropic.com/legal/consumer-terms) (Pro/Max) or [Commercial Terms](https://www.anthropic.com/legal/commercial-terms) (API), and the [Acceptable Use Policy](https://www.anthropic.com/legal/aup). Notably: consumer subscriptions are for individual use, may not be resold or used to power products for end users, and heavy automated usage counts against your subscription's rate limits. **For anything beyond personal/internal use, use an Anthropic API key under the Commercial Terms** (and then you likely want `langchain-anthropic` directly).
|
|
184
|
+
|
|
185
|
+
## License
|
|
186
|
+
|
|
187
|
+
MIT
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""langchain-claude-cli — ChatAnthropic drop-in backed by the Claude Code CLI."""
|
|
2
|
+
|
|
3
|
+
from langchain_claude_cli._compat import ClaudeCliCompatWarning
|
|
4
|
+
from langchain_claude_cli.chat_models import (
|
|
5
|
+
ChatClaudeCli,
|
|
6
|
+
ClaudeCliBudgetExceededError,
|
|
7
|
+
)
|
|
8
|
+
from langchain_claude_cli.tools import (
|
|
9
|
+
ALL_TOOLS,
|
|
10
|
+
NETWORK_TOOLS,
|
|
11
|
+
READ_ONLY_TOOLS,
|
|
12
|
+
SHELL_TOOLS,
|
|
13
|
+
WRITE_TOOLS,
|
|
14
|
+
ClaudeTool,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"ALL_TOOLS",
|
|
19
|
+
"NETWORK_TOOLS",
|
|
20
|
+
"READ_ONLY_TOOLS",
|
|
21
|
+
"SHELL_TOOLS",
|
|
22
|
+
"WRITE_TOOLS",
|
|
23
|
+
"ChatClaudeCli",
|
|
24
|
+
"ClaudeCliBudgetExceededError",
|
|
25
|
+
"ClaudeCliCompatWarning",
|
|
26
|
+
"ClaudeTool",
|
|
27
|
+
]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""ChatAnthropic signature-compatibility layer: no-op params and one-shot warnings."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import warnings
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ClaudeCliCompatWarning(UserWarning):
|
|
9
|
+
"""A ChatAnthropic parameter was accepted but has no effect via the Claude CLI."""
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
_warned: set[str] = set()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def warn_once(param: str, message: str) -> None:
|
|
16
|
+
"""Emit a ClaudeCliCompatWarning once per process for a given parameter."""
|
|
17
|
+
if param in _warned:
|
|
18
|
+
return
|
|
19
|
+
_warned.add(param)
|
|
20
|
+
warnings.warn(message, ClaudeCliCompatWarning, stacklevel=3)
|