agnt5 0.2.8a2__cp310-abi3-macosx_10_12_x86_64.whl → 0.2.8a3__cp310-abi3-macosx_10_12_x86_64.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 agnt5 might be problematic. Click here for more details.
- agnt5/__init__.py +2 -0
- agnt5/_core.abi3.so +0 -0
- agnt5/agent.py +99 -15
- agnt5/agent_session.py +110 -0
- agnt5/entity.py +38 -19
- agnt5/worker.py +45 -11
- {agnt5-0.2.8a2.dist-info → agnt5-0.2.8a3.dist-info}/METADATA +1 -1
- {agnt5-0.2.8a2.dist-info → agnt5-0.2.8a3.dist-info}/RECORD +9 -8
- {agnt5-0.2.8a2.dist-info → agnt5-0.2.8a3.dist-info}/WHEEL +0 -0
agnt5/__init__.py
CHANGED
|
@@ -7,6 +7,7 @@ with built-in durability guarantees and state management.
|
|
|
7
7
|
|
|
8
8
|
from ._compat import _import_error, _rust_available
|
|
9
9
|
from .agent import Agent, AgentContext, AgentRegistry, AgentResult, Handoff, agent, handoff
|
|
10
|
+
from .agent_session import AgentSession
|
|
10
11
|
from .client import Client, RunError
|
|
11
12
|
from .context import Context
|
|
12
13
|
from .function import FunctionContext
|
|
@@ -66,6 +67,7 @@ __all__ = [
|
|
|
66
67
|
"Agent",
|
|
67
68
|
"AgentRegistry",
|
|
68
69
|
"AgentResult",
|
|
70
|
+
"AgentSession",
|
|
69
71
|
"Handoff",
|
|
70
72
|
"handoff",
|
|
71
73
|
# Types
|
agnt5/_core.abi3.so
CHANGED
|
Binary file
|
agnt5/agent.py
CHANGED
|
@@ -102,17 +102,25 @@ class AgentContext(Context):
|
|
|
102
102
|
# FunctionContext or base Context - create new state manager
|
|
103
103
|
self._state_manager = EntityStateManager()
|
|
104
104
|
logger.debug(f"AgentContext created new state manager (parent has no state)")
|
|
105
|
-
except RuntimeError:
|
|
105
|
+
except RuntimeError as e:
|
|
106
106
|
# _get_state_manager() failed (not in worker context) - create standalone
|
|
107
107
|
self._state_manager = EntityStateManager()
|
|
108
|
-
logger.debug(f"AgentContext created standalone state manager")
|
|
108
|
+
logger.debug(f"AgentContext created standalone state manager (not in worker context)")
|
|
109
109
|
else:
|
|
110
|
-
#
|
|
111
|
-
|
|
112
|
-
|
|
110
|
+
# Try to get from worker context first
|
|
111
|
+
try:
|
|
112
|
+
self._state_manager = _get_state_manager()
|
|
113
|
+
logger.debug(f"AgentContext got state manager from worker context")
|
|
114
|
+
except RuntimeError as e:
|
|
115
|
+
# Standalone - create new state manager
|
|
116
|
+
self._state_manager = EntityStateManager()
|
|
117
|
+
logger.debug(f"AgentContext created standalone state manager")
|
|
113
118
|
|
|
114
|
-
# Conversation key for state storage
|
|
119
|
+
# Conversation key for state storage (used for in-memory state)
|
|
115
120
|
self._conversation_key = f"agent:{agent_name}:{self._session_id}:messages"
|
|
121
|
+
# Entity key for database persistence (without :messages suffix to match API expectations)
|
|
122
|
+
self._entity_key = f"agent:{agent_name}:{self._session_id}"
|
|
123
|
+
logger.debug(f"AgentContext initialized - session_id={self._session_id}")
|
|
116
124
|
|
|
117
125
|
@property
|
|
118
126
|
def state(self):
|
|
@@ -143,14 +151,49 @@ class AgentContext(Context):
|
|
|
143
151
|
"""Get session identifier for this agent context."""
|
|
144
152
|
return self._session_id
|
|
145
153
|
|
|
146
|
-
def get_conversation_history(self) -> List[Message]:
|
|
154
|
+
async def get_conversation_history(self) -> List[Message]:
|
|
147
155
|
"""
|
|
148
|
-
Retrieve conversation history from state.
|
|
156
|
+
Retrieve conversation history from state, loading from database if needed.
|
|
149
157
|
|
|
150
158
|
Returns:
|
|
151
159
|
List of Message objects from conversation history
|
|
152
160
|
"""
|
|
161
|
+
# Try to load from database first if not in memory
|
|
162
|
+
entity_type = "AgentSession"
|
|
163
|
+
entity_key = self._entity_key # Use entity_key without :messages suffix
|
|
164
|
+
state_key = (entity_type, entity_key)
|
|
165
|
+
|
|
166
|
+
# Check if we need to load from platform
|
|
167
|
+
if state_key not in self._state_manager._states and self._state_manager._rust_manager:
|
|
168
|
+
try:
|
|
169
|
+
result = await self._state_manager._rust_manager.py_load_state(
|
|
170
|
+
entity_type, entity_key
|
|
171
|
+
)
|
|
172
|
+
found, state_json_bytes, version = result
|
|
173
|
+
if found:
|
|
174
|
+
import json
|
|
175
|
+
state_json = state_json_bytes.decode('utf-8') if isinstance(state_json_bytes, bytes) else state_json_bytes
|
|
176
|
+
session_data = json.loads(state_json)
|
|
177
|
+
|
|
178
|
+
# Extract messages from session object (might be old format or new format)
|
|
179
|
+
if isinstance(session_data, dict) and "messages" in session_data:
|
|
180
|
+
# New format with session metadata
|
|
181
|
+
messages_data = session_data["messages"]
|
|
182
|
+
elif isinstance(session_data, list):
|
|
183
|
+
# Old format - just messages array
|
|
184
|
+
messages_data = session_data
|
|
185
|
+
else:
|
|
186
|
+
messages_data = []
|
|
187
|
+
|
|
188
|
+
# Load messages into in-memory state (store just messages, not full session object)
|
|
189
|
+
self._state_manager.load_state_from_platform(state_key, json.dumps(messages_data), version)
|
|
190
|
+
logger.info(f"Loaded conversation history from database: {entity_key} (version {version})")
|
|
191
|
+
except Exception as e:
|
|
192
|
+
logger.warning(f"Failed to load conversation history from database: {e}")
|
|
193
|
+
|
|
194
|
+
# Get from in-memory state
|
|
153
195
|
messages_data = self.state.get(self._conversation_key, [])
|
|
196
|
+
logger.debug(f"Loaded {len(messages_data)} messages from conversation history")
|
|
154
197
|
|
|
155
198
|
# Convert dict representations back to Message objects
|
|
156
199
|
messages = []
|
|
@@ -174,13 +217,15 @@ class AgentContext(Context):
|
|
|
174
217
|
|
|
175
218
|
return messages
|
|
176
219
|
|
|
177
|
-
def save_conversation_history(self, messages: List[Message]) -> None:
|
|
220
|
+
async def save_conversation_history(self, messages: List[Message]) -> None:
|
|
178
221
|
"""
|
|
179
|
-
Save conversation history to state.
|
|
222
|
+
Save conversation history to state and persist to database.
|
|
180
223
|
|
|
181
224
|
Args:
|
|
182
225
|
messages: List of Message objects to persist
|
|
183
226
|
"""
|
|
227
|
+
logger.debug(f"Saving {len(messages)} messages to conversation history")
|
|
228
|
+
|
|
184
229
|
# Convert Message objects to dict for JSON serialization
|
|
185
230
|
messages_data = []
|
|
186
231
|
for msg in messages:
|
|
@@ -189,8 +234,47 @@ class AgentContext(Context):
|
|
|
189
234
|
"content": msg.content
|
|
190
235
|
})
|
|
191
236
|
|
|
237
|
+
# Save to in-memory state
|
|
192
238
|
self.state.set(self._conversation_key, messages_data)
|
|
193
239
|
|
|
240
|
+
# Persist to database via Rust EntityStateManager
|
|
241
|
+
if self._state_manager._rust_manager:
|
|
242
|
+
try:
|
|
243
|
+
import json
|
|
244
|
+
import time
|
|
245
|
+
entity_type = "AgentSession"
|
|
246
|
+
entity_key = self._entity_key # Use entity_key without :messages suffix
|
|
247
|
+
state_key = (entity_type, entity_key)
|
|
248
|
+
|
|
249
|
+
# Get current version
|
|
250
|
+
expected_version = self._state_manager._versions.get(state_key, 0)
|
|
251
|
+
|
|
252
|
+
# Build session object with metadata for the sessions API
|
|
253
|
+
now = time.time()
|
|
254
|
+
session_data = {
|
|
255
|
+
"session_id": self._session_id,
|
|
256
|
+
"agent_name": self._agent_name,
|
|
257
|
+
"created_at": now if expected_version == 0 else None, # Only set on first save
|
|
258
|
+
"last_message_time": now,
|
|
259
|
+
"message_count": len(messages_data),
|
|
260
|
+
"messages": messages_data,
|
|
261
|
+
"metadata": {}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
# Serialize to JSON bytes
|
|
265
|
+
state_json = json.dumps(session_data).encode('utf-8')
|
|
266
|
+
|
|
267
|
+
# Save to platform
|
|
268
|
+
new_version = await self._state_manager._rust_manager.py_save_state(
|
|
269
|
+
entity_type, entity_key, state_json, expected_version
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
# Update version tracking
|
|
273
|
+
self._state_manager._versions[state_key] = new_version
|
|
274
|
+
logger.info(f"Persisted conversation history to database: {entity_key} (version {expected_version} -> {new_version})")
|
|
275
|
+
except Exception as e:
|
|
276
|
+
logger.error(f"Failed to persist conversation history to database: {e}")
|
|
277
|
+
|
|
194
278
|
|
|
195
279
|
class Handoff:
|
|
196
280
|
"""Configuration for agent-to-agent handoff.
|
|
@@ -665,11 +749,11 @@ class Agent:
|
|
|
665
749
|
|
|
666
750
|
# Load conversation history from state (if AgentContext)
|
|
667
751
|
if isinstance(context, AgentContext):
|
|
668
|
-
messages: List[Message] = context.get_conversation_history()
|
|
752
|
+
messages: List[Message] = await context.get_conversation_history()
|
|
669
753
|
# Add new user message
|
|
670
754
|
messages.append(Message.user(user_message))
|
|
671
755
|
# Save updated conversation
|
|
672
|
-
context.save_conversation_history(messages)
|
|
756
|
+
await context.save_conversation_history(messages)
|
|
673
757
|
else:
|
|
674
758
|
# Fallback for non-AgentContext (shouldn't happen with code above)
|
|
675
759
|
messages = [Message.user(user_message)]
|
|
@@ -795,7 +879,7 @@ class Agent:
|
|
|
795
879
|
)
|
|
796
880
|
# Save conversation before returning
|
|
797
881
|
if isinstance(context, AgentContext):
|
|
798
|
-
context.save_conversation_history(messages)
|
|
882
|
+
await context.save_conversation_history(messages)
|
|
799
883
|
# Return immediately with handoff result
|
|
800
884
|
return AgentResult(
|
|
801
885
|
output=result["output"],
|
|
@@ -835,7 +919,7 @@ class Agent:
|
|
|
835
919
|
self.logger.debug(f"Agent completed after {iteration + 1} iterations")
|
|
836
920
|
# Save conversation before returning
|
|
837
921
|
if isinstance(context, AgentContext):
|
|
838
|
-
context.save_conversation_history(messages)
|
|
922
|
+
await context.save_conversation_history(messages)
|
|
839
923
|
return AgentResult(
|
|
840
924
|
output=response.text,
|
|
841
925
|
tool_calls=all_tool_calls,
|
|
@@ -847,7 +931,7 @@ class Agent:
|
|
|
847
931
|
final_output = messages[-1].content if messages else "No output generated"
|
|
848
932
|
# Save conversation before returning
|
|
849
933
|
if isinstance(context, AgentContext):
|
|
850
|
-
context.save_conversation_history(messages)
|
|
934
|
+
await context.save_conversation_history(messages)
|
|
851
935
|
return AgentResult(
|
|
852
936
|
output=final_output,
|
|
853
937
|
tool_calls=all_tool_calls,
|
agnt5/agent_session.py
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"""Agent session management for multi-turn conversations.
|
|
2
|
+
|
|
3
|
+
Provides AgentSession entity to track and persist conversation metadata
|
|
4
|
+
across multiple agent invocations. Session state is backed by the entity
|
|
5
|
+
infrastructure for durability.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import time
|
|
11
|
+
from typing import Optional, Dict, Any
|
|
12
|
+
|
|
13
|
+
from .entity import Entity
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class AgentSession(Entity):
|
|
17
|
+
"""
|
|
18
|
+
Entity representing an agent conversation session.
|
|
19
|
+
|
|
20
|
+
Tracks metadata about multi-turn conversations including:
|
|
21
|
+
- Session creation and last activity timestamps
|
|
22
|
+
- Message count
|
|
23
|
+
- Agent identification
|
|
24
|
+
- Custom metadata
|
|
25
|
+
|
|
26
|
+
The actual conversation messages are stored separately in AgentContext
|
|
27
|
+
using the session_id as the key. This entity only tracks session metadata.
|
|
28
|
+
|
|
29
|
+
Example:
|
|
30
|
+
```python
|
|
31
|
+
# Create new session
|
|
32
|
+
session = AgentSession("session-123")
|
|
33
|
+
session.create(agent_name="tutor", metadata={"user_id": "user-456"})
|
|
34
|
+
|
|
35
|
+
# Update on each message
|
|
36
|
+
session.add_message()
|
|
37
|
+
|
|
38
|
+
# Get session summary
|
|
39
|
+
summary = session.get_summary()
|
|
40
|
+
```
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
def __init__(self, session_id: str):
|
|
44
|
+
"""
|
|
45
|
+
Initialize agent session entity.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
session_id: Unique session identifier
|
|
49
|
+
"""
|
|
50
|
+
self.session_id = session_id
|
|
51
|
+
self.agent_name: str = ""
|
|
52
|
+
self.created_at: float = 0.0
|
|
53
|
+
self.last_message_time: float = 0.0
|
|
54
|
+
self.message_count: int = 0
|
|
55
|
+
self.metadata: Dict[str, Any] = {}
|
|
56
|
+
|
|
57
|
+
def create(self, agent_name: str, metadata: Optional[Dict[str, Any]] = None) -> None:
|
|
58
|
+
"""
|
|
59
|
+
Initialize a new session.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
agent_name: Name of the agent for this session
|
|
63
|
+
metadata: Optional additional session metadata
|
|
64
|
+
"""
|
|
65
|
+
current_time = time.time()
|
|
66
|
+
self.agent_name = agent_name
|
|
67
|
+
self.created_at = current_time
|
|
68
|
+
self.last_message_time = current_time
|
|
69
|
+
self.message_count = 0
|
|
70
|
+
self.metadata = metadata or {}
|
|
71
|
+
|
|
72
|
+
def add_message(self) -> None:
|
|
73
|
+
"""
|
|
74
|
+
Record a new message in the session.
|
|
75
|
+
|
|
76
|
+
Updates message count and last activity timestamp.
|
|
77
|
+
"""
|
|
78
|
+
self.message_count += 1
|
|
79
|
+
self.last_message_time = time.time()
|
|
80
|
+
|
|
81
|
+
def get_summary(self) -> Dict[str, Any]:
|
|
82
|
+
"""
|
|
83
|
+
Get session metadata summary.
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
Dictionary with session metadata including:
|
|
87
|
+
- session_id
|
|
88
|
+
- agent_name
|
|
89
|
+
- created_at
|
|
90
|
+
- last_message_time
|
|
91
|
+
- message_count
|
|
92
|
+
- metadata
|
|
93
|
+
"""
|
|
94
|
+
return {
|
|
95
|
+
"session_id": self.session_id,
|
|
96
|
+
"agent_name": self.agent_name,
|
|
97
|
+
"created_at": self.created_at,
|
|
98
|
+
"last_message_time": self.last_message_time,
|
|
99
|
+
"message_count": self.message_count,
|
|
100
|
+
"metadata": self.metadata,
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
def update_metadata(self, metadata: Dict[str, Any]) -> None:
|
|
104
|
+
"""
|
|
105
|
+
Update session metadata.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
metadata: Metadata to merge into existing metadata
|
|
109
|
+
"""
|
|
110
|
+
self.metadata.update(metadata)
|
agnt5/entity.py
CHANGED
|
@@ -497,15 +497,25 @@ def _create_entity_method_wrapper(entity_type: str, method):
|
|
|
497
497
|
lock = state_manager.get_or_create_lock(state_key)
|
|
498
498
|
|
|
499
499
|
async with lock:
|
|
500
|
-
#
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
500
|
+
# Load state from platform if not in memory
|
|
501
|
+
if state_key not in state_manager._states and state_manager._rust_manager:
|
|
502
|
+
try:
|
|
503
|
+
# Call Rust manager to load state from platform
|
|
504
|
+
result = await state_manager._rust_manager.py_load_state(
|
|
505
|
+
entity_type, self._key
|
|
506
|
+
)
|
|
507
|
+
# result is a tuple: (found, state_json, version)
|
|
508
|
+
found, state_json_bytes, version = result
|
|
509
|
+
if found:
|
|
510
|
+
# Decode and load state
|
|
511
|
+
state_json = state_json_bytes.decode('utf-8') if isinstance(state_json_bytes, bytes) else state_json_bytes
|
|
512
|
+
state_manager.load_state_from_platform(
|
|
513
|
+
state_key, state_json, version
|
|
514
|
+
)
|
|
515
|
+
logger.info(f"Loaded entity state from platform: {entity_type}:{self._key} (version {version})")
|
|
516
|
+
except Exception as e:
|
|
517
|
+
logger.warning(f"Failed to load entity state from platform: {e}")
|
|
518
|
+
# Continue with empty state
|
|
509
519
|
|
|
510
520
|
# Get or create state for this entity instance
|
|
511
521
|
state_dict = state_manager.get_or_create_state(state_key)
|
|
@@ -519,16 +529,25 @@ def _create_entity_method_wrapper(entity_type: str, method):
|
|
|
519
529
|
result = await method(self, *args, **kwargs)
|
|
520
530
|
logger.debug("Completed %s:%s.%s", entity_type, self._key, method.__name__)
|
|
521
531
|
|
|
522
|
-
#
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
+
# Save state to platform after successful execution
|
|
533
|
+
if state_manager._rust_manager:
|
|
534
|
+
try:
|
|
535
|
+
import json
|
|
536
|
+
# Get current version
|
|
537
|
+
expected_version = state_manager._versions.get(state_key, 0)
|
|
538
|
+
# Serialize state
|
|
539
|
+
state_json = json.dumps(state_dict).encode('utf-8')
|
|
540
|
+
# Call Rust manager to save state
|
|
541
|
+
new_version = await state_manager._rust_manager.py_save_state(
|
|
542
|
+
entity_type, self._key, state_json, expected_version
|
|
543
|
+
)
|
|
544
|
+
# Update version
|
|
545
|
+
state_manager._versions[state_key] = new_version
|
|
546
|
+
logger.info(f"Saved entity state to platform: {entity_type}:{self._key} (version {expected_version} -> {new_version})")
|
|
547
|
+
except Exception as e:
|
|
548
|
+
logger.error(f"Failed to save entity state to platform: {e}")
|
|
549
|
+
# Don't fail the method execution just because persistence failed
|
|
550
|
+
# The state is still in memory
|
|
532
551
|
|
|
533
552
|
return result
|
|
534
553
|
|
agnt5/worker.py
CHANGED
|
@@ -128,10 +128,11 @@ class Worker:
|
|
|
128
128
|
|
|
129
129
|
# Import Rust worker
|
|
130
130
|
try:
|
|
131
|
-
from ._core import PyWorker, PyWorkerConfig, PyComponentInfo
|
|
131
|
+
from ._core import PyWorker, PyWorkerConfig, PyComponentInfo, EntityStateManager as RustEntityStateManager
|
|
132
132
|
self._PyWorker = PyWorker
|
|
133
133
|
self._PyWorkerConfig = PyWorkerConfig
|
|
134
134
|
self._PyComponentInfo = PyComponentInfo
|
|
135
|
+
self._RustEntityStateManager = RustEntityStateManager
|
|
135
136
|
except ImportError as e:
|
|
136
137
|
raise ImportError(
|
|
137
138
|
f"Failed to import Rust core worker: {e}. "
|
|
@@ -148,9 +149,16 @@ class Worker:
|
|
|
148
149
|
# Create Rust worker instance
|
|
149
150
|
self._rust_worker = self._PyWorker(self._rust_config)
|
|
150
151
|
|
|
151
|
-
#
|
|
152
|
+
# Get tenant_id for entity state manager
|
|
153
|
+
import os
|
|
154
|
+
tenant_id = os.getenv("AGNT5_TENANT_ID", "00000000-0000-0000-0000-000000000001")
|
|
155
|
+
|
|
156
|
+
# Create Rust entity state manager
|
|
157
|
+
self._rust_entity_state_manager = self._RustEntityStateManager(tenant_id)
|
|
158
|
+
|
|
159
|
+
# Create worker-scoped entity state manager with Rust manager
|
|
152
160
|
from .entity import EntityStateManager
|
|
153
|
-
self._entity_state_manager = EntityStateManager()
|
|
161
|
+
self._entity_state_manager = EntityStateManager(rust_entity_state_manager=self._rust_entity_state_manager)
|
|
154
162
|
|
|
155
163
|
# Component registration: auto-discover or explicit
|
|
156
164
|
if auto_register:
|
|
@@ -1027,11 +1035,16 @@ class Worker:
|
|
|
1027
1035
|
)
|
|
1028
1036
|
|
|
1029
1037
|
async def _execute_agent(self, agent, input_data: bytes, request):
|
|
1030
|
-
"""Execute an agent."""
|
|
1038
|
+
"""Execute an agent with session support for multi-turn conversations."""
|
|
1031
1039
|
import json
|
|
1032
|
-
|
|
1040
|
+
import uuid
|
|
1041
|
+
from .agent import AgentContext
|
|
1042
|
+
from .entity import _entity_state_manager_ctx
|
|
1033
1043
|
from ._core import PyExecuteComponentResponse
|
|
1034
1044
|
|
|
1045
|
+
# Set entity state manager in context so AgentContext can access it
|
|
1046
|
+
_entity_state_manager_ctx.set(self._entity_state_manager)
|
|
1047
|
+
|
|
1035
1048
|
try:
|
|
1036
1049
|
# Parse input data
|
|
1037
1050
|
input_dict = json.loads(input_data.decode("utf-8")) if input_data else {}
|
|
@@ -1041,16 +1054,30 @@ class Worker:
|
|
|
1041
1054
|
if not user_message:
|
|
1042
1055
|
raise ValueError("Agent invocation requires 'message' parameter")
|
|
1043
1056
|
|
|
1044
|
-
#
|
|
1045
|
-
|
|
1046
|
-
|
|
1057
|
+
# Extract or generate session_id for multi-turn conversation support
|
|
1058
|
+
# If session_id is provided, the agent will load previous conversation history
|
|
1059
|
+
# If not provided, a new session is created with auto-generated ID
|
|
1060
|
+
session_id = input_dict.get("session_id")
|
|
1061
|
+
|
|
1062
|
+
if not session_id:
|
|
1063
|
+
session_id = str(uuid.uuid4())
|
|
1064
|
+
logger.info(f"Created new agent session: {session_id}")
|
|
1065
|
+
else:
|
|
1066
|
+
logger.info(f"Using existing agent session: {session_id}")
|
|
1067
|
+
|
|
1068
|
+
# Create AgentContext with session support for conversation persistence
|
|
1069
|
+
# AgentContext automatically loads/saves conversation history based on session_id
|
|
1070
|
+
ctx = AgentContext(
|
|
1071
|
+
run_id=request.invocation_id,
|
|
1072
|
+
agent_name=agent.name,
|
|
1073
|
+
session_id=session_id,
|
|
1047
1074
|
runtime_context=request.runtime_context,
|
|
1048
1075
|
)
|
|
1049
1076
|
|
|
1050
|
-
# Execute agent
|
|
1077
|
+
# Execute agent - conversation history is automatically included
|
|
1051
1078
|
agent_result = await agent.run(user_message, context=ctx)
|
|
1052
1079
|
|
|
1053
|
-
# Build response
|
|
1080
|
+
# Build response with agent output and tool calls
|
|
1054
1081
|
result = {
|
|
1055
1082
|
"output": agent_result.output,
|
|
1056
1083
|
"tool_calls": agent_result.tool_calls,
|
|
@@ -1059,13 +1086,16 @@ class Worker:
|
|
|
1059
1086
|
# Serialize result
|
|
1060
1087
|
output_data = json.dumps(result).encode("utf-8")
|
|
1061
1088
|
|
|
1089
|
+
# Return session_id in metadata so UI can persist it
|
|
1090
|
+
metadata = {"session_id": session_id}
|
|
1091
|
+
|
|
1062
1092
|
return PyExecuteComponentResponse(
|
|
1063
1093
|
invocation_id=request.invocation_id,
|
|
1064
1094
|
success=True,
|
|
1065
1095
|
output_data=output_data,
|
|
1066
1096
|
state_update=None,
|
|
1067
1097
|
error_message=None,
|
|
1068
|
-
metadata=
|
|
1098
|
+
metadata=metadata,
|
|
1069
1099
|
is_chunk=False,
|
|
1070
1100
|
done=True,
|
|
1071
1101
|
chunk_index=0,
|
|
@@ -1127,6 +1157,10 @@ class Worker:
|
|
|
1127
1157
|
if self.metadata:
|
|
1128
1158
|
self._rust_worker.set_service_metadata(self.metadata)
|
|
1129
1159
|
|
|
1160
|
+
# Set entity state manager on Rust worker for database persistence
|
|
1161
|
+
logger.info("Configuring entity state manager for database persistence")
|
|
1162
|
+
self._rust_worker.set_entity_state_manager(self._rust_entity_state_manager)
|
|
1163
|
+
|
|
1130
1164
|
# Get the current event loop to pass to Rust for concurrent Python async execution
|
|
1131
1165
|
# This allows Rust to execute Python async functions on the same event loop
|
|
1132
1166
|
# without spawn_blocking overhead, enabling true concurrency
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
agnt5-0.2.
|
|
2
|
-
agnt5-0.2.
|
|
3
|
-
agnt5/__init__.py,sha256=
|
|
1
|
+
agnt5-0.2.8a3.dist-info/METADATA,sha256=CSD_9YZ9vmaRf7sXcVSefdJ2YeIZnwQ2PZCohtvv5TY,996
|
|
2
|
+
agnt5-0.2.8a3.dist-info/WHEEL,sha256=eZxluNosN814qqPoiTnB1GwMrzvnR_7wE3Goh6BHRg8,105
|
|
3
|
+
agnt5/__init__.py,sha256=dlJ3rUXiWIZMd0LpGGhgaItkdYlcp3yuEufQb-Yqh9A,2105
|
|
4
4
|
agnt5/_compat.py,sha256=BGuy3v5VDOHVa5f3Z-C22iMN19lAt0mPmXwF3qSSWxI,369
|
|
5
|
-
agnt5/_core.abi3.so,sha256
|
|
5
|
+
agnt5/_core.abi3.so,sha256=-OEUHiGnOMzN5khT65z0mb1clTG8fOV7_urZe6N-KPY,12533812
|
|
6
6
|
agnt5/_retry_utils.py,sha256=loHsWY5BR4wZy57IzcDEjQAy88DHVwVIr25Cn1d9GPA,5801
|
|
7
7
|
agnt5/_schema_utils.py,sha256=MR67RW757T4Oq2Jqf4kB61H_b51zwaf3CLWELnkngRo,9572
|
|
8
8
|
agnt5/_telemetry.py,sha256=bIY9AvBRjJBTHoBPbfR6X1OgaiUf-T0vCoi0_snsWXA,5957
|
|
9
|
-
agnt5/agent.py,sha256=
|
|
9
|
+
agnt5/agent.py,sha256=fLX8k7cJ5-OKF9OU0Ykd__62mGFrYuToGUK0UdpNtas,41171
|
|
10
|
+
agnt5/agent_session.py,sha256=mZ61mVax6Wt1ArocwdVEx4Kju6veFYtqxtSNWeKOve0,3161
|
|
10
11
|
agnt5/client.py,sha256=kXksazgxdVXWaG9OkjJA4cWruNtcS-ENhtnkrIdw-Nk,23212
|
|
11
12
|
agnt5/context.py,sha256=S2OzPkhn_jnqSWfT21mSYOux8vHaLKQxcAvggZDHQek,2378
|
|
12
|
-
agnt5/entity.py,sha256=
|
|
13
|
+
agnt5/entity.py,sha256=KXSDklsqe9PoIKGz4hZpcmHJFLJKGe0Am8-3FH72Fxk,26150
|
|
13
14
|
agnt5/exceptions.py,sha256=mZ0q-NK6OKhYxgwBJpIbgpgzk-CJaFIHDbp1EE-pS7I,925
|
|
14
15
|
agnt5/function.py,sha256=f1vaAlJRwuo8cxCOGEd8XPido00mOhlPS8UJJx-6hJI,11041
|
|
15
16
|
agnt5/lm.py,sha256=9dFjd6eQ3f3lFZe7H7rWZherYiP_58MT1F5xpwD8PCg,23195
|
|
@@ -17,6 +18,6 @@ agnt5/tool.py,sha256=uc4L-Q9QyLzQDe-MZKk2Wo3o5e-mK8tfaQwVDgQdouQ,13133
|
|
|
17
18
|
agnt5/tracing.py,sha256=Mh2-OfnQM61lM_P8gxJstafdsUA8Gxoo1lP-Joxhub8,5980
|
|
18
19
|
agnt5/types.py,sha256=Zb71ZMwvrt1p4SH18cAKunp2y5tao_W5_jGYaPDejQo,2840
|
|
19
20
|
agnt5/version.py,sha256=rOq1mObLihnnKgKqBrwZA0zwOPudEKVFcW1a48ynkqc,573
|
|
20
|
-
agnt5/worker.py,sha256=
|
|
21
|
+
agnt5/worker.py,sha256=ALX8g8ij4GZ465mgEa17CO9I7Ybysv8w9uJWQRSd3g8,48685
|
|
21
22
|
agnt5/workflow.py,sha256=sU8Gk7unxE_Gla7Fe-KlXfcBvYa2326GciuoR26CCr0,19585
|
|
22
|
-
agnt5-0.2.
|
|
23
|
+
agnt5-0.2.8a3.dist-info/RECORD,,
|
|
File without changes
|