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
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AgentConfig - Canonical JSON schema for portable agent definitions.
|
|
3
|
+
|
|
4
|
+
This schema defines the format for agent configurations that can be:
|
|
5
|
+
1. Stored in Django as JSON revisions
|
|
6
|
+
2. Loaded from standalone .json files
|
|
7
|
+
3. Used by agent_runtime_core without Django dependency
|
|
8
|
+
|
|
9
|
+
Example:
|
|
10
|
+
# Load from file
|
|
11
|
+
config = AgentConfig.from_file("my_agent.json")
|
|
12
|
+
|
|
13
|
+
# Create runtime and run
|
|
14
|
+
runtime = JsonAgentRuntime(config, llm_client)
|
|
15
|
+
result = await runtime.run(ctx)
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from dataclasses import dataclass, field
|
|
19
|
+
from datetime import datetime
|
|
20
|
+
from typing import Any, Optional
|
|
21
|
+
import json
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class SubAgentToolConfig:
|
|
27
|
+
"""
|
|
28
|
+
Configuration for a sub-agent tool (agent-as-tool pattern).
|
|
29
|
+
|
|
30
|
+
This allows an agent to delegate to another agent as if it were a tool.
|
|
31
|
+
The sub-agent can either be referenced by slug (resolved at runtime)
|
|
32
|
+
or embedded inline (for portable standalone configs).
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
name: str # Tool name the parent uses to invoke this agent
|
|
36
|
+
description: str # When to use this agent (shown to parent LLM)
|
|
37
|
+
|
|
38
|
+
# Reference to sub-agent (one of these should be set)
|
|
39
|
+
agent_slug: str = "" # Reference by slug (resolved at runtime from registry)
|
|
40
|
+
agent_config: Optional["AgentConfig"] = None # Embedded config (for standalone)
|
|
41
|
+
|
|
42
|
+
# Invocation settings
|
|
43
|
+
invocation_mode: str = "delegate" # "delegate" or "handoff"
|
|
44
|
+
context_mode: str = "full" # "full", "summary", or "message_only"
|
|
45
|
+
max_turns: Optional[int] = None
|
|
46
|
+
|
|
47
|
+
def to_dict(self) -> dict:
|
|
48
|
+
result = {
|
|
49
|
+
"name": self.name,
|
|
50
|
+
"description": self.description,
|
|
51
|
+
"tool_type": "subagent",
|
|
52
|
+
"invocation_mode": self.invocation_mode,
|
|
53
|
+
"context_mode": self.context_mode,
|
|
54
|
+
}
|
|
55
|
+
if self.agent_slug:
|
|
56
|
+
result["agent_slug"] = self.agent_slug
|
|
57
|
+
if self.agent_config:
|
|
58
|
+
result["agent_config"] = self.agent_config.to_dict()
|
|
59
|
+
if self.max_turns is not None:
|
|
60
|
+
result["max_turns"] = self.max_turns
|
|
61
|
+
return result
|
|
62
|
+
|
|
63
|
+
@classmethod
|
|
64
|
+
def from_dict(cls, data: dict) -> "SubAgentToolConfig":
|
|
65
|
+
agent_config = None
|
|
66
|
+
if "agent_config" in data and data["agent_config"]:
|
|
67
|
+
# Defer import to avoid circular dependency
|
|
68
|
+
agent_config = AgentConfig.from_dict(data["agent_config"])
|
|
69
|
+
|
|
70
|
+
return cls(
|
|
71
|
+
name=data["name"],
|
|
72
|
+
description=data["description"],
|
|
73
|
+
agent_slug=data.get("agent_slug", ""),
|
|
74
|
+
agent_config=agent_config,
|
|
75
|
+
invocation_mode=data.get("invocation_mode", "delegate"),
|
|
76
|
+
context_mode=data.get("context_mode", "full"),
|
|
77
|
+
max_turns=data.get("max_turns"),
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@dataclass
|
|
82
|
+
class ToolConfig:
|
|
83
|
+
"""Configuration for a single tool."""
|
|
84
|
+
|
|
85
|
+
name: str
|
|
86
|
+
description: str
|
|
87
|
+
parameters: dict # JSON Schema for parameters
|
|
88
|
+
function_path: str # Import path like "myapp.services.orders.lookup_order"
|
|
89
|
+
|
|
90
|
+
# Optional metadata
|
|
91
|
+
requires_confirmation: bool = False
|
|
92
|
+
is_safe: bool = True # No side effects
|
|
93
|
+
timeout_seconds: int = 30
|
|
94
|
+
|
|
95
|
+
def to_dict(self) -> dict:
|
|
96
|
+
return {
|
|
97
|
+
"name": self.name,
|
|
98
|
+
"description": self.description,
|
|
99
|
+
"parameters": self.parameters,
|
|
100
|
+
"function_path": self.function_path,
|
|
101
|
+
"requires_confirmation": self.requires_confirmation,
|
|
102
|
+
"is_safe": self.is_safe,
|
|
103
|
+
"timeout_seconds": self.timeout_seconds,
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
@classmethod
|
|
107
|
+
def from_dict(cls, data: dict) -> "ToolConfig":
|
|
108
|
+
return cls(
|
|
109
|
+
name=data["name"],
|
|
110
|
+
description=data["description"],
|
|
111
|
+
parameters=data.get("parameters", {}),
|
|
112
|
+
function_path=data.get("function_path", ""),
|
|
113
|
+
requires_confirmation=data.get("requires_confirmation", False),
|
|
114
|
+
is_safe=data.get("is_safe", True),
|
|
115
|
+
timeout_seconds=data.get("timeout_seconds", 30),
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@dataclass
|
|
120
|
+
class KnowledgeConfig:
|
|
121
|
+
"""Configuration for a knowledge source."""
|
|
122
|
+
|
|
123
|
+
name: str
|
|
124
|
+
knowledge_type: str # "text", "file", "url"
|
|
125
|
+
inclusion_mode: str = "always" # "always", "on_demand", "rag"
|
|
126
|
+
|
|
127
|
+
# Content (depends on type)
|
|
128
|
+
content: str = "" # For text type
|
|
129
|
+
file_path: str = "" # For file type
|
|
130
|
+
url: str = "" # For url type
|
|
131
|
+
|
|
132
|
+
def to_dict(self) -> dict:
|
|
133
|
+
return {
|
|
134
|
+
"name": self.name,
|
|
135
|
+
"type": self.knowledge_type,
|
|
136
|
+
"inclusion_mode": self.inclusion_mode,
|
|
137
|
+
"content": self.content,
|
|
138
|
+
"file_path": self.file_path,
|
|
139
|
+
"url": self.url,
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
@classmethod
|
|
143
|
+
def from_dict(cls, data: dict) -> "KnowledgeConfig":
|
|
144
|
+
return cls(
|
|
145
|
+
name=data["name"],
|
|
146
|
+
knowledge_type=data.get("type", "text"),
|
|
147
|
+
inclusion_mode=data.get("inclusion_mode", "always"),
|
|
148
|
+
content=data.get("content", ""),
|
|
149
|
+
file_path=data.get("file_path", ""),
|
|
150
|
+
url=data.get("url", ""),
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
@dataclass
|
|
155
|
+
class AgentConfig:
|
|
156
|
+
"""
|
|
157
|
+
Canonical configuration for an agent.
|
|
158
|
+
|
|
159
|
+
This is the portable format that can be serialized to JSON and
|
|
160
|
+
loaded by any runtime (Django or standalone).
|
|
161
|
+
|
|
162
|
+
For multi-agent systems, sub_agents contains embedded agent configs
|
|
163
|
+
that this agent can delegate to. The sub_agent_tools list defines
|
|
164
|
+
how each sub-agent is exposed as a tool.
|
|
165
|
+
"""
|
|
166
|
+
|
|
167
|
+
# Identity
|
|
168
|
+
name: str
|
|
169
|
+
slug: str
|
|
170
|
+
description: str = ""
|
|
171
|
+
|
|
172
|
+
# Core configuration
|
|
173
|
+
system_prompt: str = ""
|
|
174
|
+
model: str = "gpt-4o"
|
|
175
|
+
model_settings: dict = field(default_factory=dict)
|
|
176
|
+
|
|
177
|
+
# Tools and knowledge
|
|
178
|
+
tools: list[ToolConfig] = field(default_factory=list)
|
|
179
|
+
knowledge: list[KnowledgeConfig] = field(default_factory=list)
|
|
180
|
+
|
|
181
|
+
# Sub-agent tools (agent-as-tool pattern)
|
|
182
|
+
# These define other agents this agent can delegate to
|
|
183
|
+
sub_agent_tools: list[SubAgentToolConfig] = field(default_factory=list)
|
|
184
|
+
|
|
185
|
+
# Metadata
|
|
186
|
+
version: str = "1.0"
|
|
187
|
+
schema_version: str = "1" # For future schema migrations
|
|
188
|
+
created_at: Optional[str] = None
|
|
189
|
+
updated_at: Optional[str] = None
|
|
190
|
+
|
|
191
|
+
# Extra config (for extensibility)
|
|
192
|
+
extra: dict = field(default_factory=dict)
|
|
193
|
+
|
|
194
|
+
def to_dict(self) -> dict:
|
|
195
|
+
"""Serialize to dictionary (JSON-compatible)."""
|
|
196
|
+
result = {
|
|
197
|
+
"schema_version": self.schema_version,
|
|
198
|
+
"version": self.version,
|
|
199
|
+
"name": self.name,
|
|
200
|
+
"slug": self.slug,
|
|
201
|
+
"description": self.description,
|
|
202
|
+
"system_prompt": self.system_prompt,
|
|
203
|
+
"model": self.model,
|
|
204
|
+
"model_settings": self.model_settings,
|
|
205
|
+
"tools": [t.to_dict() for t in self.tools],
|
|
206
|
+
"knowledge": [k.to_dict() for k in self.knowledge],
|
|
207
|
+
"created_at": self.created_at,
|
|
208
|
+
"updated_at": self.updated_at,
|
|
209
|
+
"extra": self.extra,
|
|
210
|
+
}
|
|
211
|
+
# Only include sub_agent_tools if there are any
|
|
212
|
+
if self.sub_agent_tools:
|
|
213
|
+
result["sub_agent_tools"] = [s.to_dict() for s in self.sub_agent_tools]
|
|
214
|
+
return result
|
|
215
|
+
|
|
216
|
+
def to_json(self, indent: int = 2) -> str:
|
|
217
|
+
"""Serialize to JSON string."""
|
|
218
|
+
return json.dumps(self.to_dict(), indent=indent)
|
|
219
|
+
|
|
220
|
+
def save(self, path: str | Path) -> None:
|
|
221
|
+
"""Save to a JSON file."""
|
|
222
|
+
path = Path(path)
|
|
223
|
+
path.write_text(self.to_json())
|
|
224
|
+
|
|
225
|
+
@classmethod
|
|
226
|
+
def from_dict(cls, data: dict) -> "AgentConfig":
|
|
227
|
+
"""Load from dictionary."""
|
|
228
|
+
# Parse regular tools (skip subagent tools - they're in sub_agent_tools)
|
|
229
|
+
tools = []
|
|
230
|
+
for t in data.get("tools", []):
|
|
231
|
+
if t.get("tool_type") != "subagent":
|
|
232
|
+
tools.append(ToolConfig.from_dict(t))
|
|
233
|
+
|
|
234
|
+
knowledge = [KnowledgeConfig.from_dict(k) for k in data.get("knowledge", [])]
|
|
235
|
+
|
|
236
|
+
# Parse sub-agent tools
|
|
237
|
+
sub_agent_tools = []
|
|
238
|
+
for s in data.get("sub_agent_tools", []):
|
|
239
|
+
sub_agent_tools.append(SubAgentToolConfig.from_dict(s))
|
|
240
|
+
# Also check tools list for subagent type (backwards compat)
|
|
241
|
+
for t in data.get("tools", []):
|
|
242
|
+
if t.get("tool_type") == "subagent":
|
|
243
|
+
sub_agent_tools.append(SubAgentToolConfig.from_dict(t))
|
|
244
|
+
|
|
245
|
+
return cls(
|
|
246
|
+
name=data["name"],
|
|
247
|
+
slug=data["slug"],
|
|
248
|
+
description=data.get("description", ""),
|
|
249
|
+
system_prompt=data.get("system_prompt", ""),
|
|
250
|
+
model=data.get("model", "gpt-4o"),
|
|
251
|
+
model_settings=data.get("model_settings", {}),
|
|
252
|
+
tools=tools,
|
|
253
|
+
knowledge=knowledge,
|
|
254
|
+
sub_agent_tools=sub_agent_tools,
|
|
255
|
+
version=data.get("version", "1.0"),
|
|
256
|
+
schema_version=data.get("schema_version", "1"),
|
|
257
|
+
created_at=data.get("created_at"),
|
|
258
|
+
updated_at=data.get("updated_at"),
|
|
259
|
+
extra=data.get("extra", {}),
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
@classmethod
|
|
263
|
+
def from_json(cls, json_str: str) -> "AgentConfig":
|
|
264
|
+
"""Load from JSON string."""
|
|
265
|
+
return cls.from_dict(json.loads(json_str))
|
|
266
|
+
|
|
267
|
+
@classmethod
|
|
268
|
+
def from_file(cls, path: str | Path) -> "AgentConfig":
|
|
269
|
+
"""Load from a JSON file."""
|
|
270
|
+
path = Path(path)
|
|
271
|
+
return cls.from_json(path.read_text())
|
|
272
|
+
|
|
273
|
+
def with_timestamp(self) -> "AgentConfig":
|
|
274
|
+
"""Return a copy with updated timestamp."""
|
|
275
|
+
now = datetime.utcnow().isoformat() + "Z"
|
|
276
|
+
return AgentConfig(
|
|
277
|
+
name=self.name,
|
|
278
|
+
slug=self.slug,
|
|
279
|
+
description=self.description,
|
|
280
|
+
system_prompt=self.system_prompt,
|
|
281
|
+
model=self.model,
|
|
282
|
+
model_settings=self.model_settings,
|
|
283
|
+
tools=self.tools,
|
|
284
|
+
knowledge=self.knowledge,
|
|
285
|
+
sub_agent_tools=self.sub_agent_tools,
|
|
286
|
+
version=self.version,
|
|
287
|
+
schema_version=self.schema_version,
|
|
288
|
+
created_at=self.created_at or now,
|
|
289
|
+
updated_at=now,
|
|
290
|
+
extra=self.extra,
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
def get_all_embedded_agents(self) -> dict[str, "AgentConfig"]:
|
|
294
|
+
"""
|
|
295
|
+
Get all embedded agent configs (for standalone execution).
|
|
296
|
+
|
|
297
|
+
Returns a dict mapping slug -> AgentConfig for all sub-agents
|
|
298
|
+
that have embedded configs (not just slug references).
|
|
299
|
+
"""
|
|
300
|
+
agents = {}
|
|
301
|
+
for sub_tool in self.sub_agent_tools:
|
|
302
|
+
if sub_tool.agent_config:
|
|
303
|
+
agents[sub_tool.agent_config.slug] = sub_tool.agent_config
|
|
304
|
+
# Recursively get nested sub-agents
|
|
305
|
+
agents.update(sub_tool.agent_config.get_all_embedded_agents())
|
|
306
|
+
return agents
|
|
307
|
+
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"""
|
|
2
|
+
File processing module for agent_runtime_core.
|
|
3
|
+
|
|
4
|
+
Provides pluggable file processors for reading various file types,
|
|
5
|
+
OCR integration, and AI vision capabilities.
|
|
6
|
+
|
|
7
|
+
Example:
|
|
8
|
+
from agent_runtime_core.files import FileProcessorRegistry, process_file
|
|
9
|
+
|
|
10
|
+
# Register processors
|
|
11
|
+
registry = FileProcessorRegistry()
|
|
12
|
+
registry.auto_register() # Register all available processors
|
|
13
|
+
|
|
14
|
+
# Process a file
|
|
15
|
+
result = await registry.process("document.pdf", file_bytes)
|
|
16
|
+
print(result.text) # Extracted text
|
|
17
|
+
print(result.metadata) # File metadata
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from .base import (
|
|
21
|
+
FileProcessor,
|
|
22
|
+
FileProcessorRegistry,
|
|
23
|
+
ProcessedFile,
|
|
24
|
+
FileType,
|
|
25
|
+
ProcessingOptions,
|
|
26
|
+
)
|
|
27
|
+
from .processors import (
|
|
28
|
+
TextFileProcessor,
|
|
29
|
+
PDFProcessor,
|
|
30
|
+
ImageProcessor,
|
|
31
|
+
DocxProcessor,
|
|
32
|
+
XlsxProcessor,
|
|
33
|
+
CsvProcessor,
|
|
34
|
+
)
|
|
35
|
+
from .ocr import (
|
|
36
|
+
OCRProvider,
|
|
37
|
+
TesseractOCR,
|
|
38
|
+
GoogleVisionOCR,
|
|
39
|
+
AWSTextractOCR,
|
|
40
|
+
AzureDocumentOCR,
|
|
41
|
+
)
|
|
42
|
+
from .vision import (
|
|
43
|
+
VisionProvider,
|
|
44
|
+
OpenAIVision,
|
|
45
|
+
AnthropicVision,
|
|
46
|
+
GeminiVision,
|
|
47
|
+
)
|
|
48
|
+
from .tools import (
|
|
49
|
+
FileTools,
|
|
50
|
+
FileToolsConfig,
|
|
51
|
+
get_file_read_schema,
|
|
52
|
+
get_file_write_schema,
|
|
53
|
+
get_file_list_schema,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
__all__ = [
|
|
57
|
+
# Base classes
|
|
58
|
+
"FileProcessor",
|
|
59
|
+
"FileProcessorRegistry",
|
|
60
|
+
"ProcessedFile",
|
|
61
|
+
"FileType",
|
|
62
|
+
"ProcessingOptions",
|
|
63
|
+
# Processors
|
|
64
|
+
"TextFileProcessor",
|
|
65
|
+
"PDFProcessor",
|
|
66
|
+
"ImageProcessor",
|
|
67
|
+
"DocxProcessor",
|
|
68
|
+
"XlsxProcessor",
|
|
69
|
+
"CsvProcessor",
|
|
70
|
+
# OCR
|
|
71
|
+
"OCRProvider",
|
|
72
|
+
"TesseractOCR",
|
|
73
|
+
"GoogleVisionOCR",
|
|
74
|
+
"AWSTextractOCR",
|
|
75
|
+
"AzureDocumentOCR",
|
|
76
|
+
# Vision
|
|
77
|
+
"VisionProvider",
|
|
78
|
+
"OpenAIVision",
|
|
79
|
+
"AnthropicVision",
|
|
80
|
+
"GeminiVision",
|
|
81
|
+
# Tools
|
|
82
|
+
"FileTools",
|
|
83
|
+
"FileToolsConfig",
|
|
84
|
+
"get_file_read_schema",
|
|
85
|
+
"get_file_write_schema",
|
|
86
|
+
"get_file_list_schema",
|
|
87
|
+
]
|
|
88
|
+
|