- Delete .aitbc.yaml.example CLI configuration template - Delete .lycheeignore link checker exclusion rules - Delete .nvmrc Node.js version specification - Add advanced search panel with filters for address, amount range, transaction type, time range, and validator - Add analytics dashboard with transaction volume, active addresses, and block time metrics - Add Chart.js integration
628 lines
22 KiB
Python
628 lines
22 KiB
Python
"""Agent commands for AITBC CLI - Advanced AI Agent Management"""
|
|
|
|
import click
|
|
import httpx
|
|
import json
|
|
import time
|
|
import uuid
|
|
from typing import Optional, Dict, Any, List
|
|
from pathlib import Path
|
|
from ..utils import output, error, success, warning
|
|
|
|
|
|
@click.group()
|
|
def agent():
|
|
"""Advanced AI agent workflow and execution management"""
|
|
pass
|
|
|
|
|
|
@agent.command()
|
|
@click.option("--name", required=True, help="Agent workflow name")
|
|
@click.option("--description", default="", help="Agent description")
|
|
@click.option("--workflow-file", type=click.File('r'), help="Workflow definition from JSON file")
|
|
@click.option("--verification", default="basic", type=click.Choice(["basic", "full", "zero-knowledge"]),
|
|
help="Verification level for agent execution")
|
|
@click.option("--max-execution-time", default=3600, help="Maximum execution time in seconds")
|
|
@click.option("--max-cost-budget", default=0.0, help="Maximum cost budget")
|
|
@click.pass_context
|
|
def create(ctx, name: str, description: str, workflow_file, verification: str,
|
|
max_execution_time: int, max_cost_budget: float):
|
|
"""Create a new AI agent workflow"""
|
|
config = ctx.obj['config']
|
|
|
|
# Build workflow data
|
|
workflow_data = {
|
|
"name": name,
|
|
"description": description,
|
|
"verification_level": verification,
|
|
"max_execution_time": max_execution_time,
|
|
"max_cost_budget": max_cost_budget
|
|
}
|
|
|
|
if workflow_file:
|
|
try:
|
|
workflow_spec = json.load(workflow_file)
|
|
workflow_data.update(workflow_spec)
|
|
except Exception as e:
|
|
error(f"Failed to read workflow file: {e}")
|
|
return
|
|
|
|
try:
|
|
with httpx.Client() as client:
|
|
response = client.post(
|
|
f"{config.coordinator_url}/agents/workflows",
|
|
headers={"X-Api-Key": config.api_key or ""},
|
|
json=workflow_data
|
|
)
|
|
|
|
if response.status_code == 201:
|
|
workflow = response.json()
|
|
success(f"Agent workflow created: {workflow['id']}")
|
|
output(workflow, ctx.obj['output_format'])
|
|
else:
|
|
error(f"Failed to create agent workflow: {response.status_code}")
|
|
if response.text:
|
|
error(response.text)
|
|
ctx.exit(1)
|
|
except Exception as e:
|
|
error(f"Network error: {e}")
|
|
ctx.exit(1)
|
|
|
|
|
|
@agent.command()
|
|
@click.option("--type", "agent_type", help="Filter by agent type")
|
|
@click.option("--status", help="Filter by status")
|
|
@click.option("--verification", help="Filter by verification level")
|
|
@click.option("--limit", default=20, help="Number of agents to list")
|
|
@click.option("--owner", help="Filter by owner ID")
|
|
@click.pass_context
|
|
def list(ctx, agent_type: Optional[str], status: Optional[str],
|
|
verification: Optional[str], limit: int, owner: Optional[str]):
|
|
"""List available AI agent workflows"""
|
|
config = ctx.obj['config']
|
|
|
|
params = {"limit": limit}
|
|
if agent_type:
|
|
params["type"] = agent_type
|
|
if status:
|
|
params["status"] = status
|
|
if verification:
|
|
params["verification"] = verification
|
|
if owner:
|
|
params["owner"] = owner
|
|
|
|
try:
|
|
with httpx.Client() as client:
|
|
response = client.get(
|
|
f"{config.coordinator_url}/agents/workflows",
|
|
headers={"X-Api-Key": config.api_key or ""},
|
|
params=params
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
workflows = response.json()
|
|
output(workflows, ctx.obj['output_format'])
|
|
else:
|
|
error(f"Failed to list agent workflows: {response.status_code}")
|
|
ctx.exit(1)
|
|
except Exception as e:
|
|
error(f"Network error: {e}")
|
|
ctx.exit(1)
|
|
|
|
|
|
@agent.command()
|
|
@click.argument("agent_id")
|
|
@click.option("--inputs", type=click.File('r'), help="Input data from JSON file")
|
|
@click.option("--verification", default="basic", type=click.Choice(["basic", "full", "zero-knowledge"]),
|
|
help="Verification level for this execution")
|
|
@click.option("--priority", default="normal", type=click.Choice(["low", "normal", "high"]),
|
|
help="Execution priority")
|
|
@click.option("--timeout", default=3600, help="Execution timeout in seconds")
|
|
@click.pass_context
|
|
def execute(ctx, agent_id: str, inputs, verification: str, priority: str, timeout: int):
|
|
"""Execute an AI agent workflow"""
|
|
config = ctx.obj['config']
|
|
|
|
# Prepare execution data
|
|
execution_data = {
|
|
"verification_level": verification,
|
|
"priority": priority,
|
|
"timeout_seconds": timeout
|
|
}
|
|
|
|
if inputs:
|
|
try:
|
|
input_data = json.load(inputs)
|
|
execution_data["inputs"] = input_data
|
|
except Exception as e:
|
|
error(f"Failed to read inputs file: {e}")
|
|
return
|
|
|
|
try:
|
|
with httpx.Client() as client:
|
|
response = client.post(
|
|
f"{config.coordinator_url}/agents/{agent_id}/execute",
|
|
headers={"X-Api-Key": config.api_key or ""},
|
|
json=execution_data
|
|
)
|
|
|
|
if response.status_code == 202:
|
|
execution = response.json()
|
|
success(f"Agent execution started: {execution['id']}")
|
|
output(execution, ctx.obj['output_format'])
|
|
else:
|
|
error(f"Failed to start agent execution: {response.status_code}")
|
|
if response.text:
|
|
error(response.text)
|
|
ctx.exit(1)
|
|
except Exception as e:
|
|
error(f"Network error: {e}")
|
|
ctx.exit(1)
|
|
|
|
|
|
@agent.command()
|
|
@click.argument("execution_id")
|
|
@click.option("--watch", is_flag=True, help="Watch execution status in real-time")
|
|
@click.option("--interval", default=5, help="Watch interval in seconds")
|
|
@click.pass_context
|
|
def status(ctx, execution_id: str, watch: bool, interval: int):
|
|
"""Get status of agent execution"""
|
|
config = ctx.obj['config']
|
|
|
|
def get_status():
|
|
try:
|
|
with httpx.Client() as client:
|
|
response = client.get(
|
|
f"{config.coordinator_url}/agents/executions/{execution_id}",
|
|
headers={"X-Api-Key": config.api_key or ""}
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
return response.json()
|
|
else:
|
|
error(f"Failed to get execution status: {response.status_code}")
|
|
return None
|
|
except Exception as e:
|
|
error(f"Network error: {e}")
|
|
return None
|
|
|
|
if watch:
|
|
click.echo(f"Watching execution {execution_id} (Ctrl+C to stop)...")
|
|
while True:
|
|
status_data = get_status()
|
|
if status_data:
|
|
click.clear()
|
|
click.echo(f"Execution Status: {status_data.get('status', 'Unknown')}")
|
|
click.echo(f"Progress: {status_data.get('progress', 0)}%")
|
|
click.echo(f"Current Step: {status_data.get('current_step', 'N/A')}")
|
|
click.echo(f"Cost: ${status_data.get('total_cost', 0.0):.4f}")
|
|
|
|
if status_data.get('status') in ['completed', 'failed']:
|
|
break
|
|
|
|
time.sleep(interval)
|
|
else:
|
|
status_data = get_status()
|
|
if status_data:
|
|
output(status_data, ctx.obj['output_format'])
|
|
|
|
|
|
@agent.command()
|
|
@click.argument("execution_id")
|
|
@click.option("--verify", is_flag=True, help="Verify cryptographic receipt")
|
|
@click.option("--download", type=click.Path(), help="Download receipt to file")
|
|
@click.pass_context
|
|
def receipt(ctx, execution_id: str, verify: bool, download: Optional[str]):
|
|
"""Get verifiable receipt for completed execution"""
|
|
config = ctx.obj['config']
|
|
|
|
try:
|
|
with httpx.Client() as client:
|
|
response = client.get(
|
|
f"{config.coordinator_url}/agents/executions/{execution_id}/receipt",
|
|
headers={"X-Api-Key": config.api_key or ""}
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
receipt_data = response.json()
|
|
|
|
if verify:
|
|
# Verify receipt
|
|
verify_response = client.post(
|
|
f"{config.coordinator_url}/agents/receipts/verify",
|
|
headers={"X-Api-Key": config.api_key or ""},
|
|
json={"receipt": receipt_data}
|
|
)
|
|
|
|
if verify_response.status_code == 200:
|
|
verification_result = verify_response.json()
|
|
receipt_data["verification"] = verification_result
|
|
|
|
if verification_result.get("valid"):
|
|
success("Receipt verification: PASSED")
|
|
else:
|
|
warning("Receipt verification: FAILED")
|
|
else:
|
|
warning("Could not verify receipt")
|
|
|
|
if download:
|
|
with open(download, 'w') as f:
|
|
json.dump(receipt_data, f, indent=2)
|
|
success(f"Receipt downloaded to {download}")
|
|
else:
|
|
output(receipt_data, ctx.obj['output_format'])
|
|
else:
|
|
error(f"Failed to get execution receipt: {response.status_code}")
|
|
ctx.exit(1)
|
|
except Exception as e:
|
|
error(f"Network error: {e}")
|
|
ctx.exit(1)
|
|
|
|
|
|
@click.group()
|
|
def network():
|
|
"""Multi-agent collaborative network management"""
|
|
pass
|
|
|
|
|
|
agent.add_command(network)
|
|
|
|
|
|
@network.command()
|
|
@click.option("--name", required=True, help="Network name")
|
|
@click.option("--agents", required=True, help="Comma-separated list of agent IDs")
|
|
@click.option("--description", default="", help="Network description")
|
|
@click.option("--coordination", default="centralized",
|
|
type=click.Choice(["centralized", "decentralized", "hybrid"]),
|
|
help="Coordination strategy")
|
|
@click.pass_context
|
|
def create(ctx, name: str, agents: str, description: str, coordination: str):
|
|
"""Create collaborative agent network"""
|
|
config = ctx.obj['config']
|
|
|
|
agent_ids = [agent_id.strip() for agent_id in agents.split(',')]
|
|
|
|
network_data = {
|
|
"name": name,
|
|
"description": description,
|
|
"agents": agent_ids,
|
|
"coordination_strategy": coordination
|
|
}
|
|
|
|
try:
|
|
with httpx.Client() as client:
|
|
response = client.post(
|
|
f"{config.coordinator_url}/agents/networks",
|
|
headers={"X-Api-Key": config.api_key or ""},
|
|
json=network_data
|
|
)
|
|
|
|
if response.status_code == 201:
|
|
network = response.json()
|
|
success(f"Agent network created: {network['id']}")
|
|
output(network, ctx.obj['output_format'])
|
|
else:
|
|
error(f"Failed to create agent network: {response.status_code}")
|
|
if response.text:
|
|
error(response.text)
|
|
ctx.exit(1)
|
|
except Exception as e:
|
|
error(f"Network error: {e}")
|
|
ctx.exit(1)
|
|
|
|
|
|
@network.command()
|
|
@click.argument("network_id")
|
|
@click.option("--task", type=click.File('r'), required=True, help="Task definition JSON file")
|
|
@click.option("--priority", default="normal", type=click.Choice(["low", "normal", "high"]),
|
|
help="Execution priority")
|
|
@click.pass_context
|
|
def execute(ctx, network_id: str, task, priority: str):
|
|
"""Execute collaborative task on agent network"""
|
|
config = ctx.obj['config']
|
|
|
|
try:
|
|
task_data = json.load(task)
|
|
except Exception as e:
|
|
error(f"Failed to read task file: {e}")
|
|
return
|
|
|
|
execution_data = {
|
|
"task": task_data,
|
|
"priority": priority
|
|
}
|
|
|
|
try:
|
|
with httpx.Client() as client:
|
|
response = client.post(
|
|
f"{config.coordinator_url}/agents/networks/{network_id}/execute",
|
|
headers={"X-Api-Key": config.api_key or ""},
|
|
json=execution_data
|
|
)
|
|
|
|
if response.status_code == 202:
|
|
execution = response.json()
|
|
success(f"Network execution started: {execution['id']}")
|
|
output(execution, ctx.obj['output_format'])
|
|
else:
|
|
error(f"Failed to start network execution: {response.status_code}")
|
|
if response.text:
|
|
error(response.text)
|
|
ctx.exit(1)
|
|
except Exception as e:
|
|
error(f"Network error: {e}")
|
|
ctx.exit(1)
|
|
|
|
|
|
@network.command()
|
|
@click.argument("network_id")
|
|
@click.option("--metrics", default="all", help="Comma-separated metrics to show")
|
|
@click.option("--real-time", is_flag=True, help="Show real-time metrics")
|
|
@click.pass_context
|
|
def status(ctx, network_id: str, metrics: str, real_time: bool):
|
|
"""Get agent network status and performance metrics"""
|
|
config = ctx.obj['config']
|
|
|
|
params = {}
|
|
if metrics != "all":
|
|
params["metrics"] = metrics
|
|
|
|
try:
|
|
with httpx.Client() as client:
|
|
response = client.get(
|
|
f"{config.coordinator_url}/agents/networks/{network_id}/status",
|
|
headers={"X-Api-Key": config.api_key or ""},
|
|
params=params
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
status_data = response.json()
|
|
output(status_data, ctx.obj['output_format'])
|
|
else:
|
|
error(f"Failed to get network status: {response.status_code}")
|
|
ctx.exit(1)
|
|
except Exception as e:
|
|
error(f"Network error: {e}")
|
|
ctx.exit(1)
|
|
|
|
|
|
@network.command()
|
|
@click.argument("network_id")
|
|
@click.option("--objective", default="efficiency",
|
|
type=click.Choice(["speed", "efficiency", "cost", "quality"]),
|
|
help="Optimization objective")
|
|
@click.pass_context
|
|
def optimize(ctx, network_id: str, objective: str):
|
|
"""Optimize agent network collaboration"""
|
|
config = ctx.obj['config']
|
|
|
|
optimization_data = {"objective": objective}
|
|
|
|
try:
|
|
with httpx.Client() as client:
|
|
response = client.post(
|
|
f"{config.coordinator_url}/agents/networks/{network_id}/optimize",
|
|
headers={"X-Api-Key": config.api_key or ""},
|
|
json=optimization_data
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
result = response.json()
|
|
success(f"Network optimization completed")
|
|
output(result, ctx.obj['output_format'])
|
|
else:
|
|
error(f"Failed to optimize network: {response.status_code}")
|
|
if response.text:
|
|
error(response.text)
|
|
ctx.exit(1)
|
|
except Exception as e:
|
|
error(f"Network error: {e}")
|
|
ctx.exit(1)
|
|
|
|
|
|
@click.group()
|
|
def learning():
|
|
"""Agent adaptive learning and training management"""
|
|
pass
|
|
|
|
|
|
agent.add_command(learning)
|
|
|
|
|
|
@learning.command()
|
|
@click.argument("agent_id")
|
|
@click.option("--mode", default="reinforcement",
|
|
type=click.Choice(["reinforcement", "transfer", "meta"]),
|
|
help="Learning mode")
|
|
@click.option("--feedback-source", help="Feedback data source")
|
|
@click.option("--learning-rate", default=0.001, help="Learning rate")
|
|
@click.pass_context
|
|
def enable(ctx, agent_id: str, mode: str, feedback_source: Optional[str], learning_rate: float):
|
|
"""Enable adaptive learning for agent"""
|
|
config = ctx.obj['config']
|
|
|
|
learning_config = {
|
|
"mode": mode,
|
|
"learning_rate": learning_rate
|
|
}
|
|
|
|
if feedback_source:
|
|
learning_config["feedback_source"] = feedback_source
|
|
|
|
try:
|
|
with httpx.Client() as client:
|
|
response = client.post(
|
|
f"{config.coordinator_url}/agents/{agent_id}/learning/enable",
|
|
headers={"X-Api-Key": config.api_key or ""},
|
|
json=learning_config
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
result = response.json()
|
|
success(f"Adaptive learning enabled for agent {agent_id}")
|
|
output(result, ctx.obj['output_format'])
|
|
else:
|
|
error(f"Failed to enable learning: {response.status_code}")
|
|
if response.text:
|
|
error(response.text)
|
|
ctx.exit(1)
|
|
except Exception as e:
|
|
error(f"Network error: {e}")
|
|
ctx.exit(1)
|
|
|
|
|
|
@learning.command()
|
|
@click.argument("agent_id")
|
|
@click.option("--feedback", type=click.File('r'), required=True, help="Feedback data JSON file")
|
|
@click.option("--epochs", default=10, help="Number of training epochs")
|
|
@click.pass_context
|
|
def train(ctx, agent_id: str, feedback, epochs: int):
|
|
"""Train agent with feedback data"""
|
|
config = ctx.obj['config']
|
|
|
|
try:
|
|
feedback_data = json.load(feedback)
|
|
except Exception as e:
|
|
error(f"Failed to read feedback file: {e}")
|
|
return
|
|
|
|
training_data = {
|
|
"feedback": feedback_data,
|
|
"epochs": epochs
|
|
}
|
|
|
|
try:
|
|
with httpx.Client() as client:
|
|
response = client.post(
|
|
f"{config.coordinator_url}/agents/{agent_id}/learning/train",
|
|
headers={"X-Api-Key": config.api_key or ""},
|
|
json=training_data
|
|
)
|
|
|
|
if response.status_code == 202:
|
|
training = response.json()
|
|
success(f"Training started: {training['id']}")
|
|
output(training, ctx.obj['output_format'])
|
|
else:
|
|
error(f"Failed to start training: {response.status_code}")
|
|
if response.text:
|
|
error(response.text)
|
|
ctx.exit(1)
|
|
except Exception as e:
|
|
error(f"Network error: {e}")
|
|
ctx.exit(1)
|
|
|
|
|
|
@learning.command()
|
|
@click.argument("agent_id")
|
|
@click.option("--metrics", default="accuracy,efficiency", help="Comma-separated metrics to show")
|
|
@click.pass_context
|
|
def progress(ctx, agent_id: str, metrics: str):
|
|
"""Review agent learning progress"""
|
|
config = ctx.obj['config']
|
|
|
|
params = {"metrics": metrics}
|
|
|
|
try:
|
|
with httpx.Client() as client:
|
|
response = client.get(
|
|
f"{config.coordinator_url}/agents/{agent_id}/learning/progress",
|
|
headers={"X-Api-Key": config.api_key or ""},
|
|
params=params
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
progress_data = response.json()
|
|
output(progress_data, ctx.obj['output_format'])
|
|
else:
|
|
error(f"Failed to get learning progress: {response.status_code}")
|
|
ctx.exit(1)
|
|
except Exception as e:
|
|
error(f"Network error: {e}")
|
|
ctx.exit(1)
|
|
|
|
|
|
@learning.command()
|
|
@click.argument("agent_id")
|
|
@click.option("--format", default="onnx", type=click.Choice(["onnx", "pickle", "torch"]),
|
|
help="Export format")
|
|
@click.option("--output", type=click.Path(), help="Output file path")
|
|
@click.pass_context
|
|
def export(ctx, agent_id: str, format: str, output: Optional[str]):
|
|
"""Export learned agent model"""
|
|
config = ctx.obj['config']
|
|
|
|
params = {"format": format}
|
|
|
|
try:
|
|
with httpx.Client() as client:
|
|
response = client.get(
|
|
f"{config.coordinator_url}/agents/{agent_id}/learning/export",
|
|
headers={"X-Api-Key": config.api_key or ""},
|
|
params=params
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
if output:
|
|
with open(output, 'wb') as f:
|
|
f.write(response.content)
|
|
success(f"Model exported to {output}")
|
|
else:
|
|
# Output metadata about the export
|
|
export_info = response.headers.get('X-Export-Info', '{}')
|
|
try:
|
|
info_data = json.loads(export_info)
|
|
output(info_data, ctx.obj['output_format'])
|
|
except:
|
|
output({"status": "export_ready", "format": format}, ctx.obj['output_format'])
|
|
else:
|
|
error(f"Failed to export model: {response.status_code}")
|
|
ctx.exit(1)
|
|
except Exception as e:
|
|
error(f"Network error: {e}")
|
|
ctx.exit(1)
|
|
|
|
|
|
@click.command()
|
|
@click.option("--type", required=True,
|
|
type=click.Choice(["optimization", "feature", "bugfix", "documentation"]),
|
|
help="Contribution type")
|
|
@click.option("--description", required=True, help="Contribution description")
|
|
@click.option("--github-repo", default="oib/AITBC", help="GitHub repository")
|
|
@click.option("--branch", default="main", help="Target branch")
|
|
@click.pass_context
|
|
def submit_contribution(ctx, type: str, description: str, github_repo: str, branch: str):
|
|
"""Submit contribution to platform via GitHub"""
|
|
config = ctx.obj['config']
|
|
|
|
contribution_data = {
|
|
"type": type,
|
|
"description": description,
|
|
"github_repo": github_repo,
|
|
"target_branch": branch
|
|
}
|
|
|
|
try:
|
|
with httpx.Client() as client:
|
|
response = client.post(
|
|
f"{config.coordinator_url}/agents/contributions",
|
|
headers={"X-Api-Key": config.api_key or ""},
|
|
json=contribution_data
|
|
)
|
|
|
|
if response.status_code == 201:
|
|
result = response.json()
|
|
success(f"Contribution submitted: {result['id']}")
|
|
output(result, ctx.obj['output_format'])
|
|
else:
|
|
error(f"Failed to submit contribution: {response.status_code}")
|
|
if response.text:
|
|
error(response.text)
|
|
ctx.exit(1)
|
|
except Exception as e:
|
|
error(f"Network error: {e}")
|
|
ctx.exit(1)
|
|
|
|
|
|
agent.add_command(submit_contribution)
|