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.
Files changed (63) hide show
  1. lionagi/adapters/_utils.py +10 -23
  2. lionagi/adapters/async_postgres_adapter.py +83 -79
  3. lionagi/ln/__init__.py +4 -4
  4. lionagi/ln/_json_dump.py +0 -6
  5. lionagi/ln/fuzzy/__init__.py +4 -1
  6. lionagi/ln/fuzzy/_fuzzy_validate.py +109 -0
  7. lionagi/ln/fuzzy/_to_dict.py +388 -0
  8. lionagi/models/__init__.py +0 -2
  9. lionagi/operations/__init__.py +0 -6
  10. lionagi/operations/_visualize_graph.py +285 -0
  11. lionagi/operations/brainstorm/brainstorm.py +14 -12
  12. lionagi/operations/builder.py +23 -302
  13. lionagi/operations/communicate/communicate.py +1 -1
  14. lionagi/operations/flow.py +14 -11
  15. lionagi/operations/node.py +14 -3
  16. lionagi/operations/operate/operate.py +5 -11
  17. lionagi/operations/parse/parse.py +2 -3
  18. lionagi/operations/types.py +0 -2
  19. lionagi/operations/utils.py +11 -5
  20. lionagi/protocols/generic/pile.py +3 -7
  21. lionagi/protocols/graph/graph.py +23 -6
  22. lionagi/protocols/graph/node.py +0 -2
  23. lionagi/protocols/messages/message.py +0 -1
  24. lionagi/protocols/operatives/operative.py +2 -2
  25. lionagi/protocols/types.py +0 -15
  26. lionagi/service/connections/endpoint.py +11 -5
  27. lionagi/service/connections/match_endpoint.py +2 -10
  28. lionagi/service/connections/providers/types.py +1 -3
  29. lionagi/service/hooks/hook_event.py +1 -1
  30. lionagi/service/hooks/hook_registry.py +1 -1
  31. lionagi/service/rate_limited_processor.py +1 -1
  32. lionagi/session/branch.py +24 -18
  33. lionagi/session/session.py +2 -18
  34. lionagi/utils.py +3 -335
  35. lionagi/version.py +1 -1
  36. {lionagi-0.16.2.dist-info → lionagi-0.17.0.dist-info}/METADATA +4 -13
  37. {lionagi-0.16.2.dist-info → lionagi-0.17.0.dist-info}/RECORD +39 -61
  38. lionagi/adapters/postgres_model_adapter.py +0 -131
  39. lionagi/libs/concurrency.py +0 -1
  40. lionagi/libs/nested/__init__.py +0 -3
  41. lionagi/libs/nested/flatten.py +0 -172
  42. lionagi/libs/nested/nfilter.py +0 -59
  43. lionagi/libs/nested/nget.py +0 -45
  44. lionagi/libs/nested/ninsert.py +0 -104
  45. lionagi/libs/nested/nmerge.py +0 -158
  46. lionagi/libs/nested/npop.py +0 -69
  47. lionagi/libs/nested/nset.py +0 -94
  48. lionagi/libs/nested/unflatten.py +0 -83
  49. lionagi/libs/nested/utils.py +0 -189
  50. lionagi/libs/parse.py +0 -31
  51. lionagi/libs/schema/json_schema.py +0 -231
  52. lionagi/libs/unstructured/__init__.py +0 -0
  53. lionagi/libs/unstructured/pdf_to_image.py +0 -45
  54. lionagi/libs/unstructured/read_image_to_base64.py +0 -33
  55. lionagi/libs/validate/fuzzy_match_keys.py +0 -7
  56. lionagi/libs/validate/fuzzy_validate_mapping.py +0 -144
  57. lionagi/libs/validate/string_similarity.py +0 -7
  58. lionagi/libs/validate/xml_parser.py +0 -203
  59. lionagi/models/note.py +0 -387
  60. lionagi/protocols/graph/_utils.py +0 -22
  61. lionagi/service/connections/providers/claude_code_.py +0 -299
  62. {lionagi-0.16.2.dist-info → lionagi-0.17.0.dist-info}/WHEEL +0 -0
  63. {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_