claude-agent-sdk 0.0.23__py3-none-any.whl
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.
Potentially problematic release.
This version of claude-agent-sdk might be problematic. Click here for more details.
- claude_agent_sdk/__init__.py +325 -0
- claude_agent_sdk/_errors.py +56 -0
- claude_agent_sdk/_internal/__init__.py +1 -0
- claude_agent_sdk/_internal/client.py +121 -0
- claude_agent_sdk/_internal/message_parser.py +172 -0
- claude_agent_sdk/_internal/query.py +523 -0
- claude_agent_sdk/_internal/transport/__init__.py +68 -0
- claude_agent_sdk/_internal/transport/subprocess_cli.py +456 -0
- claude_agent_sdk/_version.py +3 -0
- claude_agent_sdk/client.py +325 -0
- claude_agent_sdk/py.typed +0 -0
- claude_agent_sdk/query.py +126 -0
- claude_agent_sdk/types.py +412 -0
- claude_agent_sdk-0.0.23.dist-info/METADATA +309 -0
- claude_agent_sdk-0.0.23.dist-info/RECORD +17 -0
- claude_agent_sdk-0.0.23.dist-info/WHEEL +4 -0
- claude_agent_sdk-0.0.23.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
"""Claude SDK Client for interacting with Claude Code."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
from collections.abc import AsyncIterable, AsyncIterator
|
|
6
|
+
from dataclasses import replace
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from ._errors import CLIConnectionError
|
|
10
|
+
from .types import ClaudeAgentOptions, HookEvent, HookMatcher, Message, ResultMessage
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ClaudeSDKClient:
|
|
14
|
+
"""
|
|
15
|
+
Client for bidirectional, interactive conversations with Claude Code.
|
|
16
|
+
|
|
17
|
+
This client provides full control over the conversation flow with support
|
|
18
|
+
for streaming, interrupts, and dynamic message sending. For simple one-shot
|
|
19
|
+
queries, consider using the query() function instead.
|
|
20
|
+
|
|
21
|
+
Key features:
|
|
22
|
+
- **Bidirectional**: Send and receive messages at any time
|
|
23
|
+
- **Stateful**: Maintains conversation context across messages
|
|
24
|
+
- **Interactive**: Send follow-ups based on responses
|
|
25
|
+
- **Control flow**: Support for interrupts and session management
|
|
26
|
+
|
|
27
|
+
When to use ClaudeSDKClient:
|
|
28
|
+
- Building chat interfaces or conversational UIs
|
|
29
|
+
- Interactive debugging or exploration sessions
|
|
30
|
+
- Multi-turn conversations with context
|
|
31
|
+
- When you need to react to Claude's responses
|
|
32
|
+
- Real-time applications with user input
|
|
33
|
+
- When you need interrupt capabilities
|
|
34
|
+
|
|
35
|
+
When to use query() instead:
|
|
36
|
+
- Simple one-off questions
|
|
37
|
+
- Batch processing of prompts
|
|
38
|
+
- Fire-and-forget automation scripts
|
|
39
|
+
- When all inputs are known upfront
|
|
40
|
+
- Stateless operations
|
|
41
|
+
|
|
42
|
+
See examples/streaming_mode.py for full examples of ClaudeSDKClient in
|
|
43
|
+
different scenarios.
|
|
44
|
+
|
|
45
|
+
Caveat: As of v0.0.20, you cannot use a ClaudeSDKClient instance across
|
|
46
|
+
different async runtime contexts (e.g., different trio nurseries or asyncio
|
|
47
|
+
task groups). The client internally maintains a persistent anyio task group
|
|
48
|
+
for reading messages that remains active from connect() until disconnect().
|
|
49
|
+
This means you must complete all operations with the client within the same
|
|
50
|
+
async context where it was connected. Ideally, this limitation should not
|
|
51
|
+
exist.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
def __init__(self, options: ClaudeAgentOptions | None = None):
|
|
55
|
+
"""Initialize Claude SDK client."""
|
|
56
|
+
if options is None:
|
|
57
|
+
options = ClaudeAgentOptions()
|
|
58
|
+
self.options = options
|
|
59
|
+
self._transport: Any | None = None
|
|
60
|
+
self._query: Any | None = None
|
|
61
|
+
os.environ["CLAUDE_CODE_ENTRYPOINT"] = "sdk-py-client"
|
|
62
|
+
|
|
63
|
+
def _convert_hooks_to_internal_format(
|
|
64
|
+
self, hooks: dict[HookEvent, list[HookMatcher]]
|
|
65
|
+
) -> dict[str, list[dict[str, Any]]]:
|
|
66
|
+
"""Convert HookMatcher format to internal Query format."""
|
|
67
|
+
internal_hooks: dict[str, list[dict[str, Any]]] = {}
|
|
68
|
+
for event, matchers in hooks.items():
|
|
69
|
+
internal_hooks[event] = []
|
|
70
|
+
for matcher in matchers:
|
|
71
|
+
# Convert HookMatcher to internal dict format
|
|
72
|
+
internal_matcher = {
|
|
73
|
+
"matcher": matcher.matcher if hasattr(matcher, "matcher") else None,
|
|
74
|
+
"hooks": matcher.hooks if hasattr(matcher, "hooks") else [],
|
|
75
|
+
}
|
|
76
|
+
internal_hooks[event].append(internal_matcher)
|
|
77
|
+
return internal_hooks
|
|
78
|
+
|
|
79
|
+
async def connect(
|
|
80
|
+
self, prompt: str | AsyncIterable[dict[str, Any]] | None = None
|
|
81
|
+
) -> None:
|
|
82
|
+
"""Connect to Claude with a prompt or message stream."""
|
|
83
|
+
|
|
84
|
+
from ._internal.query import Query
|
|
85
|
+
from ._internal.transport.subprocess_cli import SubprocessCLITransport
|
|
86
|
+
|
|
87
|
+
# Auto-connect with empty async iterable if no prompt is provided
|
|
88
|
+
async def _empty_stream() -> AsyncIterator[dict[str, Any]]:
|
|
89
|
+
# Never yields, but indicates that this function is an iterator and
|
|
90
|
+
# keeps the connection open.
|
|
91
|
+
# This yield is never reached but makes this an async generator
|
|
92
|
+
return
|
|
93
|
+
yield {} # type: ignore[unreachable]
|
|
94
|
+
|
|
95
|
+
actual_prompt = _empty_stream() if prompt is None else prompt
|
|
96
|
+
|
|
97
|
+
# Validate and configure permission settings (matching TypeScript SDK logic)
|
|
98
|
+
if self.options.can_use_tool:
|
|
99
|
+
# canUseTool callback requires streaming mode (AsyncIterable prompt)
|
|
100
|
+
if isinstance(prompt, str):
|
|
101
|
+
raise ValueError(
|
|
102
|
+
"can_use_tool callback requires streaming mode. "
|
|
103
|
+
"Please provide prompt as an AsyncIterable instead of a string."
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
# canUseTool and permission_prompt_tool_name are mutually exclusive
|
|
107
|
+
if self.options.permission_prompt_tool_name:
|
|
108
|
+
raise ValueError(
|
|
109
|
+
"can_use_tool callback cannot be used with permission_prompt_tool_name. "
|
|
110
|
+
"Please use one or the other."
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
# Automatically set permission_prompt_tool_name to "stdio" for control protocol
|
|
114
|
+
options = replace(self.options, permission_prompt_tool_name="stdio")
|
|
115
|
+
else:
|
|
116
|
+
options = self.options
|
|
117
|
+
|
|
118
|
+
self._transport = SubprocessCLITransport(
|
|
119
|
+
prompt=actual_prompt,
|
|
120
|
+
options=options,
|
|
121
|
+
)
|
|
122
|
+
await self._transport.connect()
|
|
123
|
+
|
|
124
|
+
# Extract SDK MCP servers from options
|
|
125
|
+
sdk_mcp_servers = {}
|
|
126
|
+
if self.options.mcp_servers and isinstance(self.options.mcp_servers, dict):
|
|
127
|
+
for name, config in self.options.mcp_servers.items():
|
|
128
|
+
if isinstance(config, dict) and config.get("type") == "sdk":
|
|
129
|
+
sdk_mcp_servers[name] = config["instance"] # type: ignore[typeddict-item]
|
|
130
|
+
|
|
131
|
+
# Create Query to handle control protocol
|
|
132
|
+
self._query = Query(
|
|
133
|
+
transport=self._transport,
|
|
134
|
+
is_streaming_mode=True, # ClaudeSDKClient always uses streaming mode
|
|
135
|
+
can_use_tool=self.options.can_use_tool,
|
|
136
|
+
hooks=self._convert_hooks_to_internal_format(self.options.hooks)
|
|
137
|
+
if self.options.hooks
|
|
138
|
+
else None,
|
|
139
|
+
sdk_mcp_servers=sdk_mcp_servers,
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
# Start reading messages and initialize
|
|
143
|
+
await self._query.start()
|
|
144
|
+
await self._query.initialize()
|
|
145
|
+
|
|
146
|
+
# If we have an initial prompt stream, start streaming it
|
|
147
|
+
if prompt is not None and isinstance(prompt, AsyncIterable) and self._query._tg:
|
|
148
|
+
self._query._tg.start_soon(self._query.stream_input, prompt)
|
|
149
|
+
|
|
150
|
+
async def receive_messages(self) -> AsyncIterator[Message]:
|
|
151
|
+
"""Receive all messages from Claude."""
|
|
152
|
+
if not self._query:
|
|
153
|
+
raise CLIConnectionError("Not connected. Call connect() first.")
|
|
154
|
+
|
|
155
|
+
from ._internal.message_parser import parse_message
|
|
156
|
+
|
|
157
|
+
async for data in self._query.receive_messages():
|
|
158
|
+
yield parse_message(data)
|
|
159
|
+
|
|
160
|
+
async def query(
|
|
161
|
+
self, prompt: str | AsyncIterable[dict[str, Any]], session_id: str = "default"
|
|
162
|
+
) -> None:
|
|
163
|
+
"""
|
|
164
|
+
Send a new request in streaming mode.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
prompt: Either a string message or an async iterable of message dictionaries
|
|
168
|
+
session_id: Session identifier for the conversation
|
|
169
|
+
"""
|
|
170
|
+
if not self._query or not self._transport:
|
|
171
|
+
raise CLIConnectionError("Not connected. Call connect() first.")
|
|
172
|
+
|
|
173
|
+
# Handle string prompts
|
|
174
|
+
if isinstance(prompt, str):
|
|
175
|
+
message = {
|
|
176
|
+
"type": "user",
|
|
177
|
+
"message": {"role": "user", "content": prompt},
|
|
178
|
+
"parent_tool_use_id": None,
|
|
179
|
+
"session_id": session_id,
|
|
180
|
+
}
|
|
181
|
+
await self._transport.write(json.dumps(message) + "\n")
|
|
182
|
+
else:
|
|
183
|
+
# Handle AsyncIterable prompts - stream them
|
|
184
|
+
async for msg in prompt:
|
|
185
|
+
# Ensure session_id is set on each message
|
|
186
|
+
if "session_id" not in msg:
|
|
187
|
+
msg["session_id"] = session_id
|
|
188
|
+
await self._transport.write(json.dumps(msg) + "\n")
|
|
189
|
+
|
|
190
|
+
async def interrupt(self) -> None:
|
|
191
|
+
"""Send interrupt signal (only works with streaming mode)."""
|
|
192
|
+
if not self._query:
|
|
193
|
+
raise CLIConnectionError("Not connected. Call connect() first.")
|
|
194
|
+
await self._query.interrupt()
|
|
195
|
+
|
|
196
|
+
async def set_permission_mode(self, mode: str) -> None:
|
|
197
|
+
"""Change permission mode during conversation (only works with streaming mode).
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
mode: The permission mode to set. Valid options:
|
|
201
|
+
- 'default': CLI prompts for dangerous tools
|
|
202
|
+
- 'acceptEdits': Auto-accept file edits
|
|
203
|
+
- 'bypassPermissions': Allow all tools (use with caution)
|
|
204
|
+
|
|
205
|
+
Example:
|
|
206
|
+
```python
|
|
207
|
+
async with ClaudeSDKClient() as client:
|
|
208
|
+
# Start with default permissions
|
|
209
|
+
await client.query("Help me analyze this codebase")
|
|
210
|
+
|
|
211
|
+
# Review mode done, switch to auto-accept edits
|
|
212
|
+
await client.set_permission_mode('acceptEdits')
|
|
213
|
+
await client.query("Now implement the fix we discussed")
|
|
214
|
+
```
|
|
215
|
+
"""
|
|
216
|
+
if not self._query:
|
|
217
|
+
raise CLIConnectionError("Not connected. Call connect() first.")
|
|
218
|
+
await self._query.set_permission_mode(mode)
|
|
219
|
+
|
|
220
|
+
async def set_model(self, model: str | None = None) -> None:
|
|
221
|
+
"""Change the AI model during conversation (only works with streaming mode).
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
model: The model to use, or None to use default. Examples:
|
|
225
|
+
- 'claude-sonnet-4-20250514'
|
|
226
|
+
- 'claude-opus-4-1-20250805'
|
|
227
|
+
- 'claude-opus-4-20250514'
|
|
228
|
+
|
|
229
|
+
Example:
|
|
230
|
+
```python
|
|
231
|
+
async with ClaudeSDKClient() as client:
|
|
232
|
+
# Start with default model
|
|
233
|
+
await client.query("Help me understand this problem")
|
|
234
|
+
|
|
235
|
+
# Switch to a different model for implementation
|
|
236
|
+
await client.set_model('claude-3-5-sonnet-20241022')
|
|
237
|
+
await client.query("Now implement the solution")
|
|
238
|
+
```
|
|
239
|
+
"""
|
|
240
|
+
if not self._query:
|
|
241
|
+
raise CLIConnectionError("Not connected. Call connect() first.")
|
|
242
|
+
await self._query.set_model(model)
|
|
243
|
+
|
|
244
|
+
async def get_server_info(self) -> dict[str, Any] | None:
|
|
245
|
+
"""Get server initialization info including available commands and output styles.
|
|
246
|
+
|
|
247
|
+
Returns initialization information from the Claude Code server including:
|
|
248
|
+
- Available commands (slash commands, system commands, etc.)
|
|
249
|
+
- Current and available output styles
|
|
250
|
+
- Server capabilities
|
|
251
|
+
|
|
252
|
+
Returns:
|
|
253
|
+
Dictionary with server info, or None if not in streaming mode
|
|
254
|
+
|
|
255
|
+
Example:
|
|
256
|
+
```python
|
|
257
|
+
async with ClaudeSDKClient() as client:
|
|
258
|
+
info = await client.get_server_info()
|
|
259
|
+
if info:
|
|
260
|
+
print(f"Commands available: {len(info.get('commands', []))}")
|
|
261
|
+
print(f"Output style: {info.get('output_style', 'default')}")
|
|
262
|
+
```
|
|
263
|
+
"""
|
|
264
|
+
if not self._query:
|
|
265
|
+
raise CLIConnectionError("Not connected. Call connect() first.")
|
|
266
|
+
# Return the initialization result that was already obtained during connect
|
|
267
|
+
return getattr(self._query, "_initialization_result", None)
|
|
268
|
+
|
|
269
|
+
async def receive_response(self) -> AsyncIterator[Message]:
|
|
270
|
+
"""
|
|
271
|
+
Receive messages from Claude until and including a ResultMessage.
|
|
272
|
+
|
|
273
|
+
This async iterator yields all messages in sequence and automatically terminates
|
|
274
|
+
after yielding a ResultMessage (which indicates the response is complete).
|
|
275
|
+
It's a convenience method over receive_messages() for single-response workflows.
|
|
276
|
+
|
|
277
|
+
**Stopping Behavior:**
|
|
278
|
+
- Yields each message as it's received
|
|
279
|
+
- Terminates immediately after yielding a ResultMessage
|
|
280
|
+
- The ResultMessage IS included in the yielded messages
|
|
281
|
+
- If no ResultMessage is received, the iterator continues indefinitely
|
|
282
|
+
|
|
283
|
+
Yields:
|
|
284
|
+
Message: Each message received (UserMessage, AssistantMessage, SystemMessage, ResultMessage)
|
|
285
|
+
|
|
286
|
+
Example:
|
|
287
|
+
```python
|
|
288
|
+
async with ClaudeSDKClient() as client:
|
|
289
|
+
await client.query("What's the capital of France?")
|
|
290
|
+
|
|
291
|
+
async for msg in client.receive_response():
|
|
292
|
+
if isinstance(msg, AssistantMessage):
|
|
293
|
+
for block in msg.content:
|
|
294
|
+
if isinstance(block, TextBlock):
|
|
295
|
+
print(f"Claude: {block.text}")
|
|
296
|
+
elif isinstance(msg, ResultMessage):
|
|
297
|
+
print(f"Cost: ${msg.total_cost_usd:.4f}")
|
|
298
|
+
# Iterator will terminate after this message
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Note:
|
|
302
|
+
To collect all messages: `messages = [msg async for msg in client.receive_response()]`
|
|
303
|
+
The final message in the list will always be a ResultMessage.
|
|
304
|
+
"""
|
|
305
|
+
async for message in self.receive_messages():
|
|
306
|
+
yield message
|
|
307
|
+
if isinstance(message, ResultMessage):
|
|
308
|
+
return
|
|
309
|
+
|
|
310
|
+
async def disconnect(self) -> None:
|
|
311
|
+
"""Disconnect from Claude."""
|
|
312
|
+
if self._query:
|
|
313
|
+
await self._query.close()
|
|
314
|
+
self._query = None
|
|
315
|
+
self._transport = None
|
|
316
|
+
|
|
317
|
+
async def __aenter__(self) -> "ClaudeSDKClient":
|
|
318
|
+
"""Enter async context - automatically connects with empty stream for interactive use."""
|
|
319
|
+
await self.connect()
|
|
320
|
+
return self
|
|
321
|
+
|
|
322
|
+
async def __aexit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> bool:
|
|
323
|
+
"""Exit async context - always disconnects."""
|
|
324
|
+
await self.disconnect()
|
|
325
|
+
return False
|
|
File without changes
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""Query function for one-shot interactions with Claude Code."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from collections.abc import AsyncIterable, AsyncIterator
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from ._internal.client import InternalClient
|
|
8
|
+
from ._internal.transport import Transport
|
|
9
|
+
from .types import ClaudeAgentOptions, Message
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
async def query(
|
|
13
|
+
*,
|
|
14
|
+
prompt: str | AsyncIterable[dict[str, Any]],
|
|
15
|
+
options: ClaudeAgentOptions | None = None,
|
|
16
|
+
transport: Transport | None = None,
|
|
17
|
+
) -> AsyncIterator[Message]:
|
|
18
|
+
"""
|
|
19
|
+
Query Claude Code for one-shot or unidirectional streaming interactions.
|
|
20
|
+
|
|
21
|
+
This function is ideal for simple, stateless queries where you don't need
|
|
22
|
+
bidirectional communication or conversation management. For interactive,
|
|
23
|
+
stateful conversations, use ClaudeSDKClient instead.
|
|
24
|
+
|
|
25
|
+
Key differences from ClaudeSDKClient:
|
|
26
|
+
- **Unidirectional**: Send all messages upfront, receive all responses
|
|
27
|
+
- **Stateless**: Each query is independent, no conversation state
|
|
28
|
+
- **Simple**: Fire-and-forget style, no connection management
|
|
29
|
+
- **No interrupts**: Cannot interrupt or send follow-up messages
|
|
30
|
+
|
|
31
|
+
When to use query():
|
|
32
|
+
- Simple one-off questions ("What is 2+2?")
|
|
33
|
+
- Batch processing of independent prompts
|
|
34
|
+
- Code generation or analysis tasks
|
|
35
|
+
- Automated scripts and CI/CD pipelines
|
|
36
|
+
- When you know all inputs upfront
|
|
37
|
+
|
|
38
|
+
When to use ClaudeSDKClient:
|
|
39
|
+
- Interactive conversations with follow-ups
|
|
40
|
+
- Chat applications or REPL-like interfaces
|
|
41
|
+
- When you need to send messages based on responses
|
|
42
|
+
- When you need interrupt capabilities
|
|
43
|
+
- Long-running sessions with state
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
prompt: The prompt to send to Claude. Can be a string for single-shot queries
|
|
47
|
+
or an AsyncIterable[dict] for streaming mode with continuous interaction.
|
|
48
|
+
In streaming mode, each dict should have the structure:
|
|
49
|
+
{
|
|
50
|
+
"type": "user",
|
|
51
|
+
"message": {"role": "user", "content": "..."},
|
|
52
|
+
"parent_tool_use_id": None,
|
|
53
|
+
"session_id": "..."
|
|
54
|
+
}
|
|
55
|
+
options: Optional configuration (defaults to ClaudeAgentOptions() if None).
|
|
56
|
+
Set options.permission_mode to control tool execution:
|
|
57
|
+
- 'default': CLI prompts for dangerous tools
|
|
58
|
+
- 'acceptEdits': Auto-accept file edits
|
|
59
|
+
- 'bypassPermissions': Allow all tools (use with caution)
|
|
60
|
+
Set options.cwd for working directory.
|
|
61
|
+
transport: Optional transport implementation. If provided, this will be used
|
|
62
|
+
instead of the default transport selection based on options.
|
|
63
|
+
The transport will be automatically configured with the prompt and options.
|
|
64
|
+
|
|
65
|
+
Yields:
|
|
66
|
+
Messages from the conversation
|
|
67
|
+
|
|
68
|
+
Example - Simple query:
|
|
69
|
+
```python
|
|
70
|
+
# One-off question
|
|
71
|
+
async for message in query(prompt="What is the capital of France?"):
|
|
72
|
+
print(message)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Example - With options:
|
|
76
|
+
```python
|
|
77
|
+
# Code generation with specific settings
|
|
78
|
+
async for message in query(
|
|
79
|
+
prompt="Create a Python web server",
|
|
80
|
+
options=ClaudeAgentOptions(
|
|
81
|
+
system_prompt="You are an expert Python developer",
|
|
82
|
+
cwd="/home/user/project"
|
|
83
|
+
)
|
|
84
|
+
):
|
|
85
|
+
print(message)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Example - Streaming mode (still unidirectional):
|
|
89
|
+
```python
|
|
90
|
+
async def prompts():
|
|
91
|
+
yield {"type": "user", "message": {"role": "user", "content": "Hello"}}
|
|
92
|
+
yield {"type": "user", "message": {"role": "user", "content": "How are you?"}}
|
|
93
|
+
|
|
94
|
+
# All prompts are sent, then all responses received
|
|
95
|
+
async for message in query(prompt=prompts()):
|
|
96
|
+
print(message)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Example - With custom transport:
|
|
100
|
+
```python
|
|
101
|
+
from claude_agent_sdk import query, Transport
|
|
102
|
+
|
|
103
|
+
class MyCustomTransport(Transport):
|
|
104
|
+
# Implement custom transport logic
|
|
105
|
+
pass
|
|
106
|
+
|
|
107
|
+
transport = MyCustomTransport()
|
|
108
|
+
async for message in query(
|
|
109
|
+
prompt="Hello",
|
|
110
|
+
transport=transport
|
|
111
|
+
):
|
|
112
|
+
print(message)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
"""
|
|
116
|
+
if options is None:
|
|
117
|
+
options = ClaudeAgentOptions()
|
|
118
|
+
|
|
119
|
+
os.environ["CLAUDE_CODE_ENTRYPOINT"] = "sdk-py"
|
|
120
|
+
|
|
121
|
+
client = InternalClient()
|
|
122
|
+
|
|
123
|
+
async for message in client.process_query(
|
|
124
|
+
prompt=prompt, options=options, transport=transport
|
|
125
|
+
):
|
|
126
|
+
yield message
|