a2a-rs 0.4.0

Rust implementation of the Agent-to-Agent (A2A) Protocol
Documentation
# SQLx Storage Implementation

The a2a-rs library now includes a persistent storage alternative to the in-memory storage using SQLx, supporting SQLite, PostgreSQL, and MySQL databases.

## Features

- **Persistent task storage** - Tasks survive application restarts
- **Multi-process support** - Multiple processes can share the same database
- **ACID transactions** - Ensures data consistency
- **Automatic migrations** - Database schema is set up automatically
- **Database flexibility** - Supports SQLite, PostgreSQL, and MySQL
- **Push notification persistence** - Notification configurations are stored in the database

## Setup

### Dependencies

Add the SQLx storage feature to your `Cargo.toml`:

```toml
[dependencies]
a2a-rs = { version = "0.1", features = ["sqlite"] }  # For SQLite
# or
a2a-rs = { version = "0.1", features = ["postgres"] }  # For PostgreSQL  
# or
a2a-rs = { version = "0.1", features = ["mysql"] }     # For MySQL
```

### Database Configuration

Use the `DatabaseConfig` builder to configure your database connection:

```rust
use a2a_rs::adapter::storage::{DatabaseConfig, SqlxTaskStorage};

// SQLite in-memory (for testing)
let config = DatabaseConfig::default();

// SQLite file
let config = DatabaseConfig::builder()
    .url("sqlite:tasks.db".to_string())
    .max_connections(5)
    .build();

// PostgreSQL
let config = DatabaseConfig::builder()
    .url("postgres://user:password@localhost/myapp".to_string())
    .max_connections(20)
    .timeout_seconds(10)
    .build();

// From environment variables
let config = DatabaseConfig::from_env()?;
```

### Environment Variables

Set these environment variables for automatic configuration:

- `DATABASE_URL` - Required, the database connection URL
- `DATABASE_MAX_CONNECTIONS` - Optional, defaults to 10
- `DATABASE_TIMEOUT_SECONDS` - Optional, defaults to 30
- `DATABASE_ENABLE_LOGGING` - Optional, defaults to false

## Usage

### Basic Usage

```rust
use a2a_rs::adapter::storage::SqlxTaskStorage;
use a2a_rs::port::AsyncTaskManager;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create storage instance
    let storage = SqlxTaskStorage::new("sqlite::memory:").await?;
    
    // Create a task
    let task = storage.create_task("my-task-1", "my-context").await?;
    
    // Update task status
    storage.update_task_status("my-task-1", TaskState::Working).await?;
    
    // Retrieve task with history
    let task_with_history = storage.get_task("my-task-1", Some(10)).await?;
    
    Ok(())
}
```

### Replacing InMemoryTaskStorage

The SQLx storage implements the same traits as the in-memory storage, making it a drop-in replacement:

```rust
// Before (in-memory)
let storage = InMemoryTaskStorage::new();

// After (persistent)
let storage = SqlxTaskStorage::new("sqlite:tasks.db").await?;
```

## Database Schema

The SQLx storage automatically creates the following tables:

### `tasks` table
- `id` (TEXT, PRIMARY KEY) - Task identifier
- `context_id` (TEXT) - Task context
- `status_state` (TEXT) - Current task state
- `status_message` (TEXT) - Optional status message
- `created_at` (TIMESTAMP) - Creation timestamp
- `updated_at` (TIMESTAMP) - Last update timestamp
- `metadata` (JSON) - Task metadata
- `artifacts` (JSON) - Task artifacts

### `task_history` table
- `id` (INTEGER, PRIMARY KEY) - History entry ID
- `task_id` (TEXT) - References tasks.id
- `timestamp` (TIMESTAMP) - History entry timestamp
- `status_state` (TEXT) - Task state at this point
- `message` (JSON) - Message associated with this history entry

### `push_notification_configs` table
- `task_id` (TEXT, PRIMARY KEY) - References tasks.id
- `webhook_url` (TEXT) - Push notification webhook URL
- `created_at` (TIMESTAMP) - Configuration creation timestamp

## Examples

### Run the SQLx Storage Demo

```bash
# SQLite in-memory
cargo run --example sqlx_storage_demo --features sqlite

# SQLite file
DATABASE_URL=sqlite:tasks.db cargo run --example sqlx_storage_demo --features sqlite

# PostgreSQL (requires running PostgreSQL server)
DATABASE_URL=postgres://user:password@localhost/a2a_test cargo run --example sqlx_storage_demo --features postgres
```

### Compare Storage Implementations

```bash
cargo run --example storage_comparison --features sqlite
```

## Performance Characteristics

Based on benchmarks:

- **InMemory Storage**: ~0.6ms for 100 operations
- **SQLx Storage**: ~480ms for 100 operations (800x slower)

The SQLx storage is optimized for data persistence and consistency rather than raw performance. For high-throughput scenarios where persistence isn't required, consider using the in-memory storage.

## Production Considerations

1. **Connection Pooling**: Configure appropriate `max_connections` based on your workload
2. **Database Maintenance**: Regular vacuuming/optimization for SQLite, standard maintenance for PostgreSQL/MySQL
3. **Monitoring**: Enable query logging during development with `enable_logging: true`
4. **Backup Strategy**: Implement regular database backups for production deployments
5. **Migration Strategy**: The current implementation runs migrations on startup - consider external migration tools for production

## Limitations

1. **Single Database Type**: Currently optimized for SQLite, PostgreSQL and MySQL support is experimental
2. **Schema Evolution**: No migration strategy for schema changes beyond the initial setup
3. **History Loading**: Full history reconstruction from database is not fully implemented
4. **Concurrent Access**: While ACID-compliant, high-concurrency scenarios may need additional optimization

## Testing

Run the SQLx storage tests:

```bash
cargo test --test sqlx_storage_test --features sqlite
```

The tests cover:
- Task lifecycle operations
- Concurrent access patterns
- Push notification persistence
- Database migrations
- Error handling scenarios