agent-runtime-core 0.6.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.
Files changed (33) hide show
  1. agent_runtime_core/__init__.py +118 -2
  2. agent_runtime_core/agentic_loop.py +254 -0
  3. agent_runtime_core/config.py +54 -4
  4. agent_runtime_core/config_schema.py +307 -0
  5. agent_runtime_core/contexts.py +348 -0
  6. agent_runtime_core/interfaces.py +106 -0
  7. agent_runtime_core/json_runtime.py +509 -0
  8. agent_runtime_core/llm/__init__.py +80 -7
  9. agent_runtime_core/llm/anthropic.py +133 -12
  10. agent_runtime_core/llm/models_config.py +180 -0
  11. agent_runtime_core/memory/__init__.py +70 -0
  12. agent_runtime_core/memory/manager.py +554 -0
  13. agent_runtime_core/memory/mixin.py +294 -0
  14. agent_runtime_core/multi_agent.py +569 -0
  15. agent_runtime_core/persistence/__init__.py +2 -0
  16. agent_runtime_core/persistence/file.py +277 -0
  17. agent_runtime_core/rag/__init__.py +65 -0
  18. agent_runtime_core/rag/chunking.py +224 -0
  19. agent_runtime_core/rag/indexer.py +253 -0
  20. agent_runtime_core/rag/retriever.py +261 -0
  21. agent_runtime_core/runner.py +193 -15
  22. agent_runtime_core/tool_calling_agent.py +88 -130
  23. agent_runtime_core/tools.py +179 -0
  24. agent_runtime_core/vectorstore/__init__.py +193 -0
  25. agent_runtime_core/vectorstore/base.py +138 -0
  26. agent_runtime_core/vectorstore/embeddings.py +242 -0
  27. agent_runtime_core/vectorstore/sqlite_vec.py +328 -0
  28. agent_runtime_core/vectorstore/vertex.py +295 -0
  29. {agent_runtime_core-0.6.0.dist-info → agent_runtime_core-0.7.1.dist-info}/METADATA +202 -1
  30. agent_runtime_core-0.7.1.dist-info/RECORD +57 -0
  31. agent_runtime_core-0.6.0.dist-info/RECORD +0 -38
  32. {agent_runtime_core-0.6.0.dist-info → agent_runtime_core-0.7.1.dist-info}/WHEEL +0 -0
  33. {agent_runtime_core-0.6.0.dist-info → agent_runtime_core-0.7.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,179 @@
1
+ """
2
+ Tool utilities for building tool schemas.
3
+
4
+ This module provides utilities for creating tool schemas that can be passed
5
+ to LLMs for function calling. The ToolSchemaBuilder provides a fluent API
6
+ for building schemas without manually constructing JSON.
7
+
8
+ Example:
9
+ from agent_runtime_core.tools import ToolSchemaBuilder
10
+
11
+ # Build a tool schema fluently
12
+ schema = (
13
+ ToolSchemaBuilder("get_weather")
14
+ .description("Get the current weather for a location")
15
+ .param("location", "string", "City name", required=True)
16
+ .param("units", "string", "Temperature units", enum=["celsius", "fahrenheit"])
17
+ .build()
18
+ )
19
+
20
+ # Convert to OpenAI format for LLM calls
21
+ openai_format = schema.to_openai_format()
22
+
23
+ Note: For registering tools with handlers, use Tool and ToolRegistry from
24
+ agent_runtime_core.interfaces. This module is for schema building only.
25
+ """
26
+
27
+ from dataclasses import dataclass, field
28
+ from typing import Any, Optional, Sequence
29
+
30
+
31
+ @dataclass
32
+ class ToolParameter:
33
+ """
34
+ Definition of a tool parameter.
35
+
36
+ Attributes:
37
+ name: Parameter name
38
+ type: JSON Schema type (string, integer, number, boolean, array, object)
39
+ description: Human-readable description
40
+ required: Whether the parameter is required
41
+ enum: Optional list of allowed values
42
+ items: For array types, the schema of array items
43
+ default: Default value if not provided
44
+ """
45
+ name: str
46
+ type: str
47
+ description: str = ""
48
+ required: bool = False
49
+ enum: Optional[list[str]] = None
50
+ items: Optional[dict[str, Any]] = None
51
+ default: Optional[Any] = None
52
+
53
+ def to_schema(self) -> dict[str, Any]:
54
+ """Convert to JSON Schema format."""
55
+ schema: dict[str, Any] = {"type": self.type}
56
+ if self.description:
57
+ schema["description"] = self.description
58
+ if self.enum:
59
+ schema["enum"] = self.enum
60
+ if self.items:
61
+ schema["items"] = self.items
62
+ if self.default is not None:
63
+ schema["default"] = self.default
64
+ return schema
65
+
66
+
67
+ @dataclass
68
+ class ToolSchema:
69
+ """
70
+ Complete tool schema in OpenAI function calling format.
71
+
72
+ Example:
73
+ schema = ToolSchema(
74
+ name="get_weather",
75
+ description="Get the current weather for a location",
76
+ parameters=[
77
+ ToolParameter("location", "string", "City name", required=True),
78
+ ToolParameter("units", "string", "Temperature units", enum=["celsius", "fahrenheit"]),
79
+ ],
80
+ )
81
+
82
+ # Convert to OpenAI format
83
+ openai_schema = schema.to_openai_format()
84
+ """
85
+ name: str
86
+ description: str
87
+ parameters: list[ToolParameter] = field(default_factory=list)
88
+
89
+ def to_openai_format(self) -> dict[str, Any]:
90
+ """Convert to OpenAI function calling format."""
91
+ properties = {}
92
+ required = []
93
+
94
+ for param in self.parameters:
95
+ properties[param.name] = param.to_schema()
96
+ if param.required:
97
+ required.append(param.name)
98
+
99
+ return {
100
+ "type": "function",
101
+ "function": {
102
+ "name": self.name,
103
+ "description": self.description,
104
+ "parameters": {
105
+ "type": "object",
106
+ "properties": properties,
107
+ "required": required,
108
+ },
109
+ },
110
+ }
111
+
112
+
113
+ class ToolSchemaBuilder:
114
+ """
115
+ Builder for creating tool schemas fluently.
116
+
117
+ Example:
118
+ schema = (
119
+ ToolSchemaBuilder("submit_order")
120
+ .description("Submit a customer order")
121
+ .param("customer_id", "string", "Customer ID", required=True)
122
+ .param("items", "array", "Order items", items={"type": "string"})
123
+ .param("priority", "string", "Priority level", enum=["low", "normal", "high"])
124
+ .build()
125
+ )
126
+ """
127
+
128
+ def __init__(self, name: str):
129
+ """Initialize builder with tool name."""
130
+ self._name = name
131
+ self._description = ""
132
+ self._parameters: list[ToolParameter] = []
133
+
134
+ def description(self, desc: str) -> "ToolSchemaBuilder":
135
+ """Set the tool description."""
136
+ self._description = desc
137
+ return self
138
+
139
+ def param(
140
+ self,
141
+ name: str,
142
+ type: str,
143
+ description: str = "",
144
+ required: bool = False,
145
+ enum: Optional[list[str]] = None,
146
+ items: Optional[dict[str, Any]] = None,
147
+ default: Optional[Any] = None,
148
+ ) -> "ToolSchemaBuilder":
149
+ """Add a parameter to the tool."""
150
+ self._parameters.append(
151
+ ToolParameter(
152
+ name=name,
153
+ type=type,
154
+ description=description,
155
+ required=required,
156
+ enum=enum,
157
+ items=items,
158
+ default=default,
159
+ )
160
+ )
161
+ return self
162
+
163
+ def build(self) -> ToolSchema:
164
+ """Build the tool schema."""
165
+ return ToolSchema(
166
+ name=self._name,
167
+ description=self._description,
168
+ parameters=self._parameters,
169
+ )
170
+
171
+ def to_openai_format(self) -> dict[str, Any]:
172
+ """Build and convert to OpenAI format in one step."""
173
+ return self.build().to_openai_format()
174
+
175
+
176
+ def schemas_to_openai_format(schemas: Sequence[ToolSchema]) -> list[dict[str, Any]]:
177
+ """Convert a sequence of ToolSchema objects to OpenAI format."""
178
+ return [schema.to_openai_format() for schema in schemas]
179
+
@@ -0,0 +1,193 @@
1
+ """
2
+ Vector store module for agent_runtime_core.
3
+
4
+ Provides pluggable vector storage backends for similarity search:
5
+ - sqlite-vec: Lightweight, local development (requires: pip install sqlite-vec)
6
+ - pgvector: Production PostgreSQL (requires: pip install pgvector psycopg[binary])
7
+ - Vertex AI: Enterprise-scale managed (requires: pip install google-cloud-aiplatform)
8
+
9
+ Example usage:
10
+ from agent_runtime_core.vectorstore import (
11
+ get_vector_store,
12
+ get_embedding_client,
13
+ VectorStore,
14
+ EmbeddingClient,
15
+ )
16
+
17
+ # Get clients
18
+ vector_store = get_vector_store("sqlite_vec", path="./vectors.db")
19
+ embeddings = get_embedding_client("openai")
20
+
21
+ # Index a document
22
+ text = "The quick brown fox jumps over the lazy dog"
23
+ vector = await embeddings.embed(text)
24
+ await vector_store.add(
25
+ id="doc-1",
26
+ vector=vector,
27
+ content=text,
28
+ metadata={"source": "example"},
29
+ )
30
+
31
+ # Search
32
+ query = "fast animal"
33
+ query_vector = await embeddings.embed(query)
34
+ results = await vector_store.search(query_vector, limit=5)
35
+ for r in results:
36
+ print(f"{r.score:.3f}: {r.content}")
37
+ """
38
+
39
+ from typing import Optional
40
+
41
+ from agent_runtime_core.vectorstore.base import (
42
+ VectorStore,
43
+ VectorRecord,
44
+ VectorSearchResult,
45
+ )
46
+ from agent_runtime_core.vectorstore.embeddings import (
47
+ EmbeddingClient,
48
+ OpenAIEmbeddings,
49
+ VertexAIEmbeddings,
50
+ )
51
+
52
+
53
+ def get_vector_store(backend: str = "sqlite_vec", **kwargs) -> VectorStore:
54
+ """
55
+ Factory function to get a vector store instance.
56
+
57
+ Args:
58
+ backend: The backend to use. Options:
59
+ - "sqlite_vec": SQLite with sqlite-vec extension (default)
60
+ - "pgvector": PostgreSQL with pgvector extension
61
+ - "vertex": Google Vertex AI Vector Search
62
+ **kwargs: Backend-specific configuration options
63
+
64
+ Returns:
65
+ A VectorStore instance
66
+
67
+ Raises:
68
+ ValueError: If the backend is unknown
69
+ ImportError: If required dependencies are not installed
70
+
71
+ Examples:
72
+ # SQLite-vec (local development)
73
+ store = get_vector_store("sqlite_vec", path="./vectors.db")
74
+
75
+ # PGVector (production PostgreSQL)
76
+ store = get_vector_store("pgvector", connection_string="postgresql://...")
77
+
78
+ # Vertex AI (enterprise scale)
79
+ store = get_vector_store(
80
+ "vertex",
81
+ project_id="my-project",
82
+ location="us-central1",
83
+ index_endpoint_id="...",
84
+ deployed_index_id="...",
85
+ )
86
+ """
87
+ if backend == "sqlite_vec":
88
+ from agent_runtime_core.vectorstore.sqlite_vec import SqliteVecStore
89
+
90
+ return SqliteVecStore(**kwargs)
91
+ elif backend == "pgvector":
92
+ # Import from django_agent_runtime if available
93
+ try:
94
+ from django_agent_runtime.vectorstore import PgVectorStore
95
+
96
+ return PgVectorStore(**kwargs)
97
+ except ImportError:
98
+ raise ImportError(
99
+ "PgVectorStore requires django_agent_runtime. "
100
+ "Install with: pip install django-agent-runtime[pgvector]"
101
+ )
102
+ elif backend == "vertex":
103
+ from agent_runtime_core.vectorstore.vertex import VertexVectorStore
104
+
105
+ return VertexVectorStore(**kwargs)
106
+ else:
107
+ raise ValueError(
108
+ f"Unknown vector store backend: {backend}. "
109
+ f"Available backends: sqlite_vec, pgvector, vertex"
110
+ )
111
+
112
+
113
+ def get_embedding_client(
114
+ provider: str = "openai",
115
+ model: Optional[str] = None,
116
+ **kwargs,
117
+ ) -> EmbeddingClient:
118
+ """
119
+ Factory function to get an embedding client.
120
+
121
+ Args:
122
+ provider: The provider to use. Options:
123
+ - "openai": OpenAI embeddings (default)
124
+ - "vertex": Google Vertex AI embeddings
125
+ model: Optional model name override
126
+ **kwargs: Provider-specific configuration options
127
+
128
+ Returns:
129
+ An EmbeddingClient instance
130
+
131
+ Raises:
132
+ ValueError: If the provider is unknown
133
+ ImportError: If required dependencies are not installed
134
+
135
+ Examples:
136
+ # OpenAI (default model: text-embedding-3-small)
137
+ client = get_embedding_client("openai")
138
+
139
+ # OpenAI with specific model
140
+ client = get_embedding_client("openai", model="text-embedding-3-large")
141
+
142
+ # Vertex AI
143
+ client = get_embedding_client(
144
+ "vertex",
145
+ model="text-embedding-004",
146
+ project_id="my-project",
147
+ )
148
+ """
149
+ if provider == "openai":
150
+ if model:
151
+ kwargs["model"] = model
152
+ return OpenAIEmbeddings(**kwargs)
153
+ elif provider == "vertex":
154
+ if model:
155
+ kwargs["model"] = model
156
+ return VertexAIEmbeddings(**kwargs)
157
+ else:
158
+ raise ValueError(
159
+ f"Unknown embedding provider: {provider}. "
160
+ f"Available providers: openai, vertex"
161
+ )
162
+
163
+
164
+ # Lazy imports for optional backends
165
+ def __getattr__(name: str):
166
+ """Lazy import for optional backends."""
167
+ if name == "SqliteVecStore":
168
+ from agent_runtime_core.vectorstore.sqlite_vec import SqliteVecStore
169
+
170
+ return SqliteVecStore
171
+ elif name == "VertexVectorStore":
172
+ from agent_runtime_core.vectorstore.vertex import VertexVectorStore
173
+
174
+ return VertexVectorStore
175
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
176
+
177
+
178
+ __all__ = [
179
+ # Abstract interfaces
180
+ "VectorStore",
181
+ "VectorRecord",
182
+ "VectorSearchResult",
183
+ "EmbeddingClient",
184
+ # Implementations
185
+ "OpenAIEmbeddings",
186
+ "VertexAIEmbeddings",
187
+ "SqliteVecStore",
188
+ "VertexVectorStore",
189
+ # Factory functions
190
+ "get_vector_store",
191
+ "get_embedding_client",
192
+ ]
193
+
@@ -0,0 +1,138 @@
1
+ """
2
+ Abstract base classes for vector storage backends.
3
+
4
+ These interfaces define the contract that all vector storage backends must implement.
5
+ Implementations can use different backends like sqlite-vec, pgvector, or Vertex AI.
6
+ """
7
+
8
+ from abc import ABC, abstractmethod
9
+ from dataclasses import dataclass, field
10
+ from typing import Optional
11
+
12
+
13
+ @dataclass
14
+ class VectorRecord:
15
+ """A stored vector with its content and metadata."""
16
+
17
+ id: str
18
+ vector: list[float]
19
+ content: str
20
+ metadata: dict = field(default_factory=dict)
21
+
22
+
23
+ @dataclass
24
+ class VectorSearchResult:
25
+ """A search result with similarity score."""
26
+
27
+ id: str
28
+ content: str
29
+ score: float # Similarity score (higher = more similar)
30
+ metadata: dict = field(default_factory=dict)
31
+
32
+
33
+ class VectorStore(ABC):
34
+ """
35
+ Abstract interface for vector storage and similarity search.
36
+
37
+ Vector stores handle storing embeddings and performing similarity searches.
38
+ Different backends can be used depending on scale and deployment requirements:
39
+ - sqlite-vec: Lightweight, local development
40
+ - pgvector: Production PostgreSQL deployments
41
+ - Vertex AI: Enterprise-scale managed infrastructure
42
+ """
43
+
44
+ @abstractmethod
45
+ async def add(
46
+ self,
47
+ id: str,
48
+ vector: list[float],
49
+ content: str,
50
+ metadata: Optional[dict] = None,
51
+ ) -> None:
52
+ """
53
+ Add a vector with its content and metadata.
54
+
55
+ Args:
56
+ id: Unique identifier for the vector
57
+ vector: The embedding vector
58
+ content: Original text content
59
+ metadata: Optional metadata dictionary
60
+ """
61
+ ...
62
+
63
+ @abstractmethod
64
+ async def add_batch(
65
+ self,
66
+ items: list[tuple[str, list[float], str, Optional[dict]]],
67
+ ) -> None:
68
+ """
69
+ Add multiple vectors efficiently.
70
+
71
+ Args:
72
+ items: List of (id, vector, content, metadata) tuples
73
+ """
74
+ ...
75
+
76
+ @abstractmethod
77
+ async def search(
78
+ self,
79
+ query_vector: list[float],
80
+ limit: int = 10,
81
+ filter: Optional[dict] = None,
82
+ ) -> list[VectorSearchResult]:
83
+ """
84
+ Search for similar vectors.
85
+
86
+ Args:
87
+ query_vector: The query embedding vector
88
+ limit: Maximum number of results to return
89
+ filter: Optional metadata filter (equality matching)
90
+
91
+ Returns:
92
+ List of VectorSearchResult ordered by similarity (highest first)
93
+ """
94
+ ...
95
+
96
+ @abstractmethod
97
+ async def delete(self, id: str) -> bool:
98
+ """
99
+ Delete a vector by ID.
100
+
101
+ Args:
102
+ id: The vector ID to delete
103
+
104
+ Returns:
105
+ True if the vector existed and was deleted
106
+ """
107
+ ...
108
+
109
+ @abstractmethod
110
+ async def delete_by_filter(self, filter: dict) -> int:
111
+ """
112
+ Delete vectors matching filter.
113
+
114
+ Args:
115
+ filter: Metadata filter for deletion (equality matching)
116
+
117
+ Returns:
118
+ Number of vectors deleted
119
+ """
120
+ ...
121
+
122
+ @abstractmethod
123
+ async def get(self, id: str) -> Optional[VectorRecord]:
124
+ """
125
+ Get a vector by ID.
126
+
127
+ Args:
128
+ id: The vector ID to retrieve
129
+
130
+ Returns:
131
+ VectorRecord if found, None otherwise
132
+ """
133
+ ...
134
+
135
+ async def close(self) -> None:
136
+ """Close connections. Override if needed."""
137
+ pass
138
+