aixtools 0.1.5__py3-none-any.whl → 0.1.6__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 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.5'
32
- __version_tuple__ = version_tuple = (0, 1, 5)
31
+ __version__ = version = '0.1.6'
32
+ __version_tuple__ = version_tuple = (0, 1, 6)
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")
@@ -0,0 +1,7 @@
1
+ """
2
+ Provides a Vault client for storing and retrieving user service api keys.
3
+ """
4
+
5
+ from .vault import VaultClient
6
+
7
+ __all__ = ["VaultClient"]
@@ -0,0 +1,73 @@
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 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 store_user_service_api_key(self, *, user_id: str, service_name: str, user_api_key: str):
31
+ """
32
+ Store user's service api key in the Vault at the specified vault mount
33
+ point, where the path is <path_prefix>/<env>/<user_id>/<service_name>.
34
+ """
35
+ secret_path = None
36
+ try:
37
+ secret_path = f"{config.VAULT_PATH_PREFIX}/{config.VAULT_ENV}/{user_id}/{service_name}"
38
+ print("secret_path", secret_path)
39
+ secret_dict = {"user-api-key": user_api_key}
40
+ self.client.secrets.kv.v2.create_or_update_secret(
41
+ secret_path, secret=secret_dict, mount_point=config.VAULT_MOUNT_POINT
42
+ )
43
+
44
+ logger.info("Secret written to path %s", secret_path)
45
+ except Exception as e:
46
+ logger.error("Failed to write secret to path %s: %s", secret_path, str(e))
47
+ raise VaultAuthError(e) from e
48
+
49
+ def read_user_service_api_key(self, *, user_id: str, service_name) -> Optional[str]:
50
+ """
51
+ Read user's service api key in from vault at the specified mount point,
52
+ where the path is <path_prefix>/<env>/<user_id>/<service_name>.
53
+ """
54
+ secret_path = None
55
+
56
+ try:
57
+ secret_path = f"{config.VAULT_PATH_PREFIX}/{config.VAULT_ENV}/{user_id}/{service_name}"
58
+ logger.info("Reading secret from path %s", secret_path)
59
+ response = self.client.secrets.kv.v2.read_secret_version(
60
+ secret_path, mount_point=config.VAULT_MOUNT_POINT, raise_on_deleted_version=True
61
+ )
62
+ secret_data = response["data"]["data"]
63
+ user_api_key = secret_data["user-api-key"]
64
+ logger.info("Secret read from path %s ", secret_path)
65
+ return user_api_key
66
+ except InvalidPath:
67
+ # Secret path does not exist
68
+ logger.warning("Secret path does not exist %s ", secret_path)
69
+ return None
70
+
71
+ except Exception as e:
72
+ logger.error("Failed to read secret from path %s: %s", secret_path, str(e))
73
+ raise VaultAuthError(e) from e
@@ -0,0 +1,668 @@
1
+ Metadata-Version: 2.4
2
+ Name: aixtools
3
+ Version: 0.1.6
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=rdxBMYpwzYxiWk08QbPLHSAxHoDfeKWwyaJIAM0lSic,704
2
+ aixtools/_version.py,sha256=riGXiVTWXmtdoju9hVCWvTxpszEMAAIK0sZZWoLKlnU,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=x6zfDDAwD0dQglRJnlENxYXZKo_IMUaSLo9Ed6XKboc,4446
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=JeAnRnsXm_etkTUntE9ABIiNlI8M81E2b85IQHfGehI,2817
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
- aixtools-0.1.5.dist-info/METADATA,sha256=QbJnhcWkwh9yMwKh5e95XmVuLKVAltsOx2bce11oKbs,10170
113
- aixtools-0.1.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
114
- aixtools-0.1.5.dist-info/entry_points.txt,sha256=dHoutULEZx7xXSqJrZdViSVjfInJibfLibi2nRXL3SE,56
115
- aixtools-0.1.5.dist-info/top_level.txt,sha256=ee4eF-0pqu45zCUVml0mWIhnXQgqMQper2-49BBVHLY,40
116
- aixtools-0.1.5.dist-info/RECORD,,
114
+ tests/unit/vault/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
115
+ tests/unit/vault/test_vault.py,sha256=YzmJ-JZo8OLGNcmc845knCh3zp8jhkANVgKT09cuhSU,4250
116
+ aixtools-0.1.6.dist-info/METADATA,sha256=6JFv550ISVltjdNxLIcsM0TNd-O7KS-g2ZsvCuanuJ0,18569
117
+ aixtools-0.1.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
118
+ aixtools-0.1.6.dist-info/entry_points.txt,sha256=dHoutULEZx7xXSqJrZdViSVjfInJibfLibi2nRXL3SE,56
119
+ aixtools-0.1.6.dist-info/top_level.txt,sha256=ee4eF-0pqu45zCUVml0mWIhnXQgqMQper2-49BBVHLY,40
120
+ aixtools-0.1.6.dist-info/RECORD,,
File without changes
@@ -0,0 +1,114 @@
1
+ from unittest.mock import MagicMock, patch
2
+
3
+ import pytest
4
+ from hvac.exceptions import InvalidPath
5
+
6
+ from aixtools.vault.vault import VaultClient, VaultAuthError
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(user_id=valid_params["user_id"],
36
+ service_name=valid_params['service_name'],
37
+ user_api_key=valid_params['user_api_key'])
38
+
39
+ secret_path = f"{valid_params['path_prefix']}/{valid_params['env']}/{valid_params['user_id']}/{valid_params['service_name']}"
40
+
41
+ print("expected secret path", secret_path)
42
+ patched_vault_client.client.secrets.kv.v2.create_or_update_secret.assert_called_once_with(
43
+ secret_path,
44
+ secret={"user-api-key": valid_params["user_api_key"]},
45
+ mount_point=valid_params["vault_mount_point"]
46
+ )
47
+
48
+
49
+ def test_store_user_service_api_key_invalid_path(patched_vault_client, valid_params):
50
+ patched_vault_client.client.secrets.kv.v2.create_or_update_secret.side_effect = Exception("Invalid Path")
51
+
52
+ with pytest.raises(VaultAuthError, match="Invalid Path"):
53
+ patched_vault_client.store_user_service_api_key(user_id=valid_params["user_id"],
54
+ service_name=valid_params['service_name'],
55
+ user_api_key=valid_params['user_api_key'])
56
+ patched_vault_client.client.assert_not_called()
57
+
58
+
59
+ def test_read_user_service_api_key_success(patched_vault_client):
60
+ """Test successful read of user service API key."""
61
+ mock_response = {
62
+ "data": {
63
+ "data": {
64
+ "user-api-key": "test-api-key"
65
+ }
66
+ }
67
+ }
68
+ patched_vault_client.client.secrets.kv.v2.read_secret_version.return_value = mock_response
69
+
70
+ result = patched_vault_client.read_user_service_api_key(
71
+ user_id="test-user",
72
+ service_name="test-service"
73
+ )
74
+
75
+ assert result == "test-api-key"
76
+ patched_vault_client.client.secrets.kv.v2.read_secret_version.assert_called_once_with(
77
+ "path/dev/test-user/test-service",
78
+ mount_point='secret',
79
+ raise_on_deleted_version=True
80
+ )
81
+
82
+
83
+ def test_read_user_service_api_key_secret_not_found(patched_vault_client):
84
+ """Test read_user_service_api_key when the secret path does not exist."""
85
+ patched_vault_client.client.secrets.kv.v2.read_secret_version.side_effect = InvalidPath
86
+
87
+ result = patched_vault_client.read_user_service_api_key(
88
+ user_id="test-user",
89
+ service_name="test-service"
90
+ )
91
+
92
+ assert result is None
93
+ patched_vault_client.client.secrets.kv.v2.read_secret_version.assert_called_once_with(
94
+ "path/dev/test-user/test-service",
95
+ mount_point="secret",
96
+ raise_on_deleted_version=True
97
+ )
98
+
99
+
100
+ def test_read_user_service_api_key_unexpected_error(patched_vault_client):
101
+ """Test read_user_service_api_key when an unexpected exception occurs."""
102
+ patched_vault_client.client.secrets.kv.v2.read_secret_version.side_effect = Exception("Unexpected error")
103
+
104
+ with pytest.raises(VaultAuthError, match="Unexpected error"):
105
+ patched_vault_client.read_user_service_api_key(
106
+ user_id="test-user",
107
+ service_name="test-service"
108
+ )
109
+
110
+ patched_vault_client.client.secrets.kv.v2.read_secret_version.assert_called_once_with(
111
+ "path/dev/test-user/test-service",
112
+ mount_point="secret",
113
+ raise_on_deleted_version=True
114
+ )
@@ -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
- ```