aixtools 0.1.5__py3-none-any.whl → 0.1.7__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.
Potentially problematic release.
This version of aixtools might be problematic. Click here for more details.
- aixtools/_version.py +2 -2
- aixtools/utils/config.py +7 -0
- aixtools/vault/__init__.py +7 -0
- aixtools/vault/vault.py +100 -0
- aixtools-0.1.7.dist-info/METADATA +668 -0
- {aixtools-0.1.5.dist-info → aixtools-0.1.7.dist-info}/RECORD +11 -7
- tests/unit/vault/__init__.py +0 -0
- tests/unit/vault/test_vault.py +171 -0
- aixtools-0.1.5.dist-info/METADATA +0 -357
- {aixtools-0.1.5.dist-info → aixtools-0.1.7.dist-info}/WHEEL +0 -0
- {aixtools-0.1.5.dist-info → aixtools-0.1.7.dist-info}/entry_points.txt +0 -0
- {aixtools-0.1.5.dist-info → aixtools-0.1.7.dist-info}/top_level.txt +0 -0
aixtools/_version.py
CHANGED
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.1.
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 1,
|
|
31
|
+
__version__ = version = '0.1.7'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 1, 7)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
aixtools/utils/config.py
CHANGED
|
@@ -122,3 +122,10 @@ LOGFIRE_TRACES_ENDPOINT = get_variable_env("LOGFIRE_TRACES_ENDPOINT", True, "")
|
|
|
122
122
|
GOOGLE_GENAI_USE_VERTEXAI = str2bool(get_variable_env("GOOGLE_GENAI_USE_VERTEXAI", True, True))
|
|
123
123
|
GOOGLE_CLOUD_PROJECT = get_variable_env("GOOGLE_CLOUD_PROJECT", True)
|
|
124
124
|
GOOGLE_CLOUD_LOCATION = get_variable_env("GOOGLE_CLOUD_LOCATION", True)
|
|
125
|
+
|
|
126
|
+
# vault parameters.
|
|
127
|
+
VAULT_ADDRESS = get_variable_env("VAULT_ADDRESS", default="http://localhost:8200")
|
|
128
|
+
VAULT_TOKEN = get_variable_env("VAULT_TOKEN", default="vault-token")
|
|
129
|
+
VAULT_ENV = get_variable_env("ENV", default="dev")
|
|
130
|
+
VAULT_MOUNT_POINT = get_variable_env("VAULT_MOUNT_POINT", default="secret")
|
|
131
|
+
VAULT_PATH_PREFIX = get_variable_env("VAULT_PATH_PREFIX", default="path")
|
aixtools/vault/vault.py
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# ruff: noqa: PLR0913
|
|
2
|
+
"""
|
|
3
|
+
Provides a Vault client for storing and retrieving user service api keys.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
from typing import Dict, Optional
|
|
8
|
+
|
|
9
|
+
import hvac
|
|
10
|
+
from hvac.exceptions import InvalidPath
|
|
11
|
+
|
|
12
|
+
from aixtools.utils import config
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class VaultAuthError(Exception):
|
|
18
|
+
"""Exception raised for vault authentication errors."""
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class VaultClient:
|
|
22
|
+
"""Vault client for storing and retrieving user service api keys."""
|
|
23
|
+
|
|
24
|
+
def __init__(self):
|
|
25
|
+
self.client = hvac.Client(url=config.VAULT_ADDRESS, token=config.VAULT_TOKEN)
|
|
26
|
+
|
|
27
|
+
if not self.client.is_authenticated():
|
|
28
|
+
raise VaultAuthError("Vault client authentication failed. Check vault_token.")
|
|
29
|
+
|
|
30
|
+
def _get_secret_path(self, user_id: str, service_name: str) -> str:
|
|
31
|
+
"""Generate the vault secret path for a user and service."""
|
|
32
|
+
return f"{config.VAULT_PATH_PREFIX}/{config.VAULT_ENV}/{user_id}/{service_name}"
|
|
33
|
+
|
|
34
|
+
def store_user_service_api_key(self, *, user_id: str, service_name: str, user_api_key: str):
|
|
35
|
+
"""
|
|
36
|
+
Store user's service api key in the Vault at the specified vault mount
|
|
37
|
+
point, where the path is <path_prefix>/<env>/<user_id>/<service_name>.
|
|
38
|
+
|
|
39
|
+
This is a convenience method for storing a single API key.
|
|
40
|
+
For storing multiple secrets, use store_user_service_secret().
|
|
41
|
+
"""
|
|
42
|
+
secret_dict = {"user-api-key": user_api_key}
|
|
43
|
+
self.store_user_service_secret(user_id=user_id, service_name=service_name, secret_data=secret_dict)
|
|
44
|
+
|
|
45
|
+
def read_user_service_api_key(self, *, user_id: str, service_name: str) -> Optional[str]:
|
|
46
|
+
"""
|
|
47
|
+
Read user's service api key in from vault at the specified mount point,
|
|
48
|
+
where the path is <path_prefix>/<env>/<user_id>/<service_name>.
|
|
49
|
+
|
|
50
|
+
This is a convenience method for reading a single API key.
|
|
51
|
+
For reading multiple secrets, use read_user_service_secret().
|
|
52
|
+
"""
|
|
53
|
+
secret_data = self.read_user_service_secret(user_id=user_id, service_name=service_name)
|
|
54
|
+
if secret_data is None:
|
|
55
|
+
return None
|
|
56
|
+
return secret_data.get("user-api-key")
|
|
57
|
+
|
|
58
|
+
def store_user_service_secret(self, *, user_id: str, service_name: str, secret_data: Dict[str, str]):
|
|
59
|
+
"""
|
|
60
|
+
Store complete user service secret with multiple key-value pairs in the Vault
|
|
61
|
+
at the specified vault mount point, where the path is <path_prefix>/<env>/<user_id>/<service_name>.
|
|
62
|
+
"""
|
|
63
|
+
secret_path = None
|
|
64
|
+
try:
|
|
65
|
+
secret_path = self._get_secret_path(user_id, service_name)
|
|
66
|
+
logger.info("Writing complete secret to path %s", secret_path)
|
|
67
|
+
self.client.secrets.kv.v2.create_or_update_secret(
|
|
68
|
+
secret_path, secret=secret_data, mount_point=config.VAULT_MOUNT_POINT
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
logger.info("Complete secret written to path %s", secret_path)
|
|
72
|
+
except Exception as e:
|
|
73
|
+
logger.error("Failed to write complete secret to path %s: %s", secret_path, str(e))
|
|
74
|
+
raise VaultAuthError(e) from e
|
|
75
|
+
|
|
76
|
+
def read_user_service_secret(self, *, user_id: str, service_name: str) -> Optional[Dict[str, str]]:
|
|
77
|
+
"""
|
|
78
|
+
Read complete user service secret from vault at the specified mount point,
|
|
79
|
+
where the path is <path_prefix>/<env>/<user_id>/<service_name>.
|
|
80
|
+
Returns all key-value pairs in the secret or None if the secret doesn't exist.
|
|
81
|
+
"""
|
|
82
|
+
secret_path = None
|
|
83
|
+
|
|
84
|
+
try:
|
|
85
|
+
secret_path = self._get_secret_path(user_id, service_name)
|
|
86
|
+
logger.info("Reading complete secret from path %s", secret_path)
|
|
87
|
+
response = self.client.secrets.kv.v2.read_secret_version(
|
|
88
|
+
secret_path, mount_point=config.VAULT_MOUNT_POINT, raise_on_deleted_version=True
|
|
89
|
+
)
|
|
90
|
+
secret_data = response["data"]["data"]
|
|
91
|
+
logger.info("Complete secret read from path %s", secret_path)
|
|
92
|
+
return secret_data
|
|
93
|
+
except InvalidPath:
|
|
94
|
+
# Secret path does not exist
|
|
95
|
+
logger.warning("Secret path does not exist %s", secret_path)
|
|
96
|
+
return None
|
|
97
|
+
|
|
98
|
+
except Exception as e:
|
|
99
|
+
logger.error("Failed to read complete secret from path %s: %s", secret_path, str(e))
|
|
100
|
+
raise VaultAuthError(e) from e
|
|
@@ -0,0 +1,668 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: aixtools
|
|
3
|
+
Version: 0.1.7
|
|
4
|
+
Summary: Tools for AI exploration and debugging
|
|
5
|
+
Requires-Python: >=3.11.2
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: a2a-sdk>=0.3.1
|
|
8
|
+
Requires-Dist: cachebox>=5.0.1
|
|
9
|
+
Requires-Dist: chainlit>=2.5.5
|
|
10
|
+
Requires-Dist: colorlog>=6.9.0
|
|
11
|
+
Requires-Dist: fasta2a>=0.5.0
|
|
12
|
+
Requires-Dist: fastmcp>=2.10.2
|
|
13
|
+
Requires-Dist: hvac>=2.3.0
|
|
14
|
+
Requires-Dist: ipykernel>=6.29.5
|
|
15
|
+
Requires-Dist: langchain-chroma>=0.2.3
|
|
16
|
+
Requires-Dist: langchain-ollama>=0.3.2
|
|
17
|
+
Requires-Dist: langchain-openai>=0.3.14
|
|
18
|
+
Requires-Dist: mcp>=1.11.0
|
|
19
|
+
Requires-Dist: pandas>=2.2.3
|
|
20
|
+
Requires-Dist: pydantic-ai>=0.4.10
|
|
21
|
+
Requires-Dist: pylint>=3.3.7
|
|
22
|
+
Requires-Dist: rich>=14.0.0
|
|
23
|
+
Requires-Dist: ruff>=0.11.6
|
|
24
|
+
Requires-Dist: streamlit>=1.44.1
|
|
25
|
+
Requires-Dist: watchdog>=6.0.0
|
|
26
|
+
Provides-Extra: test
|
|
27
|
+
Requires-Dist: pyyaml; extra == "test"
|
|
28
|
+
Provides-Extra: feature
|
|
29
|
+
Requires-Dist: logfire; extra == "feature"
|
|
30
|
+
|
|
31
|
+
# AIXtools
|
|
32
|
+
|
|
33
|
+
AIXtools is a comprehensive Python library for AI agent development, debugging, and deployment. It provides a complete toolkit for building, testing, and monitoring AI agents with support for multiple model providers, advanced logging, and agent-to-agent communication.
|
|
34
|
+
|
|
35
|
+
## Capabilities
|
|
36
|
+
|
|
37
|
+
Agents
|
|
38
|
+
- Agent Development & Management - `aixtools/agents/`
|
|
39
|
+
- Agent Batch Processing - `aixtools/agents/agent_batch.py`
|
|
40
|
+
- Agent Prompting System - `aixtools/agents/prompt.py`
|
|
41
|
+
|
|
42
|
+
A2A
|
|
43
|
+
- Agent-to-Agent Communication (A2A) - `aixtools/a2a/`
|
|
44
|
+
- Google SDK Integration for A2A - `aixtools/a2a/google_sdk/`
|
|
45
|
+
- PydanticAI Adapter for Google SDK - `aixtools/a2a/google_sdk/pydantic_ai_adapter/`
|
|
46
|
+
|
|
47
|
+
Databases
|
|
48
|
+
- Database Integration - `aixtools/db/`
|
|
49
|
+
- Vector Database Support - `aixtools/db/vector_db.py`
|
|
50
|
+
|
|
51
|
+
Logging & Debugging
|
|
52
|
+
- Log Viewing Application - `aixtools/log_view/`
|
|
53
|
+
- Object Logging System - `aixtools/logging/`
|
|
54
|
+
- Model Patch Logging - `aixtools/logging/model_patch_logging.py`
|
|
55
|
+
- Log Filtering System - `aixtools/logfilters/`
|
|
56
|
+
- FastMCP Logging - `aixtools/mcp/fast_mcp_log.py`
|
|
57
|
+
- Command Line Interface for Log Viewing - Entry point: `log_view`
|
|
58
|
+
- MCP (Model Context Protocol) Support - `aixtools/logging/mcp_log_models.py`, `aixtools/logging/mcp_logger.py`
|
|
59
|
+
|
|
60
|
+
Testing & Tools
|
|
61
|
+
- Testing Utilities - `aixtools/testing/`
|
|
62
|
+
- Mock Tool System - `aixtools/testing/mock_tool.py`
|
|
63
|
+
- Model Patch Caching - `aixtools/testing/model_patch_cache.py`
|
|
64
|
+
- Tool Doctor System - `aixtools/tools/doctor/`
|
|
65
|
+
- Tool Recommendation Engine - `aixtools/tools/doctor/tool_recommendation.py`
|
|
66
|
+
- FaultyMCP - `aixtools/mcp/faulty_mcp.py`
|
|
67
|
+
|
|
68
|
+
Chainlit & HTTP Server
|
|
69
|
+
- Chainlit Integration - `aixtools/app.py`, `aixtools/chainlit.md`
|
|
70
|
+
- Chainlit Utilities - `aixtools/utils/chainlit/`
|
|
71
|
+
- HTTP Server Framework - `aixtools/server/`
|
|
72
|
+
- App Mounting System - `aixtools/server/app_mounter.py`
|
|
73
|
+
|
|
74
|
+
Programming utils
|
|
75
|
+
- Persisted Dictionary - `aixtools/utils/persisted_dict.py`
|
|
76
|
+
- Enum with Description - `aixtools/utils/enum_with_description.py`
|
|
77
|
+
- Context Management - `aixtools/context.py`
|
|
78
|
+
- Configuration Management - `aixtools/utils/config.py`, `aixtools/utils/config_util.py`
|
|
79
|
+
- File Utilities - `aixtools/utils/files.py`
|
|
80
|
+
|
|
81
|
+
## Installation
|
|
82
|
+
|
|
83
|
+
### From GitHub
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
uv add aixtools
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Development Setup
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
# Create a new project
|
|
93
|
+
uv init MyNewProject
|
|
94
|
+
cd MyNewProject
|
|
95
|
+
|
|
96
|
+
# Add virtual environment and activate it
|
|
97
|
+
uv venv .venv
|
|
98
|
+
source .venv/bin/activate
|
|
99
|
+
|
|
100
|
+
# Add this package
|
|
101
|
+
uv add aixtools
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Updating
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
uv add --upgrade aixtools
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Environment Configuration
|
|
111
|
+
|
|
112
|
+
AIXtools requires environment variables for model providers.
|
|
113
|
+
|
|
114
|
+
**IMPORTANT:** Create a `.env` file based on [`.env_template`](./.env_template):
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
# Model family (azure, openai, or ollama)
|
|
118
|
+
MODEL_FAMILY=azure
|
|
119
|
+
MODEL_TIMEOUT=120
|
|
120
|
+
|
|
121
|
+
# Azure OpenAI
|
|
122
|
+
AZURE_OPENAI_ENDPOINT=https://your_endpoint.openai.azure.com
|
|
123
|
+
AZURE_OPENAI_API_VERSION=2024-06-01
|
|
124
|
+
AZURE_OPENAI_API_KEY=your_secret_key
|
|
125
|
+
AZURE_MODEL_NAME=gpt-4o
|
|
126
|
+
|
|
127
|
+
# OpenAI
|
|
128
|
+
OPENAI_MODEL_NAME=gpt-4.5-preview
|
|
129
|
+
OPENAI_API_KEY=openai_api_key
|
|
130
|
+
|
|
131
|
+
# Ollama
|
|
132
|
+
OLLAMA_MODEL_NAME=llama3.2:3b-instruct-fp16
|
|
133
|
+
OLLAMA_LOCAL_URL=http://localhost:11434/v1
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Agents
|
|
137
|
+
|
|
138
|
+
### Basic Agent Usage
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
from aixtools.agents.agent import get_agent, run_agent
|
|
142
|
+
|
|
143
|
+
async def main():
|
|
144
|
+
agent = get_agent(system_prompt="You are a helpful assistant.")
|
|
145
|
+
result, nodes = await run_agent(agent, "Explain quantum computing")
|
|
146
|
+
print(result)
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Agent Development & Management
|
|
150
|
+
|
|
151
|
+
The agent system provides a unified interface for creating and managing AI agents across different model providers.
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
from aixtools.agents.agent import get_agent, run_agent
|
|
155
|
+
|
|
156
|
+
# Create an agent with default model
|
|
157
|
+
agent = get_agent(system_prompt="You are a helpful assistant.")
|
|
158
|
+
|
|
159
|
+
# Run the agent
|
|
160
|
+
result, nodes = await run_agent(agent, "Tell me about AI")
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Agent Batch Processing
|
|
164
|
+
|
|
165
|
+
Process multiple agent queries simultaneously with built-in concurrency control and result aggregation.
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
from aixtools.agents.agent_batch import agent_batch, AgentQueryParams
|
|
169
|
+
|
|
170
|
+
# Create query parameters
|
|
171
|
+
query_parameters = [
|
|
172
|
+
AgentQueryParams(prompt="What is the meaning of life"),
|
|
173
|
+
AgentQueryParams(prompt="Who is the prime minister of Canada")
|
|
174
|
+
]
|
|
175
|
+
|
|
176
|
+
# Run queries in batches
|
|
177
|
+
async for result in agent_batch(query_parameters):
|
|
178
|
+
print(result)
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## A2A (Agent-to-Agent Communication)
|
|
182
|
+
|
|
183
|
+
The A2A module provides a comprehensive framework for enabling sophisticated communication between AI agents across different environments and platforms. It includes Google SDK integration, PydanticAI adapters, and FastA2A application conversion capabilities.
|
|
184
|
+
|
|
185
|
+
### Core Features
|
|
186
|
+
|
|
187
|
+
**Agent Application Conversion**
|
|
188
|
+
- Convert PydanticAI agents into FastA2A applications
|
|
189
|
+
- Support for session metadata extraction and context management
|
|
190
|
+
- Custom worker classes with enhanced data part support
|
|
191
|
+
- Automatic handling of user and session identification
|
|
192
|
+
|
|
193
|
+
**Remote Agent Connections**
|
|
194
|
+
- Establish connections between agents across different environments
|
|
195
|
+
- Asynchronous message sending with task polling capabilities
|
|
196
|
+
- Terminal state detection and error handling
|
|
197
|
+
- Support for various message types including text, files, and data
|
|
198
|
+
|
|
199
|
+
**Google SDK Integration**
|
|
200
|
+
- Native integration with Google's A2A SDK
|
|
201
|
+
- Card-based agent representation and discovery
|
|
202
|
+
- PydanticAI adapter for seamless Google SDK compatibility
|
|
203
|
+
- Storage and execution management for agent interactions
|
|
204
|
+
|
|
205
|
+
### Agent-to-Agent Communication (A2A)
|
|
206
|
+
|
|
207
|
+
Enable sophisticated agent interactions with Google SDK integration and PydanticAI adapters.
|
|
208
|
+
|
|
209
|
+
```python
|
|
210
|
+
from aixtools.a2a.google_sdk.remote_agent_connection import RemoteAgentConnection
|
|
211
|
+
from aixtools.a2a.app import agent_to_a2a
|
|
212
|
+
|
|
213
|
+
# Convert a PydanticAI agent to FastA2A application
|
|
214
|
+
a2a_app = agent_to_a2a(
|
|
215
|
+
agent=my_agent,
|
|
216
|
+
name="MyAgent",
|
|
217
|
+
description="A helpful AI assistant",
|
|
218
|
+
skills=[{"name": "chat", "description": "General conversation"}]
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
# Connect agents across different environments
|
|
222
|
+
connection = RemoteAgentConnection(card=agent_card, client=a2a_client)
|
|
223
|
+
response = await connection.send_message_with_polling(message)
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Databases
|
|
227
|
+
|
|
228
|
+
### Database Integration
|
|
229
|
+
|
|
230
|
+
Support for both traditional and vector databases with seamless integration.
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
from aixtools.db.database import Database
|
|
234
|
+
from aixtools.db.vector_db import VectorDB
|
|
235
|
+
|
|
236
|
+
# Traditional database
|
|
237
|
+
db = Database("sqlite:///app.db")
|
|
238
|
+
|
|
239
|
+
# Vector database for embeddings
|
|
240
|
+
vector_db = VectorDB()
|
|
241
|
+
vector_db.add_documents(documents)
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## Logging & Debugging
|
|
245
|
+
|
|
246
|
+
AixTools provides functionality for logging and debugging.
|
|
247
|
+
|
|
248
|
+
### Basic Logging and Debugging
|
|
249
|
+
|
|
250
|
+
```python
|
|
251
|
+
from aixtools.agents.agent import get_agent, run_agent
|
|
252
|
+
|
|
253
|
+
async def main():
|
|
254
|
+
# Create an agent
|
|
255
|
+
agent = get_agent(system_prompt="You are a helpful assistant.")
|
|
256
|
+
|
|
257
|
+
# Run agent - logging is automatic via ObjectLogger
|
|
258
|
+
result, nodes = await run_agent(
|
|
259
|
+
agent,
|
|
260
|
+
"Explain quantum computing",
|
|
261
|
+
debug=True, # Enable debug logging
|
|
262
|
+
log_model_requests=True # Log model requests/responses
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
print(f"Result: {result}")
|
|
266
|
+
print(f"Logged {len(nodes)} nodes")
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Log Viewing Application
|
|
270
|
+
|
|
271
|
+
Interactive Streamlit application for analyzing logged objects and debugging agent behavior.
|
|
272
|
+
|
|
273
|
+
**Features:**
|
|
274
|
+
- Log file selection and filtering
|
|
275
|
+
- Node visualization with expand/collapse
|
|
276
|
+
- Export capabilities to JSON
|
|
277
|
+
- Regex pattern matching
|
|
278
|
+
- Real-time log monitoring
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
# Run the log viewer
|
|
282
|
+
log_view
|
|
283
|
+
|
|
284
|
+
# Or specify custom log directory
|
|
285
|
+
log_view /path/to/logs
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Object Logging & Debugging
|
|
289
|
+
|
|
290
|
+
Advanced logging system with object serialization and visual debugging tools.
|
|
291
|
+
|
|
292
|
+
```python
|
|
293
|
+
from aixtools.logging.log_objects import ObjectLogger
|
|
294
|
+
|
|
295
|
+
# Log any pickleable object
|
|
296
|
+
with ObjectLogger() as logger:
|
|
297
|
+
logger.log({"message": "Hello, world!"})
|
|
298
|
+
logger.log(agent_response)
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### MCP Logger
|
|
302
|
+
|
|
303
|
+
This is an MCP server that can log MCP requests and responses.
|
|
304
|
+
|
|
305
|
+
```python
|
|
306
|
+
from aixtools.mcp.fast_mcp_log import FastMcpLog
|
|
307
|
+
|
|
308
|
+
# Use FastMCP server with logging
|
|
309
|
+
mcp = FastMcpLog("Demo")
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### Model Patching System
|
|
313
|
+
|
|
314
|
+
Dynamic model behavior modification for testing and debugging.
|
|
315
|
+
|
|
316
|
+
```python
|
|
317
|
+
from aixtools.model_patch.model_patch import ModelPatch
|
|
318
|
+
|
|
319
|
+
# Apply patches to models for testing
|
|
320
|
+
with ModelPatch() as patch:
|
|
321
|
+
patch.apply_response_override("test response")
|
|
322
|
+
result = await agent.run("test prompt")
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### FaultyMCP
|
|
326
|
+
|
|
327
|
+
A specialized MCP server designed for testing error handling and resilience in MCP client implementations. FaultyMCP simulates various failure scenarios including network errors, server crashes, and random exceptions.
|
|
328
|
+
|
|
329
|
+
**Features:**
|
|
330
|
+
- Configurable error probabilities for different request types
|
|
331
|
+
- HTTP 404 error injection for POST/DELETE requests
|
|
332
|
+
- Server crash simulation on GET requests
|
|
333
|
+
- Random exception throwing in tool operations
|
|
334
|
+
- MCP-specific error simulation (ValidationError, ResourceError, etc.)
|
|
335
|
+
- Safe mode for controlled testing
|
|
336
|
+
|
|
337
|
+
```python
|
|
338
|
+
from aixtools.mcp.faulty_mcp import run_server_on_port, config
|
|
339
|
+
|
|
340
|
+
# Configure error probabilities
|
|
341
|
+
config.prob_on_post_404 = 0.3 # 30% chance of 404 on POST
|
|
342
|
+
config.prob_on_get_crash = 0.1 # 10% chance of crash on GET
|
|
343
|
+
config.prob_in_list_tools_throw = 0.2 # 20% chance of exception in tools/list
|
|
344
|
+
|
|
345
|
+
# Run the faulty server
|
|
346
|
+
run_server_on_port()
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
**Command Line Usage:**
|
|
350
|
+
```bash
|
|
351
|
+
# Run with default error probabilities
|
|
352
|
+
python -m aixtools.mcp.faulty_mcp
|
|
353
|
+
|
|
354
|
+
# Run in safe mode (no errors by default)
|
|
355
|
+
python -m aixtools.mcp.faulty_mcp --safe-mode
|
|
356
|
+
|
|
357
|
+
# Custom configuration
|
|
358
|
+
python -m aixtools.mcp.faulty_mcp \
|
|
359
|
+
--port 8888 \
|
|
360
|
+
--prob-on-post-404 0.2 \
|
|
361
|
+
--prob-on-get-crash 0.1 \
|
|
362
|
+
--prob-in-list-tools-throw 0.3
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
By default, the "FaultyMCP" includes several tools you can use in your tests:
|
|
366
|
+
- `add(a, b)` - Basic addition (reliable)
|
|
367
|
+
- `multiply(a, b)` - Basic multiplication (reliable)
|
|
368
|
+
- `always_error()` - Always throws an exception
|
|
369
|
+
- `random_throw_exception(a, b, prob)` - Randomly throws exceptions
|
|
370
|
+
- `freeze_server(seconds)` - Simulates server freeze
|
|
371
|
+
- `throw_404_exception()` - Throws HTTP 404 error
|
|
372
|
+
|
|
373
|
+
## Testing & Tools
|
|
374
|
+
|
|
375
|
+
AIXtools provides comprehensive testing utilities and diagnostic tools for AI agent development and debugging.
|
|
376
|
+
|
|
377
|
+
### Testing Utilities
|
|
378
|
+
|
|
379
|
+
The testing module provides mock tools, model patching, and test utilities for comprehensive agent testing.
|
|
380
|
+
|
|
381
|
+
```python
|
|
382
|
+
from aixtools.testing.mock_tool import MockTool
|
|
383
|
+
from aixtools.testing.model_patch_cache import ModelPatchCache
|
|
384
|
+
from aixtools.testing.aix_test_model import AixTestModel
|
|
385
|
+
|
|
386
|
+
# Create mock tools for testing
|
|
387
|
+
mock_tool = MockTool(name="test_tool", response="mock response")
|
|
388
|
+
|
|
389
|
+
# Use model patch caching for consistent test results
|
|
390
|
+
cache = ModelPatchCache()
|
|
391
|
+
cached_response = cache.get_cached_response("test_prompt")
|
|
392
|
+
|
|
393
|
+
# Test model for controlled testing scenarios
|
|
394
|
+
test_model = AixTestModel()
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
### Tool Doctor System
|
|
398
|
+
|
|
399
|
+
Automated tool analysis and recommendation system for optimizing agent tool usage.
|
|
400
|
+
|
|
401
|
+
```python
|
|
402
|
+
from aixtools.tools.doctor.tool_doctor import ToolDoctor
|
|
403
|
+
from aixtools.tools.doctor.tool_recommendation import ToolRecommendation
|
|
404
|
+
|
|
405
|
+
# Analyze tool usage patterns
|
|
406
|
+
doctor = ToolDoctor()
|
|
407
|
+
analysis = doctor.analyze_tools(agent_logs)
|
|
408
|
+
|
|
409
|
+
# Get tool recommendations
|
|
410
|
+
recommendation = ToolRecommendation()
|
|
411
|
+
suggestions = recommendation.recommend_tools(agent_context)
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
### Mock Tool System
|
|
415
|
+
|
|
416
|
+
Create and manage mock tools for testing agent behavior without external dependencies.
|
|
417
|
+
|
|
418
|
+
```python
|
|
419
|
+
from aixtools.testing.mock_tool import MockTool
|
|
420
|
+
|
|
421
|
+
# Create a mock tool with predefined responses
|
|
422
|
+
mock_calculator = MockTool(
|
|
423
|
+
name="calculator",
|
|
424
|
+
description="Performs mathematical calculations",
|
|
425
|
+
response_map={
|
|
426
|
+
"2+2": "4",
|
|
427
|
+
"10*5": "50"
|
|
428
|
+
}
|
|
429
|
+
)
|
|
430
|
+
|
|
431
|
+
# Use in agent testing
|
|
432
|
+
agent = get_agent(tools=[mock_calculator])
|
|
433
|
+
result = await run_agent(agent, "What is 2+2?")
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### Model Patch Caching
|
|
437
|
+
|
|
438
|
+
Cache model responses for consistent testing and development workflows.
|
|
439
|
+
|
|
440
|
+
```python
|
|
441
|
+
from aixtools.testing.model_patch_cache import ModelPatchCache
|
|
442
|
+
|
|
443
|
+
# Initialize cache
|
|
444
|
+
cache = ModelPatchCache(cache_dir="./test_cache")
|
|
445
|
+
|
|
446
|
+
# Cache responses for specific prompts
|
|
447
|
+
cache.cache_response("test prompt", "cached response")
|
|
448
|
+
|
|
449
|
+
# Retrieve cached responses
|
|
450
|
+
response = cache.get_cached_response("test prompt")
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
### FaultyMCP Testing Server
|
|
454
|
+
|
|
455
|
+
Specialized MCP server for testing error handling and resilience in MCP implementations.
|
|
456
|
+
|
|
457
|
+
```python
|
|
458
|
+
from aixtools.mcp.faulty_mcp import run_server_on_port, config
|
|
459
|
+
|
|
460
|
+
# Configure error probabilities for testing
|
|
461
|
+
config.prob_on_post_404 = 0.3 # 30% chance of 404 on POST
|
|
462
|
+
config.prob_on_get_crash = 0.1 # 10% chance of crash on GET
|
|
463
|
+
config.prob_in_list_tools_throw = 0.2 # 20% chance of exception
|
|
464
|
+
|
|
465
|
+
# Run the faulty server for testing
|
|
466
|
+
run_server_on_port(port=8888)
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
**Available Test Tools:**
|
|
470
|
+
- `add(a, b)` - Reliable addition operation
|
|
471
|
+
- `multiply(a, b)` - Reliable multiplication operation
|
|
472
|
+
- `always_error()` - Always throws an exception
|
|
473
|
+
- `random_throw_exception(a, b, prob)` - Randomly throws exceptions
|
|
474
|
+
- `freeze_server(seconds)` - Simulates server freeze
|
|
475
|
+
- `throw_404_exception()` - Throws HTTP 404 error
|
|
476
|
+
|
|
477
|
+
**Command Line Usage:**
|
|
478
|
+
```bash
|
|
479
|
+
# Run with default error probabilities
|
|
480
|
+
python -m aixtools.mcp.faulty_mcp
|
|
481
|
+
|
|
482
|
+
# Run in safe mode (no errors)
|
|
483
|
+
python -m aixtools.mcp.faulty_mcp --safe-mode
|
|
484
|
+
|
|
485
|
+
# Custom configuration
|
|
486
|
+
python -m aixtools.mcp.faulty_mcp \
|
|
487
|
+
--port 8888 \
|
|
488
|
+
--prob-on-post-404 0.2 \
|
|
489
|
+
--prob-on-get-crash 0.1
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
### Running Tests
|
|
493
|
+
|
|
494
|
+
Execute the test suite using the provided scripts:
|
|
495
|
+
|
|
496
|
+
```bash
|
|
497
|
+
# Run all tests
|
|
498
|
+
./scripts/test.sh
|
|
499
|
+
|
|
500
|
+
# Run unit tests only
|
|
501
|
+
./scripts/test_unit.sh
|
|
502
|
+
|
|
503
|
+
# Run integration tests only
|
|
504
|
+
./scripts/test_integration.sh
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
## Chainlit & HTTP Server
|
|
508
|
+
|
|
509
|
+
### Chainlit Integration
|
|
510
|
+
|
|
511
|
+
Ready-to-use Chainlit application for interactive agent interfaces.
|
|
512
|
+
|
|
513
|
+
```python
|
|
514
|
+
# Run the Chainlit app
|
|
515
|
+
# Configuration in aixtools/chainlit.md
|
|
516
|
+
# Main app in aixtools/app.py
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
## Programming Utils
|
|
520
|
+
|
|
521
|
+
AIXtools provides essential programming utilities for configuration management, data persistence, file operations, and context handling.
|
|
522
|
+
|
|
523
|
+
### Persisted Dictionary
|
|
524
|
+
|
|
525
|
+
Persistent key-value storage with automatic serialization and file-based persistence.
|
|
526
|
+
|
|
527
|
+
```python
|
|
528
|
+
from aixtools.utils.persisted_dict import PersistedDict
|
|
529
|
+
|
|
530
|
+
# Create a persistent dictionary
|
|
531
|
+
cache = PersistedDict("cache.json")
|
|
532
|
+
|
|
533
|
+
# Store and retrieve data
|
|
534
|
+
cache["user_preferences"] = {"theme": "dark", "language": "en"}
|
|
535
|
+
cache["session_data"] = {"last_login": "2024-01-01"}
|
|
536
|
+
|
|
537
|
+
# Data is automatically saved to file
|
|
538
|
+
print(cache["user_preferences"]) # Persists across program restarts
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
### Enum with Description
|
|
542
|
+
|
|
543
|
+
Enhanced enum classes with built-in descriptions for better documentation and user interfaces.
|
|
544
|
+
|
|
545
|
+
```python
|
|
546
|
+
from aixtools.utils.enum_with_description import EnumWithDescription
|
|
547
|
+
|
|
548
|
+
class ModelType(EnumWithDescription):
|
|
549
|
+
GPT4 = ("gpt-4", "OpenAI GPT-4 model")
|
|
550
|
+
CLAUDE = ("claude-3", "Anthropic Claude-3 model")
|
|
551
|
+
LLAMA = ("llama-2", "Meta LLaMA-2 model")
|
|
552
|
+
|
|
553
|
+
# Access enum values and descriptions
|
|
554
|
+
print(ModelType.GPT4.value) # "gpt-4"
|
|
555
|
+
print(ModelType.GPT4.description) # "OpenAI GPT-4 model"
|
|
556
|
+
|
|
557
|
+
# Get all descriptions
|
|
558
|
+
for model in ModelType:
|
|
559
|
+
print(f"{model.value}: {model.description}")
|
|
560
|
+
```
|
|
561
|
+
|
|
562
|
+
### Context Management
|
|
563
|
+
|
|
564
|
+
Centralized context management for sharing state across components.
|
|
565
|
+
|
|
566
|
+
```python
|
|
567
|
+
from aixtools.context import Context
|
|
568
|
+
|
|
569
|
+
# Create and use context
|
|
570
|
+
context = Context()
|
|
571
|
+
context.set("user_id", "12345")
|
|
572
|
+
context.set("session_data", {"preferences": {"theme": "dark"}})
|
|
573
|
+
|
|
574
|
+
# Retrieve context data
|
|
575
|
+
user_id = context.get("user_id")
|
|
576
|
+
session_data = context.get("session_data")
|
|
577
|
+
|
|
578
|
+
# Context can be passed between components
|
|
579
|
+
def process_request(ctx: Context):
|
|
580
|
+
user_id = ctx.get("user_id")
|
|
581
|
+
# Process with user context
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
### Configuration Management
|
|
585
|
+
|
|
586
|
+
Robust configuration handling with environment variable support and validation.
|
|
587
|
+
|
|
588
|
+
```python
|
|
589
|
+
from aixtools.utils.config import Config
|
|
590
|
+
from aixtools.utils.config_util import load_config
|
|
591
|
+
|
|
592
|
+
# Load configuration from environment and files
|
|
593
|
+
config = load_config()
|
|
594
|
+
|
|
595
|
+
# Access configuration values
|
|
596
|
+
model_name = config.get("MODEL_NAME", "gpt-4")
|
|
597
|
+
api_key = config.get("API_KEY")
|
|
598
|
+
timeout = config.get("TIMEOUT", 30, int)
|
|
599
|
+
|
|
600
|
+
# Configuration with validation
|
|
601
|
+
class AppConfig(Config):
|
|
602
|
+
model_name: str = "gpt-4"
|
|
603
|
+
max_tokens: int = 1000
|
|
604
|
+
temperature: float = 0.7
|
|
605
|
+
|
|
606
|
+
app_config = AppConfig()
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
### File Utilities
|
|
610
|
+
|
|
611
|
+
Enhanced file operations with Path support and utility functions.
|
|
612
|
+
|
|
613
|
+
```python
|
|
614
|
+
from aixtools.utils.files import read_file, write_file, ensure_directory
|
|
615
|
+
from pathlib import Path
|
|
616
|
+
|
|
617
|
+
# Read and write files with automatic encoding handling
|
|
618
|
+
content = read_file("data.txt")
|
|
619
|
+
write_file("output.txt", "Hello, world!")
|
|
620
|
+
|
|
621
|
+
# Ensure directories exist
|
|
622
|
+
data_dir = Path("data/logs")
|
|
623
|
+
ensure_directory(data_dir)
|
|
624
|
+
|
|
625
|
+
# Work with file paths
|
|
626
|
+
config_path = Path("config") / "settings.json"
|
|
627
|
+
if config_path.exists():
|
|
628
|
+
config_data = read_file(config_path)
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
### Chainlit Utilities
|
|
632
|
+
|
|
633
|
+
Specialized utilities for Chainlit integration and agent display.
|
|
634
|
+
|
|
635
|
+
```python
|
|
636
|
+
from aixtools.utils.chainlit.cl_agent_show import show_agent_response
|
|
637
|
+
from aixtools.utils.chainlit.cl_utils import format_message
|
|
638
|
+
|
|
639
|
+
# Display agent responses in Chainlit
|
|
640
|
+
await show_agent_response(
|
|
641
|
+
response="Hello, how can I help you?",
|
|
642
|
+
metadata={"model": "gpt-4", "tokens": 150}
|
|
643
|
+
)
|
|
644
|
+
|
|
645
|
+
# Format messages for Chainlit display
|
|
646
|
+
formatted_msg = format_message(
|
|
647
|
+
content="Processing your request...",
|
|
648
|
+
message_type="info"
|
|
649
|
+
)
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
### General Utilities
|
|
653
|
+
|
|
654
|
+
Common utility functions for everyday programming tasks.
|
|
655
|
+
|
|
656
|
+
```python
|
|
657
|
+
from aixtools.utils.utils import safe_json_loads, timestamp_now, hash_string
|
|
658
|
+
|
|
659
|
+
# Safe JSON parsing
|
|
660
|
+
data = safe_json_loads('{"key": "value"}', default={})
|
|
661
|
+
|
|
662
|
+
# Get current timestamp
|
|
663
|
+
now = timestamp_now()
|
|
664
|
+
|
|
665
|
+
# Generate hash for strings
|
|
666
|
+
file_hash = hash_string("content to hash")
|
|
667
|
+
```
|
|
668
|
+
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
aixtools/__init__.py,sha256=9NGHm7LjsQmsvjTZvw6QFJexSvAU4bCoN_KBk9SCa00,260
|
|
2
|
-
aixtools/_version.py,sha256=
|
|
2
|
+
aixtools/_version.py,sha256=szvPIs2C82UunpzuvVg3MbF4QhzbBYTsVJ8DmPfq6_E,704
|
|
3
3
|
aixtools/app.py,sha256=JzQ0nrv_bjDQokllIlGHOV0HEb-V8N6k_nGQH-TEsVU,5227
|
|
4
4
|
aixtools/chainlit.md,sha256=yC37Ly57vjKyiIvK4oUvf4DYxZCwH7iocTlx7bLeGLU,761
|
|
5
5
|
aixtools/context.py,sha256=I_MD40ZnvRm5WPKAKqBUAdXIf8YaurkYUUHSVVy-QvU,598
|
|
@@ -68,7 +68,7 @@ aixtools/tools/doctor/__init__.py,sha256=FPwYzC1eJyw8IH0-BP0wgxSprLy6Y_4yXCek749
|
|
|
68
68
|
aixtools/tools/doctor/tool_doctor.py,sha256=flp00mbFwVI0-Ii_xC4YDW6Vrn-EAExA1TtQkY6cOZE,2583
|
|
69
69
|
aixtools/tools/doctor/tool_recommendation.py,sha256=t-l5bm6kwnXs1NH-ZZVTWhVrEAmWa460M44bi_Bip4g,1463
|
|
70
70
|
aixtools/utils/__init__.py,sha256=xT6almZBQYMfj4h7Hq9QXDHyVXbOOTxqLsmJsxYYnSw,757
|
|
71
|
-
aixtools/utils/config.py,sha256=
|
|
71
|
+
aixtools/utils/config.py,sha256=pNWVMC1V9Hn2KEqaXaLbhxCI_iwQfGiVKKaZLrRM4ug,4820
|
|
72
72
|
aixtools/utils/config_util.py,sha256=3Ya4Qqhj1RJ1qtTTykQ6iayf5uxlpigPXgEJlTi1wn4,2229
|
|
73
73
|
aixtools/utils/enum_with_description.py,sha256=zjSzWxG74eR4x7dpmb74pLTYCWNSMvauHd7_9LpDYIw,1088
|
|
74
74
|
aixtools/utils/files.py,sha256=8JnxwHJRJcjWCdFpjzWmo0po2fRg8esj4H7sOxElYXU,517
|
|
@@ -76,6 +76,8 @@ aixtools/utils/persisted_dict.py,sha256=0jQzV7oF-A6Or-HjcU6V7aMXWQL67SOKpULgmtFw
|
|
|
76
76
|
aixtools/utils/utils.py,sha256=5911Ej1ES2NU_FKIWA3CWKhKnwgjvi1aDR2aiD6Xv3E,4880
|
|
77
77
|
aixtools/utils/chainlit/cl_agent_show.py,sha256=vaRuowp4BRvhxEr5hw0zHEJ7iaSF_5bo_9BH7pGPPpw,4398
|
|
78
78
|
aixtools/utils/chainlit/cl_utils.py,sha256=fxaxdkcZg6uHdM8uztxdPowg3a2f7VR7B26VPY4t-3c,5738
|
|
79
|
+
aixtools/vault/__init__.py,sha256=fsr_NuX3GZ9WZ7dGfe0gp_5-z3URxAfwVRXw7Xyc0dU,141
|
|
80
|
+
aixtools/vault/vault.py,sha256=WkzBTEYM-Vqjyoa5x5imbEDi0ePBklMjD_aAdvIK-34,4293
|
|
79
81
|
docker/mcp-base/Dockerfile,sha256=sSpbt0sasSBHHeGwPIpJpiEQMU5HGeXzerK8biVSt7Q,1547
|
|
80
82
|
notebooks/example_faulty_mcp_server.ipynb,sha256=b2Cy3GXfj-gOBZ7SoUzj25F1rxp5u-32EWPHWQ-sxn8,1729
|
|
81
83
|
notebooks/example_mcp_server_stdio.ipynb,sha256=ya4dRKNFU2vQxob-uIhKHGAzINXGQ6MehgKVmSCpHLk,1634
|
|
@@ -109,8 +111,10 @@ tests/unit/server/test_path.py,sha256=1QKiKLLRga9GNxmaUEt_wEZ9U14yzB-7PIhAOgB4ww
|
|
|
109
111
|
tests/unit/server/test_utils.py,sha256=kvhzdgNfsJl5tqcRBWg2yTR5GPpyrFCOmEIOuHb3904,14848
|
|
110
112
|
tests/unit/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
111
113
|
tests/unit/utils/test_files.py,sha256=AKFmXQqXstyKd2PreE4EmQyhQYeqOmu1Sp80MwHrf_Q,5782
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
aixtools-0.1.
|
|
115
|
-
aixtools-0.1.
|
|
116
|
-
aixtools-0.1.
|
|
114
|
+
tests/unit/vault/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
115
|
+
tests/unit/vault/test_vault.py,sha256=R_RTDsralvE0JhuIrHQTb85gU9ipDJD7aoYIMdcg0o4,7264
|
|
116
|
+
aixtools-0.1.7.dist-info/METADATA,sha256=PRE6AkiaiOoNeUWBs9PhV2O0jhSRRkPvqOvfodz57Lo,18569
|
|
117
|
+
aixtools-0.1.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
118
|
+
aixtools-0.1.7.dist-info/entry_points.txt,sha256=dHoutULEZx7xXSqJrZdViSVjfInJibfLibi2nRXL3SE,56
|
|
119
|
+
aixtools-0.1.7.dist-info/top_level.txt,sha256=ee4eF-0pqu45zCUVml0mWIhnXQgqMQper2-49BBVHLY,40
|
|
120
|
+
aixtools-0.1.7.dist-info/RECORD,,
|
|
File without changes
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
from unittest.mock import MagicMock, patch
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
from hvac.exceptions import InvalidPath
|
|
5
|
+
|
|
6
|
+
from aixtools.vault.vault import VaultAuthError, VaultClient
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@pytest.fixture
|
|
10
|
+
def patched_vault_client():
|
|
11
|
+
with patch("aixtools.vault.vault.hvac.Client") as mock_hvac_client_cls:
|
|
12
|
+
fake_hvac_client = MagicMock()
|
|
13
|
+
fake_hvac_client.is_authenticated.return_value = True
|
|
14
|
+
mock_hvac_client_cls.return_value = fake_hvac_client
|
|
15
|
+
|
|
16
|
+
client = VaultClient()
|
|
17
|
+
return client
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@pytest.fixture
|
|
21
|
+
def valid_params():
|
|
22
|
+
return {
|
|
23
|
+
"vault_mount_point": "secret",
|
|
24
|
+
"path_prefix": "path",
|
|
25
|
+
"env": "dev",
|
|
26
|
+
"user_id": "test-user",
|
|
27
|
+
"service_name": "test-service",
|
|
28
|
+
"user_api_key": "test-api-key",
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def test_store_user_service_api_key_success(patched_vault_client, valid_params):
|
|
33
|
+
patched_vault_client.client.secrets.kv.v2.create_or_update_secret.return_value = {}
|
|
34
|
+
|
|
35
|
+
patched_vault_client.store_user_service_api_key(
|
|
36
|
+
user_id=valid_params["user_id"],
|
|
37
|
+
service_name=valid_params["service_name"],
|
|
38
|
+
user_api_key=valid_params["user_api_key"],
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
secret_path = (
|
|
42
|
+
f"{valid_params['path_prefix']}/{valid_params['env']}/{valid_params['user_id']}/{valid_params['service_name']}"
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
patched_vault_client.client.secrets.kv.v2.create_or_update_secret.assert_called_once_with(
|
|
46
|
+
secret_path,
|
|
47
|
+
secret={"user-api-key": valid_params["user_api_key"]},
|
|
48
|
+
mount_point=valid_params["vault_mount_point"],
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def test_store_user_service_api_key_invalid_path(patched_vault_client, valid_params):
|
|
53
|
+
patched_vault_client.client.secrets.kv.v2.create_or_update_secret.side_effect = Exception("Invalid Path")
|
|
54
|
+
|
|
55
|
+
with pytest.raises(VaultAuthError, match="Invalid Path"):
|
|
56
|
+
patched_vault_client.store_user_service_api_key(
|
|
57
|
+
user_id=valid_params["user_id"],
|
|
58
|
+
service_name=valid_params["service_name"],
|
|
59
|
+
user_api_key=valid_params["user_api_key"],
|
|
60
|
+
)
|
|
61
|
+
patched_vault_client.client.assert_not_called()
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def test_read_user_service_api_key_success(patched_vault_client):
|
|
65
|
+
"""Test successful read of user service API key."""
|
|
66
|
+
mock_response = {"data": {"data": {"user-api-key": "test-api-key"}}}
|
|
67
|
+
patched_vault_client.client.secrets.kv.v2.read_secret_version.return_value = mock_response
|
|
68
|
+
|
|
69
|
+
result = patched_vault_client.read_user_service_api_key(user_id="test-user", service_name="test-service")
|
|
70
|
+
|
|
71
|
+
assert result == "test-api-key"
|
|
72
|
+
patched_vault_client.client.secrets.kv.v2.read_secret_version.assert_called_once_with(
|
|
73
|
+
"path/dev/test-user/test-service", mount_point="secret", raise_on_deleted_version=True
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def test_read_user_service_api_key_secret_not_found(patched_vault_client):
|
|
78
|
+
"""Test read_user_service_api_key when the secret path does not exist."""
|
|
79
|
+
patched_vault_client.client.secrets.kv.v2.read_secret_version.side_effect = InvalidPath
|
|
80
|
+
|
|
81
|
+
result = patched_vault_client.read_user_service_api_key(user_id="test-user", service_name="test-service")
|
|
82
|
+
|
|
83
|
+
assert result is None
|
|
84
|
+
patched_vault_client.client.secrets.kv.v2.read_secret_version.assert_called_once_with(
|
|
85
|
+
"path/dev/test-user/test-service", mount_point="secret", raise_on_deleted_version=True
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def test_read_user_service_api_key_unexpected_error(patched_vault_client):
|
|
90
|
+
"""Test read_user_service_api_key when an unexpected exception occurs."""
|
|
91
|
+
patched_vault_client.client.secrets.kv.v2.read_secret_version.side_effect = Exception("Unexpected error")
|
|
92
|
+
|
|
93
|
+
with pytest.raises(VaultAuthError, match="Unexpected error"):
|
|
94
|
+
patched_vault_client.read_user_service_api_key(user_id="test-user", service_name="test-service")
|
|
95
|
+
|
|
96
|
+
patched_vault_client.client.secrets.kv.v2.read_secret_version.assert_called_once_with(
|
|
97
|
+
"path/dev/test-user/test-service", mount_point="secret", raise_on_deleted_version=True
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def test_store_user_service_secret_success(patched_vault_client, valid_params):
|
|
102
|
+
"""Test successful storage of complete user service secret."""
|
|
103
|
+
secret_data = {"api_key": "test-api-key", "token": "test-token", "endpoint": "https://api.example.com"}
|
|
104
|
+
patched_vault_client.client.secrets.kv.v2.create_or_update_secret.return_value = {}
|
|
105
|
+
|
|
106
|
+
patched_vault_client.store_user_service_secret(
|
|
107
|
+
user_id=valid_params["user_id"],
|
|
108
|
+
service_name=valid_params["service_name"],
|
|
109
|
+
secret_data=secret_data,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
secret_path = (
|
|
113
|
+
f"{valid_params['path_prefix']}/{valid_params['env']}/{valid_params['user_id']}/{valid_params['service_name']}"
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
patched_vault_client.client.secrets.kv.v2.create_or_update_secret.assert_called_once_with(
|
|
117
|
+
secret_path,
|
|
118
|
+
secret=secret_data,
|
|
119
|
+
mount_point=valid_params["vault_mount_point"],
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def test_store_user_service_secret_error(patched_vault_client, valid_params):
|
|
124
|
+
"""Test store_user_service_secret when an error occurs."""
|
|
125
|
+
secret_data = {"api_key": "test-api-key", "token": "test-token"}
|
|
126
|
+
patched_vault_client.client.secrets.kv.v2.create_or_update_secret.side_effect = Exception("Storage error")
|
|
127
|
+
|
|
128
|
+
with pytest.raises(VaultAuthError, match="Storage error"):
|
|
129
|
+
patched_vault_client.store_user_service_secret(
|
|
130
|
+
user_id=valid_params["user_id"],
|
|
131
|
+
service_name=valid_params["service_name"],
|
|
132
|
+
secret_data=secret_data,
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def test_read_user_service_secret_success(patched_vault_client):
|
|
137
|
+
"""Test successful read of complete user service secret."""
|
|
138
|
+
secret_data = {"api_key": "test-api-key", "token": "test-token", "endpoint": "https://api.example.com"}
|
|
139
|
+
mock_response = {"data": {"data": secret_data}}
|
|
140
|
+
patched_vault_client.client.secrets.kv.v2.read_secret_version.return_value = mock_response
|
|
141
|
+
|
|
142
|
+
result = patched_vault_client.read_user_service_secret(user_id="test-user", service_name="test-service")
|
|
143
|
+
|
|
144
|
+
assert result == secret_data
|
|
145
|
+
patched_vault_client.client.secrets.kv.v2.read_secret_version.assert_called_once_with(
|
|
146
|
+
"path/dev/test-user/test-service", mount_point="secret", raise_on_deleted_version=True
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def test_read_user_service_secret_not_found(patched_vault_client):
|
|
151
|
+
"""Test read_user_service_secret when the secret path does not exist."""
|
|
152
|
+
patched_vault_client.client.secrets.kv.v2.read_secret_version.side_effect = InvalidPath
|
|
153
|
+
|
|
154
|
+
result = patched_vault_client.read_user_service_secret(user_id="test-user", service_name="test-service")
|
|
155
|
+
|
|
156
|
+
assert result is None
|
|
157
|
+
patched_vault_client.client.secrets.kv.v2.read_secret_version.assert_called_once_with(
|
|
158
|
+
"path/dev/test-user/test-service", mount_point="secret", raise_on_deleted_version=True
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def test_read_user_service_secret_error(patched_vault_client):
|
|
163
|
+
"""Test read_user_service_secret when an unexpected exception occurs."""
|
|
164
|
+
patched_vault_client.client.secrets.kv.v2.read_secret_version.side_effect = Exception("Read error")
|
|
165
|
+
|
|
166
|
+
with pytest.raises(VaultAuthError, match="Read error"):
|
|
167
|
+
patched_vault_client.read_user_service_secret(user_id="test-user", service_name="test-service")
|
|
168
|
+
|
|
169
|
+
patched_vault_client.client.secrets.kv.v2.read_secret_version.assert_called_once_with(
|
|
170
|
+
"path/dev/test-user/test-service", mount_point="secret", raise_on_deleted_version=True
|
|
171
|
+
)
|
|
@@ -1,357 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: aixtools
|
|
3
|
-
Version: 0.1.5
|
|
4
|
-
Summary: Tools for AI exploration and debugging
|
|
5
|
-
Requires-Python: >=3.11.2
|
|
6
|
-
Description-Content-Type: text/markdown
|
|
7
|
-
Requires-Dist: a2a-sdk>=0.3.1
|
|
8
|
-
Requires-Dist: cachebox>=5.0.1
|
|
9
|
-
Requires-Dist: chainlit>=2.5.5
|
|
10
|
-
Requires-Dist: colorlog>=6.9.0
|
|
11
|
-
Requires-Dist: fasta2a>=0.5.0
|
|
12
|
-
Requires-Dist: fastmcp>=2.10.2
|
|
13
|
-
Requires-Dist: ipykernel>=6.29.5
|
|
14
|
-
Requires-Dist: langchain-chroma>=0.2.3
|
|
15
|
-
Requires-Dist: langchain-ollama>=0.3.2
|
|
16
|
-
Requires-Dist: langchain-openai>=0.3.14
|
|
17
|
-
Requires-Dist: mcp>=1.11.0
|
|
18
|
-
Requires-Dist: pandas>=2.2.3
|
|
19
|
-
Requires-Dist: pydantic-ai>=0.4.10
|
|
20
|
-
Requires-Dist: pylint>=3.3.7
|
|
21
|
-
Requires-Dist: rich>=14.0.0
|
|
22
|
-
Requires-Dist: ruff>=0.11.6
|
|
23
|
-
Requires-Dist: streamlit>=1.44.1
|
|
24
|
-
Requires-Dist: watchdog>=6.0.0
|
|
25
|
-
Provides-Extra: test
|
|
26
|
-
Requires-Dist: pyyaml; extra == "test"
|
|
27
|
-
Provides-Extra: feature
|
|
28
|
-
Requires-Dist: logfire; extra == "feature"
|
|
29
|
-
|
|
30
|
-
# AiXplore-tools
|
|
31
|
-
|
|
32
|
-
AiXplore-tools (`axitools` for short) is a Python library to support AI agent development and debugging. It serves two main purposes:
|
|
33
|
-
|
|
34
|
-
1. **Utility Library**: A collection of utility functions and classes for agent projects
|
|
35
|
-
2. **Debugging Tool**: A Streamlit app (`log_view`) for visualizing and debugging agent applications by viewing messages logged by `ObjectLogger`
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
## `.venv`
|
|
39
|
-
|
|
40
|
-
```
|
|
41
|
-
# Create a new environment
|
|
42
|
-
uv venv .venv
|
|
43
|
-
source .venv/bin/activate
|
|
44
|
-
|
|
45
|
-
# Add packages
|
|
46
|
-
uv add pydantic-ai
|
|
47
|
-
uv add mcp[cli]
|
|
48
|
-
uv add chainlit
|
|
49
|
-
uv add streamlit
|
|
50
|
-
|
|
51
|
-
# Add langchain
|
|
52
|
-
uv add langchain-chroma
|
|
53
|
-
uv add langchain-ollama
|
|
54
|
-
uv add langchain-openai
|
|
55
|
-
|
|
56
|
-
# Other packages
|
|
57
|
-
uv add colorlog
|
|
58
|
-
uv add pandas
|
|
59
|
-
uv add rich
|
|
60
|
-
uv add ruff
|
|
61
|
-
uv add watchdog
|
|
62
|
-
uv add ipykernel
|
|
63
|
-
|
|
64
|
-
# Install this code as a package
|
|
65
|
-
uv pip install -e .
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
## Installation
|
|
69
|
-
|
|
70
|
-
Installing the package from GitHub, you can use `uv add` (prefered)
|
|
71
|
-
```
|
|
72
|
-
uv add https://github.com/your-org/aixtools.git
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
or using the `pip` commamnd
|
|
76
|
-
```
|
|
77
|
-
uv pip install https://github.com/your-org/aixtools.git
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
Remember to set up your [`.env` file](#environment-configuration).
|
|
81
|
-
|
|
82
|
-
### Updating
|
|
83
|
-
|
|
84
|
-
This package is in active development and changes often.
|
|
85
|
-
|
|
86
|
-
You'll want to force uv to re-install or update it to the latest commit, even if the version hasn’t changed.
|
|
87
|
-
|
|
88
|
-
```
|
|
89
|
-
uv add --upgrade https://github.com/your-org/aixtools.git
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
### Example: Creatng a new project
|
|
93
|
-
|
|
94
|
-
```
|
|
95
|
-
# Create a new project
|
|
96
|
-
uv init MyNewProject
|
|
97
|
-
cd MyNewProject
|
|
98
|
-
|
|
99
|
-
# Add a virtual environemnt and activate it
|
|
100
|
-
uv venv .venv
|
|
101
|
-
source .venv/bin/activate
|
|
102
|
-
|
|
103
|
-
# Add this package
|
|
104
|
-
uv add https://github.com/your-org/aixtools.git
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
### Environment Configuration
|
|
108
|
-
|
|
109
|
-
AIXtools requires specific environment variables to be set for proper operation, especially when working with different model providers.
|
|
110
|
-
|
|
111
|
-
Here is a [template of an `.env`](./.env_template) file you can use as reference.
|
|
112
|
-
|
|
113
|
-
#### Setting Up Environment Variables
|
|
114
|
-
|
|
115
|
-
1. Create a `.env` file in your project root based on the template below:
|
|
116
|
-
|
|
117
|
-
```
|
|
118
|
-
# Model family (azure, openai, or ollama)
|
|
119
|
-
MODEL_FAMILY=azure
|
|
120
|
-
VDB_EMBEDDINGS_MODEL_FAMILY=azure
|
|
121
|
-
|
|
122
|
-
MODEL_TIMEOUT=120
|
|
123
|
-
|
|
124
|
-
# Azure OpenAI
|
|
125
|
-
AZURE_OPENAI_ENDPOINT=https://your_endpoint.openai.azure.com
|
|
126
|
-
AZURE_OPENAI_API_VERSION=2024-06-01
|
|
127
|
-
AZURE_OPENAI_API_KEY=your_secret_key
|
|
128
|
-
AZURE_MODEL_NAME=gpt-4o
|
|
129
|
-
AZURE_OPENAI_PROVIDER_ID=azure
|
|
130
|
-
AZURE_VDB_EMBEDDINGS_MODEL_NAME=text-embedding-3-small
|
|
131
|
-
|
|
132
|
-
# OpenAI
|
|
133
|
-
OPENAI_MODEL_NAME=gpt-4.5-preview
|
|
134
|
-
OPENAI_API_KEY=openai_api_key
|
|
135
|
-
OPENAI_VDB_EMBEDDINGS_MODEL_NAME=text-embedding-3-small
|
|
136
|
-
|
|
137
|
-
# Ollama models
|
|
138
|
-
OLLAMA_MODEL_NAME=llama3.2:3b-instruct-fp16
|
|
139
|
-
OLLAMA_LOCAL_URL=http://localhost:11434/v1
|
|
140
|
-
OLLAMA_VDB_EMBEDDINGS_MODEL_NAME=snowflake-arctic-embed2:latest
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
2. Configure the variables according to your needs:
|
|
144
|
-
- Set `MODEL_FAMILY` to your preferred model provider (`azure`, `openai`, or `ollama`)
|
|
145
|
-
- Provide the appropriate API keys and endpoints for your chosen provider
|
|
146
|
-
- Adjust model names and timeouts as needed
|
|
147
|
-
|
|
148
|
-
#### Important Environment Variables
|
|
149
|
-
|
|
150
|
-
| Variable | Description | Required |
|
|
151
|
-
|----------|-------------|----------|
|
|
152
|
-
| `MODEL_FAMILY` | The model provider to use (azure, openai, ollama) | Yes |
|
|
153
|
-
| `MODEL_TIMEOUT` | Timeout in seconds for model requests | Yes |
|
|
154
|
-
| `AZURE_*` | Azure OpenAI configuration (if using Azure) | If MODEL_FAMILY=azure |
|
|
155
|
-
| `OPENAI_*` | OpenAI configuration (if using OpenAI) | If MODEL_FAMILY=openai |
|
|
156
|
-
| `OLLAMA_*` | Ollama configuration (if using Ollama) | If MODEL_FAMILY=ollama |
|
|
157
|
-
|
|
158
|
-
## Debugging tools: `log_view` and `ObjectLogger`
|
|
159
|
-
|
|
160
|
-
The `ObjectLogger` provides a simple logging facility, these logs can then be visualized with `log_view` app.
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
### `ObjectLogger`
|
|
164
|
-
|
|
165
|
-
The `ObjectLogger` class allows you to log objects to a file for later analysis. This is particularly useful for debugging agent interactions.
|
|
166
|
-
|
|
167
|
-
`ObjectLogger` simply serializes objects to a pickle file. It first removes unserializeable parts of the objects (e.g. like `async` managers).
|
|
168
|
-
|
|
169
|
-
#### Basic Usage
|
|
170
|
-
|
|
171
|
-
```python
|
|
172
|
-
from aixtools.utils.log_objects import ObjectLogger
|
|
173
|
-
|
|
174
|
-
# Create a logger as a context manager
|
|
175
|
-
with ObjectLogger() as logger:
|
|
176
|
-
# Log any pickleable object
|
|
177
|
-
logger.log({"message": "Hello, world!"})
|
|
178
|
-
|
|
179
|
-
# Log agent responses or any other objects
|
|
180
|
-
logger.log(agent_response)
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
#### Logging Agent Interactions
|
|
184
|
-
|
|
185
|
-
The function `run_agent` logs each node from the agent run, roughtly it looks like this:
|
|
186
|
-
|
|
187
|
-
```python
|
|
188
|
-
async def run_agent(agent: Agent, prompt: str | list[str]):
|
|
189
|
-
nodes = []
|
|
190
|
-
async with agent.iter(prompt) as agent_run:
|
|
191
|
-
with ObjectLogger(debug=debug) as agent_logger:
|
|
192
|
-
async for node in agent_run:
|
|
193
|
-
agent_logger.log(node)
|
|
194
|
-
nodes.append(node)
|
|
195
|
-
result = agent_run.result
|
|
196
|
-
return result.data, nodes
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
#### Saving Multiple Objects
|
|
200
|
-
|
|
201
|
-
```python
|
|
202
|
-
from aixtools.utils.log_objects import save_objects_to_logfile
|
|
203
|
-
|
|
204
|
-
# Save a list of objects to a log file
|
|
205
|
-
objects = [obj1, obj2, obj3]
|
|
206
|
-
save_objects_to_logfile(objects)
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
### log_view App
|
|
210
|
-
|
|
211
|
-
The `log_view` app allows you to visualize and analyze the objects logged by `ObjectLogger`.
|
|
212
|
-
|
|
213
|
-
It is a simple Streamlit app that you can run locally and view the log files.
|
|
214
|
-
|
|
215
|
-
#### Running the App
|
|
216
|
-
|
|
217
|
-
You can run the app using the command-line script installed with the package:
|
|
218
|
-
|
|
219
|
-
```bash
|
|
220
|
-
log_view
|
|
221
|
-
```
|
|
222
|
-
|
|
223
|
-
Or specify a custom log directory:
|
|
224
|
-
|
|
225
|
-
```bash
|
|
226
|
-
log_view /path/to/logs
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
#### Features
|
|
230
|
-
|
|
231
|
-
The log_view app provides several features for analyzing logged objects:
|
|
232
|
-
|
|
233
|
-
- **Log File Selection**: Choose from available log files
|
|
234
|
-
- **Filtering**: Filter nodes by text, type, attributes, or regex patterns
|
|
235
|
-
- **Visualization**: Expand/collapse nodes to view details
|
|
236
|
-
- **Export**: Export filtered nodes to JSON
|
|
237
|
-
|
|
238
|
-
#### Example Workflow
|
|
239
|
-
|
|
240
|
-
1. Log agent interactions using `ObjectLogger`
|
|
241
|
-
2. Run the `log_view` app to analyze the logs
|
|
242
|
-
3. Filter and explore the logged objects
|
|
243
|
-
4. Export interesting findings for further analysis
|
|
244
|
-
|
|
245
|
-
## Additional Utilities
|
|
246
|
-
|
|
247
|
-
AIXtools provides several other utilities to support agent development:
|
|
248
|
-
|
|
249
|
-
### PersistedDict
|
|
250
|
-
|
|
251
|
-
A dictionary that persists to a file on disk as JSON or pickle:
|
|
252
|
-
|
|
253
|
-
```python
|
|
254
|
-
from aixtools.utils.persisted_dict import PersistedDict
|
|
255
|
-
|
|
256
|
-
# Create a persisted dictionary
|
|
257
|
-
data = PersistedDict("data.json")
|
|
258
|
-
|
|
259
|
-
# Use it like a regular dictionary
|
|
260
|
-
data["key"] = "value" # Automatically saved to disk
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
## Agent Utilities
|
|
264
|
-
|
|
265
|
-
Functions for creating and running agents with different model providers:
|
|
266
|
-
|
|
267
|
-
```python
|
|
268
|
-
from aixtools.agents.agent import get_agent, run_agent
|
|
269
|
-
|
|
270
|
-
# Create an agent with the default model (from MODEL_FAMILY)
|
|
271
|
-
agent = get_agent(system_prompt="You are a helpful assistant.")
|
|
272
|
-
|
|
273
|
-
# Create an agent with a specific model
|
|
274
|
-
from aixtools.agents.agent import get_model_openai
|
|
275
|
-
model = get_model_openai()
|
|
276
|
-
agent = get_agent(system_prompt="You are a helpful assistant.", model=model)
|
|
277
|
-
|
|
278
|
-
# Run the agent
|
|
279
|
-
result, nodes = await run_agent(agent, "Tell me about AI")
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
### Batch Processing
|
|
283
|
-
|
|
284
|
-
Run multiple agent queries simultaneously:
|
|
285
|
-
|
|
286
|
-
```python
|
|
287
|
-
from aixtools.agents.agent_batch import agent_batch, AgentQueryParams
|
|
288
|
-
|
|
289
|
-
# Create query parameters
|
|
290
|
-
query_parameters = [
|
|
291
|
-
AgentQueryParams(prompt="What is the meaning of life"),
|
|
292
|
-
AgentQueryParams(prompt="Who is the prime minister of Canada")
|
|
293
|
-
]
|
|
294
|
-
|
|
295
|
-
# Run queries in batches
|
|
296
|
-
async for result in agent_batch(query_parameters):
|
|
297
|
-
print(result)
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
## Project Structure
|
|
301
|
-
|
|
302
|
-
```
|
|
303
|
-
aixtools/
|
|
304
|
-
├── __init__.py # Package initialization
|
|
305
|
-
├── log_view.py # Entry point for log_view app
|
|
306
|
-
├── agents/ # Agent-related functionality
|
|
307
|
-
│ ├── agent.py # Core agent functions
|
|
308
|
-
│ └── agent_batch.py # Batch processing for agents
|
|
309
|
-
├── log_view/ # Log viewer application
|
|
310
|
-
│ ├── app.py # Main Streamlit application
|
|
311
|
-
│ ├── display.py # Node display utilities
|
|
312
|
-
│ ├── export.py # Export functionality
|
|
313
|
-
│ ├── filters.py # Node filtering
|
|
314
|
-
│ ├── log_utils.py # Log file utilities
|
|
315
|
-
│ └── node_utils.py # Node processing utilities
|
|
316
|
-
└── utils/ # Utility functions and classes
|
|
317
|
-
├── config.py # Configuration utilities
|
|
318
|
-
├── log_objects.py # Object logging functionality
|
|
319
|
-
├── persisted_dict.py # Persistent dictionary
|
|
320
|
-
└── utils.py # General utilities
|
|
321
|
-
|
|
322
|
-
## Logging
|
|
323
|
-
|
|
324
|
-
The logging system is configured using a standard Python `dictConfig` schema. By default, it will look for a `logging.yaml` or `logging.json` file in your project's root directory. You can also specify a custom path using the `LOGGING_CONFIG_PATH` environment variable.
|
|
325
|
-
|
|
326
|
-
If no configuration file is found, a default colorized console logger will be used.
|
|
327
|
-
|
|
328
|
-
### Example `logging.yaml`
|
|
329
|
-
|
|
330
|
-
```yaml
|
|
331
|
-
version: 1
|
|
332
|
-
disable_existing_loggers: false
|
|
333
|
-
formatters:
|
|
334
|
-
default:
|
|
335
|
-
format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
336
|
-
color:
|
|
337
|
-
"()": "colorlog.ColoredFormatter"
|
|
338
|
-
"format": "%(log_color)s%(levelname)-8s%(reset)s [%(name)s] %(message)s"
|
|
339
|
-
handlers:
|
|
340
|
-
console:
|
|
341
|
-
class: colorlog.StreamHandler
|
|
342
|
-
formatter: color
|
|
343
|
-
level: DEBUG
|
|
344
|
-
file:
|
|
345
|
-
class: logging.handlers.RotatingFileHandler
|
|
346
|
-
formatter: default
|
|
347
|
-
filename: app.log
|
|
348
|
-
maxBytes: 10485760 # 10MB
|
|
349
|
-
backupCount: 5
|
|
350
|
-
level: INFO
|
|
351
|
-
root:
|
|
352
|
-
handlers: [console, file]
|
|
353
|
-
level: DEBUG
|
|
354
|
-
loggers:
|
|
355
|
-
aixtools:
|
|
356
|
-
level: INFO
|
|
357
|
-
```
|
|
File without changes
|
|
File without changes
|
|
File without changes
|