lionagi 0.16.2__py3-none-any.whl → 0.17.0__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.
- lionagi/adapters/_utils.py +10 -23
- lionagi/adapters/async_postgres_adapter.py +83 -79
- lionagi/ln/__init__.py +4 -4
- lionagi/ln/_json_dump.py +0 -6
- lionagi/ln/fuzzy/__init__.py +4 -1
- lionagi/ln/fuzzy/_fuzzy_validate.py +109 -0
- lionagi/ln/fuzzy/_to_dict.py +388 -0
- lionagi/models/__init__.py +0 -2
- lionagi/operations/__init__.py +0 -6
- lionagi/operations/_visualize_graph.py +285 -0
- lionagi/operations/brainstorm/brainstorm.py +14 -12
- lionagi/operations/builder.py +23 -302
- lionagi/operations/communicate/communicate.py +1 -1
- lionagi/operations/flow.py +14 -11
- lionagi/operations/node.py +14 -3
- lionagi/operations/operate/operate.py +5 -11
- lionagi/operations/parse/parse.py +2 -3
- lionagi/operations/types.py +0 -2
- lionagi/operations/utils.py +11 -5
- lionagi/protocols/generic/pile.py +3 -7
- lionagi/protocols/graph/graph.py +23 -6
- lionagi/protocols/graph/node.py +0 -2
- lionagi/protocols/messages/message.py +0 -1
- lionagi/protocols/operatives/operative.py +2 -2
- lionagi/protocols/types.py +0 -15
- lionagi/service/connections/endpoint.py +11 -5
- lionagi/service/connections/match_endpoint.py +2 -10
- lionagi/service/connections/providers/types.py +1 -3
- lionagi/service/hooks/hook_event.py +1 -1
- lionagi/service/hooks/hook_registry.py +1 -1
- lionagi/service/rate_limited_processor.py +1 -1
- lionagi/session/branch.py +24 -18
- lionagi/session/session.py +2 -18
- lionagi/utils.py +3 -335
- lionagi/version.py +1 -1
- {lionagi-0.16.2.dist-info → lionagi-0.17.0.dist-info}/METADATA +4 -13
- {lionagi-0.16.2.dist-info → lionagi-0.17.0.dist-info}/RECORD +39 -61
- lionagi/adapters/postgres_model_adapter.py +0 -131
- lionagi/libs/concurrency.py +0 -1
- lionagi/libs/nested/__init__.py +0 -3
- lionagi/libs/nested/flatten.py +0 -172
- lionagi/libs/nested/nfilter.py +0 -59
- lionagi/libs/nested/nget.py +0 -45
- lionagi/libs/nested/ninsert.py +0 -104
- lionagi/libs/nested/nmerge.py +0 -158
- lionagi/libs/nested/npop.py +0 -69
- lionagi/libs/nested/nset.py +0 -94
- lionagi/libs/nested/unflatten.py +0 -83
- lionagi/libs/nested/utils.py +0 -189
- lionagi/libs/parse.py +0 -31
- lionagi/libs/schema/json_schema.py +0 -231
- lionagi/libs/unstructured/__init__.py +0 -0
- lionagi/libs/unstructured/pdf_to_image.py +0 -45
- lionagi/libs/unstructured/read_image_to_base64.py +0 -33
- lionagi/libs/validate/fuzzy_match_keys.py +0 -7
- lionagi/libs/validate/fuzzy_validate_mapping.py +0 -144
- lionagi/libs/validate/string_similarity.py +0 -7
- lionagi/libs/validate/xml_parser.py +0 -203
- lionagi/models/note.py +0 -387
- lionagi/protocols/graph/_utils.py +0 -22
- lionagi/service/connections/providers/claude_code_.py +0 -299
- {lionagi-0.16.2.dist-info → lionagi-0.17.0.dist-info}/WHEEL +0 -0
- {lionagi-0.16.2.dist-info → lionagi-0.17.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,299 +0,0 @@
|
|
1
|
-
# Copyright (c) 2025, HaiyangLi <quantocean.li at gmail dot com>
|
2
|
-
#
|
3
|
-
# SPDX-License-Identifier: Apache-2.0
|
4
|
-
|
5
|
-
from __future__ import annotations
|
6
|
-
|
7
|
-
import warnings
|
8
|
-
|
9
|
-
from pydantic import BaseModel
|
10
|
-
|
11
|
-
from lionagi import ln
|
12
|
-
from lionagi.libs.schema.as_readable import as_readable
|
13
|
-
from lionagi.service.connections.endpoint import Endpoint
|
14
|
-
from lionagi.service.connections.endpoint_config import EndpointConfig
|
15
|
-
from lionagi.utils import to_dict, to_list
|
16
|
-
|
17
|
-
from ...third_party.claude_code import (
|
18
|
-
CLAUDE_CODE_OPTION_PARAMS,
|
19
|
-
HAS_CLAUDE_CODE_SDK,
|
20
|
-
ClaudeCodeRequest,
|
21
|
-
ClaudePermission,
|
22
|
-
stream_cc_sdk_events,
|
23
|
-
)
|
24
|
-
|
25
|
-
__all__ = (
|
26
|
-
"ClaudeCodeRequest",
|
27
|
-
"CLAUDE_CODE_OPTION_PARAMS", # backward compatibility
|
28
|
-
"ClaudePermission", # backward compatibility
|
29
|
-
"ClaudeCodeEndpoint",
|
30
|
-
)
|
31
|
-
|
32
|
-
|
33
|
-
# --------------------------------------------------------------------------- SDK endpoint
|
34
|
-
|
35
|
-
_get_config = lambda: EndpointConfig(
|
36
|
-
name="claude_code",
|
37
|
-
provider="claude_code",
|
38
|
-
base_url="internal",
|
39
|
-
endpoint="query",
|
40
|
-
request_options=ClaudeCodeRequest,
|
41
|
-
timeout=3000,
|
42
|
-
api_key="dummy-key",
|
43
|
-
)
|
44
|
-
|
45
|
-
|
46
|
-
ENDPOINT_CONFIG = _get_config() # backward compatibility
|
47
|
-
|
48
|
-
|
49
|
-
class ClaudeCodeEndpoint(Endpoint):
|
50
|
-
"""Direct Python-SDK (non-CLI) endpoint - unchanged except for bug-fixes."""
|
51
|
-
|
52
|
-
def __init__(self, config: EndpointConfig = None, **kwargs):
|
53
|
-
if not HAS_CLAUDE_CODE_SDK:
|
54
|
-
raise ImportError(
|
55
|
-
"claude_code_sdk is not installed. "
|
56
|
-
"Please install it with `uv pip install lionagi[claude_code_sdk]`."
|
57
|
-
)
|
58
|
-
warnings.warn(
|
59
|
-
"The claude_code `query` endpoint is deprecated. Use `query_cli` endpoint instead.",
|
60
|
-
DeprecationWarning,
|
61
|
-
)
|
62
|
-
|
63
|
-
config = config or _get_config()
|
64
|
-
super().__init__(config=config, **kwargs)
|
65
|
-
|
66
|
-
def create_payload(self, request: dict | BaseModel, **kwargs):
|
67
|
-
req_dict = {**self.config.kwargs, **to_dict(request), **kwargs}
|
68
|
-
messages = req_dict.pop("messages")
|
69
|
-
req_obj = ClaudeCodeRequest.create(messages=messages, **req_dict)
|
70
|
-
return {"request": req_obj}, {}
|
71
|
-
|
72
|
-
async def stream(self, request: dict | BaseModel, **kwargs):
|
73
|
-
payload, _ = self.create_payload(request, **kwargs)
|
74
|
-
async for chunk in stream_cc_sdk_events(payload["request"]):
|
75
|
-
yield chunk
|
76
|
-
|
77
|
-
def _parse_claude_code_response(self, responses: list) -> dict:
|
78
|
-
"""Parse Claude Code responses into a clean chat completions-like format.
|
79
|
-
|
80
|
-
Claude Code returns a list of messages:
|
81
|
-
- SystemMessage: initialization info
|
82
|
-
- AssistantMessage(s): actual assistant responses with content blocks
|
83
|
-
- UserMessage(s): for tool use interactions
|
84
|
-
- ResultMessage: final result with metadata
|
85
|
-
|
86
|
-
When Claude Code uses tools, the ResultMessage.result may be None.
|
87
|
-
In that case, we need to look at the tool results in UserMessages.
|
88
|
-
"""
|
89
|
-
results = {
|
90
|
-
"session_id": None,
|
91
|
-
"model": "claude-code",
|
92
|
-
"result": "",
|
93
|
-
"tool_uses": [],
|
94
|
-
"tool_results": [],
|
95
|
-
"is_error": False,
|
96
|
-
"num_turns": None,
|
97
|
-
"total_cost_usd": None,
|
98
|
-
"usage": {
|
99
|
-
"prompt_tokens": 0,
|
100
|
-
"completion_tokens": 0,
|
101
|
-
"total_tokens": 0,
|
102
|
-
},
|
103
|
-
}
|
104
|
-
from claude_code_sdk import types as cc_types
|
105
|
-
|
106
|
-
for response in responses:
|
107
|
-
if isinstance(response, cc_types.SystemMessage):
|
108
|
-
results["session_id"] = response.data.get("session_id")
|
109
|
-
results["model"] = response.data.get("model", "claude-code")
|
110
|
-
if isinstance(
|
111
|
-
response, cc_types.AssistantMessage | cc_types.UserMessage
|
112
|
-
):
|
113
|
-
for block in to_list(
|
114
|
-
response.content,
|
115
|
-
flatten=True,
|
116
|
-
flatten_tuple_set=True,
|
117
|
-
dropna=True,
|
118
|
-
):
|
119
|
-
if isinstance(block, cc_types.TextBlock):
|
120
|
-
results["result"] += block.text.strip() + "\n"
|
121
|
-
|
122
|
-
if isinstance(block, cc_types.ToolUseBlock):
|
123
|
-
entry = {
|
124
|
-
"id": block.id,
|
125
|
-
"name": block.name,
|
126
|
-
"input": block.input,
|
127
|
-
}
|
128
|
-
results["tool_uses"].append(entry)
|
129
|
-
|
130
|
-
if isinstance(block, cc_types.ToolResultBlock):
|
131
|
-
results["tool_results"].append(
|
132
|
-
{
|
133
|
-
"tool_use_id": block.tool_use_id,
|
134
|
-
"content": block.content,
|
135
|
-
"is_error": block.is_error,
|
136
|
-
}
|
137
|
-
)
|
138
|
-
|
139
|
-
if isinstance(response, cc_types.ResultMessage):
|
140
|
-
if response.result:
|
141
|
-
results["result"] = str(response.result).strip()
|
142
|
-
results["usage"] = response.usage
|
143
|
-
results["is_error"] = response.is_error
|
144
|
-
results["total_cost_usd"] = response.total_cost_usd
|
145
|
-
results["num_turns"] = response.num_turns
|
146
|
-
results["duration_ms"] = response.duration_ms
|
147
|
-
results["duration_api_ms"] = response.duration_api_ms
|
148
|
-
|
149
|
-
return results
|
150
|
-
|
151
|
-
async def _call(
|
152
|
-
self,
|
153
|
-
payload: dict,
|
154
|
-
headers: dict,
|
155
|
-
**kwargs,
|
156
|
-
):
|
157
|
-
from claude_code_sdk import query as sdk_query
|
158
|
-
from claude_code_sdk import types as cc_types
|
159
|
-
|
160
|
-
responses = []
|
161
|
-
request: ClaudeCodeRequest = payload["request"]
|
162
|
-
system: cc_types.SystemMessage = None
|
163
|
-
|
164
|
-
# 1. stream the Claude Code response
|
165
|
-
async for chunk in self._stream_claude_code(**payload):
|
166
|
-
if request.verbose_output:
|
167
|
-
_display_message(chunk, theme=request.cli_display_theme)
|
168
|
-
|
169
|
-
if isinstance(chunk, cc_types.SystemMessage):
|
170
|
-
system = chunk
|
171
|
-
responses.append(chunk)
|
172
|
-
|
173
|
-
# 2. If the last response is not a ResultMessage and auto_finish is True,
|
174
|
-
# we need to query Claude Code again to get the final result message.
|
175
|
-
if request.auto_finish and not isinstance(
|
176
|
-
responses[-1], cc_types.ResultMessage
|
177
|
-
):
|
178
|
-
options = request.as_claude_options()
|
179
|
-
options.continue_conversation = True
|
180
|
-
options.max_turns = 1
|
181
|
-
if system:
|
182
|
-
options.resume = (
|
183
|
-
system.data.get("session_id", None) if system else None
|
184
|
-
)
|
185
|
-
|
186
|
-
async for chunk in sdk_query(
|
187
|
-
prompt="Please provide a the final result message only",
|
188
|
-
options=options,
|
189
|
-
):
|
190
|
-
if isinstance(chunk, cc_types.ResultMessage):
|
191
|
-
if request.verbose_output:
|
192
|
-
str_ = _verbose_output(chunk)
|
193
|
-
if str_:
|
194
|
-
as_readable(
|
195
|
-
str_,
|
196
|
-
md=True,
|
197
|
-
display_str=True,
|
198
|
-
format_curly=True,
|
199
|
-
max_panel_width=100,
|
200
|
-
theme=request.cli_display_theme,
|
201
|
-
)
|
202
|
-
|
203
|
-
responses.append(chunk)
|
204
|
-
|
205
|
-
|
206
|
-
def _display_message(chunk, theme):
|
207
|
-
from claude_code_sdk import types as cc_types
|
208
|
-
|
209
|
-
if isinstance(
|
210
|
-
chunk,
|
211
|
-
cc_types.SystemMessage
|
212
|
-
| cc_types.AssistantMessage
|
213
|
-
| cc_types.UserMessage,
|
214
|
-
):
|
215
|
-
str_ = _verbose_output(chunk)
|
216
|
-
if str_:
|
217
|
-
if str_.startswith("Claude:"):
|
218
|
-
as_readable(
|
219
|
-
str_,
|
220
|
-
md=True,
|
221
|
-
display_str=True,
|
222
|
-
max_panel_width=100,
|
223
|
-
theme=theme,
|
224
|
-
)
|
225
|
-
else:
|
226
|
-
as_readable(
|
227
|
-
str_,
|
228
|
-
format_curly=True,
|
229
|
-
display_str=True,
|
230
|
-
max_panel_width=100,
|
231
|
-
theme=theme,
|
232
|
-
)
|
233
|
-
|
234
|
-
if isinstance(chunk, cc_types.ResultMessage):
|
235
|
-
str_ = _verbose_output(chunk)
|
236
|
-
as_readable(
|
237
|
-
str_,
|
238
|
-
md=True,
|
239
|
-
display_str=True,
|
240
|
-
format_curly=True,
|
241
|
-
max_panel_width=100,
|
242
|
-
theme=theme,
|
243
|
-
)
|
244
|
-
|
245
|
-
|
246
|
-
def _verbose_output(res) -> str:
|
247
|
-
from claude_code_sdk import types as cc_types
|
248
|
-
|
249
|
-
str_ = ""
|
250
|
-
if isinstance(res, cc_types.SystemMessage):
|
251
|
-
str_ = f"Claude Code Session Started: {res.data.get('session_id', 'unknown')}"
|
252
|
-
str_ += f"\nModel: {res.data.get('model', 'claude-code')}\n---"
|
253
|
-
return str_
|
254
|
-
|
255
|
-
if isinstance(res, cc_types.AssistantMessage | cc_types.UserMessage):
|
256
|
-
for block in to_list(
|
257
|
-
res.content, flatten=True, flatten_tuple_set=True, dropna=True
|
258
|
-
):
|
259
|
-
if isinstance(block, cc_types.TextBlock):
|
260
|
-
text = (
|
261
|
-
block.text.strip() if isinstance(block.text, str) else ""
|
262
|
-
)
|
263
|
-
str_ += f"Claude:\n{text}"
|
264
|
-
|
265
|
-
if isinstance(block, cc_types.ToolUseBlock):
|
266
|
-
inp_ = None
|
267
|
-
|
268
|
-
if isinstance(block.input, dict | list):
|
269
|
-
inp_ = ln.json_dumps(
|
270
|
-
block.input,
|
271
|
-
pretty=True,
|
272
|
-
sort_keys=True,
|
273
|
-
append_newline=True,
|
274
|
-
)
|
275
|
-
else:
|
276
|
-
inp_ = str(block.input)
|
277
|
-
|
278
|
-
input = inp_[:200] + "..." if len(inp_) > 200 else inp_
|
279
|
-
str_ += (
|
280
|
-
f"Tool Use: {block.name} - {block.id}\n - Input: {input}"
|
281
|
-
)
|
282
|
-
|
283
|
-
if isinstance(block, cc_types.ToolResultBlock):
|
284
|
-
content = str(block.content)
|
285
|
-
content = (
|
286
|
-
content[:200] + "..." if len(content) > 200 else content
|
287
|
-
)
|
288
|
-
str_ += (
|
289
|
-
f"Tool Result: {block.tool_use_id}\n - Content: {content}"
|
290
|
-
)
|
291
|
-
return str_
|
292
|
-
|
293
|
-
if isinstance(res, cc_types.ResultMessage):
|
294
|
-
str_ += f"Session Completion - {res.session_id}"
|
295
|
-
str_ += f"\nResult: {res.result or 'No result'}"
|
296
|
-
str_ += f"\n- Cost: ${res.total_cost_usd:.4f} USD"
|
297
|
-
str_ += f"\n- Duration: {res.duration_ms} ms (API: {res.duration_api_ms} ms)"
|
298
|
-
str_ += f"\n- Turns: {res.num_turns}"
|
299
|
-
return str_
|
File without changes
|
File without changes
|