agent-runtime-core 0.7.0__py3-none-any.whl → 0.8.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.
- agent_runtime_core/__init__.py +109 -2
- 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/files/__init__.py +88 -0
- agent_runtime_core/files/base.py +343 -0
- agent_runtime_core/files/ocr.py +406 -0
- agent_runtime_core/files/processors.py +508 -0
- agent_runtime_core/files/tools.py +317 -0
- agent_runtime_core/files/vision.py +360 -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.8.0.dist-info}/METADATA +236 -1
- agent_runtime_core-0.8.0.dist-info/RECORD +63 -0
- agent_runtime_core-0.7.0.dist-info/RECORD +0 -39
- {agent_runtime_core-0.7.0.dist-info → agent_runtime_core-0.8.0.dist-info}/WHEEL +0 -0
- {agent_runtime_core-0.7.0.dist-info → agent_runtime_core-0.8.0.dist-info}/licenses/LICENSE +0 -0
agent_runtime_core/__init__.py
CHANGED
|
@@ -34,16 +34,18 @@ Example usage:
|
|
|
34
34
|
return RunResult(final_output={"message": "Hello!"})
|
|
35
35
|
"""
|
|
36
36
|
|
|
37
|
-
__version__ = "0.
|
|
37
|
+
__version__ = "0.8.0"
|
|
38
38
|
|
|
39
39
|
# Core interfaces
|
|
40
40
|
from agent_runtime_core.interfaces import (
|
|
41
41
|
AgentRuntime,
|
|
42
42
|
EventType,
|
|
43
|
+
EventVisibility,
|
|
43
44
|
ErrorInfo,
|
|
44
45
|
LLMClient,
|
|
45
46
|
LLMResponse,
|
|
46
47
|
LLMStreamChunk,
|
|
48
|
+
LLMToolCall,
|
|
47
49
|
Message,
|
|
48
50
|
RunContext,
|
|
49
51
|
RunResult,
|
|
@@ -57,6 +59,12 @@ from agent_runtime_core.interfaces import (
|
|
|
57
59
|
# Tool Calling Agent base class
|
|
58
60
|
from agent_runtime_core.tool_calling_agent import ToolCallingAgent
|
|
59
61
|
|
|
62
|
+
# Agentic loop helper
|
|
63
|
+
from agent_runtime_core.agentic_loop import (
|
|
64
|
+
run_agentic_loop,
|
|
65
|
+
AgenticLoopResult,
|
|
66
|
+
)
|
|
67
|
+
|
|
60
68
|
# Configuration
|
|
61
69
|
from agent_runtime_core.config import (
|
|
62
70
|
RuntimeConfig,
|
|
@@ -128,6 +136,7 @@ from agent_runtime_core.persistence import (
|
|
|
128
136
|
FileConversationStore,
|
|
129
137
|
FileTaskStore,
|
|
130
138
|
FilePreferencesStore,
|
|
139
|
+
FileKnowledgeStore,
|
|
131
140
|
# Manager
|
|
132
141
|
PersistenceManager,
|
|
133
142
|
PersistenceConfig,
|
|
@@ -135,6 +144,69 @@ from agent_runtime_core.persistence import (
|
|
|
135
144
|
configure_persistence,
|
|
136
145
|
)
|
|
137
146
|
|
|
147
|
+
# Agent configuration schema (portable JSON format)
|
|
148
|
+
from agent_runtime_core.config_schema import (
|
|
149
|
+
AgentConfig,
|
|
150
|
+
ToolConfig,
|
|
151
|
+
KnowledgeConfig,
|
|
152
|
+
SubAgentToolConfig,
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
# JSON-based runtime (loads from AgentConfig)
|
|
156
|
+
from agent_runtime_core.json_runtime import (
|
|
157
|
+
JsonAgentRuntime,
|
|
158
|
+
ConfiguredTool,
|
|
159
|
+
SubAgentTool,
|
|
160
|
+
resolve_function,
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
# Vector store (optional - requires additional dependencies)
|
|
164
|
+
# Import these directly from agent_runtime_core.vectorstore when needed:
|
|
165
|
+
# from agent_runtime_core.vectorstore import (
|
|
166
|
+
# VectorStore, VectorRecord, VectorSearchResult,
|
|
167
|
+
# EmbeddingClient, OpenAIEmbeddings, VertexAIEmbeddings,
|
|
168
|
+
# get_vector_store, get_embedding_client,
|
|
169
|
+
# )
|
|
170
|
+
|
|
171
|
+
# RAG (Retrieval Augmented Generation)
|
|
172
|
+
from agent_runtime_core.rag import (
|
|
173
|
+
chunk_text,
|
|
174
|
+
ChunkingConfig,
|
|
175
|
+
TextChunk,
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
# RAG services are imported lazily to avoid circular dependencies
|
|
179
|
+
# Import directly when needed:
|
|
180
|
+
# from agent_runtime_core.rag import KnowledgeIndexer, KnowledgeRetriever
|
|
181
|
+
|
|
182
|
+
# Tool schema builder utilities
|
|
183
|
+
from agent_runtime_core.tools import (
|
|
184
|
+
ToolSchema,
|
|
185
|
+
ToolSchemaBuilder,
|
|
186
|
+
ToolParameter,
|
|
187
|
+
schemas_to_openai_format,
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
# Multi-agent support (agent-as-tool pattern)
|
|
191
|
+
from agent_runtime_core.multi_agent import (
|
|
192
|
+
AgentTool,
|
|
193
|
+
AgentInvocationResult,
|
|
194
|
+
InvocationMode,
|
|
195
|
+
ContextMode,
|
|
196
|
+
SubAgentContext,
|
|
197
|
+
invoke_agent,
|
|
198
|
+
create_agent_tool_handler,
|
|
199
|
+
register_agent_tools,
|
|
200
|
+
build_sub_agent_messages,
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
# Cross-conversation memory
|
|
204
|
+
# Import directly when needed for full functionality:
|
|
205
|
+
# from agent_runtime_core.memory import (
|
|
206
|
+
# MemoryManager, MemoryConfig, MemoryEnabledAgent,
|
|
207
|
+
# ExtractedMemory, RecalledMemory, with_memory,
|
|
208
|
+
# )
|
|
209
|
+
|
|
138
210
|
__all__ = [
|
|
139
211
|
# Version
|
|
140
212
|
"__version__",
|
|
@@ -143,6 +215,7 @@ __all__ = [
|
|
|
143
215
|
"LLMClient",
|
|
144
216
|
"LLMResponse",
|
|
145
217
|
"LLMStreamChunk",
|
|
218
|
+
"LLMToolCall",
|
|
146
219
|
"Message",
|
|
147
220
|
"RunContext",
|
|
148
221
|
"RunResult",
|
|
@@ -151,8 +224,12 @@ __all__ = [
|
|
|
151
224
|
"ToolDefinition",
|
|
152
225
|
"TraceSink",
|
|
153
226
|
"EventType",
|
|
227
|
+
"EventVisibility",
|
|
154
228
|
"ErrorInfo",
|
|
155
|
-
|
|
229
|
+
# Tool calling
|
|
230
|
+
"ToolCallingAgent",
|
|
231
|
+
"run_agentic_loop",
|
|
232
|
+
"AgenticLoopResult",
|
|
156
233
|
# Configuration
|
|
157
234
|
"RuntimeConfig",
|
|
158
235
|
"configure",
|
|
@@ -204,9 +281,39 @@ __all__ = [
|
|
|
204
281
|
"FileConversationStore",
|
|
205
282
|
"FileTaskStore",
|
|
206
283
|
"FilePreferencesStore",
|
|
284
|
+
"FileKnowledgeStore",
|
|
207
285
|
# Persistence - Manager
|
|
208
286
|
"PersistenceManager",
|
|
209
287
|
"PersistenceConfig",
|
|
210
288
|
"get_persistence_manager",
|
|
211
289
|
"configure_persistence",
|
|
290
|
+
# Agent configuration schema
|
|
291
|
+
"AgentConfig",
|
|
292
|
+
"ToolConfig",
|
|
293
|
+
"KnowledgeConfig",
|
|
294
|
+
"SubAgentToolConfig",
|
|
295
|
+
# JSON-based runtime
|
|
296
|
+
"JsonAgentRuntime",
|
|
297
|
+
"ConfiguredTool",
|
|
298
|
+
"SubAgentTool",
|
|
299
|
+
"resolve_function",
|
|
300
|
+
# RAG (Retrieval Augmented Generation)
|
|
301
|
+
"chunk_text",
|
|
302
|
+
"ChunkingConfig",
|
|
303
|
+
"TextChunk",
|
|
304
|
+
# Tool schema builder
|
|
305
|
+
"ToolSchema",
|
|
306
|
+
"ToolSchemaBuilder",
|
|
307
|
+
"ToolParameter",
|
|
308
|
+
"schemas_to_openai_format",
|
|
309
|
+
# Multi-agent support
|
|
310
|
+
"AgentTool",
|
|
311
|
+
"AgentInvocationResult",
|
|
312
|
+
"InvocationMode",
|
|
313
|
+
"ContextMode",
|
|
314
|
+
"SubAgentContext",
|
|
315
|
+
"invoke_agent",
|
|
316
|
+
"create_agent_tool_handler",
|
|
317
|
+
"register_agent_tools",
|
|
318
|
+
"build_sub_agent_messages",
|
|
212
319
|
]
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Reusable agentic loop for tool-calling agents.
|
|
3
|
+
|
|
4
|
+
This module provides a flexible `run_agentic_loop` function that handles
|
|
5
|
+
the standard tool-calling pattern:
|
|
6
|
+
1. Call LLM with tools
|
|
7
|
+
2. If tool calls, execute them and loop back
|
|
8
|
+
3. If no tool calls, return final response
|
|
9
|
+
|
|
10
|
+
This can be used by any agent implementation without requiring inheritance.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import json
|
|
14
|
+
import logging
|
|
15
|
+
from dataclasses import dataclass
|
|
16
|
+
from typing import Any, Callable, Optional, Awaitable, Union
|
|
17
|
+
|
|
18
|
+
from agent_runtime_core.interfaces import (
|
|
19
|
+
RunContext,
|
|
20
|
+
EventType,
|
|
21
|
+
LLMClient,
|
|
22
|
+
LLMResponse,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
logger = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
# Type alias for tool executor function
|
|
28
|
+
ToolExecutor = Callable[[str, dict], Awaitable[Any]]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass
|
|
32
|
+
class AgenticLoopResult:
|
|
33
|
+
"""Result from running the agentic loop."""
|
|
34
|
+
|
|
35
|
+
final_content: str
|
|
36
|
+
"""The final text response from the LLM."""
|
|
37
|
+
|
|
38
|
+
messages: list[dict]
|
|
39
|
+
"""All messages including tool calls and results."""
|
|
40
|
+
|
|
41
|
+
iterations: int
|
|
42
|
+
"""Number of iterations the loop ran."""
|
|
43
|
+
|
|
44
|
+
usage: dict
|
|
45
|
+
"""Token usage from the final LLM call."""
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
async def run_agentic_loop(
|
|
49
|
+
llm: LLMClient,
|
|
50
|
+
messages: list[dict],
|
|
51
|
+
tools: Optional[list[dict]],
|
|
52
|
+
execute_tool: ToolExecutor,
|
|
53
|
+
ctx: RunContext,
|
|
54
|
+
*,
|
|
55
|
+
model: Optional[str] = None,
|
|
56
|
+
max_iterations: int = 15,
|
|
57
|
+
emit_events: bool = True,
|
|
58
|
+
**llm_kwargs,
|
|
59
|
+
) -> AgenticLoopResult:
|
|
60
|
+
"""
|
|
61
|
+
Run the standard agentic tool-calling loop.
|
|
62
|
+
|
|
63
|
+
This handles the common pattern of:
|
|
64
|
+
1. Call LLM with available tools
|
|
65
|
+
2. If LLM returns tool calls, execute them
|
|
66
|
+
3. Add tool results to messages and loop back to step 1
|
|
67
|
+
4. If LLM returns a text response (no tool calls), return it
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
llm: The LLM client to use for generation
|
|
71
|
+
messages: Initial messages (should include system prompt)
|
|
72
|
+
tools: List of tool schemas in OpenAI format, or None for no tools
|
|
73
|
+
execute_tool: Async function that executes a tool: (name, args) -> result
|
|
74
|
+
ctx: Run context for emitting events
|
|
75
|
+
model: Model to use (passed to LLM client)
|
|
76
|
+
max_iterations: Maximum loop iterations to prevent infinite loops
|
|
77
|
+
emit_events: Whether to emit TOOL_CALL and TOOL_RESULT events
|
|
78
|
+
**llm_kwargs: Additional kwargs passed to llm.generate()
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
AgenticLoopResult with final content, messages, and metadata
|
|
82
|
+
|
|
83
|
+
Example:
|
|
84
|
+
async def my_tool_executor(name: str, args: dict) -> Any:
|
|
85
|
+
if name == "get_weather":
|
|
86
|
+
return {"temp": 72, "conditions": "sunny"}
|
|
87
|
+
raise ValueError(f"Unknown tool: {name}")
|
|
88
|
+
|
|
89
|
+
result = await run_agentic_loop(
|
|
90
|
+
llm=my_llm_client,
|
|
91
|
+
messages=[{"role": "system", "content": "You are helpful."}],
|
|
92
|
+
tools=[{"type": "function", "function": {...}}],
|
|
93
|
+
execute_tool=my_tool_executor,
|
|
94
|
+
ctx=ctx,
|
|
95
|
+
model="gpt-4o",
|
|
96
|
+
)
|
|
97
|
+
"""
|
|
98
|
+
iteration = 0
|
|
99
|
+
final_content = ""
|
|
100
|
+
last_response: Optional[LLMResponse] = None
|
|
101
|
+
consecutive_errors = 0
|
|
102
|
+
max_consecutive_errors = 3 # Bail out if tool keeps failing
|
|
103
|
+
|
|
104
|
+
while iteration < max_iterations:
|
|
105
|
+
iteration += 1
|
|
106
|
+
print(f"[agentic-loop] Iteration {iteration}/{max_iterations}, messages={len(messages)}", flush=True)
|
|
107
|
+
logger.debug(f"Agentic loop iteration {iteration}/{max_iterations}")
|
|
108
|
+
|
|
109
|
+
# Call LLM
|
|
110
|
+
if tools:
|
|
111
|
+
response = await llm.generate(
|
|
112
|
+
messages,
|
|
113
|
+
model=model,
|
|
114
|
+
tools=tools,
|
|
115
|
+
**llm_kwargs,
|
|
116
|
+
)
|
|
117
|
+
else:
|
|
118
|
+
response = await llm.generate(
|
|
119
|
+
messages,
|
|
120
|
+
model=model,
|
|
121
|
+
**llm_kwargs,
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
last_response = response
|
|
125
|
+
|
|
126
|
+
# Check for tool calls
|
|
127
|
+
if response.tool_calls:
|
|
128
|
+
# Add assistant message with tool calls to conversation
|
|
129
|
+
messages.append(response.message)
|
|
130
|
+
|
|
131
|
+
# Execute each tool call
|
|
132
|
+
for tool_call in response.tool_calls:
|
|
133
|
+
# Debug: log raw tool call to help diagnose empty args issue
|
|
134
|
+
print(f"[agentic-loop] Raw tool_call type={type(tool_call).__name__}", flush=True)
|
|
135
|
+
if hasattr(tool_call, '_data'):
|
|
136
|
+
print(f"[agentic-loop] tool_call._data={tool_call._data}", flush=True)
|
|
137
|
+
|
|
138
|
+
# Handle both ToolCall objects (with .id, .name, .arguments) and dicts
|
|
139
|
+
if hasattr(tool_call, 'id') and not isinstance(tool_call, dict):
|
|
140
|
+
# ToolCall object
|
|
141
|
+
tool_call_id = tool_call.id
|
|
142
|
+
tool_name = tool_call.name
|
|
143
|
+
tool_args = tool_call.arguments
|
|
144
|
+
print(f"[agentic-loop] Parsed: name={tool_name}, args={tool_args}", flush=True)
|
|
145
|
+
else:
|
|
146
|
+
# Dict format
|
|
147
|
+
tool_call_id = tool_call.get("id")
|
|
148
|
+
tool_name = tool_call.get("function", {}).get("name")
|
|
149
|
+
tool_args_str = tool_call.get("function", {}).get("arguments", "{}")
|
|
150
|
+
logger.debug(f"Dict tool_call: id={tool_call_id}, name={tool_name}, args_str={tool_args_str}")
|
|
151
|
+
# Parse arguments (handle both string and dict)
|
|
152
|
+
if isinstance(tool_args_str, dict):
|
|
153
|
+
tool_args = tool_args_str
|
|
154
|
+
else:
|
|
155
|
+
try:
|
|
156
|
+
tool_args = json.loads(tool_args_str)
|
|
157
|
+
except json.JSONDecodeError:
|
|
158
|
+
logger.warning(f"Failed to parse tool args: {tool_args_str}")
|
|
159
|
+
tool_args = {}
|
|
160
|
+
|
|
161
|
+
# Emit tool call event
|
|
162
|
+
if emit_events:
|
|
163
|
+
await ctx.emit(EventType.TOOL_CALL, {
|
|
164
|
+
"id": tool_call_id,
|
|
165
|
+
"name": tool_name,
|
|
166
|
+
"arguments": tool_args,
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
# Execute the tool
|
|
170
|
+
try:
|
|
171
|
+
result = await execute_tool(tool_name, tool_args)
|
|
172
|
+
# Reset error counter on success
|
|
173
|
+
if not isinstance(result, dict) or "error" not in result:
|
|
174
|
+
consecutive_errors = 0
|
|
175
|
+
else:
|
|
176
|
+
consecutive_errors += 1
|
|
177
|
+
except Exception as e:
|
|
178
|
+
logger.exception(f"Error executing tool {tool_name}")
|
|
179
|
+
result = {"error": str(e)}
|
|
180
|
+
consecutive_errors += 1
|
|
181
|
+
|
|
182
|
+
# Emit tool result event
|
|
183
|
+
if emit_events:
|
|
184
|
+
await ctx.emit(EventType.TOOL_RESULT, {
|
|
185
|
+
"tool_call_id": tool_call_id,
|
|
186
|
+
"name": tool_name,
|
|
187
|
+
"result": result,
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
# Add tool result to messages
|
|
191
|
+
result_str = json.dumps(result) if not isinstance(result, str) else result
|
|
192
|
+
messages.append({
|
|
193
|
+
"role": "tool",
|
|
194
|
+
"tool_call_id": tool_call_id,
|
|
195
|
+
"content": result_str,
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
# Check for too many consecutive errors
|
|
199
|
+
if consecutive_errors >= max_consecutive_errors:
|
|
200
|
+
error_msg = result.get('error', 'Unknown error') if isinstance(result, dict) else str(result)
|
|
201
|
+
logger.warning(f"Aborting agentic loop after {consecutive_errors} consecutive tool errors: {error_msg}")
|
|
202
|
+
|
|
203
|
+
# Emit error event for run history
|
|
204
|
+
if emit_events:
|
|
205
|
+
await ctx.emit(EventType.ERROR, {
|
|
206
|
+
"error": f"Tool loop aborted after {consecutive_errors} consecutive errors",
|
|
207
|
+
"last_error": error_msg,
|
|
208
|
+
"tool_name": tool_name,
|
|
209
|
+
"iterations": iteration,
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
# Add error to messages for conversation history
|
|
213
|
+
final_content = f"I encountered repeated errors while trying to complete this task. The last error was: {error_msg}"
|
|
214
|
+
messages.append({
|
|
215
|
+
"role": "assistant",
|
|
216
|
+
"content": final_content,
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
if emit_events:
|
|
220
|
+
await ctx.emit(EventType.ASSISTANT_MESSAGE, {
|
|
221
|
+
"content": final_content,
|
|
222
|
+
"role": "assistant",
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
return AgenticLoopResult(
|
|
226
|
+
final_content=final_content,
|
|
227
|
+
messages=messages,
|
|
228
|
+
iterations=iteration,
|
|
229
|
+
usage=last_response.usage if last_response else {},
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
# Continue the loop to get next response
|
|
233
|
+
continue
|
|
234
|
+
|
|
235
|
+
# No tool calls - we have the final response
|
|
236
|
+
final_content = response.message.get("content", "")
|
|
237
|
+
messages.append(response.message)
|
|
238
|
+
|
|
239
|
+
# Emit assistant message event for the final response
|
|
240
|
+
if emit_events and final_content:
|
|
241
|
+
await ctx.emit(EventType.ASSISTANT_MESSAGE, {
|
|
242
|
+
"content": final_content,
|
|
243
|
+
"role": "assistant",
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
break
|
|
247
|
+
|
|
248
|
+
return AgenticLoopResult(
|
|
249
|
+
final_content=final_content,
|
|
250
|
+
messages=messages,
|
|
251
|
+
iterations=iteration,
|
|
252
|
+
usage=last_response.usage if last_response else {},
|
|
253
|
+
)
|
|
254
|
+
|
agent_runtime_core/config.py
CHANGED
|
@@ -59,7 +59,35 @@ class RuntimeConfig:
|
|
|
59
59
|
max_retries: int = 3
|
|
60
60
|
retry_backoff_base: int = 2
|
|
61
61
|
retry_backoff_max: int = 300
|
|
62
|
-
|
|
62
|
+
|
|
63
|
+
# Conversation history settings
|
|
64
|
+
# When True, agents automatically receive message history from previous runs
|
|
65
|
+
# in the same conversation. This enables multi-turn conversations by default.
|
|
66
|
+
include_conversation_history: bool = True
|
|
67
|
+
|
|
68
|
+
# Maximum number of history messages to include (None = no limit)
|
|
69
|
+
# Useful for limiting context window usage with long conversations
|
|
70
|
+
max_history_messages: Optional[int] = None
|
|
71
|
+
|
|
72
|
+
# Whether to automatically persist messages after each run
|
|
73
|
+
# When True, final_messages are saved to the conversation store
|
|
74
|
+
auto_persist_messages: bool = True
|
|
75
|
+
|
|
76
|
+
# Vector store settings
|
|
77
|
+
vector_store_backend: str = "none" # none, sqlite_vec, pgvector, vertex
|
|
78
|
+
vector_store_path: Optional[str] = None # For sqlite_vec file path
|
|
79
|
+
|
|
80
|
+
# Embedding settings
|
|
81
|
+
embedding_provider: str = "openai" # openai, vertex
|
|
82
|
+
embedding_model: str = "text-embedding-3-small"
|
|
83
|
+
|
|
84
|
+
# Vertex AI settings (for vertex vector store and embeddings)
|
|
85
|
+
vertex_project_id: Optional[str] = None
|
|
86
|
+
vertex_location: str = "us-central1"
|
|
87
|
+
vertex_index_endpoint_id: Optional[str] = None
|
|
88
|
+
vertex_deployed_index_id: Optional[str] = None
|
|
89
|
+
vertex_index_id: Optional[str] = None
|
|
90
|
+
|
|
63
91
|
def get_openai_api_key(self) -> Optional[str]:
|
|
64
92
|
"""Get OpenAI API key from config or environment."""
|
|
65
93
|
return self.openai_api_key or os.environ.get("OPENAI_API_KEY")
|
|
@@ -150,8 +178,19 @@ def _apply_env_vars(config: RuntimeConfig) -> None:
|
|
|
150
178
|
"AGENT_RUNTIME_LANGFUSE_PUBLIC_KEY": "langfuse_public_key",
|
|
151
179
|
"AGENT_RUNTIME_LANGFUSE_SECRET_KEY": "langfuse_secret_key",
|
|
152
180
|
"AGENT_RUNTIME_LANGFUSE_HOST": "langfuse_host",
|
|
181
|
+
# Vector store settings
|
|
182
|
+
"AGENT_RUNTIME_VECTOR_STORE_BACKEND": "vector_store_backend",
|
|
183
|
+
"AGENT_RUNTIME_VECTOR_STORE_PATH": "vector_store_path",
|
|
184
|
+
"AGENT_RUNTIME_EMBEDDING_PROVIDER": "embedding_provider",
|
|
185
|
+
"AGENT_RUNTIME_EMBEDDING_MODEL": "embedding_model",
|
|
186
|
+
# Vertex AI settings
|
|
187
|
+
"AGENT_RUNTIME_VERTEX_PROJECT_ID": "vertex_project_id",
|
|
188
|
+
"AGENT_RUNTIME_VERTEX_LOCATION": "vertex_location",
|
|
189
|
+
"AGENT_RUNTIME_VERTEX_INDEX_ENDPOINT_ID": "vertex_index_endpoint_id",
|
|
190
|
+
"AGENT_RUNTIME_VERTEX_DEPLOYED_INDEX_ID": "vertex_deployed_index_id",
|
|
191
|
+
"AGENT_RUNTIME_VERTEX_INDEX_ID": "vertex_index_id",
|
|
153
192
|
}
|
|
154
|
-
|
|
193
|
+
|
|
155
194
|
int_fields = {
|
|
156
195
|
"AGENT_RUNTIME_RUN_TIMEOUT_SECONDS": "run_timeout_seconds",
|
|
157
196
|
"AGENT_RUNTIME_HEARTBEAT_INTERVAL_SECONDS": "heartbeat_interval_seconds",
|
|
@@ -159,14 +198,25 @@ def _apply_env_vars(config: RuntimeConfig) -> None:
|
|
|
159
198
|
"AGENT_RUNTIME_MAX_RETRIES": "max_retries",
|
|
160
199
|
"AGENT_RUNTIME_RETRY_BACKOFF_BASE": "retry_backoff_base",
|
|
161
200
|
"AGENT_RUNTIME_RETRY_BACKOFF_MAX": "retry_backoff_max",
|
|
201
|
+
"AGENT_RUNTIME_MAX_HISTORY_MESSAGES": "max_history_messages",
|
|
162
202
|
}
|
|
163
|
-
|
|
203
|
+
|
|
204
|
+
bool_fields = {
|
|
205
|
+
"AGENT_RUNTIME_INCLUDE_CONVERSATION_HISTORY": "include_conversation_history",
|
|
206
|
+
"AGENT_RUNTIME_AUTO_PERSIST_MESSAGES": "auto_persist_messages",
|
|
207
|
+
}
|
|
208
|
+
|
|
164
209
|
for env_var, attr in env_mapping.items():
|
|
165
210
|
value = os.environ.get(env_var)
|
|
166
211
|
if value is not None:
|
|
167
212
|
setattr(config, attr, value)
|
|
168
|
-
|
|
213
|
+
|
|
169
214
|
for env_var, attr in int_fields.items():
|
|
170
215
|
value = os.environ.get(env_var)
|
|
171
216
|
if value is not None:
|
|
172
217
|
setattr(config, attr, int(value))
|
|
218
|
+
|
|
219
|
+
for env_var, attr in bool_fields.items():
|
|
220
|
+
value = os.environ.get(env_var)
|
|
221
|
+
if value is not None:
|
|
222
|
+
setattr(config, attr, value.lower() in ("true", "1", "yes", "on"))
|