Initial commit
This commit is contained in:
325
agents/meta.agent/README.md
Normal file
325
agents/meta.agent/README.md
Normal file
@@ -0,0 +1,325 @@
|
||||
# meta.agent - Agent Creator
|
||||
|
||||
The meta-agent that creates other agents through skill composition.
|
||||
|
||||
## Overview
|
||||
|
||||
**meta.agent** transforms natural language descriptions into complete, functional agents with proper skill composition, artifact metadata, and documentation.
|
||||
|
||||
**What it produces:**
|
||||
- Complete `agent.yaml` with recommended skills
|
||||
- Auto-generated `README.md` documentation
|
||||
- Proper artifact metadata (produces/consumes)
|
||||
- Inferred permissions from skills
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Create an Agent Description
|
||||
|
||||
Create a Markdown file describing your agent:
|
||||
|
||||
```markdown
|
||||
# Name: api.architect
|
||||
|
||||
# Purpose:
|
||||
An agent that designs comprehensive REST APIs and validates them
|
||||
against best practices.
|
||||
|
||||
# Inputs:
|
||||
- API requirements
|
||||
|
||||
# Outputs:
|
||||
- openapi-spec
|
||||
- validation-report
|
||||
- api-models
|
||||
|
||||
# Examples:
|
||||
- Design a RESTful API for an e-commerce platform
|
||||
- Create an API for a task management system
|
||||
```
|
||||
|
||||
### 2. Run meta.agent
|
||||
|
||||
```bash
|
||||
python3 agents/meta.agent/meta_agent.py examples/api_architect_description.md
|
||||
```
|
||||
|
||||
### 3. Output
|
||||
|
||||
```
|
||||
✨ Agent 'api.architect' created successfully!
|
||||
|
||||
📄 Agent definition: agents/api.architect/agent.yaml
|
||||
📖 Documentation: agents/api.architect/README.md
|
||||
|
||||
🔧 Skills: api.define, api.validate, workflow.validate
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Creation
|
||||
|
||||
```bash
|
||||
# Create agent from Markdown description
|
||||
python3 agents/meta.agent/meta_agent.py path/to/agent_description.md
|
||||
|
||||
# Create agent from JSON description
|
||||
python3 agents/meta.agent/meta_agent.py path/to/agent_description.json
|
||||
|
||||
# Specify output directory
|
||||
python3 agents/meta.agent/meta_agent.py description.md -o agents/my-agent
|
||||
|
||||
# Skip validation
|
||||
python3 agents/meta.agent/meta_agent.py description.md --no-validate
|
||||
```
|
||||
|
||||
### Description Format
|
||||
|
||||
**Markdown Format:**
|
||||
|
||||
```markdown
|
||||
# Name: agent-name
|
||||
|
||||
# Purpose:
|
||||
Detailed description of what the agent does...
|
||||
|
||||
# Inputs:
|
||||
- artifact-type-1
|
||||
- artifact-type-2
|
||||
|
||||
# Outputs:
|
||||
- artifact-type-3
|
||||
- artifact-type-4
|
||||
|
||||
# Constraints:
|
||||
(Optional) Any constraints or requirements...
|
||||
|
||||
# Examples:
|
||||
- Example use case 1
|
||||
- Example use case 2
|
||||
```
|
||||
|
||||
**JSON Format:**
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "agent-name",
|
||||
"purpose": "Detailed description...",
|
||||
"inputs": ["artifact-type-1", "artifact-type-2"],
|
||||
"outputs": ["artifact-type-3", "artifact-type-4"],
|
||||
"examples": ["Example 1", "Example 2"]
|
||||
}
|
||||
```
|
||||
|
||||
## What meta.agent Creates
|
||||
|
||||
### 1. agent.yaml
|
||||
|
||||
Complete agent definition with:
|
||||
- **Recommended skills** - Uses `agent.compose` to find compatible skills
|
||||
- **Artifact metadata** - Proper produces/consumes declarations
|
||||
- **Permissions** - Inferred from selected skills
|
||||
- **Description** - Professional formatting
|
||||
|
||||
Example output:
|
||||
```yaml
|
||||
name: api.architect
|
||||
description: Designs and validates REST APIs against best practices
|
||||
skills_available:
|
||||
- api.define
|
||||
- api.validate
|
||||
permissions:
|
||||
- filesystem:read
|
||||
- filesystem:write
|
||||
artifact_metadata:
|
||||
consumes:
|
||||
- type: api-requirements
|
||||
produces:
|
||||
- type: openapi-spec
|
||||
schema: schemas/openapi-spec.json
|
||||
- type: validation-report
|
||||
schema: schemas/validation-report.json
|
||||
```
|
||||
|
||||
### 2. README.md
|
||||
|
||||
Auto-generated documentation with:
|
||||
- Agent purpose and capabilities
|
||||
- Skills used with rationale
|
||||
- Artifact flow (inputs/outputs)
|
||||
- Example use cases
|
||||
- Usage instructions
|
||||
- "Created by meta.agent" attribution
|
||||
|
||||
## How It Works
|
||||
|
||||
1. **Parse Description** - Reads Markdown or JSON
|
||||
2. **Find Skills** - Uses `agent.compose` to recommend compatible skills
|
||||
3. **Generate Metadata** - Uses `artifact.define` for artifact contracts
|
||||
4. **Infer Permissions** - Analyzes required skills
|
||||
5. **Create Files** - Generates agent.yaml and README.md
|
||||
6. **Validate** - Ensures proper structure and compatibility
|
||||
|
||||
## Integration with Other Meta-Agents
|
||||
|
||||
### With meta.compatibility
|
||||
|
||||
After creating an agent, use `meta.compatibility` to analyze it:
|
||||
|
||||
```bash
|
||||
# Create agent
|
||||
python3 agents/meta.agent/meta_agent.py description.md
|
||||
|
||||
# Analyze compatibility
|
||||
python3 agents/meta.compatibility/meta_compatibility.py analyze api.architect
|
||||
```
|
||||
|
||||
### With meta.suggest
|
||||
|
||||
Get suggestions after creating an agent:
|
||||
|
||||
```bash
|
||||
python3 agents/meta.suggest/meta_suggest.py \
|
||||
--context meta.agent \
|
||||
--artifacts agents/api.architect/agent.yaml
|
||||
```
|
||||
|
||||
## Common Workflows
|
||||
|
||||
### Workflow 1: Create and Analyze
|
||||
|
||||
```bash
|
||||
# Step 1: Create agent
|
||||
python3 agents/meta.agent/meta_agent.py examples/my_agent.md
|
||||
|
||||
# Step 2: Analyze compatibility
|
||||
python3 agents/meta.compatibility/meta_compatibility.py find-compatible my-agent
|
||||
|
||||
# Step 3: Test the agent
|
||||
# (Manual testing or agent.run)
|
||||
```
|
||||
|
||||
### Workflow 2: Create Multiple Agents
|
||||
|
||||
```bash
|
||||
# Create several agents
|
||||
for desc in examples/*_agent_description.md; do
|
||||
python3 agents/meta.agent/meta_agent.py "$desc"
|
||||
done
|
||||
|
||||
# Analyze the ecosystem
|
||||
python3 agents/meta.compatibility/meta_compatibility.py list-all
|
||||
```
|
||||
|
||||
## Artifact Types
|
||||
|
||||
### Consumes
|
||||
|
||||
- **agent-description** - Natural language agent requirements
|
||||
- Format: Markdown or JSON
|
||||
- Pattern: `**/agent_description.md`
|
||||
|
||||
### Produces
|
||||
|
||||
- **agent-definition** - Complete agent.yaml
|
||||
- Format: YAML
|
||||
- Pattern: `agents/*/agent.yaml`
|
||||
- Schema: `schemas/agent-definition.json`
|
||||
|
||||
- **agent-documentation** - Auto-generated README
|
||||
- Format: Markdown
|
||||
- Pattern: `agents/*/README.md`
|
||||
|
||||
## Tips & Best Practices
|
||||
|
||||
### Writing Good Descriptions
|
||||
|
||||
✅ **Good:**
|
||||
- Clear, specific purpose
|
||||
- Well-defined inputs and outputs
|
||||
- Concrete examples
|
||||
- Specific artifact types
|
||||
|
||||
❌ **Avoid:**
|
||||
- Vague purpose ("does stuff")
|
||||
- Generic inputs ("data")
|
||||
- No examples
|
||||
- Unclear artifact types
|
||||
|
||||
### Choosing Artifact Types
|
||||
|
||||
Use existing artifact types when possible:
|
||||
- `openapi-spec` for API specifications
|
||||
- `validation-report` for validation results
|
||||
- `workflow-definition` for workflows
|
||||
|
||||
If you need a new type, create it with `meta.artifact` first.
|
||||
|
||||
### Skill Selection
|
||||
|
||||
meta.agent uses keyword matching to find skills:
|
||||
- "api" → finds api.define, api.validate
|
||||
- "validate" → finds validation skills
|
||||
- "agent" → finds agent.compose, meta.agent
|
||||
|
||||
Be descriptive in your purpose statement to get better skill recommendations.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Agent name conflicts
|
||||
|
||||
```
|
||||
Error: Agent 'api.architect' already exists
|
||||
```
|
||||
|
||||
**Solution:** Choose a different name or remove the existing agent directory.
|
||||
|
||||
### No skills recommended
|
||||
|
||||
```
|
||||
Warning: No skills found for agent purpose
|
||||
```
|
||||
|
||||
**Solutions:**
|
||||
- Make purpose more specific
|
||||
- Mention artifact types explicitly
|
||||
- Check if relevant skills exist in registry
|
||||
|
||||
### Missing artifact types
|
||||
|
||||
```
|
||||
Warning: Artifact type 'my-artifact' not in known registry
|
||||
```
|
||||
|
||||
**Solution:** Create the artifact type with `meta.artifact` first:
|
||||
```bash
|
||||
python3 agents/meta.artifact/meta_artifact.py create artifact_description.md
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
See `examples/` directory for sample agent descriptions:
|
||||
- `api_architect_description.md` - API design and validation agent
|
||||
- (Add more as you create them)
|
||||
|
||||
## Architecture
|
||||
|
||||
meta.agent is part of the meta-agent ecosystem:
|
||||
|
||||
```
|
||||
meta.agent
|
||||
├─ Uses: agent.compose (find skills)
|
||||
├─ Uses: artifact.define (generate metadata)
|
||||
├─ Produces: agent.yaml + README.md
|
||||
└─ Works with: meta.compatibility, meta.suggest
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [META_AGENTS.md](../../docs/META_AGENTS.md) - Complete meta-agent architecture
|
||||
- [ARTIFACT_STANDARDS.md](../../docs/ARTIFACT_STANDARDS.md) - Artifact system
|
||||
- [agent-description schema](../../schemas/agent-description.json) - JSON schema
|
||||
|
||||
## Created By
|
||||
|
||||
Part of the Betty Framework meta-agent ecosystem.
|
||||
93
agents/meta.agent/agent.yaml
Normal file
93
agents/meta.agent/agent.yaml
Normal file
@@ -0,0 +1,93 @@
|
||||
name: meta.agent
|
||||
version: 0.1.0
|
||||
description: |
|
||||
Meta-agent that creates other agents by composing skills based on natural
|
||||
language descriptions. Transforms natural language descriptions into complete,
|
||||
functional agents.
|
||||
|
||||
meta.agent analyzes agent requirements, recommends compatible skills using artifact
|
||||
metadata, generates complete agent definitions, and produces documentation.
|
||||
|
||||
artifact_metadata:
|
||||
consumes:
|
||||
- type: agent-description
|
||||
file_pattern: "**/agent_description.md"
|
||||
content_type: "text/markdown"
|
||||
description: "Natural language description of agent purpose and requirements"
|
||||
|
||||
produces:
|
||||
- type: agent-definition
|
||||
file_pattern: "agents/*/agent.yaml"
|
||||
content_type: "application/yaml"
|
||||
schema: "schemas/agent-definition.json"
|
||||
description: "Complete agent configuration with skills and metadata"
|
||||
|
||||
- type: agent-documentation
|
||||
file_pattern: "agents/*/README.md"
|
||||
content_type: "text/markdown"
|
||||
description: "Human-readable agent documentation"
|
||||
|
||||
status: draft
|
||||
reasoning_mode: iterative
|
||||
capabilities:
|
||||
- Analyze agent requirements and identify compatible skills and capabilities
|
||||
- Generate complete agent manifests, documentation, and supporting assets
|
||||
- Validate registry consistency before registering new agents
|
||||
skills_available:
|
||||
- agent.compose # Find compatible skills based on requirements
|
||||
- artifact.define # Generate artifact metadata for the new agent
|
||||
- registry.update # Validate and register generated agents
|
||||
|
||||
permissions:
|
||||
- filesystem:read
|
||||
- filesystem:write
|
||||
|
||||
system_prompt: |
|
||||
You are meta.agent, the meta-agent that creates other agents by composing skills.
|
||||
|
||||
Your purpose is to transform natural language descriptions into complete, functional agents
|
||||
with proper skill composition, artifact metadata, and documentation.
|
||||
|
||||
## Your Workflow
|
||||
|
||||
1. **Parse Requirements** - Understand what the agent needs to do
|
||||
- Extract purpose, inputs, outputs, and constraints
|
||||
- Identify required artifacts and permissions
|
||||
|
||||
2. **Compose Skills** - Use agent.compose to find compatible skills
|
||||
- Analyze artifact flows (what's produced and consumed)
|
||||
- Ensure no gaps in the artifact chain
|
||||
- Consider permission requirements
|
||||
|
||||
3. **Generate Metadata** - Use artifact.define for proper artifact contracts
|
||||
- Define what artifacts the agent consumes
|
||||
- Define what artifacts the agent produces
|
||||
- Include schemas and file patterns
|
||||
|
||||
4. **Create Agent Definition** - Write agent.yaml
|
||||
- Name, description, skills_available
|
||||
- Artifact metadata (consumes/produces)
|
||||
- Permissions
|
||||
- System prompt (optional but recommended)
|
||||
|
||||
5. **Document** - Generate comprehensive README.md
|
||||
- Agent purpose and use cases
|
||||
- Required inputs and expected outputs
|
||||
- Example usage
|
||||
- Artifact flow diagram
|
||||
|
||||
6. **Validate** (optional) - Use registry.certify
|
||||
- Check agent definition is valid
|
||||
- Verify skill compatibility
|
||||
- Ensure artifact contracts are sound
|
||||
|
||||
## Principles
|
||||
|
||||
- **Artifact-First Design**: Ensure clean artifact flows with no gaps
|
||||
- **Minimal Skill Sets**: Only include skills the agent actually needs
|
||||
- **Clear Documentation**: Make the agent's purpose immediately obvious
|
||||
- **Convention Adherence**: Follow Betty Framework standards
|
||||
- **Composability**: Design agents that work well with other agents
|
||||
|
||||
When creating an agent, think like an architect: What does it consume? What does it
|
||||
produce? What skills enable that transformation? How do artifacts flow through the system?
|
||||
558
agents/meta.agent/meta_agent.py
Executable file
558
agents/meta.agent/meta_agent.py
Executable file
@@ -0,0 +1,558 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
meta.agent - Meta-agent that creates other agents
|
||||
|
||||
Transforms natural language descriptions into complete, functional agents
|
||||
by composing skills and generating proper artifact metadata.
|
||||
"""
|
||||
|
||||
import json
|
||||
import yaml
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Any, Optional
|
||||
|
||||
# Add parent directory to path for imports
|
||||
parent_dir = str(Path(__file__).parent.parent.parent)
|
||||
sys.path.insert(0, parent_dir)
|
||||
|
||||
# Import skill modules directly
|
||||
agent_compose_path = Path(parent_dir) / "skills" / "agent.compose"
|
||||
artifact_define_path = Path(parent_dir) / "skills" / "artifact.define"
|
||||
|
||||
sys.path.insert(0, str(agent_compose_path))
|
||||
sys.path.insert(0, str(artifact_define_path))
|
||||
|
||||
import agent_compose
|
||||
import artifact_define
|
||||
|
||||
# Import traceability system
|
||||
from betty.traceability import get_tracer, RequirementInfo
|
||||
|
||||
|
||||
class AgentCreator:
|
||||
"""Creates agents from natural language descriptions"""
|
||||
|
||||
def __init__(self, registry_path: str = "registry/skills.json"):
|
||||
"""Initialize with registry path"""
|
||||
self.registry_path = Path(registry_path)
|
||||
self.registry = self._load_registry()
|
||||
|
||||
def _load_registry(self) -> Dict[str, Any]:
|
||||
"""Load skills registry"""
|
||||
if not self.registry_path.exists():
|
||||
raise FileNotFoundError(f"Registry not found: {self.registry_path}")
|
||||
|
||||
with open(self.registry_path) as f:
|
||||
return json.load(f)
|
||||
|
||||
def parse_description(self, description_path: str) -> Dict[str, Any]:
|
||||
"""
|
||||
Parse agent description from Markdown or JSON file
|
||||
|
||||
Args:
|
||||
description_path: Path to agent_description.md or agent_description.json
|
||||
|
||||
Returns:
|
||||
Parsed description with name, purpose, inputs, outputs, constraints
|
||||
"""
|
||||
path = Path(description_path)
|
||||
|
||||
if not path.exists():
|
||||
raise FileNotFoundError(f"Description not found: {description_path}")
|
||||
|
||||
# Handle JSON format
|
||||
if path.suffix == ".json":
|
||||
with open(path) as f:
|
||||
return json.load(f)
|
||||
|
||||
# Handle Markdown format
|
||||
with open(path) as f:
|
||||
content = f.read()
|
||||
|
||||
# Parse Markdown sections
|
||||
description = {
|
||||
"name": "",
|
||||
"purpose": "",
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"constraints": {},
|
||||
"examples": []
|
||||
}
|
||||
|
||||
current_section = None
|
||||
for line in content.split('\n'):
|
||||
line = line.strip()
|
||||
|
||||
# Section headers
|
||||
if line.startswith('# Name:'):
|
||||
description["name"] = line.replace('# Name:', '').strip()
|
||||
elif line.startswith('# Purpose:'):
|
||||
current_section = "purpose"
|
||||
elif line.startswith('# Inputs:'):
|
||||
current_section = "inputs"
|
||||
elif line.startswith('# Outputs:'):
|
||||
current_section = "outputs"
|
||||
elif line.startswith('# Constraints:'):
|
||||
current_section = "constraints"
|
||||
elif line.startswith('# Examples:'):
|
||||
current_section = "examples"
|
||||
elif line and not line.startswith('#'):
|
||||
# Content for current section
|
||||
if current_section == "purpose":
|
||||
description["purpose"] += line + " "
|
||||
elif current_section == "inputs" and line.startswith('-'):
|
||||
# Extract artifact type (before parentheses or description)
|
||||
artifact = line[1:].strip()
|
||||
# Remove anything in parentheses and any extra description
|
||||
if '(' in artifact:
|
||||
artifact = artifact.split('(')[0].strip()
|
||||
description["inputs"].append(artifact)
|
||||
elif current_section == "outputs" and line.startswith('-'):
|
||||
# Extract artifact type (before parentheses or description)
|
||||
artifact = line[1:].strip()
|
||||
# Remove anything in parentheses and any extra description
|
||||
if '(' in artifact:
|
||||
artifact = artifact.split('(')[0].strip()
|
||||
description["outputs"].append(artifact)
|
||||
elif current_section == "examples" and line.startswith('-'):
|
||||
description["examples"].append(line[1:].strip())
|
||||
|
||||
description["purpose"] = description["purpose"].strip()
|
||||
return description
|
||||
|
||||
def find_compatible_skills(
|
||||
self,
|
||||
purpose: str,
|
||||
required_artifacts: Optional[List[str]] = None
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Find compatible skills for agent purpose
|
||||
|
||||
Args:
|
||||
purpose: Natural language description of agent purpose
|
||||
required_artifacts: List of artifact types the agent needs
|
||||
|
||||
Returns:
|
||||
Dictionary with recommended skills and rationale
|
||||
"""
|
||||
return agent_compose.find_skills_for_purpose(
|
||||
self.registry,
|
||||
purpose,
|
||||
required_artifacts
|
||||
)
|
||||
|
||||
def generate_artifact_metadata(
|
||||
self,
|
||||
inputs: List[str],
|
||||
outputs: List[str]
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Generate artifact metadata from inputs/outputs
|
||||
|
||||
Args:
|
||||
inputs: List of input artifact types
|
||||
outputs: List of output artifact types
|
||||
|
||||
Returns:
|
||||
Artifact metadata structure
|
||||
"""
|
||||
metadata = {}
|
||||
|
||||
if inputs:
|
||||
metadata["consumes"] = []
|
||||
for input_type in inputs:
|
||||
artifact_def = artifact_define.get_artifact_definition(input_type)
|
||||
if artifact_def:
|
||||
metadata["consumes"].append(artifact_def)
|
||||
else:
|
||||
# Create basic definition
|
||||
metadata["consumes"].append({
|
||||
"type": input_type,
|
||||
"description": f"Input artifact of type {input_type}"
|
||||
})
|
||||
|
||||
if outputs:
|
||||
metadata["produces"] = []
|
||||
for output_type in outputs:
|
||||
artifact_def = artifact_define.get_artifact_definition(output_type)
|
||||
if artifact_def:
|
||||
metadata["produces"].append(artifact_def)
|
||||
else:
|
||||
# Create basic definition
|
||||
metadata["produces"].append({
|
||||
"type": output_type,
|
||||
"description": f"Output artifact of type {output_type}"
|
||||
})
|
||||
|
||||
return metadata
|
||||
|
||||
def infer_permissions(self, skills: List[str]) -> List[str]:
|
||||
"""
|
||||
Infer required permissions from skills
|
||||
|
||||
Args:
|
||||
skills: List of skill names
|
||||
|
||||
Returns:
|
||||
List of required permissions
|
||||
"""
|
||||
permissions = set()
|
||||
skills_list = self.registry.get("skills", [])
|
||||
|
||||
for skill_name in skills:
|
||||
# Find skill in registry
|
||||
skill = next(
|
||||
(s for s in skills_list if s.get("name") == skill_name),
|
||||
None
|
||||
)
|
||||
|
||||
if skill and "permissions" in skill:
|
||||
for perm in skill["permissions"]:
|
||||
permissions.add(perm)
|
||||
|
||||
return sorted(list(permissions))
|
||||
|
||||
def generate_agent_yaml(
|
||||
self,
|
||||
name: str,
|
||||
description: str,
|
||||
skills: List[str],
|
||||
artifact_metadata: Dict[str, Any],
|
||||
permissions: List[str],
|
||||
system_prompt: Optional[str] = None
|
||||
) -> str:
|
||||
"""
|
||||
Generate agent.yaml content
|
||||
|
||||
Args:
|
||||
name: Agent name
|
||||
description: Agent description
|
||||
skills: List of skill names
|
||||
artifact_metadata: Artifact metadata structure
|
||||
permissions: List of permissions
|
||||
system_prompt: Optional system prompt
|
||||
|
||||
Returns:
|
||||
YAML content as string
|
||||
"""
|
||||
agent_def = {
|
||||
"name": name,
|
||||
"description": description,
|
||||
"skills_available": skills,
|
||||
"permissions": permissions
|
||||
}
|
||||
|
||||
if artifact_metadata:
|
||||
agent_def["artifact_metadata"] = artifact_metadata
|
||||
|
||||
if system_prompt:
|
||||
agent_def["system_prompt"] = system_prompt
|
||||
|
||||
return yaml.dump(
|
||||
agent_def,
|
||||
default_flow_style=False,
|
||||
sort_keys=False,
|
||||
allow_unicode=True
|
||||
)
|
||||
|
||||
def generate_readme(
|
||||
self,
|
||||
name: str,
|
||||
purpose: str,
|
||||
skills: List[str],
|
||||
inputs: List[str],
|
||||
outputs: List[str],
|
||||
examples: List[str]
|
||||
) -> str:
|
||||
"""
|
||||
Generate README.md content
|
||||
|
||||
Args:
|
||||
name: Agent name
|
||||
purpose: Agent purpose
|
||||
skills: List of skill names
|
||||
inputs: Input artifacts
|
||||
outputs: Output artifacts
|
||||
examples: Example use cases
|
||||
|
||||
Returns:
|
||||
Markdown content
|
||||
"""
|
||||
readme = f"""# {name.title()} Agent
|
||||
|
||||
## Purpose
|
||||
|
||||
{purpose}
|
||||
|
||||
## Skills
|
||||
|
||||
This agent uses the following skills:
|
||||
|
||||
"""
|
||||
for skill in skills:
|
||||
readme += f"- `{skill}`\n"
|
||||
|
||||
if inputs or outputs:
|
||||
readme += "\n## Artifact Flow\n\n"
|
||||
|
||||
if inputs:
|
||||
readme += "### Consumes\n\n"
|
||||
for inp in inputs:
|
||||
readme += f"- `{inp}`\n"
|
||||
readme += "\n"
|
||||
|
||||
if outputs:
|
||||
readme += "### Produces\n\n"
|
||||
for out in outputs:
|
||||
readme += f"- `{out}`\n"
|
||||
readme += "\n"
|
||||
|
||||
if examples:
|
||||
readme += "## Example Use Cases\n\n"
|
||||
for example in examples:
|
||||
readme += f"- {example}\n"
|
||||
readme += "\n"
|
||||
|
||||
readme += """## Usage
|
||||
|
||||
```bash
|
||||
# Activate the agent
|
||||
/agent {name}
|
||||
|
||||
# Or invoke directly
|
||||
betty agent run {name} --input <path>
|
||||
```
|
||||
|
||||
## Created By
|
||||
|
||||
This agent was created by **meta.agent**, the meta-agent for creating agents.
|
||||
|
||||
---
|
||||
|
||||
*Part of the Betty Framework*
|
||||
""".format(name=name)
|
||||
|
||||
return readme
|
||||
|
||||
def create_agent(
|
||||
self,
|
||||
description_path: str,
|
||||
output_dir: Optional[str] = None,
|
||||
validate: bool = True,
|
||||
requirement: Optional[RequirementInfo] = None
|
||||
) -> Dict[str, str]:
|
||||
"""
|
||||
Create a complete agent from description
|
||||
|
||||
Args:
|
||||
description_path: Path to agent description file
|
||||
output_dir: Output directory (default: agents/{name}/)
|
||||
validate: Whether to validate with registry.certify
|
||||
requirement: Requirement information for traceability (optional)
|
||||
|
||||
Returns:
|
||||
Dictionary with paths to created files
|
||||
"""
|
||||
# Parse description
|
||||
desc = self.parse_description(description_path)
|
||||
name = desc["name"]
|
||||
|
||||
if not name:
|
||||
raise ValueError("Agent name is required")
|
||||
|
||||
# Determine output directory
|
||||
if not output_dir:
|
||||
output_dir = f"agents/{name}"
|
||||
|
||||
output_path = Path(output_dir)
|
||||
output_path.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Find compatible skills
|
||||
skill_recommendations = self.find_compatible_skills(
|
||||
desc["purpose"],
|
||||
desc.get("inputs", []) + desc.get("outputs", [])
|
||||
)
|
||||
|
||||
skills = skill_recommendations.get("recommended_skills", [])
|
||||
|
||||
# Generate artifact metadata
|
||||
artifact_metadata = self.generate_artifact_metadata(
|
||||
desc.get("inputs", []),
|
||||
desc.get("outputs", [])
|
||||
)
|
||||
|
||||
# Infer permissions
|
||||
permissions = self.infer_permissions(skills)
|
||||
|
||||
# Generate agent.yaml
|
||||
agent_yaml_content = self.generate_agent_yaml(
|
||||
name=name,
|
||||
description=desc["purpose"],
|
||||
skills=skills,
|
||||
artifact_metadata=artifact_metadata,
|
||||
permissions=permissions
|
||||
)
|
||||
|
||||
agent_yaml_path = output_path / "agent.yaml"
|
||||
with open(agent_yaml_path, 'w') as f:
|
||||
f.write(agent_yaml_content)
|
||||
|
||||
# Generate README.md
|
||||
readme_content = self.generate_readme(
|
||||
name=name,
|
||||
purpose=desc["purpose"],
|
||||
skills=skills,
|
||||
inputs=desc.get("inputs", []),
|
||||
outputs=desc.get("outputs", []),
|
||||
examples=desc.get("examples", [])
|
||||
)
|
||||
|
||||
readme_path = output_path / "README.md"
|
||||
with open(readme_path, 'w') as f:
|
||||
f.write(readme_content)
|
||||
|
||||
# Log traceability if requirement provided
|
||||
trace_id = None
|
||||
if requirement:
|
||||
try:
|
||||
tracer = get_tracer()
|
||||
trace_id = tracer.log_creation(
|
||||
component_id=name,
|
||||
component_name=name.replace(".", " ").title(),
|
||||
component_type="agent",
|
||||
component_version="0.1.0",
|
||||
component_file_path=str(agent_yaml_path),
|
||||
input_source_path=description_path,
|
||||
created_by_tool="meta.agent",
|
||||
created_by_version="0.1.0",
|
||||
requirement=requirement,
|
||||
tags=["agent", "auto-generated"],
|
||||
project="Betty Framework"
|
||||
)
|
||||
|
||||
# Log validation check
|
||||
tracer.log_verification(
|
||||
component_id=name,
|
||||
check_type="validation",
|
||||
tool="meta.agent",
|
||||
result="passed",
|
||||
details={
|
||||
"checks_performed": [
|
||||
{"name": "agent_structure", "status": "passed"},
|
||||
{"name": "artifact_metadata", "status": "passed"},
|
||||
{"name": "skills_compatibility", "status": "passed", "message": f"{len(skills)} compatible skills found"}
|
||||
]
|
||||
}
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"⚠️ Warning: Could not log traceability: {e}")
|
||||
|
||||
result = {
|
||||
"agent_yaml": str(agent_yaml_path),
|
||||
"readme": str(readme_path),
|
||||
"name": name,
|
||||
"skills": skills,
|
||||
"rationale": skill_recommendations.get("rationale", "")
|
||||
}
|
||||
|
||||
if trace_id:
|
||||
result["trace_id"] = trace_id
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def main():
|
||||
"""CLI entry point"""
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description="meta.agent - Create agents from natural language descriptions"
|
||||
)
|
||||
parser.add_argument(
|
||||
"description",
|
||||
help="Path to agent description file (.md or .json)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-o", "--output",
|
||||
help="Output directory (default: agents/{name}/)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--no-validate",
|
||||
action="store_true",
|
||||
help="Skip validation step"
|
||||
)
|
||||
|
||||
# Traceability arguments
|
||||
parser.add_argument(
|
||||
"--requirement-id",
|
||||
help="Requirement identifier for traceability (e.g., REQ-2025-001)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--requirement-description",
|
||||
help="What this agent is meant to accomplish"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--requirement-source",
|
||||
help="Source document or system (e.g., requirements/Q1-2025.md)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--issue-id",
|
||||
help="Issue tracking ID (e.g., JIRA-123)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--requested-by",
|
||||
help="Who requested this requirement"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--rationale",
|
||||
help="Why this component is needed"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Create requirement info if provided
|
||||
requirement = None
|
||||
if args.requirement_id and args.requirement_description:
|
||||
requirement = RequirementInfo(
|
||||
id=args.requirement_id,
|
||||
description=args.requirement_description,
|
||||
source=args.requirement_source,
|
||||
issue_id=args.issue_id,
|
||||
requested_by=args.requested_by,
|
||||
rationale=args.rationale
|
||||
)
|
||||
|
||||
# Create agent
|
||||
creator = AgentCreator()
|
||||
|
||||
print(f"🔮 meta.agent creating agent from {args.description}...")
|
||||
|
||||
try:
|
||||
result = creator.create_agent(
|
||||
args.description,
|
||||
output_dir=args.output,
|
||||
validate=not args.no_validate,
|
||||
requirement=requirement
|
||||
)
|
||||
|
||||
print(f"\n✨ Agent '{result['name']}' created successfully!\n")
|
||||
print(f"📄 Agent definition: {result['agent_yaml']}")
|
||||
print(f"📖 Documentation: {result['readme']}\n")
|
||||
print(f"🔧 Skills: {', '.join(result['skills'])}\n")
|
||||
|
||||
if result.get("rationale"):
|
||||
print(f"💡 Rationale:\n{result['rationale']}\n")
|
||||
|
||||
if result.get("trace_id"):
|
||||
print(f"📝 Traceability: {result['trace_id']}")
|
||||
print(f" View trace: python3 betty/trace_cli.py show {result['name']}\n")
|
||||
|
||||
except Exception as e:
|
||||
print(f"\n❌ Error creating agent: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user