agent-runtime-core 0.7.0__py3-none-any.whl → 0.7.1__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.
- agent_runtime_core/__init__.py +108 -1
- agent_runtime_core/agentic_loop.py +254 -0
- agent_runtime_core/config.py +54 -4
- agent_runtime_core/config_schema.py +307 -0
- agent_runtime_core/interfaces.py +106 -0
- agent_runtime_core/json_runtime.py +509 -0
- agent_runtime_core/llm/__init__.py +80 -7
- agent_runtime_core/llm/anthropic.py +133 -12
- agent_runtime_core/llm/models_config.py +180 -0
- agent_runtime_core/memory/__init__.py +70 -0
- agent_runtime_core/memory/manager.py +554 -0
- agent_runtime_core/memory/mixin.py +294 -0
- agent_runtime_core/multi_agent.py +569 -0
- agent_runtime_core/persistence/__init__.py +2 -0
- agent_runtime_core/persistence/file.py +277 -0
- agent_runtime_core/rag/__init__.py +65 -0
- agent_runtime_core/rag/chunking.py +224 -0
- agent_runtime_core/rag/indexer.py +253 -0
- agent_runtime_core/rag/retriever.py +261 -0
- agent_runtime_core/runner.py +193 -15
- agent_runtime_core/tool_calling_agent.py +88 -130
- agent_runtime_core/tools.py +179 -0
- agent_runtime_core/vectorstore/__init__.py +193 -0
- agent_runtime_core/vectorstore/base.py +138 -0
- agent_runtime_core/vectorstore/embeddings.py +242 -0
- agent_runtime_core/vectorstore/sqlite_vec.py +328 -0
- agent_runtime_core/vectorstore/vertex.py +295 -0
- {agent_runtime_core-0.7.0.dist-info → agent_runtime_core-0.7.1.dist-info}/METADATA +202 -1
- agent_runtime_core-0.7.1.dist-info/RECORD +57 -0
- agent_runtime_core-0.7.0.dist-info/RECORD +0 -39
- {agent_runtime_core-0.7.0.dist-info → agent_runtime_core-0.7.1.dist-info}/WHEEL +0 -0
- {agent_runtime_core-0.7.0.dist-info → agent_runtime_core-0.7.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Memory mixin for adding cross-conversation memory to agents.
|
|
3
|
+
|
|
4
|
+
This mixin can be combined with ToolCallingAgent or any AgentRuntime
|
|
5
|
+
to add automatic memory extraction and recall.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
from typing import Any, Optional
|
|
10
|
+
|
|
11
|
+
from agent_runtime_core.interfaces import LLMClient, RunContext, RunResult
|
|
12
|
+
from agent_runtime_core.persistence.base import KnowledgeStore, FactType
|
|
13
|
+
from agent_runtime_core.memory.manager import (
|
|
14
|
+
MemoryManager,
|
|
15
|
+
MemoryConfig,
|
|
16
|
+
RecalledMemory,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
logger = logging.getLogger(__name__)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class MemoryEnabledAgent:
|
|
23
|
+
"""
|
|
24
|
+
Mixin that adds cross-conversation memory to agents.
|
|
25
|
+
|
|
26
|
+
Add this mixin to your agent class to enable automatic memory
|
|
27
|
+
extraction and recall. The mixin hooks into the agent lifecycle
|
|
28
|
+
to:
|
|
29
|
+
|
|
30
|
+
1. Recall relevant memories before each run
|
|
31
|
+
2. Inject memories into the system prompt
|
|
32
|
+
3. Extract new memories after each run
|
|
33
|
+
|
|
34
|
+
Example:
|
|
35
|
+
from agent_runtime_core import ToolCallingAgent, ToolRegistry
|
|
36
|
+
from agent_runtime_core.memory import MemoryEnabledAgent
|
|
37
|
+
|
|
38
|
+
class MyAgent(MemoryEnabledAgent, ToolCallingAgent):
|
|
39
|
+
memory_enabled = True
|
|
40
|
+
|
|
41
|
+
@property
|
|
42
|
+
def key(self) -> str:
|
|
43
|
+
return "my-agent"
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def system_prompt(self) -> str:
|
|
47
|
+
return "You are a helpful assistant."
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def tools(self) -> ToolRegistry:
|
|
51
|
+
return ToolRegistry()
|
|
52
|
+
|
|
53
|
+
Configuration:
|
|
54
|
+
- memory_enabled: Set to True to enable memory (default: False)
|
|
55
|
+
- memory_config: Optional MemoryConfig instance
|
|
56
|
+
- memory_prompt_style: How to format memories ("list", "prose", "structured")
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
# Class-level configuration (can be overridden in subclasses)
|
|
60
|
+
memory_enabled: bool = False
|
|
61
|
+
memory_config: Optional[MemoryConfig] = None
|
|
62
|
+
memory_prompt_style: str = "list"
|
|
63
|
+
|
|
64
|
+
# Instance state (set during initialization)
|
|
65
|
+
_memory_manager: Optional[MemoryManager] = None
|
|
66
|
+
_recalled_memories: list[RecalledMemory] = []
|
|
67
|
+
|
|
68
|
+
def configure_memory(
|
|
69
|
+
self,
|
|
70
|
+
knowledge_store: KnowledgeStore,
|
|
71
|
+
llm_client: Optional[LLMClient] = None,
|
|
72
|
+
config: Optional[MemoryConfig] = None,
|
|
73
|
+
) -> None:
|
|
74
|
+
"""
|
|
75
|
+
Configure the memory system for this agent.
|
|
76
|
+
|
|
77
|
+
Call this before running the agent if memory_enabled is True.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
knowledge_store: Store for persisting memories
|
|
81
|
+
llm_client: LLM client for extraction (uses agent's client if not provided)
|
|
82
|
+
config: Memory configuration
|
|
83
|
+
"""
|
|
84
|
+
if llm_client is None:
|
|
85
|
+
# Try to get from agent's get_llm_client method
|
|
86
|
+
if hasattr(self, 'get_llm_client'):
|
|
87
|
+
llm_client = self.get_llm_client()
|
|
88
|
+
else:
|
|
89
|
+
raise ValueError("llm_client required when agent doesn't have get_llm_client")
|
|
90
|
+
|
|
91
|
+
self._memory_manager = MemoryManager(
|
|
92
|
+
knowledge_store=knowledge_store,
|
|
93
|
+
llm_client=llm_client,
|
|
94
|
+
config=config or self.memory_config or MemoryConfig(),
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
def get_memory_manager(self) -> Optional[MemoryManager]:
|
|
98
|
+
"""Get the memory manager instance."""
|
|
99
|
+
return self._memory_manager
|
|
100
|
+
|
|
101
|
+
async def recall_memories_for_context(
|
|
102
|
+
self,
|
|
103
|
+
ctx: RunContext,
|
|
104
|
+
) -> list[RecalledMemory]:
|
|
105
|
+
"""
|
|
106
|
+
Recall relevant memories for the current context.
|
|
107
|
+
|
|
108
|
+
Override this method to customize memory recall logic.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
ctx: The run context
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
List of relevant memories
|
|
115
|
+
"""
|
|
116
|
+
if not self._memory_manager:
|
|
117
|
+
return []
|
|
118
|
+
|
|
119
|
+
# Get user_id from context metadata if available
|
|
120
|
+
user_id = ctx.metadata.get("user_id") or ctx.metadata.get("user")
|
|
121
|
+
|
|
122
|
+
# Recall memories based on input messages
|
|
123
|
+
return await self._memory_manager.recall_memories(
|
|
124
|
+
messages=ctx.input_messages,
|
|
125
|
+
user_id=str(user_id) if user_id else None,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
def format_memories_for_prompt(
|
|
129
|
+
self,
|
|
130
|
+
memories: list[RecalledMemory],
|
|
131
|
+
) -> str:
|
|
132
|
+
"""
|
|
133
|
+
Format memories for inclusion in the system prompt.
|
|
134
|
+
|
|
135
|
+
Override this method to customize memory formatting.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
memories: List of recalled memories
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
Formatted string to append to system prompt
|
|
142
|
+
"""
|
|
143
|
+
if not self._memory_manager or not memories:
|
|
144
|
+
return ""
|
|
145
|
+
|
|
146
|
+
return self._memory_manager.format_memories_for_prompt(
|
|
147
|
+
memories,
|
|
148
|
+
format_style=self.memory_prompt_style,
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
async def extract_memories_from_run(
|
|
152
|
+
self,
|
|
153
|
+
ctx: RunContext,
|
|
154
|
+
result: RunResult,
|
|
155
|
+
) -> None:
|
|
156
|
+
"""
|
|
157
|
+
Extract memories from a completed run.
|
|
158
|
+
|
|
159
|
+
Override this method to customize memory extraction logic.
|
|
160
|
+
|
|
161
|
+
Args:
|
|
162
|
+
ctx: The run context
|
|
163
|
+
result: The run result
|
|
164
|
+
"""
|
|
165
|
+
if not self._memory_manager:
|
|
166
|
+
return
|
|
167
|
+
|
|
168
|
+
# Get user_id from context metadata
|
|
169
|
+
user_id = ctx.metadata.get("user_id") or ctx.metadata.get("user")
|
|
170
|
+
|
|
171
|
+
# Combine input messages with result messages for extraction
|
|
172
|
+
all_messages = list(ctx.input_messages)
|
|
173
|
+
if result.final_messages:
|
|
174
|
+
all_messages.extend(result.final_messages)
|
|
175
|
+
|
|
176
|
+
# Extract memories
|
|
177
|
+
await self._memory_manager.extract_memories(
|
|
178
|
+
messages=all_messages,
|
|
179
|
+
user_id=str(user_id) if user_id else None,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
# ==========================================================================
|
|
183
|
+
# Hooks for ToolCallingAgent integration
|
|
184
|
+
# ==========================================================================
|
|
185
|
+
|
|
186
|
+
async def before_run(self, ctx: RunContext) -> None:
|
|
187
|
+
"""
|
|
188
|
+
Hook called before the agent run starts.
|
|
189
|
+
|
|
190
|
+
Recalls relevant memories and stores them for prompt injection.
|
|
191
|
+
"""
|
|
192
|
+
# Call parent's before_run if it exists
|
|
193
|
+
if hasattr(super(), 'before_run'):
|
|
194
|
+
await super().before_run(ctx)
|
|
195
|
+
|
|
196
|
+
if self.memory_enabled and self._memory_manager:
|
|
197
|
+
self._recalled_memories = await self.recall_memories_for_context(ctx)
|
|
198
|
+
if self._recalled_memories:
|
|
199
|
+
logger.info(f"Recalled {len(self._recalled_memories)} memories for run")
|
|
200
|
+
|
|
201
|
+
async def after_run(self, ctx: RunContext, result: RunResult) -> RunResult:
|
|
202
|
+
"""
|
|
203
|
+
Hook called after the agent run completes.
|
|
204
|
+
|
|
205
|
+
Extracts memories from the conversation.
|
|
206
|
+
"""
|
|
207
|
+
# Call parent's after_run if it exists
|
|
208
|
+
if hasattr(super(), 'after_run'):
|
|
209
|
+
result = await super().after_run(ctx, result)
|
|
210
|
+
|
|
211
|
+
if self.memory_enabled and self._memory_manager:
|
|
212
|
+
await self.extract_memories_from_run(ctx, result)
|
|
213
|
+
|
|
214
|
+
return result
|
|
215
|
+
|
|
216
|
+
@property
|
|
217
|
+
def system_prompt_with_memory(self) -> str:
|
|
218
|
+
"""
|
|
219
|
+
Get the system prompt with memories injected.
|
|
220
|
+
|
|
221
|
+
This is used internally by the mixin. Override system_prompt
|
|
222
|
+
in your agent class, not this property.
|
|
223
|
+
"""
|
|
224
|
+
base_prompt = self.system_prompt if hasattr(self, 'system_prompt') else ""
|
|
225
|
+
|
|
226
|
+
if not self.memory_enabled or not self._recalled_memories:
|
|
227
|
+
return base_prompt
|
|
228
|
+
|
|
229
|
+
memory_text = self.format_memories_for_prompt(self._recalled_memories)
|
|
230
|
+
if memory_text:
|
|
231
|
+
return f"{base_prompt}\n\n{memory_text}"
|
|
232
|
+
|
|
233
|
+
return base_prompt
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
# =============================================================================
|
|
237
|
+
# Convenience function for creating memory-enabled agents
|
|
238
|
+
# =============================================================================
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def with_memory(
|
|
242
|
+
agent_class: type,
|
|
243
|
+
knowledge_store: KnowledgeStore,
|
|
244
|
+
llm_client: Optional[LLMClient] = None,
|
|
245
|
+
config: Optional[MemoryConfig] = None,
|
|
246
|
+
) -> type:
|
|
247
|
+
"""
|
|
248
|
+
Create a memory-enabled version of an agent class.
|
|
249
|
+
|
|
250
|
+
This is a convenience function for adding memory to existing agents
|
|
251
|
+
without modifying their class definition.
|
|
252
|
+
|
|
253
|
+
Example:
|
|
254
|
+
from agent_runtime_core import ToolCallingAgent
|
|
255
|
+
from agent_runtime_core.memory import with_memory
|
|
256
|
+
|
|
257
|
+
# Original agent
|
|
258
|
+
class MyAgent(ToolCallingAgent):
|
|
259
|
+
...
|
|
260
|
+
|
|
261
|
+
# Memory-enabled version
|
|
262
|
+
MemoryMyAgent = with_memory(
|
|
263
|
+
MyAgent,
|
|
264
|
+
knowledge_store=FileKnowledgeStore(),
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
agent = MemoryMyAgent()
|
|
268
|
+
|
|
269
|
+
Args:
|
|
270
|
+
agent_class: The agent class to enhance
|
|
271
|
+
knowledge_store: Store for persisting memories
|
|
272
|
+
llm_client: Optional LLM client for extraction
|
|
273
|
+
config: Optional memory configuration
|
|
274
|
+
|
|
275
|
+
Returns:
|
|
276
|
+
A new class with memory capabilities
|
|
277
|
+
"""
|
|
278
|
+
class MemoryEnabledVersion(MemoryEnabledAgent, agent_class):
|
|
279
|
+
memory_enabled = True
|
|
280
|
+
memory_config = config
|
|
281
|
+
|
|
282
|
+
def __init__(self, *args, **kwargs):
|
|
283
|
+
super().__init__(*args, **kwargs)
|
|
284
|
+
self.configure_memory(
|
|
285
|
+
knowledge_store=knowledge_store,
|
|
286
|
+
llm_client=llm_client,
|
|
287
|
+
config=config,
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
MemoryEnabledVersion.__name__ = f"MemoryEnabled{agent_class.__name__}"
|
|
291
|
+
MemoryEnabledVersion.__qualname__ = f"MemoryEnabled{agent_class.__qualname__}"
|
|
292
|
+
|
|
293
|
+
return MemoryEnabledVersion
|
|
294
|
+
|