| Crates.io | miyabi-a2a |
| lib.rs | miyabi-a2a |
| version | 0.1.2 |
| created_at | 2025-11-22 06:57:31.4812+00 |
| updated_at | 2025-11-22 06:57:31.4812+00 |
| description | Agent-to-Agent (A2A) task storage and communication for Miyabi |
| homepage | |
| repository | https://github.com/ShunsukeHayashi/Miyabi |
| max_upload_size | |
| id | 1944962 |
| size | 1,160,467 |
Agent-to-Agent (A2A) task storage and communication for Miyabi.
miyabi-a2a provides task storage and coordination infrastructure for multi-agent collaboration in the Miyabi framework. Tasks are persisted as GitHub Issues, providing natural visualization and workflow integration.
Add to your Cargo.toml:
[dependencies]
miyabi-a2a = { version = "0.1.0", path = "../miyabi-a2a" }
use miyabi_a2a::{GitHubTaskStorage, TaskStorage, A2ATask, TaskStatus, TaskType};
use chrono::Utc;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Create storage backend
let storage = GitHubTaskStorage::new(
std::env::var("GITHUB_TOKEN")?,
"owner".to_string(),
"repo".to_string(),
)?;
// Create a new task
let task = A2ATask {
id: 0, // Will be assigned by storage
title: "Implement feature X".to_string(),
description: "Detailed implementation plan...".to_string(),
status: TaskStatus::Pending,
task_type: TaskType::CodeGeneration,
agent: Some("CodeGenAgent".to_string()),
context_id: Some("project-123".to_string()),
priority: 3,
created_at: Utc::now(),
updated_at: Utc::now(),
issue_url: String::new(),
};
// Save task (creates GitHub Issue)
let task_id = storage.save_task(task).await?;
println!("Created task #{}", task_id);
// Retrieve task
if let Some(task) = storage.get_task(task_id).await? {
println!("Task: {} - Status: {:?}", task.title, task.status);
}
Ok(())
}
A2ATaskRepresents a task that can be exchanged between agents.
pub struct A2ATask {
pub id: u64, // GitHub Issue number
pub title: String,
pub description: String,
pub status: TaskStatus,
pub task_type: TaskType,
pub agent: Option<String>,
pub context_id: Option<String>,
pub priority: u8, // 0-5, higher = more urgent
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
pub issue_url: String,
}
TaskStatusTask lifecycle states:
Pending: Task created, awaiting processingInProgress: Task currently being worked onCompleted: Task successfully completedFailed: Task failed with errorsBlocked: Task blocked by dependenciesTaskTypeTask classification:
CodeGeneration: Code generation taskCodeReview: Code review taskTesting: Testing taskDeployment: Deployment taskDocumentation: Documentation taskAnalysis: Analysis tasksave_task(task: A2ATask) -> Result<u64>Create a new task. Returns the assigned task ID (GitHub Issue number).
let task_id = storage.save_task(task).await?;
get_task(id: u64) -> Result<Option<A2ATask>>Retrieve a task by ID. Returns None if not found.
if let Some(task) = storage.get_task(42).await? {
println!("Found task: {}", task.title);
}
list_tasks(filter: TaskFilter) -> Result<Vec<A2ATask>>List tasks with optional filters.
use miyabi_a2a::TaskFilter;
let filter = TaskFilter {
status: Some(TaskStatus::InProgress),
context_id: Some("project-123".to_string()),
limit: Some(10),
..Default::default()
};
let tasks = storage.list_tasks(filter).await?;
list_tasks_paginated(filter: TaskFilter) -> Result<PaginatedResult<A2ATask>>List tasks with cursor-based pagination for efficient navigation through large task lists.
Pagination Features:
has_more flag for detecting last pageuse miyabi_a2a::TaskFilter;
// First page (50 items by default)
let filter = TaskFilter {
status: Some(TaskStatus::Pending),
limit: Some(50),
..Default::default()
};
let page1 = storage.list_tasks_paginated(filter).await?;
println!("Page 1: {} items, has_more: {}", page1.items.len(), page1.has_more);
// Navigate to next page
if let Some(cursor) = page1.next_cursor {
let filter = TaskFilter {
cursor: Some(cursor),
limit: Some(50),
..Default::default()
};
let page2 = storage.list_tasks_paginated(filter).await?;
println!("Page 2: {} items", page2.items.len());
// Navigate back to previous page
if let Some(cursor) = page2.previous_cursor {
let filter = TaskFilter {
cursor: Some(cursor),
..Default::default()
};
let page1_again = storage.list_tasks_paginated(filter).await?;
}
}
Cursor Format: Opaque Base64-encoded JSON containing {last_id, last_updated, direction}. Cursors are stable across requests.
Performance: Same as list_tasks() - uses API-level filtering for status, in-memory for other criteria.
update_task(id: u64, update: TaskUpdate) -> Result<()>Update an existing task.
use miyabi_a2a::TaskUpdate;
let update = TaskUpdate {
status: Some(TaskStatus::Completed),
description: Some("Updated description".to_string()),
..Default::default()
};
storage.update_task(42, update).await?;
delete_task(id: u64) -> Result<()>Delete a task (closes GitHub Issue).
storage.delete_task(42).await?;
Tasks use GitHub labels for status and type tracking:
Status Labels:
a2a:pendinga2a:in-progressa2a:completeda2a:faileda2a:blockedType Labels:
a2a:codegena2a:reviewa2a:testinga2a:deploymenta2a:documentationa2a:analysisThe GitHub token requires the following scopes:
repo (full repository access)Set via environment variable:
export GITHUB_TOKEN=ghp_your_token_here
# Run unit tests
cargo test --package miyabi-a2a
# Run with GitHub integration (requires GITHUB_TOKEN)
GITHUB_TOKEN=ghp_xxx cargo test --package miyabi-a2a -- --ignored
Hybrid Filtering: API-level + In-memory filtering for optimal performance.
// Status filtering: API-level (GitHub labels)
let filter = TaskFilter {
status: Some(TaskStatus::Pending),
limit: Some(30),
..Default::default()
};
let tasks = storage.list_tasks(filter).await?;
Status Filtering: Uses GitHub API label queries
// GitHub API request
GET /repos/:owner/:repo/issues?labels=a2a:pending&per_page=30
Performance:
Other Filters: context_id, agent, last_updated_after
Before (MVP):
100 Issues fetch → 100 transfers → In-memory filter → 10 matches
Network: 100 Issues | Time: ~200ms
After (Optimized):
Label filter → 10 Issues fetch → 10 transfers → In-memory filter → 10 matches
Network: 10 Issues | Time: ~50ms
Improvement:
Cursor-based Pagination (Issue #279):
GraphQL API (Future):
See the examples directory for complete usage examples:
┌─────────────────────────────────────────┐
│ TaskStorage Trait │
│ (Abstract storage interface) │
└────────────────┬────────────────────────┘
│
│ implements
▼
┌─────────────────────────────────────────┐
│ GitHubTaskStorage │
│ (GitHub Issues backend) │
└────────────────┬────────────────────────┘
│
│ uses
▼
┌─────────────────────────────────────────┐
│ octocrab │
│ (GitHub API client) │
└─────────────────────────────────────────┘
Apache-2.0