Compare commits
74 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4ff1ccda21 | |||
| 74e754b4e1 | |||
| f332e40000 | |||
| d6064147e4 | |||
| 1fb5005bf5 | |||
| 57fbb0479b | |||
| 26154cc648 | |||
| e207cee4ff | |||
| e7a2d957f5 | |||
| 7e5f02eebe | |||
| 37a3fce27d | |||
| 7976c1dac7 | |||
| da2bac1b48 | |||
| 4096eba564 | |||
| 3f3a23e4b2 | |||
| 934e3145b8 | |||
| 6155ccbf4d | |||
| 6cadc81be8 | |||
| 412521edb0 | |||
| fd00471189 | |||
| 65c3fcf76d | |||
| 2fe83187d6 | |||
| e65052c237 | |||
| 38bc7c12ae | |||
| 22c95b62ce | |||
| 9684311176 | |||
| a1229d8e98 | |||
| ad1b10db63 | |||
| 96308637d6 | |||
| 4d341611a4 | |||
| ef94bfe1fb | |||
| a58b52f420 | |||
| 7852990073 | |||
| 14c9478080 | |||
| c5ebd91651 | |||
| 088f3cc817 | |||
| 50087bb24c | |||
| c869e1955a | |||
| 8293f75152 | |||
| 3ccf4bc383 | |||
| e71d850b79 | |||
| 774911b46c | |||
| 480ade22ce | |||
| bd31323876 | |||
| 2f3b8b27b8 | |||
| d39abf4312 | |||
| ec7058414f | |||
| 8dc63771ca | |||
| ee0ae20d06 | |||
| eaa54d9d4a | |||
| cadf401f23 | |||
| 24dd41410a | |||
| 2e5ed77909 | |||
| 0ae0bfda83 | |||
| 22007e7aa9 | |||
| 05dde7414f | |||
| 721cfb1ac8 | |||
| 5973168a8c | |||
| 56ed24a092 | |||
| ca031f3ee1 | |||
| 169827636f | |||
| 30f1c700ce | |||
| bc070c3e39 | |||
| 2194301260 | |||
| e6900647f8 | |||
| e1d8624483 | |||
| f614ee7f15 | |||
| d64020e024 | |||
| 975a002796 | |||
| 6e6b83848f | |||
| 3fb255c906 | |||
| cd51d663fb | |||
| 3fd8f9f97a | |||
| 2180a60c21 |
@@ -26,5 +26,10 @@
|
||||
"mcp__agent-builder__list_mcp_tools",
|
||||
"mcp__agent-builder__add_mcp_server"
|
||||
]
|
||||
}
|
||||
},
|
||||
"enabledMcpjsonServers": [
|
||||
"agent-builder",
|
||||
"tools"
|
||||
],
|
||||
"enableAllProjectMcpServers": true
|
||||
}
|
||||
|
||||
@@ -964,11 +964,11 @@ class {agent_class_name}:
|
||||
with open(mcp_config_path) as f:
|
||||
mcp_servers = json.load(f)
|
||||
|
||||
for server_name, server_config in mcp_servers.items():
|
||||
server_config["name"] = server_name
|
||||
for server_config in mcp_servers.get("servers", []):
|
||||
# Resolve relative cwd paths
|
||||
if "cwd" in server_config and not Path(server_config["cwd"]).is_absolute():
|
||||
server_config["cwd"] = str(agent_dir / server_config["cwd"])
|
||||
cwd = server_config.get("cwd")
|
||||
if cwd and not Path(cwd).is_absolute():
|
||||
server_config["cwd"] = str(agent_dir / cwd)
|
||||
tool_registry.register_mcp_server(server_config)
|
||||
|
||||
llm = None
|
||||
|
||||
@@ -225,14 +225,11 @@ class OnlineResearchAgent:
|
||||
with open(mcp_config_path) as f:
|
||||
mcp_servers = json.load(f)
|
||||
|
||||
for server_name, server_config in mcp_servers.items():
|
||||
server_config["name"] = server_name
|
||||
for server_config in mcp_servers.get("servers", []):
|
||||
# Resolve relative cwd paths
|
||||
if (
|
||||
"cwd" in server_config
|
||||
and not Path(server_config["cwd"]).is_absolute()
|
||||
):
|
||||
server_config["cwd"] = str(agent_dir / server_config["cwd"])
|
||||
cwd = server_config.get("cwd")
|
||||
if cwd and not Path(cwd).is_absolute():
|
||||
server_config["cwd"] = str(agent_dir / cwd)
|
||||
tool_registry.register_mcp_server(server_config)
|
||||
|
||||
llm = None
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
# Triage Issue Skill
|
||||
|
||||
Analyze a GitHub issue, verify claims against the codebase, and close invalid issues with a technical response.
|
||||
|
||||
## Trigger
|
||||
|
||||
User provides a GitHub issue URL or number, e.g.:
|
||||
- `/triage-issue 1970`
|
||||
- `/triage-issue https://github.com/adenhq/hive/issues/1970`
|
||||
|
||||
## Workflow
|
||||
|
||||
### Step 1: Fetch Issue Details
|
||||
|
||||
```bash
|
||||
gh issue view <number> --repo adenhq/hive --json title,body,state,labels,author
|
||||
```
|
||||
|
||||
Extract:
|
||||
- Title
|
||||
- Body (the claim/bug report)
|
||||
- Current state
|
||||
- Labels
|
||||
- Author
|
||||
|
||||
If issue is already closed, inform user and stop.
|
||||
|
||||
### Step 2: Analyze the Claim
|
||||
|
||||
Read the issue body and identify:
|
||||
1. **The core claim** - What is the user asserting?
|
||||
2. **Technical specifics** - File paths, function names, code snippets mentioned
|
||||
3. **Expected behavior** - What do they think should happen?
|
||||
4. **Severity claimed** - Security issue? Bug? Feature request?
|
||||
|
||||
### Step 3: Investigate the Codebase
|
||||
|
||||
For each technical claim:
|
||||
1. Find the referenced code using Grep/Glob/Read
|
||||
2. Understand the actual implementation
|
||||
3. Check if the claim accurately describes the behavior
|
||||
4. Look for related tests, documentation, or design decisions
|
||||
|
||||
### Step 4: Evaluate Validity
|
||||
|
||||
Categorize the issue as one of:
|
||||
|
||||
| Category | Action |
|
||||
|----------|--------|
|
||||
| **Valid Bug** | Do NOT close. Inform user this is a real issue. |
|
||||
| **Valid Feature Request** | Do NOT close. Suggest labeling appropriately. |
|
||||
| **Misunderstanding** | Prepare technical explanation for why behavior is correct. |
|
||||
| **Fundamentally Flawed** | Prepare critique explaining the technical impossibility or design rationale. |
|
||||
| **Duplicate** | Find the original issue and prepare duplicate notice. |
|
||||
| **Incomplete** | Prepare request for more information. |
|
||||
|
||||
### Step 5: Draft Response
|
||||
|
||||
For issues to be closed, draft a response that:
|
||||
|
||||
1. **Acknowledges the concern** - Don't be dismissive
|
||||
2. **Explains the actual behavior** - With code references
|
||||
3. **Provides technical rationale** - Why it works this way
|
||||
4. **References industry standards** - If applicable
|
||||
5. **Offers alternatives** - If there's a better approach for the user
|
||||
|
||||
Use this template:
|
||||
|
||||
```markdown
|
||||
## Analysis
|
||||
|
||||
[Brief summary of what was investigated]
|
||||
|
||||
## Technical Details
|
||||
|
||||
[Explanation with code references]
|
||||
|
||||
## Why This Is Working As Designed
|
||||
|
||||
[Rationale]
|
||||
|
||||
## Recommendation
|
||||
|
||||
[What the user should do instead, if applicable]
|
||||
|
||||
---
|
||||
*This issue was reviewed and closed by the maintainers.*
|
||||
```
|
||||
|
||||
### Step 6: User Review
|
||||
|
||||
Present the draft to the user with:
|
||||
|
||||
```
|
||||
## Issue #<number>: <title>
|
||||
|
||||
**Claim:** <summary of claim>
|
||||
|
||||
**Finding:** <valid/invalid/misunderstanding/etc>
|
||||
|
||||
**Draft Response:**
|
||||
<the markdown response>
|
||||
|
||||
---
|
||||
Do you want me to post this comment and close the issue?
|
||||
```
|
||||
|
||||
Use AskUserQuestion with options:
|
||||
- "Post and close" - Post comment, close issue
|
||||
- "Edit response" - Let user modify the response
|
||||
- "Skip" - Don't take action
|
||||
|
||||
### Step 7: Execute Action
|
||||
|
||||
If user approves:
|
||||
|
||||
```bash
|
||||
# Post comment
|
||||
gh issue comment <number> --repo adenhq/hive --body "<response>"
|
||||
|
||||
# Close issue
|
||||
gh issue close <number> --repo adenhq/hive --reason "not planned"
|
||||
```
|
||||
|
||||
Report success with link to the issue.
|
||||
|
||||
## Important Guidelines
|
||||
|
||||
1. **Never close valid issues** - If there's any merit to the claim, don't close it
|
||||
2. **Be respectful** - The reporter took time to file the issue
|
||||
3. **Be technical** - Provide code references and evidence
|
||||
4. **Be educational** - Help them understand, don't just dismiss
|
||||
5. **Check twice** - Make sure you understand the code before declaring something invalid
|
||||
6. **Consider edge cases** - Maybe their environment reveals a real issue
|
||||
|
||||
## Example Critiques
|
||||
|
||||
### Security Misunderstanding
|
||||
> "The claim that secrets are exposed in plaintext misunderstands the encryption architecture. While `SecretStr` is used for logging protection, actual encryption is provided by Fernet (AES-128-CBC) at the storage layer. The code path is: serialize → encrypt → write. Only encrypted bytes touch disk."
|
||||
|
||||
### Impossible Request
|
||||
> "The requested feature would require [X] which violates [fundamental constraint]. This is not a limitation of our implementation but a fundamental property of [technology/protocol]."
|
||||
|
||||
### Already Handled
|
||||
> "This scenario is already handled by [code reference]. The reporter may be using an older version or misconfigured environment."
|
||||
@@ -22,6 +22,9 @@ jobs:
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- name: Run auto-close-duplicates tests
|
||||
run: bun test scripts/auto-close-duplicates
|
||||
|
||||
- name: Auto-close duplicate issues
|
||||
run: bun run scripts/auto-close-duplicates.ts
|
||||
env:
|
||||
|
||||
@@ -41,7 +41,10 @@ jobs:
|
||||
|
||||
test:
|
||||
name: Test Python Framework
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"agent-builder": {
|
||||
"command": "python",
|
||||
"command": "core/.venv/bin/python",
|
||||
"args": ["-m", "framework.mcp.agent_builder_server"],
|
||||
"cwd": "core",
|
||||
"env": {
|
||||
"PYTHONPATH": "../tools/src"
|
||||
}
|
||||
"cwd": "."
|
||||
},
|
||||
"tools": {
|
||||
"command": "python",
|
||||
"args": ["mcp_server.py", "--stdio"],
|
||||
"cwd": "tools",
|
||||
"env": {
|
||||
"PYTHONPATH": "src"
|
||||
}
|
||||
"command": "tools/.venv/bin/python",
|
||||
"args": ["-m", "aden_tools.mcp_server", "--stdio"],
|
||||
"cwd": "."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
3.11
|
||||
+11
-10
@@ -47,21 +47,22 @@ If a high-quality PR is submitted for a "stale" assigned issue (no activity for
|
||||
2. Clone your fork: `git clone https://github.com/YOUR_USERNAME/hive.git`
|
||||
3. Create a feature branch: `git checkout -b feature/your-feature-name`
|
||||
4. Make your changes
|
||||
5. Run tests: `PYTHONPATH=core:exports python -m pytest`
|
||||
5. Run checks and tests:
|
||||
```bash
|
||||
make check # Lint and format checks
|
||||
cd core && python -m pytest tests/ -v # Core tests
|
||||
```
|
||||
6. Commit your changes following our commit conventions
|
||||
7. Push to your fork and submit a Pull Request
|
||||
|
||||
## Development Setup
|
||||
|
||||
```bash
|
||||
# Install Python packages
|
||||
./scripts/setup-python.sh
|
||||
|
||||
# Verify installation
|
||||
python -c "import framework; import aden_tools; print('✓ Setup complete')"
|
||||
|
||||
# Install Claude Code skills (optional)
|
||||
# Install Python packages and verify setup
|
||||
./quickstart.sh
|
||||
|
||||
# Verify installation manually (optional)
|
||||
python -c "import framework; import aden_tools; print('✓ Setup complete')"
|
||||
```
|
||||
|
||||
> **Windows Users:**
|
||||
@@ -103,7 +104,7 @@ docs(readme): update installation instructions
|
||||
1. **Get assigned to the issue first** (see [Issue Assignment Policy](#issue-assignment-policy))
|
||||
2. Update documentation if needed
|
||||
3. Add tests for new functionality
|
||||
4. Ensure all tests pass
|
||||
4. Ensure `make check` and core tests pass (`cd core && python -m pytest tests/ -v`)
|
||||
5. Update the CHANGELOG.md if applicable
|
||||
6. Request review from maintainers
|
||||
|
||||
@@ -117,7 +118,7 @@ feat(component): add new feature description
|
||||
## Project Structure
|
||||
|
||||
- `core/` - Core framework (agent runtime, graph executor, protocols)
|
||||
- `tools/` - MCP Tools Package (19 tools for agent capabilities)
|
||||
- `tools/` - MCP Tools Package (tools for agent capabilities)
|
||||
- `exports/` - Agent packages and examples
|
||||
- `docs/` - Documentation
|
||||
- `scripts/` - Build and utility scripts
|
||||
|
||||
+28
-76
@@ -23,8 +23,8 @@ Aden Agent Framework is a Python-based system for building goal-driven, self-imp
|
||||
| Package | Directory | Description | Tech Stack |
|
||||
| ------------- | ---------- | --------------------------------------- | ------------ |
|
||||
| **framework** | `/core` | Core runtime, graph executor, protocols | Python 3.11+ |
|
||||
| **tools** | `/tools` | 19 MCP tools for agent capabilities | Python 3.11+ |
|
||||
| **exports** | `/exports` | Agent packages and examples | Python 3.11+ |
|
||||
| **tools** | `/tools` | MCP tools for agent capabilities | Python 3.11+ |
|
||||
| **exports** | `/exports` | Agent packages (user-created, gitignored) | Python 3.11+ |
|
||||
| **skills** | `.claude` | Claude Code skills for building/testing | Markdown |
|
||||
|
||||
### Key Principles
|
||||
@@ -63,8 +63,8 @@ git --version # Any recent version
|
||||
git clone https://github.com/adenhq/hive.git
|
||||
cd hive
|
||||
|
||||
# 2. Run automated Python setup
|
||||
./scripts/setup-python.sh
|
||||
# 2. Run automated setup
|
||||
./quickstart.sh
|
||||
```
|
||||
|
||||
The setup script performs these actions:
|
||||
@@ -115,8 +115,8 @@ python -c "import framework; print('✓ framework OK')"
|
||||
python -c "import aden_tools; print('✓ aden_tools OK')"
|
||||
python -c "import litellm; print('✓ litellm OK')"
|
||||
|
||||
# Run an example agent
|
||||
PYTHONPATH=core:exports python -m support_ticket_agent validate
|
||||
# Run an agent (after building one via /building-agents-construction)
|
||||
PYTHONPATH=core:exports python -m your_agent_name validate
|
||||
```
|
||||
|
||||
---
|
||||
@@ -151,16 +151,19 @@ hive/ # Repository root
|
||||
│ └── agent-workflow/ # Complete workflow
|
||||
| ├── SKILL.md
|
||||
│ └── examples
|
||||
orchestration
|
||||
│
|
||||
├── core/ # CORE FRAMEWORK PACKAGE
|
||||
│ ├── framework/ # Main package code
|
||||
│ │ ├── runner/ # AgentRunner - loads and runs agents
|
||||
│ │ ├── executor/ # GraphExecutor - executes node graphs
|
||||
│ │ ├── protocols/ # Standard protocols (hooks, tracing, etc.)
|
||||
│ │ ├── builder/ # Agent builder utilities
|
||||
│ │ ├── credentials/ # Credential management
|
||||
│ │ ├── graph/ # GraphExecutor - executes node graphs
|
||||
│ │ ├── llm/ # LLM provider integrations (Anthropic, OpenAI, etc.)
|
||||
│ │ ├── memory/ # Memory systems (STM, LTM/RLM)
|
||||
│ │ ├── tools/ # Tool registry and management
|
||||
│ │ ├── mcp/ # MCP server integration
|
||||
│ │ ├── runner/ # AgentRunner - loads and runs agents
|
||||
│ │ ├── runtime/ # Runtime environment
|
||||
│ │ ├── schemas/ # Data schemas
|
||||
│ │ ├── storage/ # File-based persistence
|
||||
│ │ ├── testing/ # Testing utilities
|
||||
│ │ └── __init__.py
|
||||
│ ├── pyproject.toml # Package metadata and dependencies
|
||||
│ ├── requirements.txt # Python dependencies
|
||||
@@ -168,26 +171,22 @@ orchestration
|
||||
│ ├── MCP_INTEGRATION_GUIDE.md # MCP server integration guide
|
||||
│ └── docs/ # Protocol documentation
|
||||
│
|
||||
├── tools/ # TOOLS PACKAGE (19 MCP tools)
|
||||
├── tools/ # TOOLS PACKAGE (MCP tools)
|
||||
│ ├── src/
|
||||
│ │ └── aden_tools/
|
||||
│ │ ├── tools/ # Individual tool implementations
|
||||
│ │ │ ├── web_search_tool/
|
||||
│ │ │ ├── web_scrape_tool/
|
||||
│ │ │ ├── file_system_toolkits/
|
||||
│ │ │ └── ... # 19 tools total
|
||||
│ │ │ └── ... # Additional tools
|
||||
│ │ ├── mcp_server.py # HTTP MCP server
|
||||
│ │ └── __init__.py
|
||||
│ ├── pyproject.toml # Package metadata
|
||||
│ ├── requirements.txt # Python dependencies
|
||||
│ └── README.md # Tools documentation
|
||||
│
|
||||
├── exports/ # AGENT PACKAGES
|
||||
│ ├── support_ticket_agent/ # Example: Support ticket handler
|
||||
│ ├── market_research_agent/ # Example: Market research
|
||||
│ ├── outbound_sales_agent/ # Example: Sales outreach
|
||||
│ ├── personal_assistant_agent/ # Example: Personal assistant
|
||||
│ └── ... # More agent examples
|
||||
├── exports/ # AGENT PACKAGES (user-created, gitignored)
|
||||
│ └── your_agent_name/ # Created via /building-agents-construction
|
||||
│
|
||||
├── docs/ # Documentation
|
||||
│ ├── getting-started.md # Quick start guide
|
||||
@@ -510,8 +509,8 @@ chore(deps): update React to 18.2.0
|
||||
|
||||
1. Create a feature branch from `main`
|
||||
2. Make your changes with clear commits
|
||||
3. Run tests locally: `npm run test`
|
||||
4. Run linting: `npm run lint`
|
||||
3. Run tests locally: `PYTHONPATH=core:exports python -m pytest`
|
||||
4. Run linting: `black --check .`
|
||||
5. Push and create a PR
|
||||
6. Fill out the PR template
|
||||
7. Request review from CODEOWNERS
|
||||
@@ -520,43 +519,6 @@ chore(deps): update React to 18.2.0
|
||||
|
||||
---
|
||||
|
||||
## Debugging
|
||||
|
||||
|
||||
|
||||
### Backend Debugging
|
||||
|
||||
**VS Code Debugging:**
|
||||
|
||||
1. Add Node debug configuration:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "node",
|
||||
"request": "launch",
|
||||
"name": "Debug Backend",
|
||||
"runtimeExecutable": "npm",
|
||||
"runtimeArgs": ["run", "dev"],
|
||||
"cwd": "${workspaceFolder}/hive",
|
||||
"console": "integratedTerminal"
|
||||
}
|
||||
```
|
||||
|
||||
2. Set breakpoints in your code
|
||||
3. Press F5 to start debugging
|
||||
|
||||
**Logging:**
|
||||
|
||||
```typescript
|
||||
import { logger } from "../utils/logger";
|
||||
|
||||
// Add debug logs
|
||||
logger.debug("Processing request", {
|
||||
userId: req.user.id,
|
||||
body: req.body,
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Common Tasks
|
||||
@@ -698,29 +660,19 @@ kill -9 <PID>
|
||||
```
|
||||
|
||||
|
||||
### Docker Issues
|
||||
|
||||
```bash
|
||||
# Reset Docker state
|
||||
docker compose down -v
|
||||
docker system prune -f
|
||||
docker compose build --no-cache
|
||||
docker compose up
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Environment Variables Not Loading
|
||||
|
||||
```bash
|
||||
# Regenerate from config.yaml
|
||||
npm run generate:env
|
||||
|
||||
# Verify files exist
|
||||
# Verify .env file exists at project root
|
||||
cat .env
|
||||
cat hive/.env
|
||||
|
||||
# Restart dev servers after changing env
|
||||
# Or check shell environment
|
||||
echo $ANTHROPIC_API_KEY
|
||||
|
||||
# Copy from .env.example if needed
|
||||
cp .env.example .env
|
||||
# Then edit .env with your API keys
|
||||
```
|
||||
|
||||
|
||||
|
||||
+82
-42
@@ -6,7 +6,7 @@ Complete setup guide for building and running goal-driven agents with the Aden A
|
||||
|
||||
```bash
|
||||
# Run the automated setup script
|
||||
./scripts/setup-python.sh
|
||||
./quickstart.sh
|
||||
```
|
||||
|
||||
> **Note for Windows Users:**
|
||||
@@ -109,37 +109,24 @@ All agent commands must be run from the project root with `PYTHONPATH` set:
|
||||
PYTHONPATH=core:exports python -m agent_name COMMAND
|
||||
```
|
||||
|
||||
### Example: Support Ticket Agent
|
||||
### Example Commands
|
||||
|
||||
After building an agent via `/building-agents-construction`, use these commands:
|
||||
|
||||
```bash
|
||||
# Validate agent structure
|
||||
PYTHONPATH=core:exports python -m support_ticket_agent validate
|
||||
PYTHONPATH=core:exports python -m your_agent_name validate
|
||||
|
||||
# Show agent information
|
||||
PYTHONPATH=core:exports python -m support_ticket_agent info
|
||||
PYTHONPATH=core:exports python -m your_agent_name info
|
||||
|
||||
# Run agent with input
|
||||
PYTHONPATH=core:exports python -m support_ticket_agent run --input '{
|
||||
"ticket_content": "My login is broken. Error 401.",
|
||||
"customer_id": "CUST-123",
|
||||
"ticket_id": "TKT-456"
|
||||
PYTHONPATH=core:exports python -m your_agent_name run --input '{
|
||||
"task": "Your input here"
|
||||
}'
|
||||
|
||||
# Run in mock mode (no LLM calls)
|
||||
PYTHONPATH=core:exports python -m support_ticket_agent run --mock --input '{...}'
|
||||
```
|
||||
|
||||
### Example: Other Agents
|
||||
|
||||
```bash
|
||||
# Market Research Agent
|
||||
PYTHONPATH=core:exports python -m market_research_agent info
|
||||
|
||||
# Outbound Sales Agent
|
||||
PYTHONPATH=core:exports python -m outbound_sales_agent validate
|
||||
|
||||
# Personal Assistant Agent
|
||||
PYTHONPATH=core:exports python -m personal_assistant_agent run --input '{...}'
|
||||
PYTHONPATH=core:exports python -m your_agent_name run --mock --input '{...}'
|
||||
```
|
||||
|
||||
## Building New Agents and Run Flow
|
||||
@@ -152,7 +139,7 @@ Build and run an agent using Claude Code CLI with the agent building skills:
|
||||
./quickstart.sh
|
||||
```
|
||||
|
||||
This installs agent-related Claude Code skills:
|
||||
This verifies agent-related Claude Code skills are available:
|
||||
|
||||
- `/building-agents-construction` - Step-by-step build guide
|
||||
- `/building-agents-core` - Fundamental concepts
|
||||
@@ -251,7 +238,7 @@ source .venv/bin/activate # macOS/Linux
|
||||
# .venv\Scripts\activate # Windows
|
||||
|
||||
# Then run setup
|
||||
./scripts/setup-python.sh
|
||||
./quickstart.sh
|
||||
```
|
||||
|
||||
Always activate the venv before running agents:
|
||||
@@ -280,7 +267,7 @@ cd tools && pip install -e .
|
||||
Or run the setup script:
|
||||
|
||||
```bash
|
||||
./scripts/setup-python.sh
|
||||
./quickstart.sh
|
||||
```
|
||||
|
||||
### "ModuleNotFoundError: No module named 'openai.\_models'"
|
||||
@@ -293,14 +280,14 @@ Or run the setup script:
|
||||
pip install --upgrade "openai>=1.0.0"
|
||||
```
|
||||
|
||||
### "No module named 'support_ticket_agent'"
|
||||
### "No module named 'your_agent_name'"
|
||||
|
||||
**Cause:** Not running from project root or missing PYTHONPATH
|
||||
**Cause:** Not running from project root, missing PYTHONPATH, or agent not yet created
|
||||
|
||||
**Solution:** Ensure you're in the project root directory and use:
|
||||
**Solution:** Ensure you're in the project root directory, have built an agent, and use:
|
||||
|
||||
```bash
|
||||
PYTHONPATH=core:exports python -m support_ticket_agent validate
|
||||
PYTHONPATH=core:exports python -m your_agent_name validate
|
||||
```
|
||||
|
||||
### Agent imports fail with "broken installation"
|
||||
@@ -314,7 +301,7 @@ PYTHONPATH=core:exports python -m support_ticket_agent validate
|
||||
pip uninstall -y framework tools
|
||||
|
||||
# Reinstall correctly
|
||||
./scripts/setup-python.sh
|
||||
./quickstart.sh
|
||||
```
|
||||
|
||||
## Package Structure
|
||||
@@ -325,22 +312,75 @@ The Hive framework consists of three Python packages:
|
||||
hive/
|
||||
├── core/ # Core framework (runtime, graph executor, LLM providers)
|
||||
│ ├── framework/
|
||||
│ ├── pyproject.toml
|
||||
│ └── requirements.txt
|
||||
│ ├── .venv/ # Created by quickstart.sh
|
||||
│ └── pyproject.toml
|
||||
│
|
||||
├── tools/ # Tools and MCP servers
|
||||
│ ├── src/
|
||||
│ │ └── aden_tools/ # Actual package location
|
||||
│ ├── pyproject.toml
|
||||
│ └── README.md
|
||||
│ ├── .venv/ # Created by quickstart.sh
|
||||
│ └── pyproject.toml
|
||||
│
|
||||
└── exports/ # Agent packages (your agents go here)
|
||||
├── support_ticket_agent/
|
||||
├── market_research_agent/
|
||||
├── outbound_sales_agent/
|
||||
└── personal_assistant_agent/
|
||||
└── exports/ # Agent packages (user-created, gitignored)
|
||||
└── your_agent_name/ # Created via /building-agents-construction
|
||||
```
|
||||
|
||||
## Separate Virtual Environments
|
||||
|
||||
The project uses **separate virtual environments** for `core` and `tools` packages to:
|
||||
|
||||
- Isolate dependencies and avoid conflicts
|
||||
- Allow independent development and testing of each package
|
||||
- Enable MCP servers to run with their specific dependencies
|
||||
|
||||
### How It Works
|
||||
|
||||
When you run `./quickstart.sh` or `uv sync` in each directory:
|
||||
|
||||
1. **core/.venv/** - Contains the `framework` package and its dependencies (anthropic, litellm, mcp, etc.)
|
||||
2. **tools/.venv/** - Contains the `aden_tools` package and its dependencies (beautifulsoup4, pandas, etc.)
|
||||
|
||||
### Cross-Package Imports
|
||||
|
||||
The `core` and `tools` packages are **intentionally independent**:
|
||||
|
||||
- **No cross-imports**: `framework` does not import `aden_tools` directly, and vice versa
|
||||
- **Communication via MCP**: Tools are exposed to agents through MCP servers, not direct Python imports
|
||||
- **Runtime integration**: The agent runner loads tools via the MCP protocol at runtime
|
||||
|
||||
If you need to use both packages in a single script (e.g., for testing), you have two options:
|
||||
|
||||
```bash
|
||||
# Option 1: Install both in a shared environment
|
||||
python -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install -e core/ -e tools/
|
||||
|
||||
# Option 2: Use PYTHONPATH (for quick testing)
|
||||
PYTHONPATH=core:tools/src python your_script.py
|
||||
```
|
||||
|
||||
### MCP Server Configuration
|
||||
|
||||
The `.mcp.json` at project root configures MCP servers to use their respective virtual environments:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"agent-builder": {
|
||||
"command": "core/.venv/bin/python",
|
||||
"args": ["-m", "framework.mcp.agent_builder_server"]
|
||||
},
|
||||
"tools": {
|
||||
"command": "tools/.venv/bin/python",
|
||||
"args": ["-m", "aden_tools.mcp_server", "--stdio"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This ensures each MCP server runs with its correct dependencies.
|
||||
|
||||
### Why PYTHONPATH is Required
|
||||
|
||||
The packages are installed in **editable mode** (`pip install -e`), which means:
|
||||
@@ -359,7 +399,7 @@ This design allows agents in `exports/` to be:
|
||||
### 1. Setup (Once)
|
||||
|
||||
```bash
|
||||
./scripts/setup-python.sh
|
||||
./quickstart.sh
|
||||
```
|
||||
|
||||
### 2. Build Agent (Claude Code)
|
||||
@@ -372,7 +412,7 @@ Enter goal: "Build an agent that processes customer support tickets"
|
||||
### 3. Validate Agent
|
||||
|
||||
```bash
|
||||
PYTHONPATH=core:exports python -m support_ticket_agent validate
|
||||
PYTHONPATH=core:exports python -m your_agent_name validate
|
||||
```
|
||||
|
||||
### 4. Test Agent
|
||||
@@ -384,7 +424,7 @@ claude> /testing-agent
|
||||
### 5. Run Agent
|
||||
|
||||
```bash
|
||||
PYTHONPATH=core:exports python -m support_ticket_agent run --input '{...}'
|
||||
PYTHONPATH=core:exports python -m your_agent_name run --input '{...}'
|
||||
```
|
||||
|
||||
## IDE Setup
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<a href="README.md">English</a> |
|
||||
<a href="docs/i18n/zh-CN.md">简体中文</a> |
|
||||
<a href="docs/i18n/es.md">Español</a> |
|
||||
<a href="docs/i18n/hi.md">हिन्दी</a> |
|
||||
<a href="docs/i18n/pt.md">Português</a> |
|
||||
<a href="docs/i18n/ja.md">日本語</a> |
|
||||
<a href="docs/i18n/ru.md">Русский</a> |
|
||||
@@ -66,7 +67,7 @@ Aden is a platform for building, deploying, operating, and adapting AI agents:
|
||||
### Prerequisites
|
||||
|
||||
- [Python 3.11+](https://www.python.org/downloads/) for agent development
|
||||
- [Docker](https://docs.docker.com/get-docker/) (v20.10+) - Optional, for containerized tools
|
||||
- Claude Code or Cursor for utilizing agent skills
|
||||
|
||||
### Installation
|
||||
|
||||
@@ -75,21 +76,18 @@ Aden is a platform for building, deploying, operating, and adapting AI agents:
|
||||
git clone https://github.com/adenhq/hive.git
|
||||
cd hive
|
||||
|
||||
# Run Python environment setup
|
||||
./scripts/setup-python.sh
|
||||
# Run quickstart setup
|
||||
./quickstart.sh
|
||||
```
|
||||
|
||||
This installs:
|
||||
- **framework** - Core agent runtime and graph executor
|
||||
- **aden_tools** - 19 MCP tools for agent capabilities
|
||||
- All required dependencies
|
||||
This sets up:
|
||||
- **framework** - Core agent runtime and graph executor (in `core/.venv`)
|
||||
- **aden_tools** - MCP tools for agent capabilities (in `tools/.venv`)
|
||||
- All required Python dependencies
|
||||
|
||||
### Build Your First Agent
|
||||
|
||||
```bash
|
||||
# Install Claude Code skills (one-time)
|
||||
./quickstart.sh
|
||||
|
||||
# Build an agent using Claude Code
|
||||
claude> /building-agents-construction
|
||||
|
||||
@@ -128,47 +126,34 @@ Traditional agent frameworks require you to manually design workflows, define ag
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph BUILD["🏗️ BUILD"]
|
||||
GOAL["Define Goal<br/>+ Success Criteria"] --> NODES["Add Nodes<br/>LLM/Router/Function"]
|
||||
NODES --> EDGES["Connect Edges<br/>on_success/failure/conditional"]
|
||||
EDGES --> TEST["Test & Validate"] --> APPROVE["Approve & Export"]
|
||||
end
|
||||
GOAL["Define Goal"] --> GEN["Auto-Generate Graph"]
|
||||
GEN --> EXEC["Execute Agents"]
|
||||
EXEC --> MON["Monitor & Observe"]
|
||||
MON --> CHECK{{"Pass?"}}
|
||||
CHECK -- "Yes" --> DONE["Deliver Result"]
|
||||
CHECK -- "No" --> EVOLVE["Evolve Graph"]
|
||||
EVOLVE --> EXEC
|
||||
|
||||
subgraph EXPORT["📦 EXPORT"]
|
||||
direction TB
|
||||
JSON["agent.json<br/>(GraphSpec)"]
|
||||
TOOLS["tools.py<br/>(Functions)"]
|
||||
MCP["mcp_servers.json<br/>(Integrations)"]
|
||||
end
|
||||
GOAL -.- V1["Natural Language"]
|
||||
GEN -.- V2["Instant Architecture"]
|
||||
EXEC -.- V3["Easy Integrations"]
|
||||
MON -.- V4["Full visibility"]
|
||||
EVOLVE -.- V5["Adaptability"]
|
||||
DONE -.- V6["Reliable outcomes"]
|
||||
|
||||
subgraph RUN["🚀 RUNTIME"]
|
||||
LOAD["AgentRunner<br/>Load + Parse"] --> SETUP["Setup Runtime<br/>+ ToolRegistry"]
|
||||
SETUP --> EXEC["GraphExecutor<br/>Execute Nodes"]
|
||||
|
||||
subgraph DECISION["Decision Recording"]
|
||||
DEC1["runtime.decide()<br/>intent → options → choice"]
|
||||
DEC2["runtime.record_outcome()<br/>success, result, metrics"]
|
||||
end
|
||||
end
|
||||
|
||||
subgraph INFRA["⚙️ INFRASTRUCTURE"]
|
||||
CTX["NodeContext<br/>memory • llm • tools"]
|
||||
STORE[("FileStorage<br/>Runs & Decisions")]
|
||||
end
|
||||
|
||||
APPROVE --> EXPORT
|
||||
EXPORT --> LOAD
|
||||
EXEC --> DECISION
|
||||
EXEC --> CTX
|
||||
DECISION --> STORE
|
||||
STORE -.->|"Analyze & Improve"| NODES
|
||||
|
||||
style BUILD fill:#ffbe42,stroke:#cc5d00,stroke-width:3px,color:#333
|
||||
style EXPORT fill:#fff59d,stroke:#ed8c00,stroke-width:2px,color:#333
|
||||
style RUN fill:#ffb100,stroke:#cc5d00,stroke-width:3px,color:#333
|
||||
style DECISION fill:#ffcc80,stroke:#ed8c00,stroke-width:2px,color:#333
|
||||
style INFRA fill:#e8763d,stroke:#cc5d00,stroke-width:3px,color:#fff
|
||||
style STORE fill:#ed8c00,stroke:#cc5d00,stroke-width:2px,color:#fff
|
||||
style GOAL fill:#ffbe42,stroke:#cc5d00,stroke-width:2px,color:#333
|
||||
style GEN fill:#ffb100,stroke:#cc5d00,stroke-width:2px,color:#333
|
||||
style EXEC fill:#ff9800,stroke:#cc5d00,stroke-width:2px,color:#fff
|
||||
style MON fill:#ff9800,stroke:#cc5d00,stroke-width:2px,color:#fff
|
||||
style CHECK fill:#fff59d,stroke:#ed8c00,stroke-width:2px,color:#333
|
||||
style DONE fill:#4caf50,stroke:#2e7d32,stroke-width:2px,color:#fff
|
||||
style EVOLVE fill:#e8763d,stroke:#cc5d00,stroke-width:2px,color:#fff
|
||||
style V1 fill:#fff,stroke:#ed8c00,stroke-width:1px,color:#cc5d00
|
||||
style V2 fill:#fff,stroke:#ed8c00,stroke-width:1px,color:#cc5d00
|
||||
style V3 fill:#fff,stroke:#ed8c00,stroke-width:1px,color:#cc5d00
|
||||
style V4 fill:#fff,stroke:#ed8c00,stroke-width:1px,color:#cc5d00
|
||||
style V5 fill:#fff,stroke:#ed8c00,stroke-width:1px,color:#cc5d00
|
||||
style V6 fill:#fff,stroke:#ed8c00,stroke-width:1px,color:#cc5d00
|
||||
```
|
||||
|
||||
### The Aden Advantage
|
||||
@@ -230,8 +215,8 @@ Choose other frameworks when you need:
|
||||
```
|
||||
hive/
|
||||
├── core/ # Core framework - Agent runtime, graph executor, protocols
|
||||
├── tools/ # MCP Tools Package - 19 tools for agent capabilities
|
||||
├── exports/ # Agent packages - Pre-built agents and examples
|
||||
├── tools/ # MCP Tools Package - tools for agent capabilities
|
||||
├── exports/ # Agent packages (user-created, gitignored)
|
||||
├── docs/ # Documentation and guides
|
||||
├── scripts/ # Build and utility scripts
|
||||
├── .claude/ # Claude Code skills for building agents
|
||||
@@ -250,12 +235,12 @@ For building and running goal-driven agents with the framework:
|
||||
|
||||
```bash
|
||||
# One-time setup
|
||||
./scripts/setup-python.sh
|
||||
./quickstart.sh
|
||||
|
||||
# This installs:
|
||||
# This sets up:
|
||||
# - framework package (core runtime)
|
||||
# - aden_tools package (19 MCP tools)
|
||||
# - All dependencies
|
||||
# - aden_tools package (MCP tools)
|
||||
# - All Python dependencies
|
||||
|
||||
# Build new agents using Claude Code skills
|
||||
claude> /building-agents-construction
|
||||
@@ -373,11 +358,11 @@ Yes, Aden fully supports human-in-the-loop workflows through intervention nodes
|
||||
|
||||
**Q: What monitoring and debugging tools does Aden provide?**
|
||||
|
||||
Aden includes comprehensive observability features: real-time WebSocket streaming for live agent execution monitoring, TimescaleDB-powered analytics for cost and performance metrics, health check endpoints for Kubernetes integration, and 19 MCP tools for budget management, agent status, and policy control.
|
||||
Aden includes comprehensive observability features: real-time WebSocket streaming for live agent execution monitoring, TimescaleDB-powered analytics for cost and performance metrics, health check endpoints for Kubernetes integration, and MCP tools for agent execution, including file operations, web search, data processing, and more.
|
||||
|
||||
**Q: What programming languages does Aden support?**
|
||||
|
||||
Aden provides SDKs for both Python and JavaScript/TypeScript. The Python SDK includes integration templates for LangGraph, LangFlow, and LiveKit. The backend is Node.js/TypeScript, and the frontend is React/TypeScript.
|
||||
The Hive framework is built in Python. A JavaScript/TypeScript SDK is on the roadmap.
|
||||
|
||||
**Q: Can Aden agents interact with external tools and APIs?**
|
||||
|
||||
|
||||
+189
-40
@@ -3,19 +3,92 @@
|
||||
Aden Agent Framework aims to help developers build outcome oriented, self-adaptive agents. Please find our roadmap here
|
||||
|
||||
```mermaid
|
||||
timeline
|
||||
title Aden Agent Framework Roadmap
|
||||
section Foundation
|
||||
Architecture : Node-Based Architecture : Python SDK : LLM Integration (OpenAI, Anthropic, Google) : Communication Protocol
|
||||
Coding Agent : Goal Creation Session : Worker Agent Creation : MCP Tools Integration
|
||||
Worker Agent : Human-in-the-Loop : Callback Handlers : Intervention Points : Streaming Interface
|
||||
Tools : File Use : Memory (STM/LTM) : Web Search : Web Scraper : Audit Trail
|
||||
Core : Eval System : Pydantic Validation : Docker Deployment : Documentation : Sample Agents
|
||||
section Expansion
|
||||
Intelligence : Guardrails : Streaming Mode : Semantic Search
|
||||
Platform : JavaScript SDK : Custom Tool Integrator : Credential Store
|
||||
Deployment : Self-Hosted : Cloud Services : CI/CD Pipeline
|
||||
Templates : Sales Agent : Marketing Agent : Analytics Agent : Training Agent : Smart Form Agent
|
||||
flowchart TD
|
||||
subgraph Foundation
|
||||
direction LR
|
||||
subgraph arch["Architecture"]
|
||||
a1["Node-Based Architecture"]:::done
|
||||
a2["Python SDK"]:::done
|
||||
a3["LLM Integration"]:::done
|
||||
a4["Communication Protocol"]:::done
|
||||
end
|
||||
subgraph ca["Coding Agent"]
|
||||
b1["Goal Creation Session"]:::done
|
||||
b2["Worker Agent Creation"]
|
||||
b3["MCP Tools"]:::done
|
||||
end
|
||||
subgraph wa["Worker Agent"]
|
||||
c1["Human-in-the-Loop"]:::done
|
||||
c2["Callback Handlers"]:::done
|
||||
c3["Intervention Points"]:::done
|
||||
c4["Streaming Interface"]
|
||||
end
|
||||
subgraph cred["Credentials"]
|
||||
d1["Setup Process"]:::done
|
||||
d2["Pluggable Sources"]:::done
|
||||
d3["Enterprise Secrets"]
|
||||
d4["Integration Tools"]:::done
|
||||
end
|
||||
subgraph tools["Tools"]
|
||||
e1["File Use"]:::done
|
||||
e2["Memory STM/LTM"]:::done
|
||||
e3["Web Search/Scraper"]:::done
|
||||
e4["CSV/PDF"]:::done
|
||||
e5["Excel/Email"]
|
||||
end
|
||||
subgraph core["Core"]
|
||||
f1["Eval System"]
|
||||
f2["Pydantic Validation"]:::done
|
||||
f3["Documentation"]:::done
|
||||
f4["Adaptiveness"]
|
||||
f5["Sample Agents"]
|
||||
end
|
||||
end
|
||||
|
||||
subgraph Expansion
|
||||
direction LR
|
||||
subgraph intel["Intelligence"]
|
||||
g1["Guardrails"]
|
||||
g2["Streaming Mode"]
|
||||
g3["Image Generation"]
|
||||
g4["Semantic Search"]
|
||||
end
|
||||
subgraph mem["Memory Iteration"]
|
||||
h1["Message Model & Sessions"]
|
||||
h2["Storage Migration"]
|
||||
h3["Context Building"]
|
||||
h4["Proactive Compaction"]
|
||||
h5["Token Tracking"]
|
||||
end
|
||||
subgraph evt["Event System"]
|
||||
i1["Event Bus for Nodes"]
|
||||
end
|
||||
subgraph cas["Coding Agent Support"]
|
||||
j1["Claude Code"]
|
||||
j2["Cursor"]
|
||||
j3["Opencode"]
|
||||
j4["Antigravity"]
|
||||
end
|
||||
subgraph plat["Platform"]
|
||||
k1["JavaScript/TypeScript SDK"]
|
||||
k2["Custom Tool Integrator"]
|
||||
k3["Windows Support"]
|
||||
end
|
||||
subgraph dep["Deployment"]
|
||||
l1["Self-Hosted"]
|
||||
l2["Cloud Services"]
|
||||
l3["CI/CD Pipeline"]
|
||||
end
|
||||
subgraph tmpl["Templates"]
|
||||
m1["Sales Agent"]
|
||||
m2["Marketing Agent"]
|
||||
m3["Analytics Agent"]
|
||||
m4["Training Agent"]
|
||||
m5["Smart Form Agent"]
|
||||
end
|
||||
end
|
||||
|
||||
classDef done fill:#9e9e9e,color:#fff,stroke:#757575
|
||||
```
|
||||
|
||||
---
|
||||
@@ -26,19 +99,19 @@ timeline
|
||||
- [ ] **Node-Based Architecture (Agent as a node)**
|
||||
- [x] Object schema definition
|
||||
- [x] Node wrapper SDK
|
||||
- [ ] Shared memory access
|
||||
- [x] Shared memory access
|
||||
- [ ] Default monitoring hooks
|
||||
- [ ] Tool access layer
|
||||
- [x] Tool access layer
|
||||
- [x] LLM integration layer (Natively supports all mainstream LLMs through LiteLLM)
|
||||
- [x] Anthropic
|
||||
- [x] OpenAI
|
||||
- [x] Google
|
||||
- [ ] **Communication protocol between nodes**
|
||||
- [ ] **[Coding Agent] Goal Creation Session** (separate from coding session)
|
||||
- [ ] Instruction back and forth
|
||||
- [x] **Communication protocol between nodes**
|
||||
- [x] **[Coding Agent] Goal Creation Session** (separate from coding session)
|
||||
- [x] Instruction back and forth
|
||||
- [x] Goal Object schema definition
|
||||
- [ ] Being able to generate the test cases
|
||||
- [ ] Test case validation for worker agent (Outcome driven)
|
||||
- [x] Being able to generate the test cases
|
||||
- [x] Test case validation for worker agent (Outcome driven)
|
||||
- [ ] **[Coding Agent] Worker Agent Creation**
|
||||
- [x] Coding Agent tools
|
||||
- [ ] Use Template Agent as a start
|
||||
@@ -46,21 +119,62 @@ timeline
|
||||
- [ ] **[Worker Agent] Human-in-the-Loop**
|
||||
- [x] Worker Agents request with questions and options
|
||||
- [x] Callback Handler System to receive events throughout execution
|
||||
- [ ] Tool-Based Intervention Points (tool to pause execution and request human input)
|
||||
- [x] Tool-Based Intervention Points (tool to pause execution and request human input)
|
||||
- [x] Multiple entrypoint for different event source (e.g. Human input, webhook)
|
||||
- [ ] Streaming Interface for Real-time Monitoring
|
||||
- [ ] Request State Management
|
||||
- [x] Request State Management
|
||||
|
||||
### Credential Management
|
||||
- [x] **Credentials Setup Process**
|
||||
- [x] Install Credential MCP
|
||||
- [x] **Pluggable Credential Sources**
|
||||
- [x] **Abstraction & Local Sources**
|
||||
- [x] Introduce `CredentialSource` base class
|
||||
- [x] Refactor existing logic into `EnvVarSource`
|
||||
- [x] Implementation of Source Priority Chain mechanism
|
||||
- [ ] Foundation unit tests
|
||||
- [ ] **Enterprise Secret Managers**
|
||||
- [x] `VaultSource` (HashiCorp Vault)
|
||||
- [ ] `AWSSecretsSource` (AWS Secrets Manager)
|
||||
- [ ] `AzureKeyVaultSource` (Azure Key Vault)
|
||||
- [ ] Management of optional provider dependencies
|
||||
- [ ] **Advanced Features**
|
||||
- [x] Credential expiration and auto-refresh
|
||||
- [ ] Audit logging for compliance/tracking
|
||||
- [ ] Per-environment configuration support
|
||||
- [ ] **Documentation & DX**
|
||||
- [ ] Comprehensive source documentation
|
||||
- [ ] Example configurations for all providers
|
||||
- [x] **Integration as tools coverage**
|
||||
- [x] Gsuite Tools
|
||||
- [x] Social Media
|
||||
- [ ] Twitter(X)
|
||||
- [x] Github
|
||||
- [ ] Instagram
|
||||
- [ ] SAAS
|
||||
- [ ] Hubspot
|
||||
- [ ] Slack
|
||||
- [ ] Teams
|
||||
- [ ] Zoom
|
||||
- [ ] Stripe
|
||||
- [ ] Salesforce
|
||||
|
||||
> [!IMPORTANT]
|
||||
> **Community Contribution Wanted**: We appreciate help from the community to expand the "Integration as tools" capability. Leave an issue of the integration you want to support via Hive!
|
||||
|
||||
### Essential Tools
|
||||
- [x] **File Use Tool Kit**
|
||||
- [ ] **Memory Tools**
|
||||
- [X] **Memory Tools**
|
||||
- [x] STM Layer Tool (state-based short-term memory)
|
||||
- [x] LTM Layer Tool (RLM - long-term memory)
|
||||
- [ ] **Infrastructure Tools**
|
||||
- [x] Runtime Log Tool (logs for coding agent)
|
||||
- [ ] Audit Trail Tool (decision timeline generation)
|
||||
- [ ] Web Search
|
||||
- [ ] Web Scraper
|
||||
- [x] Web Search
|
||||
- [x] Web Scraper
|
||||
- [x] CSV tools
|
||||
- [x] PDF tools
|
||||
- [ ] Excel tools
|
||||
- [ ] Email Tools
|
||||
- [ ] Recipe for "Add your own tools"
|
||||
|
||||
### Memory & File System
|
||||
@@ -75,20 +189,25 @@ timeline
|
||||
- [ ] User-driven log analysis (OSS approach)
|
||||
|
||||
### Data Validation
|
||||
- [ ] Natively Support data validation of LLMs output with Pydantic
|
||||
- [x] Natively Support data validation of LLMs output with Pydantic
|
||||
|
||||
### Developer Experience
|
||||
- [ ] **Debugging mode**
|
||||
- [ ] **Documentation**
|
||||
- [ ] Quick start guide
|
||||
- [ ] Goal creation guide
|
||||
- [ ] Agent creation guide
|
||||
- [ ] GitHub Page setup
|
||||
- [ ] README with examples
|
||||
- [ ] Contributing guidelines
|
||||
- [ ] **Distribution**
|
||||
- [ ] PyPI package
|
||||
- [ ] Docker image on Docker Hub
|
||||
- [ ] **MVP Features**
|
||||
- [ ] Debugging mode
|
||||
- [ ] CLI tools for memory management
|
||||
- [ ] CLI tools for credential management
|
||||
- [ ] **MVP Resources & Documentation**
|
||||
- [x] Quick start guide
|
||||
- [x] Goal creation guide
|
||||
- [x] Agent creation guide
|
||||
- [x] GitHub Page setup
|
||||
- [x] README with examples
|
||||
- [x] Contributing guidelines
|
||||
- [ ] Introduction Video
|
||||
|
||||
### Adaptiveness
|
||||
- [ ] Runtime data feedback loop
|
||||
- [ ] Instant Developer Feedback for improvement
|
||||
|
||||
### Sample Agents
|
||||
- [ ] Knowledge Agent
|
||||
@@ -106,9 +225,35 @@ timeline
|
||||
|
||||
### Agent Capability
|
||||
- [ ] Streaming mode support
|
||||
- [ ] Image Generation support
|
||||
- [ ] Take end user input Image and flatfile understand capability
|
||||
|
||||
### Cross-Platform
|
||||
- [ ] JavaScript / TypeScript Version SDK
|
||||
### Event-loop For Nodes (Opencode-style)
|
||||
- [ ] **Event bus**
|
||||
|
||||
### Memory System Iteration
|
||||
- [ ] **Message Model & Session Management**
|
||||
- [ ] Introduce `Message` class with structured content types
|
||||
- [ ] Implement `Session` classes for conversation state
|
||||
- [ ] **Storage Migration**
|
||||
- [ ] Implement granular per-message file persistence (`/message/[agentID]/...`)
|
||||
- [ ] Migrate from monolithic run storage
|
||||
- [ ] **Context Building & Conversation Loop**
|
||||
- [ ] Implement `Message.stream(sessionID)`
|
||||
- [ ] Update `LLMNode.execute()` for full context building
|
||||
- [ ] Implement `Message.toModelMessages()` conversion
|
||||
- [ ] **Proactive Compaction**
|
||||
- [ ] Implement proactive overflow detection
|
||||
- [ ] Develop backward-scanning pruning strategy (e.g., clearing old tool outputs)
|
||||
- [ ] **Enhanced Token Tracking**
|
||||
- [ ] Extend `LLMResponse` to track reasoning and cache tokens
|
||||
- [ ] Integrate granular token metrics into compaction logic
|
||||
|
||||
### Coding Agent Support
|
||||
- [ ] Claude Code
|
||||
- [ ] Cursor
|
||||
- [ ] Opencode
|
||||
- [ ] Antigravity
|
||||
|
||||
### File System Enhancement
|
||||
- [ ] Semantic Search integration
|
||||
@@ -148,3 +293,7 @@ timeline
|
||||
- [ ] Analytics Agent
|
||||
- [ ] Training Agent
|
||||
- [ ] Smart Entry / Form Agent (self-evolution emphasis)
|
||||
|
||||
### Cross-Platform
|
||||
- [ ] JavaScript / TypeScript Version SDK
|
||||
- [ ] Better windows support
|
||||
|
||||
+1
-1
@@ -145,7 +145,7 @@ python -m framework test-debug <agent_path> <test_name>
|
||||
python -m framework test-list <goal_id>
|
||||
```
|
||||
|
||||
For detailed testing workflows, see the [testing-agent skill](.claude/skills/testing-agent/SKILL.md).
|
||||
For detailed testing workflows, see the [testing-agent skill](../.claude/skills/testing-agent/SKILL.md).
|
||||
|
||||
### Analyzing Agent Behavior with Builder
|
||||
|
||||
|
||||
@@ -99,10 +99,10 @@ async def example_4_custom_agent_with_mcp_tools():
|
||||
"""Example 4: Build custom agent that uses MCP tools"""
|
||||
print("\n=== Example 4: Custom Agent with MCP Tools ===\n")
|
||||
|
||||
from framework.builder.workflow import WorkflowBuilder
|
||||
from framework.builder.workflow import GraphBuilder
|
||||
|
||||
# Create a workflow builder
|
||||
builder = WorkflowBuilder()
|
||||
builder = GraphBuilder()
|
||||
|
||||
# Define goal
|
||||
builder.set_goal(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Allow running as python -m framework"""
|
||||
"""Allow running as ``python -m framework``, which powers the ``hive`` console entry point."""
|
||||
|
||||
from framework.cli import main
|
||||
|
||||
|
||||
+47
-12
@@ -1,27 +1,62 @@
|
||||
"""
|
||||
Command-line interface for Goal Agent.
|
||||
Command-line interface for Aden Hive.
|
||||
|
||||
Usage:
|
||||
python -m core run exports/my-agent --input '{"key": "value"}'
|
||||
python -m core info exports/my-agent
|
||||
python -m core validate exports/my-agent
|
||||
python -m core list exports/
|
||||
python -m core dispatch exports/ --input '{"key": "value"}'
|
||||
python -m core shell exports/my-agent
|
||||
hive run exports/my-agent --input '{"key": "value"}'
|
||||
hive info exports/my-agent
|
||||
hive validate exports/my-agent
|
||||
hive list exports/
|
||||
hive dispatch exports/ --input '{"key": "value"}'
|
||||
hive shell exports/my-agent
|
||||
|
||||
Testing commands:
|
||||
python -m core test-run <agent_path> --goal <goal_id>
|
||||
python -m core test-debug <goal_id> <test_id>
|
||||
python -m core test-list <goal_id>
|
||||
python -m core test-stats <goal_id>
|
||||
hive test-run <agent_path> --goal <goal_id>
|
||||
hive test-debug <goal_id> <test_id>
|
||||
hive test-list <goal_id>
|
||||
hive test-stats <goal_id>
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def _configure_paths():
|
||||
"""Auto-configure sys.path so agents in exports/ are discoverable.
|
||||
|
||||
Resolves the project root by walking up from this file (framework/cli.py lives
|
||||
inside core/framework/) or from CWD, then adds the exports/ directory to sys.path
|
||||
if it exists. This eliminates the need for manual PYTHONPATH configuration.
|
||||
"""
|
||||
# Strategy 1: resolve relative to this file (works when installed via pip install -e core/)
|
||||
framework_dir = Path(__file__).resolve().parent # core/framework/
|
||||
core_dir = framework_dir.parent # core/
|
||||
project_root = core_dir.parent # project root
|
||||
|
||||
# Strategy 2: if project_root doesn't look right, fall back to CWD
|
||||
if not (project_root / "exports").is_dir() and not (project_root / "core").is_dir():
|
||||
project_root = Path.cwd()
|
||||
|
||||
# Add exports/ to sys.path so agents are importable as top-level packages
|
||||
exports_dir = project_root / "exports"
|
||||
if exports_dir.is_dir():
|
||||
exports_str = str(exports_dir)
|
||||
if exports_str not in sys.path:
|
||||
sys.path.insert(0, exports_str)
|
||||
|
||||
# Ensure core/ is also in sys.path (for non-editable-install scenarios)
|
||||
core_str = str(project_root / "core")
|
||||
if (project_root / "core").is_dir() and core_str not in sys.path:
|
||||
sys.path.insert(0, core_str)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Goal Agent - Build and run goal-driven agents")
|
||||
_configure_paths()
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="hive",
|
||||
description="Aden Hive - Build and run goal-driven agents",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--model",
|
||||
default="claude-haiku-4-5-20251001",
|
||||
|
||||
@@ -175,8 +175,8 @@ class AdenIntegrationInfo:
|
||||
|
||||
return cls(
|
||||
integration_id=data["integration_id"],
|
||||
integration_type=data["integration_type"],
|
||||
status=data["status"],
|
||||
integration_type=data.get("provider", data["integration_id"]),
|
||||
status=data.get("status", "unknown"),
|
||||
expires_at=expires_at,
|
||||
)
|
||||
|
||||
|
||||
@@ -612,3 +612,97 @@ class CredentialStore:
|
||||
providers=providers,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def with_aden_sync(
|
||||
cls,
|
||||
base_url: str = "https://hive.adenhq.com",
|
||||
cache_ttl_seconds: int = 300,
|
||||
local_path: str | None = None,
|
||||
auto_sync: bool = True,
|
||||
**kwargs: Any,
|
||||
) -> CredentialStore:
|
||||
"""
|
||||
Create a credential store with Aden server sync.
|
||||
|
||||
Automatically syncs OAuth2 tokens from the Aden authentication server.
|
||||
Falls back to local-only storage if ADEN_API_KEY is not set or Aden
|
||||
is unreachable.
|
||||
|
||||
Args:
|
||||
base_url: Aden server URL (default: https://hive.adenhq.com)
|
||||
cache_ttl_seconds: How long to cache credentials locally (default: 5 min)
|
||||
local_path: Path for local credential storage (default: ~/.hive/credentials)
|
||||
auto_sync: Whether to sync all credentials on startup (default: True)
|
||||
**kwargs: Additional arguments passed to CredentialStore
|
||||
|
||||
Returns:
|
||||
CredentialStore configured with Aden sync
|
||||
|
||||
Example:
|
||||
# Simple usage - just set ADEN_API_KEY env var
|
||||
store = CredentialStore.with_aden_sync()
|
||||
|
||||
# Get HubSpot token (auto-refreshed via Aden)
|
||||
token = store.get_key("hubspot", "access_token")
|
||||
"""
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from .storage import EncryptedFileStorage
|
||||
|
||||
# Determine local storage path
|
||||
if local_path is None:
|
||||
local_path = str(Path.home() / ".hive" / "credentials")
|
||||
|
||||
local_storage = EncryptedFileStorage(base_path=local_path)
|
||||
|
||||
# Check if Aden is configured
|
||||
api_key = os.environ.get("ADEN_API_KEY")
|
||||
if not api_key:
|
||||
logger.info("ADEN_API_KEY not set, using local-only credential storage")
|
||||
return cls(storage=local_storage, **kwargs)
|
||||
|
||||
# Try to setup Aden sync
|
||||
try:
|
||||
from .aden import (
|
||||
AdenCachedStorage,
|
||||
AdenClientConfig,
|
||||
AdenCredentialClient,
|
||||
AdenSyncProvider,
|
||||
)
|
||||
|
||||
# Create Aden client
|
||||
client = AdenCredentialClient(AdenClientConfig(base_url=base_url))
|
||||
|
||||
# Create sync provider
|
||||
provider = AdenSyncProvider(client=client)
|
||||
|
||||
# Use cached storage for offline resilience
|
||||
cached_storage = AdenCachedStorage(
|
||||
local_storage=local_storage,
|
||||
aden_provider=provider,
|
||||
cache_ttl_seconds=cache_ttl_seconds,
|
||||
)
|
||||
|
||||
store = cls(
|
||||
storage=cached_storage,
|
||||
providers=[provider],
|
||||
auto_refresh=True,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
# Initial sync
|
||||
if auto_sync:
|
||||
synced = provider.sync_all(store)
|
||||
logger.info(f"Synced {synced} credentials from Aden server")
|
||||
|
||||
return store
|
||||
|
||||
except ImportError:
|
||||
logger.warning("Aden components not available, using local storage")
|
||||
return cls(storage=local_storage, **kwargs)
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to setup Aden sync: {e}. Using local storage.")
|
||||
return cls(storage=local_storage, **kwargs)
|
||||
|
||||
@@ -240,7 +240,7 @@ class OutputCleaner:
|
||||
for key, value in output.items():
|
||||
if isinstance(value, str):
|
||||
repaired = _heuristic_repair(value)
|
||||
if repaired and isinstance(repaired, dict | list):
|
||||
if repaired and isinstance(repaired, (dict, list)):
|
||||
# Check if this repaired structure looks like what we want
|
||||
# e.g. if the key is 'data' and the string contained valid JSON
|
||||
fixed_output[key] = repaired
|
||||
|
||||
@@ -932,7 +932,10 @@ def _select_agent(agents_dir: Path) -> str | None:
|
||||
"""Let user select an agent from available agents."""
|
||||
if not agents_dir.exists():
|
||||
print(f"Directory not found: {agents_dir}", file=sys.stderr)
|
||||
return None
|
||||
# fixes issue #696, creates an exports folder if it does not exist
|
||||
agents_dir.mkdir(parents=True, exist_ok=True)
|
||||
print(f"Created directory: {agents_dir}", file=sys.stderr)
|
||||
# return None
|
||||
|
||||
agents = []
|
||||
for path in agents_dir.iterdir():
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""Agent Runner - loads and runs exported agents."""
|
||||
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass, field
|
||||
@@ -23,6 +24,9 @@ if TYPE_CHECKING:
|
||||
from framework.runner.protocol import AgentMessage, CapabilityResponse
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclass
|
||||
class AgentInfo:
|
||||
"""Information about an exported agent."""
|
||||
@@ -388,9 +392,9 @@ class AgentRunner:
|
||||
self._tool_registry.register_mcp_server(server_config)
|
||||
except Exception as e:
|
||||
server_name = server_config.get("name", "unknown")
|
||||
print(f"Warning: Failed to register MCP server '{server_name}': {e}")
|
||||
logger.warning(f"Failed to register MCP server '{server_name}': {e}")
|
||||
except Exception as e:
|
||||
print(f"Warning: Failed to load MCP servers config from {config_path}: {e}")
|
||||
logger.warning(f"Failed to load MCP servers config from {config_path}: {e}")
|
||||
|
||||
def set_approval_callback(self, callback: Callable) -> None:
|
||||
"""
|
||||
@@ -433,8 +437,8 @@ class AgentRunner:
|
||||
|
||||
self._llm = LiteLLMProvider(model=self.model)
|
||||
elif api_key_env:
|
||||
print(f"Warning: {api_key_env} not set. LLM calls will fail.")
|
||||
print(f"Set it with: export {api_key_env}=your-api-key")
|
||||
logger.warning(f"{api_key_env} not set. LLM calls will fail.")
|
||||
logger.warning(f"Set it with: export {api_key_env}=your-api-key")
|
||||
|
||||
# Get tools for executor/runtime
|
||||
tools = list(self._tool_registry.get_tools().values())
|
||||
|
||||
@@ -86,13 +86,13 @@ class FileStorage:
|
||||
"""Save a run to storage."""
|
||||
# Save full run using Pydantic's model_dump_json
|
||||
run_path = self.base_path / "runs" / f"{run.id}.json"
|
||||
with open(run_path, "w") as f:
|
||||
with open(run_path, "w", encoding="utf-8") as f:
|
||||
f.write(run.model_dump_json(indent=2))
|
||||
|
||||
# Save summary
|
||||
summary = RunSummary.from_run(run)
|
||||
summary_path = self.base_path / "summaries" / f"{run.id}.json"
|
||||
with open(summary_path, "w") as f:
|
||||
with open(summary_path, "w", encoding="utf-8") as f:
|
||||
f.write(summary.model_dump_json(indent=2))
|
||||
|
||||
# Update indexes
|
||||
@@ -106,7 +106,7 @@ class FileStorage:
|
||||
run_path = self.base_path / "runs" / f"{run_id}.json"
|
||||
if not run_path.exists():
|
||||
return None
|
||||
with open(run_path) as f:
|
||||
with open(run_path, encoding="utf-8") as f:
|
||||
return Run.model_validate_json(f.read())
|
||||
|
||||
def load_summary(self, run_id: str) -> RunSummary | None:
|
||||
@@ -119,7 +119,7 @@ class FileStorage:
|
||||
return RunSummary.from_run(run)
|
||||
return None
|
||||
|
||||
with open(summary_path) as f:
|
||||
with open(summary_path, encoding="utf-8") as f:
|
||||
return RunSummary.model_validate_json(f.read())
|
||||
|
||||
def delete_run(self, run_id: str) -> bool:
|
||||
@@ -178,7 +178,7 @@ class FileStorage:
|
||||
index_path = self.base_path / "indexes" / index_type / f"{key}.json"
|
||||
if not index_path.exists():
|
||||
return []
|
||||
with open(index_path) as f:
|
||||
with open(index_path, encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
|
||||
def _add_to_index(self, index_type: str, key: str, value: str) -> None:
|
||||
@@ -188,7 +188,7 @@ class FileStorage:
|
||||
values = self._get_index(index_type, key) # Already validated in _get_index
|
||||
if value not in values:
|
||||
values.append(value)
|
||||
with open(index_path, "w") as f:
|
||||
with open(index_path, "w", encoding="utf-8") as f:
|
||||
json.dump(values, f)
|
||||
|
||||
def _remove_from_index(self, index_type: str, key: str, value: str) -> None:
|
||||
@@ -198,7 +198,7 @@ class FileStorage:
|
||||
values = self._get_index(index_type, key) # Already validated in _get_index
|
||||
if value in values:
|
||||
values.remove(value)
|
||||
with open(index_path, "w") as f:
|
||||
with open(index_path, "w", encoding="utf-8") as f:
|
||||
json.dump(values, f)
|
||||
|
||||
# === UTILITY ===
|
||||
|
||||
@@ -65,7 +65,7 @@ class TestStorage:
|
||||
|
||||
# Save full test
|
||||
test_path = goal_dir / f"{test.id}.json"
|
||||
with open(test_path, "w") as f:
|
||||
with open(test_path, "w", encoding="utf-8") as f:
|
||||
f.write(test.model_dump_json(indent=2))
|
||||
|
||||
# Update indexes
|
||||
@@ -79,7 +79,7 @@ class TestStorage:
|
||||
test_path = self.base_path / "tests" / goal_id / f"{test_id}.json"
|
||||
if not test_path.exists():
|
||||
return None
|
||||
with open(test_path) as f:
|
||||
with open(test_path, encoding="utf-8") as f:
|
||||
return Test.model_validate_json(f.read())
|
||||
|
||||
def delete_test(self, goal_id: str, test_id: str) -> bool:
|
||||
@@ -175,12 +175,12 @@ class TestStorage:
|
||||
# Save with timestamp
|
||||
timestamp = result.timestamp.strftime("%Y%m%d_%H%M%S")
|
||||
result_path = results_dir / f"{timestamp}.json"
|
||||
with open(result_path, "w") as f:
|
||||
with open(result_path, "w", encoding="utf-8") as f:
|
||||
f.write(result.model_dump_json(indent=2))
|
||||
|
||||
# Update latest
|
||||
latest_path = results_dir / "latest.json"
|
||||
with open(latest_path, "w") as f:
|
||||
with open(latest_path, "w", encoding="utf-8") as f:
|
||||
f.write(result.model_dump_json(indent=2))
|
||||
|
||||
def get_latest_result(self, test_id: str) -> TestResult | None:
|
||||
@@ -188,7 +188,7 @@ class TestStorage:
|
||||
latest_path = self.base_path / "results" / test_id / "latest.json"
|
||||
if not latest_path.exists():
|
||||
return None
|
||||
with open(latest_path) as f:
|
||||
with open(latest_path, encoding="utf-8") as f:
|
||||
return TestResult.model_validate_json(f.read())
|
||||
|
||||
def get_result_history(self, test_id: str, limit: int = 10) -> list[TestResult]:
|
||||
@@ -204,7 +204,7 @@ class TestStorage:
|
||||
|
||||
results = []
|
||||
for f in result_files:
|
||||
with open(f) as file:
|
||||
with open(f, encoding="utf-8") as file:
|
||||
results.append(TestResult.model_validate_json(file.read()))
|
||||
|
||||
return results
|
||||
@@ -216,7 +216,7 @@ class TestStorage:
|
||||
index_path = self.base_path / "indexes" / index_type / f"{key}.json"
|
||||
if not index_path.exists():
|
||||
return []
|
||||
with open(index_path) as f:
|
||||
with open(index_path, encoding="utf-8") as f:
|
||||
return json.load(f)
|
||||
|
||||
def _add_to_index(self, index_type: str, key: str, value: str) -> None:
|
||||
@@ -225,7 +225,7 @@ class TestStorage:
|
||||
values = self._get_index(index_type, key)
|
||||
if value not in values:
|
||||
values.append(value)
|
||||
with open(index_path, "w") as f:
|
||||
with open(index_path, "w", encoding="utf-8") as f:
|
||||
json.dump(values, f)
|
||||
|
||||
def _remove_from_index(self, index_type: str, key: str, value: str) -> None:
|
||||
@@ -234,7 +234,7 @@ class TestStorage:
|
||||
values = self._get_index(index_type, key)
|
||||
if value in values:
|
||||
values.remove(value)
|
||||
with open(index_path, "w") as f:
|
||||
with open(index_path, "w", encoding="utf-8") as f:
|
||||
json.dump(values, f)
|
||||
|
||||
# === UTILITY ===
|
||||
|
||||
+25
-23
@@ -5,22 +5,21 @@ description = "Goal-driven agent runtime with Builder-friendly observability"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
"pydantic>=2.0",
|
||||
"anthropic>=0.40.0",
|
||||
"httpx>=0.27.0",
|
||||
"litellm>=1.81.0",
|
||||
"mcp>=1.0.0",
|
||||
"fastmcp>=2.0.0",
|
||||
"pytest>=8.0",
|
||||
"pytest-asyncio>=0.23",
|
||||
"pytest-xdist>=3.0",
|
||||
"pydantic>=2.0",
|
||||
"anthropic>=0.40.0",
|
||||
"httpx>=0.27.0",
|
||||
"litellm>=1.81.0",
|
||||
"mcp>=1.0.0",
|
||||
"fastmcp>=2.0.0",
|
||||
"pytest>=8.0",
|
||||
"pytest-asyncio>=0.23",
|
||||
"pytest-xdist>=3.0",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
dev = [
|
||||
"ruff>=0.1.0",
|
||||
"mypy>=1.0",
|
||||
]
|
||||
# [project.optional-dependencies]
|
||||
|
||||
[project.scripts]
|
||||
hive = "framework.cli:main"
|
||||
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
@@ -34,14 +33,14 @@ target-version = "py311"
|
||||
line-length = 100
|
||||
|
||||
lint.select = [
|
||||
"B", # bugbear errors
|
||||
"C4", # flake8-comprehensions errors
|
||||
"E", # pycodestyle errors
|
||||
"F", # pyflakes errors
|
||||
"I", # import sorting
|
||||
"Q", # flake8-quotes errors
|
||||
"UP", # py-upgrade
|
||||
"W", # pycodestyle warnings
|
||||
"B", # bugbear errors
|
||||
"C4", # flake8-comprehensions errors
|
||||
"E", # pycodestyle errors
|
||||
"F", # pyflakes errors
|
||||
"I", # import sorting
|
||||
"Q", # flake8-quotes errors
|
||||
"UP", # py-upgrade
|
||||
"W", # pycodestyle warnings
|
||||
]
|
||||
|
||||
lint.isort.combine-as-imports = true
|
||||
@@ -52,4 +51,7 @@ lint.isort.section-order = [
|
||||
"third-party",
|
||||
"first-party",
|
||||
"local-folder",
|
||||
]
|
||||
]
|
||||
|
||||
[dependency-groups]
|
||||
dev = ["ty>=0.0.13", "ruff>=0.14.14"]
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
"""Tests for the hive CLI entry point and path auto-configuration."""
|
||||
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from framework.cli import _configure_paths
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def project_root():
|
||||
"""Return the project root directory."""
|
||||
return Path(__file__).resolve().parent.parent.parent
|
||||
|
||||
|
||||
class TestConfigurePaths:
|
||||
"""Test _configure_paths auto-discovers exports/ and core/."""
|
||||
|
||||
def test_adds_exports_to_sys_path(self, project_root):
|
||||
exports_dir = project_root / "exports"
|
||||
if not exports_dir.is_dir():
|
||||
pytest.skip("exports/ directory does not exist in this environment")
|
||||
|
||||
exports_str = str(exports_dir)
|
||||
# Remove if already present to test fresh addition
|
||||
original_path = sys.path.copy()
|
||||
sys.path = [p for p in sys.path if p != exports_str]
|
||||
|
||||
try:
|
||||
_configure_paths()
|
||||
assert exports_str in sys.path
|
||||
finally:
|
||||
sys.path = original_path
|
||||
|
||||
def test_adds_core_to_sys_path(self, project_root):
|
||||
core_dir = project_root / "core"
|
||||
core_str = str(core_dir)
|
||||
original_path = sys.path.copy()
|
||||
sys.path = [p for p in sys.path if p != core_str]
|
||||
|
||||
try:
|
||||
_configure_paths()
|
||||
assert core_str in sys.path
|
||||
finally:
|
||||
sys.path = original_path
|
||||
|
||||
def test_does_not_duplicate_paths(self):
|
||||
_configure_paths()
|
||||
# Call twice — should not create duplicates
|
||||
before = sys.path.copy()
|
||||
_configure_paths()
|
||||
assert sys.path == before
|
||||
|
||||
def test_handles_missing_exports_gracefully(self):
|
||||
"""If exports/ doesn't exist, _configure_paths should not crash."""
|
||||
_configure_paths()
|
||||
|
||||
|
||||
class TestFrameworkModule:
|
||||
"""Test ``python -m framework`` invocation (the underlying module)."""
|
||||
|
||||
def test_module_help(self, project_root):
|
||||
"""Verify ``python -m framework --help`` prints usage."""
|
||||
result = subprocess.run(
|
||||
[sys.executable, "-m", "framework", "--help"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
cwd=str(project_root / "core"),
|
||||
)
|
||||
assert result.returncode == 0
|
||||
assert "hive" in result.stdout.lower() or "goal" in result.stdout.lower()
|
||||
|
||||
def test_module_list_subcommand(self, project_root):
|
||||
"""Verify ``python -m framework list --help`` registers the subcommand."""
|
||||
result = subprocess.run(
|
||||
[sys.executable, "-m", "framework", "list", "--help"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
cwd=str(project_root / "core"),
|
||||
)
|
||||
assert result.returncode == 0
|
||||
assert "agents" in result.stdout.lower() or "directory" in result.stdout.lower()
|
||||
|
||||
|
||||
class TestHiveEntryPoint:
|
||||
"""Test the ``hive`` console_scripts entry point.
|
||||
|
||||
These tests verify the actual ``hive`` command installed by
|
||||
``pip install -e core/``. If the entry point is not installed,
|
||||
the tests are skipped gracefully.
|
||||
"""
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _require_hive(self):
|
||||
if shutil.which("hive") is None:
|
||||
pytest.skip("'hive' entry point not installed (run: pip install -e core/)")
|
||||
|
||||
def test_hive_help(self):
|
||||
"""Verify ``hive --help`` exits 0 and prints usage."""
|
||||
result = subprocess.run(
|
||||
["hive", "--help"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
assert result.returncode == 0
|
||||
assert "run" in result.stdout.lower()
|
||||
assert "validate" in result.stdout.lower()
|
||||
|
||||
def test_hive_list_help(self):
|
||||
"""Verify ``hive list --help`` exits 0."""
|
||||
result = subprocess.run(
|
||||
["hive", "list", "--help"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
assert result.returncode == 0
|
||||
|
||||
def test_hive_run_missing_agent(self):
|
||||
"""Verify ``hive run`` with a non-existent agent prints an error."""
|
||||
result = subprocess.run(
|
||||
["hive", "run", "nonexistent_agent_xyz"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
assert result.returncode != 0
|
||||
+167
-145
@@ -1,168 +1,190 @@
|
||||
# Configuration Guide
|
||||
|
||||
Hive uses a centralized configuration system based on a single `config.yaml` file. This makes it easy to configure the entire application from one place.
|
||||
Aden Hive is a Python-based agent framework. Configuration is handled through environment variables and agent-level config files. There is no centralized `config.yaml` or Docker Compose setup.
|
||||
|
||||
## Configuration Flow
|
||||
## Configuration Overview
|
||||
|
||||
```
|
||||
config.yaml --> generate-env.ts --> .env files
|
||||
├── .env (root)
|
||||
├── honeycomb/.env (frontend)
|
||||
└── hive/.env (backend)
|
||||
Environment variables (API keys, runtime flags)
|
||||
Agent config.py (per-agent settings: model, tools, storage)
|
||||
pyproject.toml (package metadata and dependencies)
|
||||
.mcp.json (MCP server connections)
|
||||
```
|
||||
|
||||
## Getting Started
|
||||
## Environment Variables
|
||||
|
||||
1. Copy the example configuration:
|
||||
```bash
|
||||
cp config.yaml.example config.yaml
|
||||
```
|
||||
|
||||
2. Edit `config.yaml` with your settings
|
||||
|
||||
3. Generate environment files:
|
||||
```bash
|
||||
npm run generate:env
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### Application Settings
|
||||
|
||||
```yaml
|
||||
app:
|
||||
# Application name - displayed in UI and logs
|
||||
name: Hive
|
||||
|
||||
# Environment mode
|
||||
# - development: enables debug features, verbose logging
|
||||
# - production: optimized for performance, minimal logging
|
||||
# - test: for running tests
|
||||
environment: development
|
||||
|
||||
# Log level: debug, info, warn, error
|
||||
log_level: info
|
||||
```
|
||||
|
||||
### Server Configuration
|
||||
|
||||
```yaml
|
||||
server:
|
||||
frontend:
|
||||
# Port for the React frontend
|
||||
port: 3000
|
||||
|
||||
backend:
|
||||
# Port for the Node.js API
|
||||
port: 4000
|
||||
|
||||
# Host to bind (0.0.0.0 = all interfaces)
|
||||
host: 0.0.0.0
|
||||
```
|
||||
|
||||
### Database Configuration
|
||||
|
||||
```yaml
|
||||
database:
|
||||
# PostgreSQL connection URL
|
||||
url: postgresql://user:password@localhost:5432/hive
|
||||
|
||||
# For SQLite (local development)
|
||||
# url: sqlite:./data/hive.db
|
||||
```
|
||||
|
||||
**Connection URL Format:**
|
||||
```
|
||||
postgresql://[user]:[password]@[host]:[port]/[database]
|
||||
```
|
||||
|
||||
### Authentication
|
||||
|
||||
```yaml
|
||||
auth:
|
||||
# JWT secret key for signing tokens
|
||||
# IMPORTANT: Change this in production!
|
||||
# Generate with: openssl rand -base64 32
|
||||
jwt_secret: your-secret-key
|
||||
|
||||
# Token expiration time
|
||||
# Examples: 1h, 7d, 30d
|
||||
jwt_expires_in: 7d
|
||||
```
|
||||
|
||||
### CORS Configuration
|
||||
|
||||
```yaml
|
||||
cors:
|
||||
# Allowed origin for cross-origin requests
|
||||
# Set to your frontend URL in production
|
||||
origin: http://localhost:3000
|
||||
```
|
||||
|
||||
### Feature Flags
|
||||
|
||||
```yaml
|
||||
features:
|
||||
# Enable/disable user registration
|
||||
registration: true
|
||||
|
||||
# Enable API rate limiting
|
||||
rate_limiting: false
|
||||
|
||||
# Enable request logging
|
||||
request_logging: true
|
||||
```
|
||||
|
||||
## Environment-Specific Configuration
|
||||
|
||||
You can create environment-specific config files:
|
||||
|
||||
- `config.yaml` - Your main configuration (git-ignored)
|
||||
- `config.yaml.example` - Template with safe defaults (committed)
|
||||
|
||||
For different environments, you might want separate files:
|
||||
### LLM Providers (at least one required for real execution)
|
||||
|
||||
```bash
|
||||
# Development
|
||||
cp config.yaml.example config.yaml
|
||||
# Edit for development settings
|
||||
# Anthropic (primary provider)
|
||||
export ANTHROPIC_API_KEY="sk-ant-..."
|
||||
|
||||
# Production
|
||||
cp config.yaml.example config.production.yaml
|
||||
# Edit for production settings
|
||||
# OpenAI (optional, for GPT models via LiteLLM)
|
||||
export OPENAI_API_KEY="sk-..."
|
||||
|
||||
# Cerebras (optional, used by output cleaner and some nodes)
|
||||
export CEREBRAS_API_KEY="..."
|
||||
|
||||
# Groq (optional, fast inference)
|
||||
export GROQ_API_KEY="..."
|
||||
```
|
||||
|
||||
The framework supports 100+ LLM providers through [LiteLLM](https://docs.litellm.ai/docs/providers). Set the corresponding environment variable for your provider.
|
||||
|
||||
### Search & Tools (optional)
|
||||
|
||||
```bash
|
||||
# Web search for agents (Brave Search)
|
||||
export BRAVE_SEARCH_API_KEY="..."
|
||||
|
||||
# Exa Search (alternative web search)
|
||||
export EXA_API_KEY="..."
|
||||
```
|
||||
|
||||
### Runtime Flags
|
||||
|
||||
```bash
|
||||
# Run agents without LLM calls (structure-only validation)
|
||||
export MOCK_MODE=1
|
||||
|
||||
# Custom credentials storage path (default: ~/.aden/credentials)
|
||||
export ADEN_CREDENTIALS_PATH="/custom/path"
|
||||
|
||||
# Custom agent storage path (default: /tmp)
|
||||
export AGENT_STORAGE_PATH="/custom/storage"
|
||||
```
|
||||
|
||||
## Agent Configuration
|
||||
|
||||
Each agent package in `exports/` contains its own `config.py`:
|
||||
|
||||
```python
|
||||
# exports/my_agent/config.py
|
||||
CONFIG = {
|
||||
"model": "claude-haiku-4-5-20251001", # Default LLM model
|
||||
"max_tokens": 4096,
|
||||
"temperature": 0.7,
|
||||
"tools": ["web_search", "pdf_read"], # MCP tools to enable
|
||||
"storage_path": "/tmp/my_agent", # Runtime data location
|
||||
}
|
||||
```
|
||||
|
||||
### Agent Graph Specification
|
||||
|
||||
Agent behavior is defined in `agent.json` (or constructed in `agent.py`):
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "my_agent",
|
||||
"name": "My Agent",
|
||||
"goal": {
|
||||
"success_criteria": [...],
|
||||
"constraints": [...]
|
||||
},
|
||||
"nodes": [...],
|
||||
"edges": [...]
|
||||
}
|
||||
```
|
||||
|
||||
See the [Getting Started Guide](getting-started.md) for building agents.
|
||||
|
||||
## MCP Server Configuration
|
||||
|
||||
MCP (Model Context Protocol) servers are configured in `.mcp.json` at the project root:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"agent-builder": {
|
||||
"command": "core/.venv/bin/python",
|
||||
"args": ["-m", "framework.mcp.agent_builder_server"],
|
||||
"cwd": "."
|
||||
},
|
||||
"tools": {
|
||||
"command": "tools/.venv/bin/python",
|
||||
"args": ["-m", "aden_tools.mcp_server", "--stdio"],
|
||||
"cwd": "."
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The tools MCP server exposes tools including web search, PDF reading, CSV processing, and file system operations.
|
||||
|
||||
## Storage
|
||||
|
||||
Aden Hive uses **file-based persistence** (no database required):
|
||||
|
||||
```
|
||||
{storage_path}/
|
||||
runs/{run_id}.json # Complete execution traces
|
||||
indexes/
|
||||
by_goal/{goal_id}.json # Runs indexed by goal
|
||||
by_status/{status}.json # Runs indexed by status
|
||||
by_node/{node_id}.json # Runs indexed by node
|
||||
summaries/{run_id}.json # Quick-load run summaries
|
||||
```
|
||||
|
||||
Storage is managed by `framework.storage.FileStorage`. No external database setup is needed.
|
||||
|
||||
## IDE Setup
|
||||
|
||||
### VS Code
|
||||
|
||||
Add to `.vscode/settings.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"python.analysis.extraPaths": [
|
||||
"${workspaceFolder}/core",
|
||||
"${workspaceFolder}/exports"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### PyCharm
|
||||
|
||||
1. Open Project Settings > Project Structure
|
||||
2. Mark `core` as Sources Root
|
||||
3. Mark `exports` as Sources Root
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
1. **Never commit `config.yaml`** - It may contain secrets
|
||||
2. **Use strong JWT secrets** - Generate with `openssl rand -base64 32`
|
||||
3. **Restrict CORS in production** - Set to your exact frontend URL
|
||||
4. **Use environment variables for CI/CD** - Override config in deployments
|
||||
|
||||
## Updating Configuration
|
||||
|
||||
After changing `config.yaml`:
|
||||
|
||||
```bash
|
||||
# Regenerate .env files
|
||||
npm run generate:env
|
||||
```
|
||||
1. **Never commit API keys** - Use environment variables or `.env` files
|
||||
2. **`.env` is git-ignored** - Copy `.env.example` to `.env` at the project root and fill in your values
|
||||
3. **Mock mode for testing** - Set `MOCK_MODE=1` to avoid LLM calls during development
|
||||
4. **Credential isolation** - Each tool validates its own credentials at runtime
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Changes Not Taking Effect
|
||||
### "ModuleNotFoundError: No module named 'framework'"
|
||||
|
||||
1. Ensure you ran `npm run generate:env`
|
||||
2. Restart the services
|
||||
3. Check if the correct `.env` file is being loaded
|
||||
Install the core package:
|
||||
|
||||
### Configuration Validation Errors
|
||||
```bash
|
||||
cd core && pip install -e .
|
||||
```
|
||||
|
||||
The backend validates configuration on startup. Check logs for specific errors.
|
||||
### API key not found
|
||||
|
||||
### Missing Environment Variables
|
||||
Ensure the environment variable is set in your current shell session:
|
||||
|
||||
If a required variable is missing, add it to:
|
||||
1. `config.yaml.example` (with safe default)
|
||||
2. `config.yaml` (with your value)
|
||||
3. `scripts/generate-env.ts` (to generate it)
|
||||
```bash
|
||||
echo $ANTHROPIC_API_KEY # Should print your key
|
||||
```
|
||||
|
||||
On Windows PowerShell:
|
||||
|
||||
```powershell
|
||||
$env:ANTHROPIC_API_KEY = "sk-ant-..."
|
||||
```
|
||||
|
||||
### Agent not found
|
||||
|
||||
Run from the project root with PYTHONPATH:
|
||||
|
||||
```bash
|
||||
PYTHONPATH=core:exports python -m my_agent validate
|
||||
```
|
||||
|
||||
See [Environment Setup](../ENVIRONMENT_SETUP.md) for detailed installation instructions.
|
||||
|
||||
+15
-11
@@ -18,10 +18,10 @@ The fastest way to get started:
|
||||
git clone https://github.com/adenhq/hive.git
|
||||
cd hive
|
||||
|
||||
# 2. Run automated Python setup
|
||||
./scripts/setup-python.sh
|
||||
# 2. Run automated setup
|
||||
./quickstart.sh
|
||||
|
||||
# 3. Verify installation
|
||||
# 3. Verify installation (optional, quickstart.sh already verifies)
|
||||
python -c "import framework; import aden_tools; print('✓ Setup complete')"
|
||||
```
|
||||
|
||||
@@ -30,8 +30,7 @@ python -c "import framework; import aden_tools; print('✓ Setup complete')"
|
||||
### Option 1: Using Claude Code Skills (Recommended)
|
||||
|
||||
```bash
|
||||
# Install Claude Code skills (one-time)
|
||||
./quickstart.sh
|
||||
# Setup already done via quickstart.sh above
|
||||
|
||||
# Start Claude Code and build an agent
|
||||
claude> /building-agents-construction
|
||||
@@ -79,15 +78,20 @@ This demonstrates the core runtime loop using pure Python functions, skipping th
|
||||
hive/
|
||||
├── core/ # Core Framework
|
||||
│ ├── framework/ # Agent runtime, graph executor
|
||||
│ │ ├── runner/ # AgentRunner - loads and runs agents
|
||||
│ │ ├── executor/ # GraphExecutor - executes node graphs
|
||||
│ │ ├── protocols/ # Standard protocols (hooks, tracing)
|
||||
│ │ ├── builder/ # Agent builder utilities
|
||||
│ │ ├── credentials/ # Credential management
|
||||
│ │ ├── graph/ # GraphExecutor - executes node graphs
|
||||
│ │ ├── llm/ # LLM provider integrations
|
||||
│ │ └── memory/ # Memory systems (STM, LTM/RLM)
|
||||
│ │ ├── mcp/ # MCP server integration
|
||||
│ │ ├── runner/ # AgentRunner - loads and runs agents
|
||||
│ │ ├── runtime/ # Runtime environment
|
||||
│ │ ├── schemas/ # Data schemas
|
||||
│ │ ├── storage/ # File-based persistence
|
||||
│ │ └── testing/ # Testing utilities
|
||||
│ └── pyproject.toml # Package metadata
|
||||
│
|
||||
├── tools/ # MCP Tools Package
|
||||
│ └── src/aden_tools/ # 19 tools for agent capabilities
|
||||
│ └── src/aden_tools/ # Tools for agent capabilities
|
||||
│ ├── tools/ # Individual tool implementations
|
||||
│ │ ├── web_search_tool/
|
||||
│ │ ├── web_scrape_tool/
|
||||
@@ -197,7 +201,7 @@ PYTHONPATH=core:exports python -m my_agent run --mock --input '{...}'
|
||||
```bash
|
||||
# Remove and reinstall
|
||||
pip uninstall -y framework tools
|
||||
./scripts/setup-python.sh
|
||||
./quickstart.sh
|
||||
```
|
||||
|
||||
## Getting Help
|
||||
|
||||
+4
-4
@@ -30,7 +30,7 @@
|
||||
<img src="https://img.shields.io/badge/OpenAI-supported-412991?style=flat-square&logo=openai" alt="OpenAI" />
|
||||
<img src="https://img.shields.io/badge/Anthropic-supported-d4a574?style=flat-square" alt="Anthropic" />
|
||||
<img src="https://img.shields.io/badge/Google_Gemini-supported-4285F4?style=flat-square&logo=google" alt="Gemini" />
|
||||
<img src="https://img.shields.io/badge/MCP-19_Tools-00ADD8?style=flat-square" alt="MCP" />
|
||||
<img src="https://img.shields.io/badge/MCP-Tools-00ADD8?style=flat-square" alt="MCP" />
|
||||
</p>
|
||||
|
||||
## Descripción General
|
||||
@@ -76,7 +76,7 @@ git clone https://github.com/adenhq/hive.git
|
||||
cd hive
|
||||
|
||||
# Ejecutar configuración del entorno Python
|
||||
./scripts/setup-python.sh
|
||||
./quickstart.sh
|
||||
```
|
||||
|
||||
Esto instala:
|
||||
@@ -229,7 +229,7 @@ Para construir y ejecutar agentes orientados a objetivos con el framework:
|
||||
|
||||
```bash
|
||||
# Configuración única
|
||||
./scripts/setup-python.sh
|
||||
./quickstart.sh
|
||||
|
||||
# Esto instala:
|
||||
# - paquete framework (runtime principal)
|
||||
@@ -253,7 +253,7 @@ Consulta [ENVIRONMENT_SETUP.md](ENVIRONMENT_SETUP.md) para instrucciones de conf
|
||||
- **[Guía del Desarrollador](DEVELOPER.md)** - Guía completa para desarrolladores
|
||||
- [Primeros Pasos](docs/getting-started.md) - Instrucciones de configuración rápida
|
||||
- [Guía de Configuración](docs/configuration.md) - Todas las opciones de configuración
|
||||
- [Visión General de Arquitectura](docs/architecture.md) - Diseño y estructura del sistema
|
||||
- [Visión General de Arquitectura](docs/architecture/README.md) - Diseño y estructura del sistema
|
||||
|
||||
## Hoja de Ruta
|
||||
|
||||
|
||||
+356
@@ -0,0 +1,356 @@
|
||||
<p align="center">
|
||||
<img width="100%" alt="Hive Banner" src="https://storage.googleapis.com/aden-prod-assets/website/aden-title-card.png" />
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="../../README.md">English</a> |
|
||||
<a href="zh-CN.md">简体中文</a> |
|
||||
<a href="es.md">Español</a> |
|
||||
<a href="pt.md">Português</a> |
|
||||
<a href="ja.md">日本語</a> |
|
||||
<a href="ru.md">Русский</a> |
|
||||
<a href="ko.md">한국어</a>
|
||||
<a href="hi.md">हिंदी</a>
|
||||
</p>
|
||||
|
||||
[](https://github.com/adenhq/hive/blob/main/LICENSE)
|
||||
[](https://www.ycombinator.com/companies/aden)
|
||||
[](https://hub.docker.com/u/adenhq)
|
||||
[](https://discord.com/invite/MXE49hrKDk)
|
||||
[](https://x.com/aden_hq)
|
||||
[](https://www.linkedin.com/company/teamaden/)
|
||||
|
||||
<p align="center">
|
||||
<img src="https://img.shields.io/badge/AI_Agents-Self--Improving-brightgreen?style=flat-square" alt="AI Agents" />
|
||||
<img src="https://img.shields.io/badge/Multi--Agent-Systems-blue?style=flat-square" alt="Multi-Agent" />
|
||||
<img src="https://img.shields.io/badge/Goal--Driven-Development-purple?style=flat-square" alt="Goal-Driven" />
|
||||
<img src="https://img.shields.io/badge/Human--in--the--Loop-orange?style=flat-square" alt="HITL" />
|
||||
<img src="https://img.shields.io/badge/Production--Ready-red?style=flat-square" alt="Production" />
|
||||
</p>
|
||||
<p align="center">
|
||||
<img src="https://img.shields.io/badge/OpenAI-supported-412991?style=flat-square&logo=openai" alt="OpenAI" />
|
||||
<img src="https://img.shields.io/badge/Anthropic-supported-d4a574?style=flat-square" alt="Anthropic" />
|
||||
<img src="https://img.shields.io/badge/Google_Gemini-supported-4285F4?style=flat-square&logo=google" alt="Gemini" />
|
||||
<img src="https://img.shields.io/badge/MCP-19_Tools-00ADD8?style=flat-square" alt="MCP" />
|
||||
</p>
|
||||
|
||||
# अवलोकन (Overview)
|
||||
|
||||
वर्कफ़्लो को हार्डकोड किए बिना भरोसेमंद और स्वयं-सुधार करने वाले AI एजेंट बनाएँ।
|
||||
आप एक कोडिंग एजेंट के साथ बातचीत के माध्यम से अपना लक्ष्य परिभाषित करते हैं, और फ़्रेमवर्क डायनेमिक रूप से बनाए गए कनेक्शन कोड के साथ एक नोड ग्राफ़ उत्पन्न करता है। जब कुछ विफल होता है, फ़्रेमवर्क उस त्रुटि का डेटा कैप्चर करता है, कोडिंग एजेंट के माध्यम से एजेंट को विकसित करता है और उसे दोबारा डिप्लॉय करता है। एकीकृत human-in-the-loop नोड्स, क्रेडेंशियल प्रबंधन और रीयल-टाइम मॉनिटरिंग आपको अनुकूलनशीलता खोए बिना पूरा नियंत्रण देते हैं।
|
||||
|
||||
पूर्ण दस्तावेज़ीकरण, उदाहरणों और मार्गदर्शिकाओं के लिए adenhq.com पर जाएँ।
|
||||
|
||||
# Aden क्या है?
|
||||
|
||||
<p align="center">
|
||||
<img width="100%" alt="Aden Architecture" src="docs/assets/aden-architecture-diagram.jpg" />
|
||||
</p>
|
||||
|
||||
Aden एक ऐसा प्लेटफ़ॉर्म है जो AI एजेंट्स को बनाने, डिप्लॉय करने, ऑपरेट करने और अनुकूलित करने के लिए उपयोग होता है:
|
||||
|
||||
- **निर्माण (Build)** – एक कोडिंग एजेंट प्राकृतिक भाषा के लक्ष्यों से विशेष वर्कर एजेंट्स (Sales, Marketing, Operations) उत्पन्न करता है
|
||||
|
||||
- **डिप्लॉय (Deploy)** – CI/CD इंटीग्रेशन के साथ हेडलेस डिप्लॉयमेंट और API के पूरे लाइफ़साइकल का प्रबंधन
|
||||
|
||||
- **ऑपरेट (Operate)** – रीयल-टाइम मॉनिटरिंग, ऑब्ज़र्वेबिलिटी और रनटाइम गार्डरेल्स एजेंट्स को भरोसेमंद बनाए रखते हैं
|
||||
|
||||
- **अनुकूलन (Adapt)** – निरंतर मूल्यांकन, सुपरविज़न और अनुकूलन यह सुनिश्चित करते हैं कि एजेंट समय के साथ बेहतर होते जाएँ
|
||||
|
||||
- **इन्फ़्रास्ट्रक्चर (Infrastructure)** – साझा मेमोरी, LLM इंटीग्रेशन, टूल्स और स्किल्स हर एजेंट को शक्ति प्रदान करते हैं
|
||||
|
||||
# त्वरित लिंक (Quick Links)
|
||||
|
||||
- **[डाक्यूमेंटेशन](https://docs.adenhq.com/)** - पूर्ण गाइड्स और API संदर्भ
|
||||
- **[सेल्फ-होस्टिंग गाइड](https://docs.adenhq.com/getting-started/quickstart)** -
|
||||
Hive को अपने इंफ़्रास्ट्रक्चर पर डिप्लॉय करें
|
||||
- **[चेंजलॉग](https://github.com/adenhq/hive/releases)** - नवीनतम अपडेट और रिलीज़
|
||||
<!-- - **[Hoja de Ruta](https://adenhq.com/roadmap)** - Funciones y planes próximos -->
|
||||
- **[इशू रिपोर्ट करें](https://github.com/adenhq/hive/issues)** - बग रिपोर्ट और फ़ीचर अनुरोध
|
||||
|
||||
## त्वरित शुरुआत
|
||||
|
||||
### आवश्यकताएँ
|
||||
|
||||
- [Python 3.11+](https://www.python.org/downloads/) - एजेंट विकास के लिए
|
||||
- [Docker](https://docs.docker.com/get-docker/) (v20.10+) -कंटेनराइज़्ड टूल्स के लिए वैकल्पिक
|
||||
|
||||
### इंस्टॉलेशन
|
||||
|
||||
```bash
|
||||
# रिपॉज़िटरी क्लोन करें
|
||||
git clone https://github.com/adenhq/hive.git
|
||||
cd hive
|
||||
|
||||
# Python वातावरण कॉन्फ़िगरेशन चलाएँ
|
||||
./scripts/setup-python.sh
|
||||
```
|
||||
|
||||
यह इंस्टॉल करता है:
|
||||
- **framework** - मुख्य एजेंट रनटाइम और ग्राफ़ एक्ज़ीक्यूटर
|
||||
- **aden_tools** - एजेंट क्षमताओं के लिए 19 MCP टूल्स
|
||||
- सभी आवश्यक डिपेंडेंसीज़
|
||||
|
||||
### अपना पहला एजेंट बनाएँ
|
||||
|
||||
```bash
|
||||
Claude Code की क्षमताएँ इंस्टॉल करें (एक बार)
|
||||
./quickstart.sh
|
||||
|
||||
# Claude Code का उपयोग करके एक एजेंट बनाएँ
|
||||
claude> /building-agents-construction
|
||||
|
||||
# अपने एजेंट का परीक्षण करें
|
||||
claude> /testing-agent
|
||||
|
||||
# अपने एजेंट को चलाएँ
|
||||
PYTHONPATH=core:exports python -m your_agent_name run --input '{...}'
|
||||
```
|
||||
|
||||
**[📖 पूर्ण कॉन्फ़िगरेशन गाइड](ENVIRONMENT_SETUP.md)** - एजेंट विकास के लिए विस्तृत निर्देश
|
||||
|
||||
## विशेषताएँ
|
||||
|
||||
- **लक्ष्य-आधारित विकास** -प्राकृतिक भाषा में लक्ष्य परिभाषित करें; कोडिंग एजेंट उन्हें हासिल करने के लिए एजेंट ग्राफ़ और कनेक्शन कोड उत्पन्न करता है
|
||||
- **स्वयं-अनुकूल एजेंट्स** - फ़्रेमवर्क विफलताओं को कैप्चर करता है, उद्देश्यों को अपडेट करता है और एजेंट ग्राफ़ को अद्यतन करता है
|
||||
- **डायनेमिक नोड कनेक्शन** - पूर्व-परिभाषित किनारों के बिना; आपके लक्ष्यों के आधार पर कनेक्शन कोड किसी भी सक्षम LLM द्वारा उत्पन्न किया जाता है
|
||||
- **SDK-रैप्ड नोड्स** - प्रत्येक नोड को साझा मेमोरी, स्थानीय RLM मेमोरी, मॉनिटरिंग, टूल्स और LLM एक्सेस डिफ़ॉल्ट रूप से मिलता है
|
||||
- **मानव-इन-द-लूप** - मानव हस्तक्षेप नोड्स जो मानव इनपुट के लिए निष्पादन को रोकते हैं, और जिनमें कॉन्फ़िगर किए जा सकने वाले टाइमआउट और एस्केलेशन होते हैं
|
||||
- **रीयल-टाइम ऑब्ज़र्वेबिलिटी** - एजेंट निष्पादन, निर्णयों और नोड्स के बीच संचार की लाइव मॉनिटरिंग के लिए WebSocket स्ट्रीमिंग
|
||||
- **लागत और बजट नियंत्रण** - खर्च की सीमाएँ, थ्रॉटल्स और मॉडल की स्वचालित डिग्रेडेशन नीतियाँ निर्धारित करें
|
||||
- **प्रोडक्शन के लिए तैयार** - स्वयं-होस्ट करने योग्य, और स्केल व विश्वसनीयता के लिए निर्मित
|
||||
|
||||
# Aden क्यों?
|
||||
|
||||
पारंपरिक एजेंट फ़्रेमवर्क्स में आपको वर्कफ़्लो मैन्युअली डिज़ाइन करने, एजेंट इंटरैक्शन्स परिभाषित करने और विफलताओं को प्रतिक्रियात्मक रूप से संभालने की आवश्यकता होती है। Aden इस पैरेडाइम को उलट देता है—**आप परिणामों का वर्णन करते हैं, और सिस्टम अपने-आप तैयार हो जाता है**.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph BUILD["🏗️ BUILD"]
|
||||
GOAL["Define Goal<br/>+ Success Criteria"] --> NODES["Add Nodes<br/>LLM/Router/Function"]
|
||||
NODES --> EDGES["Connect Edges<br/>on_success/failure/conditional"]
|
||||
EDGES --> TEST["Test & Validate"] --> APPROVE["Approve & Export"]
|
||||
end
|
||||
|
||||
subgraph EXPORT["📦 EXPORT"]
|
||||
direction TB
|
||||
JSON["agent.json<br/>(GraphSpec)"]
|
||||
TOOLS["tools.py<br/>(Functions)"]
|
||||
MCP["mcp_servers.json<br/>(Integrations)"]
|
||||
end
|
||||
|
||||
subgraph RUN["🚀 RUNTIME"]
|
||||
LOAD["AgentRunner<br/>Load + Parse"] --> SETUP["Setup Runtime<br/>+ ToolRegistry"]
|
||||
SETUP --> EXEC["GraphExecutor<br/>Execute Nodes"]
|
||||
|
||||
subgraph DECISION["Decision Recording"]
|
||||
DEC1["runtime.decide()<br/>intent → options → choice"]
|
||||
DEC2["runtime.record_outcome()<br/>success, result, metrics"]
|
||||
end
|
||||
end
|
||||
|
||||
subgraph INFRA["⚙️ INFRASTRUCTURE"]
|
||||
CTX["NodeContext<br/>memory • llm • tools"]
|
||||
STORE[("FileStorage<br/>Runs & Decisions")]
|
||||
end
|
||||
|
||||
APPROVE --> EXPORT
|
||||
EXPORT --> LOAD
|
||||
EXEC --> DECISION
|
||||
EXEC --> CTX
|
||||
DECISION --> STORE
|
||||
STORE -.->|"Analyze & Improve"| NODES
|
||||
|
||||
style BUILD fill:#ffbe42,stroke:#cc5d00,stroke-width:3px,color:#333
|
||||
style EXPORT fill:#fff59d,stroke:#ed8c00,stroke-width:2px,color:#333
|
||||
style RUN fill:#ffb100,stroke:#cc5d00,stroke-width:3px,color:#333
|
||||
style DECISION fill:#ffcc80,stroke:#ed8c00,stroke-width:2px,color:#333
|
||||
style INFRA fill:#e8763d,stroke:#cc5d00,stroke-width:3px,color:#fff
|
||||
style STORE fill:#ed8c00,stroke:#cc5d00,stroke-width:2px,color:#fff
|
||||
```
|
||||
|
||||
### Aden की बढ़त
|
||||
|
||||
| पारंपरिक फ़्रेमवर्क्स | Aden |
|
||||
|--------------------------|------|
|
||||
| एजेंट वर्कफ़्लो को हार्डकोड करना | प्राकृतिक भाषा में लक्ष्यों का वर्णन |
|
||||
| ग्राफ़ की मैन्युअल परिभाषा | स्वतः-उत्पन्न एजेंट ग्राफ़ |
|
||||
| त्रुटियों का प्रतिक्रियात्मक प्रबंधन | प्रॉएक्टिव स्वयं-विकास |
|
||||
| स्थिर टूल कॉन्फ़िगरेशन | SDK-रैप्ड डायनेमिक नोड्स |
|
||||
| अलग मॉनिटरिंग सेटअप | एकीकृत रीयल-टाइम ऑब्ज़र्वेबिलिटी |
|
||||
| DIY बजट प्रबंधन | एकीकृत लागत नियंत्रण और डिग्रेडेशन नीतियाँ |
|
||||
|
||||
### यह कैसे काम करता है
|
||||
|
||||
1. **अपना लक्ष्य परिभाषित करें** → सरल भाषा में बताएं कि आप क्या हासिल करना चाहते हैं
|
||||
2. **कोडिंग एजेंट उत्पन्न करता है** → एजेंट ग्राफ़, कनेक्शन कोड और टेस्ट केस तैयार करता है
|
||||
3. **वर्कर एजेंट्स निष्पादन करते हैं** → SDK-रैप्ड नोड्स पूर्ण ऑब्ज़र्वेबिलिटी और टूल्स तक पहुँच के साथ निष्पादित होते हैं
|
||||
4. **कंट्रोल प्लेन निगरानी करता है** → रीयल-टाइम मेट्रिक्स, बजट का प्रवर्तन और नीतियों का प्रबंधन
|
||||
5. **स्वयं-सुधार** → विफलता की स्थिति में, सिस्टम ग्राफ़ को विकसित करता है और उसे स्वचालित रूप से दोबारा डिप्लॉय करता है
|
||||
|
||||
## Aden की तुलना कैसे की जाती है
|
||||
|
||||
Aden एजेंट विकास के लिए एक मौलिक रूप से अलग दृष्टिकोण अपनाता है। जहाँ अधिकांश फ़्रेमवर्क्स आपसे वर्कफ़्लो को कोड करने या एजेंट ग्राफ़ को मैन्युअली परिभाषित करने की आवश्यकता रखते हैं, वहीं Aden एक **पूरे एजेंट सिस्टम को उत्पन्न करने के लिए एक कोडिंग एजेंट** प्राकृतिक भाषा में दिए गए लक्ष्यों से। जब एजेंट विफल होते हैं, तो फ़्रेमवर्क केवल त्रुटियाँ दर्ज नहीं करता—**एजेंट ग्राफ़ को स्वचालित रूप से विकसित करता है** और उसे दोबारा डिप्लॉय करता है.
|
||||
|
||||
> **नोट:** फ़्रेमवर्क्स की विस्तृत तुलना तालिका और अक्सर पूछे जाने वाले प्रश्नों के लिए, देखें [README.md](README.md) अंग्रेज़ी में.
|
||||
|
||||
### Aden कब चुनें
|
||||
|
||||
Aden तब चुनें जब आपको आवश्यकता हो:
|
||||
|
||||
- ऐसे एजेंट जो **विफलताओं से स्वयं-सुधार करने वाले** बिना मैन्युअल हस्तक्षेप के
|
||||
- **लक्ष्य-उन्मुख विकास** जहाँ आप वर्कफ़्लो नहीं, बल्कि परिणामों का वर्णन करते हैं
|
||||
- **प्रोडक्शन में विश्वसनीयता** स्वचालित रिकवरी और दोबारा डिप्लॉयमेंट के साथ
|
||||
- **तेज़ पुनरावृत्ति** कोड दोबारा लिखे बिना एजेंट आर्किटेक्चर में
|
||||
- **पूर्ण प्रेक्षणीयता** रीयल-टाइम निगरानी और मानवीय पर्यवेक्षण के साथ
|
||||
|
||||
ज़रूरत पड़ने पर अन्य फ़्रेमवर्क चुनें:
|
||||
|
||||
- **पूर्वानुमेय और टाइप-सुरक्षित वर्कफ़्लो** (PydanticAI, Mastra)
|
||||
- **RAG और दस्तावेज़ प्रसंस्करण** (LlamaIndex, Haystack)
|
||||
- **एजेंटों के उभरने पर शोध** (CAMEL)
|
||||
- **रीयल-टाइम वॉइस/मल्टीमॉडल** (TEN Framework)
|
||||
- **घटकों का सरल क्रमबद्ध संयोजन** (LangChain, Swarm)
|
||||
|
||||
## प्रोजेक्ट संरचना
|
||||
|
||||
```
|
||||
hive/
|
||||
├── core/ # मुख्य फ्रेमवर्क – एजेंट रनटाइम, ग्राफ़ एक्ज़ीक्यूटर, प्रोटोकॉल
|
||||
├── tools/ # MCP टूल्स पैकेज – एजेंट क्षमताओं के लिए 19 टूल
|
||||
├── exports/ # एजेंट पैकेज – पहले से बने एजेंट और उदाहरण
|
||||
├── docs/ # दस्तावेज़ और मार्गदर्शिकाएँ
|
||||
├── scripts/ # बिल्ड स्क्रिप्ट्स और यूटिलिटीज़
|
||||
├── .claude/ # एजेंट बनाने के लिए Claude Code क्षमताएँ
|
||||
├── ENVIRONMENT_SETUP.md # एजेंट डेवलपमेंट के लिए Python सेटअप गाइड
|
||||
├── DEVELOPER.md # डेवलपर गाइड
|
||||
├── CONTRIBUTING.md # योगदान दिशानिर्देश
|
||||
└── ROADMAP.md # प्रोडक्ट रोडमैप
|
||||
```
|
||||
|
||||
## विकास
|
||||
|
||||
### Python में एजेंट विकास
|
||||
|
||||
फ़्रेमवर्क के साथ लक्ष्य-उन्मुख एजेंट बनाने और चलाने के लिए:
|
||||
|
||||
```bash
|
||||
# एक-बार का कॉन्फ़िगरेशन
|
||||
./scripts/setup-python.sh
|
||||
|
||||
# यह इंस्टॉल करता है:
|
||||
# - फ्रेमवर्क पैकेज (मुख्य रनटाइम)
|
||||
# - aden_tools पैकेज (19 MCP टूल)
|
||||
# - सभी डिपेंडेंसीज़
|
||||
|
||||
# Claude Code क्षमताओं का उपयोग करके नए एजेंट बनाएं
|
||||
claude> /building-agents-construction
|
||||
|
||||
# एजेंट का परीक्षण करें
|
||||
claude> /testing-agent
|
||||
|
||||
# एजेंट चलाएँ
|
||||
PYTHONPATH=core:exports python -m agent_name run --input '{...}'
|
||||
```
|
||||
|
||||
पूरी कॉन्फ़िगरेशन निर्देशों के लिए ENVIRONMENT_SETUP.md देखें।
|
||||
|
||||
## दस्तावेज़ीकरण
|
||||
|
||||
- **[डेवलपर गाइड](DEVELOPER.md)** - डेवलपर्स के लिए पूर्ण मार्गदर्शिका
|
||||
- [शुरुआत करें](docs/getting-started.md) - त्वरित कॉन्फ़िगरेशन निर्देश
|
||||
- [कॉन्फ़िगरेशन गाइड](docs/configuration.md) - सभी कॉन्फ़िगरेशन विकल्प
|
||||
- [आर्किटेक्चर का अवलोकन](docs/architecture/README.md) - सिस्टम का डिज़ाइन और संरचना
|
||||
|
||||
## रोडमैप
|
||||
|
||||
एडेन एजेंट फ़्रेमवर्क का उद्देश्य डेवलपर्स को परिणाम-उन्मुख, स्वयं-अनुकूलित एजेंट बनाने में मदद करना है। हमारी रोडमैप यहाँ देखें।
|
||||
|
||||
[ROADMAP.md](ROADMAP.md)
|
||||
|
||||
```mermaid
|
||||
timeline
|
||||
title Aden Agent Framework Roadmap
|
||||
section Foundation
|
||||
Architecture : Node-Based Architecture : Python SDK : LLM Integration (OpenAI, Anthropic, Google) : Communication Protocol
|
||||
Coding Agent : Goal Creation Session : Worker Agent Creation : MCP Tools Integration
|
||||
Worker Agent : Human-in-the-Loop : Callback Handlers : Intervention Points : Streaming Interface
|
||||
Tools : File Use : Memory (STM/LTM) : Web Search : Web Scraper : Audit Trail
|
||||
Core : Eval System : Pydantic Validation : Docker Deployment : Documentation : Sample Agents
|
||||
section Expansion
|
||||
Intelligence : Guardrails : Streaming Mode : Semantic Search
|
||||
Platform : JavaScript SDK : Custom Tool Integrator : Credential Store
|
||||
Deployment : Self-Hosted : Cloud Services : CI/CD Pipeline
|
||||
Templates : Sales Agent : Marketing Agent : Analytics Agent : Training Agent : Smart Form Agent
|
||||
```
|
||||
|
||||
## समुदाय और सहायता
|
||||
|
||||
हम उपयोग करते हैं [Discord](https://discord.com/invite/MXE49hrKDk) सपोर्ट, फ़ीचर अनुरोधों और कम्युनिटी चर्चाओं के लिए।
|
||||
|
||||
- Discord - [हमारे समुदाय से जुड़ें](https://discord.com/invite/MXE49hrKDk)
|
||||
- Twitter/X - [@adenhq](https://x.com/aden_hq)
|
||||
- LinkedIn - [कंपनी पेज](https://www.linkedin.com/company/teamaden/)
|
||||
|
||||
## योगदान करें
|
||||
हम योगदान का स्वागत करते हैं! कृपया देखें [CONTRIBUTING.md] (CONTRIBUTING.md) दिशानिर्देशों के लिए.
|
||||
|
||||
**महत्वपूर्ण:**: कृपया PR भेजने से पहले किसी issue को अपने नाम असाइन करवाने का अनुरोध करें। उसे क्लेम करने के लिए issue पर टिप्पणी करें, और कोई मेंटेनर 24 घंटों के भीतर उसे आपको असाइन कर देगा। इससे डुप्लिकेट काम से बचाव होता है।
|
||||
|
||||
1. कोई issue खोजें या बनाएँ और असाइनमेंट का अनुरोध करें
|
||||
|
||||
2. रिपॉज़िटरी को fork करें
|
||||
|
||||
3. अपनी फीचर ब्रांच बनाएँ (git checkout -b feature/amazing-feature)
|
||||
|
||||
4. अपने बदलावों को commit करें (git commit -m 'Add amazing feature')
|
||||
|
||||
5. ब्रांच को push करें (git push origin feature/amazing-feature)
|
||||
|
||||
6. एक Pull Request खोलें
|
||||
|
||||
## हमारी टीम से जुड़ें
|
||||
|
||||
**हम भर्ती कर रहे हैं!** इंजीनियरिंग, रिसर्च और मार्केटिंग भूमिकाओं में हमारे साथ जुड़ें.
|
||||
|
||||
[खुली पदों को देखें](https://jobs.adenhq.com/a8cec478-cdbc-473c-bbd4-f4b7027ec193/applicant)
|
||||
|
||||
## सुरक्षा
|
||||
|
||||
सुरक्षा संबंधी चिंताओं के लिए, कृपया देखें [SECURITY.md](SECURITY.md).
|
||||
|
||||
## लाइसेंस
|
||||
|
||||
यह प्रोजेक्ट Apache 2.0 लाइसेंस के अंतर्गत लाइसेंस्ड है – फ़ाइल देखें [LICENSE](LICENSE)अधिक विवरण के लिए.
|
||||
|
||||
## अक्सर पूछे जाने वाले प्रश्न (FAQ)
|
||||
|
||||
> **नोट:** पूरी FAQ के लिए,[README.md](README.md) देखें.
|
||||
|
||||
**प्रश्न: क्या Aden, LangChain या अन्य एजेंट फ़्रेमवर्क पर निर्भर करता है?**
|
||||
|
||||
उत्तर: नहीं। Aden पूरी तरह से शून्य से बनाया गया है और यह LangChain, CrewAI या अन्य एजेंट फ़्रेमवर्क पर निर्भर नहीं है। यह फ्रेमवर्क हल्का और लचीला होने के लिए डिज़ाइन किया गया है, और यह पूर्वनिर्धारित घटकों पर निर्भर रहने के बजाय डायनेमिक रूप से एजेंट ग्राफ़ बनाता है।
|
||||
|
||||
**प्रश्न: Aden कौन-कौन से LLM प्रदाताओं को सपोर्ट करता है?**
|
||||
|
||||
उत्तर: Aden LiteLLM इंटीग्रेशन के माध्यम से 100 से अधिक LLM प्रदाताओं को सपोर्ट करता है, जिसमें OpenAI (GPT-4, GPT-4o), Anthropic (Claude मॉडल), Google Gemini, Mistral, Groq और कई अन्य शामिल हैं। बस संबंधित API कुंजी के लिए एनवायरनमेंट वेरिएबल सेट करें और मॉडल का नाम निर्दिष्ट करें।
|
||||
|
||||
**प्रश्न: क्या Aden ओपन-सोर्स है?**
|
||||
|
||||
उत्तर: हाँ, Aden पूरी तरह से ओपन-सोर्स है और यह Apache 2.0 लाइसेंस के तहत उपलब्ध है। हम समुदाय के योगदान और सहयोग को सक्रिय रूप से प्रोत्साहित करते हैं।
|
||||
|
||||
**प्रश्न: Aden को अन्य एजेंट फ़्रेमवर्क्स से अलग क्या बनाता है?**
|
||||
|
||||
उत्तर: Aden आपके एजेंट सिस्टम को प्राकृतिक भाषा में दिए गए लक्ष्यों से कोडिंग एजेंट के माध्यम से पूरी तरह उत्पन्न करता है—आपको वर्कफ़्लो को कोड करने या ग्राफ़ मैन्युअली डिफ़ाइन करने की आवश्यकता नहीं है। जब एजेंट फेल होते हैं, फ्रेमवर्क स्वचालित रूप से फेल होने वाले डेटा को कैप्चर करता है, एजेंट ग्राफ़ को विकसित करता है और उसे फिर से डिप्लॉय करता है। यह स्व-उन्नति चक्र Aden को अद्वितीय बनाता है।
|
||||
|
||||
**प्रश्न: क्या Aden ह्यूमन-इन-द-लूप वर्कफ़्लो को सपोर्ट करता है?**
|
||||
|
||||
उत्तर: हाँ, Aden ह्यूमन-इन-द-लूप वर्कफ़्लो को पूरी तरह सपोर्ट करता है। यह इंटरवेंशन नोड्स के माध्यम से संभव होता है, जो मानव इनपुट के लिए निष्पादन को रोकते हैं। इसमें कस्टमाइज़ेबल वेट टाइम्स और एस्केलेशन पॉलिसीज़ शामिल हैं, जिससे मानव विशेषज्ञ और AI एजेंट के बीच सहज सहयोग संभव होता है।
|
||||
|
||||
---
|
||||
|
||||
<p align="center">
|
||||
सैन फ्रांसिस्को में 🔥 जुनून के साथ बनाया गया
|
||||
</p>
|
||||
|
||||
|
||||
+4
-4
@@ -30,7 +30,7 @@
|
||||
<img src="https://img.shields.io/badge/OpenAI-supported-412991?style=flat-square&logo=openai" alt="OpenAI" />
|
||||
<img src="https://img.shields.io/badge/Anthropic-supported-d4a574?style=flat-square" alt="Anthropic" />
|
||||
<img src="https://img.shields.io/badge/Google_Gemini-supported-4285F4?style=flat-square&logo=google" alt="Gemini" />
|
||||
<img src="https://img.shields.io/badge/MCP-19_Tools-00ADD8?style=flat-square" alt="MCP" />
|
||||
<img src="https://img.shields.io/badge/MCP-Tools-00ADD8?style=flat-square" alt="MCP" />
|
||||
</p>
|
||||
|
||||
## 概要
|
||||
@@ -76,7 +76,7 @@ git clone https://github.com/adenhq/hive.git
|
||||
cd hive
|
||||
|
||||
# Python環境セットアップを実行
|
||||
./scripts/setup-python.sh
|
||||
./quickstart.sh
|
||||
```
|
||||
|
||||
これにより以下がインストールされます:
|
||||
@@ -229,7 +229,7 @@ hive/
|
||||
|
||||
```bash
|
||||
# 1回限りのセットアップ
|
||||
./scripts/setup-python.sh
|
||||
./quickstart.sh
|
||||
|
||||
# これにより以下がインストールされます:
|
||||
# - frameworkパッケージ(コアランタイム)
|
||||
@@ -253,7 +253,7 @@ PYTHONPATH=core:exports python -m agent_name run --input '{...}'
|
||||
- **[開発者ガイド](DEVELOPER.md)** - 開発者向け総合ガイド
|
||||
- [はじめに](docs/getting-started.md) - クイックセットアップ手順
|
||||
- [設定ガイド](docs/configuration.md) - すべての設定オプション
|
||||
- [アーキテクチャ概要](docs/architecture.md) - システム設計と構造
|
||||
- [アーキテクチャ概要](docs/architecture/README.md) - システム設計と構造
|
||||
|
||||
## ロードマップ
|
||||
|
||||
|
||||
+4
-4
@@ -30,7 +30,7 @@
|
||||
<img src="https://img.shields.io/badge/OpenAI-supported-412991?style=flat-square&logo=openai" alt="OpenAI" />
|
||||
<img src="https://img.shields.io/badge/Anthropic-supported-d4a574?style=flat-square" alt="Anthropic" />
|
||||
<img src="https://img.shields.io/badge/Google_Gemini-supported-4285F4?style=flat-square&logo=google" alt="Gemini" />
|
||||
<img src="https://img.shields.io/badge/MCP-19_Tools-00ADD8?style=flat-square" alt="MCP" />
|
||||
<img src="https://img.shields.io/badge/MCP-Tools-00ADD8?style=flat-square" alt="MCP" />
|
||||
</p>
|
||||
|
||||
## 개요
|
||||
@@ -76,7 +76,7 @@ git clone https://github.com/adenhq/hive.git
|
||||
cd hive
|
||||
|
||||
# Python 환경 설정 실행
|
||||
./scripts/setup-python.sh
|
||||
./quickstart.sh
|
||||
```
|
||||
|
||||
다음 요소들이 설치됩니다:
|
||||
@@ -240,7 +240,7 @@ hive/
|
||||
|
||||
```bash
|
||||
# 최초 1회 설정
|
||||
./scripts/setup-python.sh
|
||||
./quickstart.sh
|
||||
|
||||
# 다음 항목들이 설치됨:
|
||||
# - framework 패키지 (핵심 런타임)
|
||||
@@ -264,7 +264,7 @@ PYTHONPATH=core:exports python -m agent_name run --input '{...}'
|
||||
- **[개발자 가이드](DEVELOPER.md)** - 개발자를 위한 종합 가이드
|
||||
- [시작하기](docs/getting-started.md) - 빠른 설정 방법
|
||||
- [설정 가이드](docs/configuration.md) - 모든 설정 옵션 안내
|
||||
- [아키텍처 개요](docs/architecture.md) - 시스템 설계 및 구조
|
||||
- [아키텍처 개요](docs/architecture/README.md) - 시스템 설계 및 구조
|
||||
|
||||
## 로드맵
|
||||
|
||||
|
||||
+4
-4
@@ -30,7 +30,7 @@
|
||||
<img src="https://img.shields.io/badge/OpenAI-supported-412991?style=flat-square&logo=openai" alt="OpenAI" />
|
||||
<img src="https://img.shields.io/badge/Anthropic-supported-d4a574?style=flat-square" alt="Anthropic" />
|
||||
<img src="https://img.shields.io/badge/Google_Gemini-supported-4285F4?style=flat-square&logo=google" alt="Gemini" />
|
||||
<img src="https://img.shields.io/badge/MCP-19_Tools-00ADD8?style=flat-square" alt="MCP" />
|
||||
<img src="https://img.shields.io/badge/MCP-Tools-00ADD8?style=flat-square" alt="MCP" />
|
||||
</p>
|
||||
|
||||
## Visão Geral
|
||||
@@ -76,7 +76,7 @@ git clone https://github.com/adenhq/hive.git
|
||||
cd hive
|
||||
|
||||
# Executar configuração do ambiente Python
|
||||
./scripts/setup-python.sh
|
||||
./quickstart.sh
|
||||
```
|
||||
|
||||
Isto instala:
|
||||
@@ -229,7 +229,7 @@ Para construir e executar agentes orientados a objetivos com o framework:
|
||||
|
||||
```bash
|
||||
# Configuração única
|
||||
./scripts/setup-python.sh
|
||||
./quickstart.sh
|
||||
|
||||
# Isto instala:
|
||||
# - pacote framework (runtime principal)
|
||||
@@ -253,7 +253,7 @@ Consulte [ENVIRONMENT_SETUP.md](ENVIRONMENT_SETUP.md) para instruções completa
|
||||
- **[Guia do Desenvolvedor](DEVELOPER.md)** - Guia abrangente para desenvolvedores
|
||||
- [Começando](docs/getting-started.md) - Instruções de configuração rápida
|
||||
- [Guia de Configuração](docs/configuration.md) - Todas as opções de configuração
|
||||
- [Visão Geral da Arquitetura](docs/architecture.md) - Design e estrutura do sistema
|
||||
- [Visão Geral da Arquitetura](docs/architecture/README.md) - Design e estrutura do sistema
|
||||
|
||||
## Roadmap
|
||||
|
||||
|
||||
+4
-4
@@ -30,7 +30,7 @@
|
||||
<img src="https://img.shields.io/badge/OpenAI-supported-412991?style=flat-square&logo=openai" alt="OpenAI" />
|
||||
<img src="https://img.shields.io/badge/Anthropic-supported-d4a574?style=flat-square" alt="Anthropic" />
|
||||
<img src="https://img.shields.io/badge/Google_Gemini-supported-4285F4?style=flat-square&logo=google" alt="Gemini" />
|
||||
<img src="https://img.shields.io/badge/MCP-19_Tools-00ADD8?style=flat-square" alt="MCP" />
|
||||
<img src="https://img.shields.io/badge/MCP-Tools-00ADD8?style=flat-square" alt="MCP" />
|
||||
</p>
|
||||
|
||||
## Обзор
|
||||
@@ -76,7 +76,7 @@ git clone https://github.com/adenhq/hive.git
|
||||
cd hive
|
||||
|
||||
# Запустить настройку окружения Python
|
||||
./scripts/setup-python.sh
|
||||
./quickstart.sh
|
||||
```
|
||||
|
||||
Это установит:
|
||||
@@ -229,7 +229,7 @@ hive/
|
||||
|
||||
```bash
|
||||
# Одноразовая настройка
|
||||
./scripts/setup-python.sh
|
||||
./quickstart.sh
|
||||
|
||||
# Это установит:
|
||||
# - пакет framework (основная среда выполнения)
|
||||
@@ -253,7 +253,7 @@ PYTHONPATH=core:exports python -m agent_name run --input '{...}'
|
||||
- **[Руководство разработчика](DEVELOPER.md)** - Полное руководство для разработчиков
|
||||
- [Начало работы](docs/getting-started.md) - Инструкции по быстрой настройке
|
||||
- [Руководство по конфигурации](docs/configuration.md) - Все опции конфигурации
|
||||
- [Обзор архитектуры](docs/architecture.md) - Дизайн и структура системы
|
||||
- [Обзор архитектуры](docs/architecture/README.md) - Дизайн и структура системы
|
||||
|
||||
## Дорожная карта
|
||||
|
||||
|
||||
+4
-4
@@ -30,7 +30,7 @@
|
||||
<img src="https://img.shields.io/badge/OpenAI-supported-412991?style=flat-square&logo=openai" alt="OpenAI" />
|
||||
<img src="https://img.shields.io/badge/Anthropic-supported-d4a574?style=flat-square" alt="Anthropic" />
|
||||
<img src="https://img.shields.io/badge/Google_Gemini-supported-4285F4?style=flat-square&logo=google" alt="Gemini" />
|
||||
<img src="https://img.shields.io/badge/MCP-19_Tools-00ADD8?style=flat-square" alt="MCP" />
|
||||
<img src="https://img.shields.io/badge/MCP-Tools-00ADD8?style=flat-square" alt="MCP" />
|
||||
</p>
|
||||
|
||||
## 概述
|
||||
@@ -76,7 +76,7 @@ git clone https://github.com/adenhq/hive.git
|
||||
cd hive
|
||||
|
||||
# 运行 Python 环境设置
|
||||
./scripts/setup-python.sh
|
||||
./quickstart.sh
|
||||
```
|
||||
|
||||
这将安装:
|
||||
@@ -229,7 +229,7 @@ hive/
|
||||
|
||||
```bash
|
||||
# 一次性设置
|
||||
./scripts/setup-python.sh
|
||||
./quickstart.sh
|
||||
|
||||
# 这将安装:
|
||||
# - framework 包(核心运行时)
|
||||
@@ -253,7 +253,7 @@ PYTHONPATH=core:exports python -m agent_name run --input '{...}'
|
||||
- **[开发者指南](DEVELOPER.md)** - 开发者综合指南
|
||||
- [入门指南](docs/getting-started.md) - 快速设置说明
|
||||
- [配置指南](docs/configuration.md) - 所有配置选项
|
||||
- [架构概述](docs/architecture.md) - 系统设计和结构
|
||||
- [架构概述](docs/architecture/README.md) - 系统设计和结构
|
||||
|
||||
## 路线图
|
||||
|
||||
|
||||
+2
-1
@@ -9,7 +9,8 @@
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"scripts": {
|
||||
"setup": "echo '⚠️ This npm setup is for the archived web application. For agent development, use: ./scripts/setup-python.sh' && bash scripts/setup.sh"
|
||||
"setup": "echo '⚠️ This npm setup is for the archived web application. For agent development, use: ./scripts/setup-python.sh' && bash scripts/setup.sh",
|
||||
"test:duplicates": "bun test scripts/auto-close-duplicates"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.10.0",
|
||||
|
||||
+100
-77
@@ -43,29 +43,40 @@ if ! command -v python &> /dev/null && ! command -v python3 &> /dev/null; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Use python3 if available, otherwise python
|
||||
PYTHON_CMD="python3"
|
||||
if ! command -v python3 &> /dev/null; then
|
||||
PYTHON_CMD="python"
|
||||
# Prefer a Python >= 3.11 if multiple are installed (common on macOS).
|
||||
PYTHON_CMD=""
|
||||
for CANDIDATE in python3.13 python3.12 python3.11 python3 python; do
|
||||
if command -v "$CANDIDATE" &> /dev/null; then
|
||||
PYTHON_MAJOR=$("$CANDIDATE" -c 'import sys; print(sys.version_info.major)')
|
||||
PYTHON_MINOR=$("$CANDIDATE" -c 'import sys; print(sys.version_info.minor)')
|
||||
if [ "$PYTHON_MAJOR" -eq 3 ] && [ "$PYTHON_MINOR" -ge 11 ]; then
|
||||
PYTHON_CMD="$CANDIDATE"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z "$PYTHON_CMD" ]; then
|
||||
# Fall back to python3/python just for a helpful detected version in the error message.
|
||||
PYTHON_CMD="python3"
|
||||
if ! command -v python3 &> /dev/null; then
|
||||
PYTHON_CMD="python"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check Python version
|
||||
# Check Python version (for logging/error messages)
|
||||
PYTHON_VERSION=$($PYTHON_CMD -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')
|
||||
PYTHON_MAJOR=$($PYTHON_CMD -c 'import sys; print(sys.version_info.major)')
|
||||
PYTHON_MINOR=$($PYTHON_CMD -c 'import sys; print(sys.version_info.minor)')
|
||||
|
||||
echo -e " Detected Python: ${GREEN}$PYTHON_VERSION${NC}"
|
||||
echo -e " Detected Python: ${GREEN}$PYTHON_VERSION${NC} (${PYTHON_CMD})"
|
||||
|
||||
if [ "$PYTHON_MAJOR" -lt 3 ] || ([ "$PYTHON_MAJOR" -eq 3 ] && [ "$PYTHON_MINOR" -lt 11 ]); then
|
||||
echo -e "${RED}Error: Python 3.11+ is required (found $PYTHON_VERSION)${NC}"
|
||||
echo "Please upgrade your Python installation"
|
||||
echo -e "${RED}Error: Python 3.11+ is required (found $PYTHON_VERSION via ${PYTHON_CMD})${NC}"
|
||||
echo "Please upgrade your Python installation or ensure python3.11+ is on your PATH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$PYTHON_MINOR" -lt 11 ]; then
|
||||
echo -e "${YELLOW} Warning: Python 3.11+ is recommended for best compatibility${NC}"
|
||||
fi
|
||||
|
||||
echo -e "${GREEN} ✓ Python version OK${NC}"
|
||||
echo ""
|
||||
|
||||
@@ -79,6 +90,30 @@ fi
|
||||
echo -e "${GREEN} ✓ pip detected${NC}"
|
||||
echo ""
|
||||
|
||||
# Check for uv (install automatically if missing)
|
||||
if ! command -v uv &> /dev/null; then
|
||||
echo -e "${YELLOW} uv not found. Installing...${NC}"
|
||||
if ! command -v curl &> /dev/null; then
|
||||
echo -e "${RED}Error: curl is not installed (needed to install uv)${NC}"
|
||||
echo "Please install curl or install uv manually from https://astral.sh/uv/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
|
||||
if ! command -v uv &> /dev/null; then
|
||||
echo -e "${RED}Error: uv installation failed${NC}"
|
||||
echo "Please install uv manually from https://astral.sh/uv/"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN} ✓ uv installed successfully${NC}"
|
||||
fi
|
||||
|
||||
UV_VERSION=$(uv --version)
|
||||
echo -e "${GREEN} ✓ uv detected: $UV_VERSION${NC}"
|
||||
echo ""
|
||||
|
||||
# ============================================================
|
||||
# Step 2: Install Python Packages
|
||||
# ============================================================
|
||||
@@ -86,16 +121,12 @@ echo ""
|
||||
echo -e "${BLUE}Step 2: Installing Python packages...${NC}"
|
||||
echo ""
|
||||
|
||||
# Upgrade pip, setuptools, and wheel
|
||||
echo " Upgrading pip, setuptools, wheel..."
|
||||
$PYTHON_CMD -m pip install --upgrade pip setuptools wheel > /dev/null 2>&1
|
||||
echo -e "${GREEN} ✓ Core tools upgraded${NC}"
|
||||
|
||||
# Install framework package from core/
|
||||
echo " Installing framework package from core/..."
|
||||
cd "$SCRIPT_DIR/core"
|
||||
|
||||
if [ -f "pyproject.toml" ]; then
|
||||
$PYTHON_CMD -m pip install -e . > /dev/null 2>&1
|
||||
uv sync > /dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
echo -e "${GREEN} ✓ framework package installed${NC}"
|
||||
else
|
||||
@@ -109,8 +140,9 @@ fi
|
||||
# Install aden_tools package from tools/
|
||||
echo " Installing aden_tools package from tools/..."
|
||||
cd "$SCRIPT_DIR/tools"
|
||||
|
||||
if [ -f "pyproject.toml" ]; then
|
||||
$PYTHON_CMD -m pip install -e . > /dev/null 2>&1
|
||||
uv sync > /dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
echo -e "${GREEN} ✓ aden_tools package installed${NC}"
|
||||
else
|
||||
@@ -122,27 +154,30 @@ else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Install MCP dependencies
|
||||
# Install MCP dependencies (in tools venv)
|
||||
echo " Installing MCP dependencies..."
|
||||
$PYTHON_CMD -m pip install mcp fastmcp > /dev/null 2>&1
|
||||
TOOLS_PYTHON="$SCRIPT_DIR/tools/.venv/bin/python"
|
||||
uv pip install --python "$TOOLS_PYTHON" mcp fastmcp > /dev/null 2>&1
|
||||
echo -e "${GREEN} ✓ MCP dependencies installed${NC}"
|
||||
|
||||
# Fix openai version compatibility
|
||||
OPENAI_VERSION=$($PYTHON_CMD -c "import openai; print(openai.__version__)" 2>/dev/null || echo "not_installed")
|
||||
# Fix openai version compatibility (in tools venv)
|
||||
TOOLS_PYTHON="$SCRIPT_DIR/tools/.venv/bin/python"
|
||||
OPENAI_VERSION=$($TOOLS_PYTHON -c "import openai; print(openai.__version__)" 2>/dev/null || echo "not_installed")
|
||||
if [ "$OPENAI_VERSION" = "not_installed" ]; then
|
||||
echo " Installing openai package..."
|
||||
$PYTHON_CMD -m pip install "openai>=1.0.0" > /dev/null 2>&1
|
||||
uv pip install --python "$TOOLS_PYTHON" "openai>=1.0.0" > /dev/null 2>&1
|
||||
echo -e "${GREEN} ✓ openai installed${NC}"
|
||||
elif [[ "$OPENAI_VERSION" =~ ^0\. ]]; then
|
||||
echo " Upgrading openai to 1.x+ for litellm compatibility..."
|
||||
$PYTHON_CMD -m pip install --upgrade "openai>=1.0.0" > /dev/null 2>&1
|
||||
uv pip install --python "$TOOLS_PYTHON" --upgrade "openai>=1.0.0" > /dev/null 2>&1
|
||||
echo -e "${GREEN} ✓ openai upgraded${NC}"
|
||||
else
|
||||
echo -e "${GREEN} ✓ openai $OPENAI_VERSION is compatible${NC}"
|
||||
fi
|
||||
|
||||
# Install click for CLI
|
||||
$PYTHON_CMD -m pip install click > /dev/null 2>&1
|
||||
# Install click for CLI (in tools venv)
|
||||
TOOLS_PYTHON="$SCRIPT_DIR/tools/.venv/bin/python"
|
||||
uv pip install --python "$TOOLS_PYTHON" click > /dev/null 2>&1
|
||||
echo -e "${GREEN} ✓ click installed${NC}"
|
||||
|
||||
cd "$SCRIPT_DIR"
|
||||
@@ -157,31 +192,42 @@ echo ""
|
||||
|
||||
IMPORT_ERRORS=0
|
||||
|
||||
# Test framework import
|
||||
if $PYTHON_CMD -c "import framework" > /dev/null 2>&1; then
|
||||
# Test imports using their respective venvs
|
||||
CORE_PYTHON="$SCRIPT_DIR/core/.venv/bin/python"
|
||||
TOOLS_PYTHON="$SCRIPT_DIR/tools/.venv/bin/python"
|
||||
|
||||
# Test framework import (from core venv)
|
||||
if [ -f "$CORE_PYTHON" ] && $CORE_PYTHON -c "import framework" > /dev/null 2>&1; then
|
||||
echo -e "${GREEN} ✓ framework imports OK${NC}"
|
||||
else
|
||||
echo -e "${RED} ✗ framework import failed${NC}"
|
||||
IMPORT_ERRORS=$((IMPORT_ERRORS + 1))
|
||||
fi
|
||||
|
||||
# Test aden_tools import
|
||||
if $PYTHON_CMD -c "import aden_tools" > /dev/null 2>&1; then
|
||||
# Test aden_tools import (from tools venv)
|
||||
if [ -f "$TOOLS_PYTHON" ] && $TOOLS_PYTHON -c "import aden_tools" > /dev/null 2>&1; then
|
||||
echo -e "${GREEN} ✓ aden_tools imports OK${NC}"
|
||||
else
|
||||
echo -e "${RED} ✗ aden_tools import failed${NC}"
|
||||
IMPORT_ERRORS=$((IMPORT_ERRORS + 1))
|
||||
fi
|
||||
|
||||
# Test litellm import
|
||||
if $PYTHON_CMD -c "import litellm" > /dev/null 2>&1; then
|
||||
echo -e "${GREEN} ✓ litellm imports OK${NC}"
|
||||
# Test litellm import (from core venv)
|
||||
if [ -f "$CORE_PYTHON" ] && $CORE_PYTHON -c "import litellm" > /dev/null 2>&1; then
|
||||
echo -e "${GREEN} ✓ litellm imports OK (core)${NC}"
|
||||
else
|
||||
echo -e "${YELLOW} ⚠ litellm import issues (may be OK)${NC}"
|
||||
echo -e "${YELLOW} ⚠ litellm import issues in core (may be OK)${NC}"
|
||||
fi
|
||||
|
||||
# Test MCP server module
|
||||
if $PYTHON_CMD -c "from framework.mcp import agent_builder_server" > /dev/null 2>&1; then
|
||||
# Test litellm import (from tools venv)
|
||||
if [ -f "$TOOLS_PYTHON" ] && $TOOLS_PYTHON -c "import litellm" > /dev/null 2>&1; then
|
||||
echo -e "${GREEN} ✓ litellm imports OK (tools)${NC}"
|
||||
else
|
||||
echo -e "${YELLOW} ⚠ litellm import issues in tools (may be OK)${NC}"
|
||||
fi
|
||||
|
||||
# Test MCP server module (from core venv)
|
||||
if [ -f "$CORE_PYTHON" ] && $CORE_PYTHON -c "from framework.mcp import agent_builder_server" > /dev/null 2>&1; then
|
||||
echo -e "${GREEN} ✓ MCP server module OK${NC}"
|
||||
else
|
||||
echo -e "${RED} ✗ MCP server module failed${NC}"
|
||||
@@ -197,10 +243,10 @@ fi
|
||||
echo ""
|
||||
|
||||
# ============================================================
|
||||
# Step 4: Install Claude Code Skills
|
||||
# Step 4: Verify Claude Code Skills
|
||||
# ============================================================
|
||||
|
||||
echo -e "${BLUE}Step 4: Installing Claude Code skills...${NC}"
|
||||
echo -e "${BLUE}Step 4: Verifying Claude Code skills...${NC}"
|
||||
echo ""
|
||||
|
||||
# Check if .claude/skills exists in this repo
|
||||
@@ -209,39 +255,16 @@ if [ ! -d "$SCRIPT_DIR/.claude/skills" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create Claude skills directory if it doesn't exist
|
||||
if [ ! -d "$CLAUDE_SKILLS_DIR" ]; then
|
||||
echo " Creating Claude skills directory: $CLAUDE_SKILLS_DIR"
|
||||
mkdir -p "$CLAUDE_SKILLS_DIR"
|
||||
fi
|
||||
|
||||
# Function to install a skill
|
||||
install_skill() {
|
||||
local skill_name=$1
|
||||
local source_dir="$SCRIPT_DIR/.claude/skills/$skill_name"
|
||||
local target_dir="$CLAUDE_SKILLS_DIR/$skill_name"
|
||||
|
||||
if [ ! -d "$source_dir" ]; then
|
||||
echo -e "${RED} ✗ Skill not found: $skill_name${NC}"
|
||||
return 1
|
||||
# Verify all 5 agent-related skills exist locally
|
||||
SKILLS=("building-agents-core" "building-agents-construction" "building-agents-patterns" "testing-agent" "agent-workflow")
|
||||
for skill in "${SKILLS[@]}"; do
|
||||
if [ -d "$SCRIPT_DIR/.claude/skills/$skill" ]; then
|
||||
echo -e "${GREEN} ✓ Found: $skill${NC}"
|
||||
else
|
||||
echo -e "${RED} ✗ Not found: $skill${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if skill already exists
|
||||
if [ -d "$target_dir" ]; then
|
||||
rm -rf "$target_dir"
|
||||
fi
|
||||
|
||||
# Copy the skill
|
||||
cp -r "$source_dir" "$target_dir"
|
||||
echo -e "${GREEN} ✓ Installed: $skill_name${NC}"
|
||||
}
|
||||
|
||||
# Install all 5 agent-related skills
|
||||
install_skill "building-agents-core"
|
||||
install_skill "building-agents-construction"
|
||||
install_skill "building-agents-patterns"
|
||||
install_skill "testing-agent"
|
||||
install_skill "agent-workflow"
|
||||
done
|
||||
|
||||
echo ""
|
||||
|
||||
@@ -312,7 +335,7 @@ echo " • framework (core agent runtime)"
|
||||
echo " • aden_tools (tools and MCP servers)"
|
||||
echo " • MCP dependencies (mcp, fastmcp)"
|
||||
echo ""
|
||||
echo "Installed Claude Code skills:"
|
||||
echo "Available Claude Code skills (in project directory):"
|
||||
echo " • /building-agents-core - Fundamental concepts"
|
||||
echo " • /building-agents-construction - Step-by-step build guide"
|
||||
echo " • /building-agents-patterns - Best practices"
|
||||
@@ -321,16 +344,16 @@ echo " • /agent-workflow - Complete workflow"
|
||||
echo ""
|
||||
echo "Usage:"
|
||||
echo " 1. Open Claude Code in this directory:"
|
||||
echo " ${BLUE}cd $SCRIPT_DIR && claude${NC}"
|
||||
echo " cd $SCRIPT_DIR && claude"
|
||||
echo ""
|
||||
echo " 2. Build a new agent:"
|
||||
echo " ${BLUE}/building-agents-construction${NC}"
|
||||
echo " /building-agents-construction"
|
||||
echo ""
|
||||
echo " 3. Test an existing agent:"
|
||||
echo " ${BLUE}/testing-agent${NC}"
|
||||
echo " /testing-agent"
|
||||
echo ""
|
||||
echo " 4. Or use the complete workflow:"
|
||||
echo " ${BLUE}/agent-workflow${NC}"
|
||||
echo " /agent-workflow"
|
||||
echo ""
|
||||
echo "MCP Tools available (when running from this directory):"
|
||||
echo " • mcp__agent-builder__create_session"
|
||||
@@ -340,6 +363,6 @@ echo " • mcp__agent-builder__run_tests"
|
||||
echo " • ... and more"
|
||||
echo ""
|
||||
echo "Documentation:"
|
||||
echo " • Skills: $CLAUDE_SKILLS_DIR/"
|
||||
echo " • Skills: $SCRIPT_DIR/.claude/skills/"
|
||||
echo " • Examples: $SCRIPT_DIR/exports/"
|
||||
echo ""
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
/**
|
||||
* Tests for auto-close-duplicates script: comment filter, 12h check,
|
||||
* author reaction, extractDuplicateIssueNumber, and decideAutoClose
|
||||
* (circular-dup and self-ref prevention).
|
||||
*/
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import {
|
||||
authorDisagreedWithDupe,
|
||||
decideAutoClose,
|
||||
extractDuplicateIssueNumber,
|
||||
getLastDupeComment,
|
||||
isDupeComment,
|
||||
isDupeCommentOldEnough,
|
||||
type GitHubComment,
|
||||
type GitHubIssue,
|
||||
type GitHubReaction,
|
||||
} from "./auto-close-duplicates";
|
||||
|
||||
describe("extractDuplicateIssueNumber", () => {
|
||||
test("extracts #123 format", () => {
|
||||
expect(
|
||||
extractDuplicateIssueNumber("Found a possible duplicate of #1275: ...")
|
||||
).toBe(1275);
|
||||
expect(extractDuplicateIssueNumber("Duplicate of #1")).toBe(1);
|
||||
expect(extractDuplicateIssueNumber("See #1000")).toBe(1000);
|
||||
});
|
||||
|
||||
test("extracts first #N when multiple present", () => {
|
||||
expect(
|
||||
extractDuplicateIssueNumber("Duplicate of #1000 and also #1275")
|
||||
).toBe(1000);
|
||||
});
|
||||
|
||||
test("extracts GitHub issue URL format", () => {
|
||||
expect(
|
||||
extractDuplicateIssueNumber(
|
||||
"Duplicate of https://github.com/adenhq/hive/issues/42"
|
||||
)
|
||||
).toBe(42);
|
||||
});
|
||||
|
||||
test("returns null when no issue number", () => {
|
||||
expect(extractDuplicateIssueNumber("No number here")).toBe(null);
|
||||
expect(extractDuplicateIssueNumber("")).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe("isDupeComment", () => {
|
||||
test("true when body has 'possible duplicate' and user is Bot", () => {
|
||||
expect(
|
||||
isDupeComment({
|
||||
id: 1,
|
||||
body: "Found a possible duplicate of #1000: same bug",
|
||||
created_at: "",
|
||||
user: { type: "Bot", id: 2 },
|
||||
})
|
||||
).toBe(true);
|
||||
expect(
|
||||
isDupeComment({
|
||||
id: 1,
|
||||
body: "Possible duplicate of #1275",
|
||||
created_at: "",
|
||||
user: { type: "Bot", id: 2 },
|
||||
})
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
test("false when body lacks 'possible duplicate'", () => {
|
||||
expect(
|
||||
isDupeComment({
|
||||
id: 1,
|
||||
body: "Not a duplicate",
|
||||
created_at: "",
|
||||
user: { type: "Bot", id: 2 },
|
||||
})
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
test("false when user is not Bot", () => {
|
||||
expect(
|
||||
isDupeComment({
|
||||
id: 1,
|
||||
body: "Found a possible duplicate of #1000",
|
||||
created_at: "",
|
||||
user: { type: "User", id: 2 },
|
||||
})
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("isDupeCommentOldEnough", () => {
|
||||
test("true when comment date is before twelveHoursAgo", () => {
|
||||
const twelveHoursAgo = new Date("2025-01-28T12:00:00Z");
|
||||
const oldComment = new Date("2025-01-28T00:00:00Z");
|
||||
expect(isDupeCommentOldEnough(oldComment, twelveHoursAgo)).toBe(true);
|
||||
});
|
||||
|
||||
test("true when comment date equals twelveHoursAgo", () => {
|
||||
const twelveHoursAgo = new Date("2025-01-28T12:00:00Z");
|
||||
expect(isDupeCommentOldEnough(twelveHoursAgo, twelveHoursAgo)).toBe(true);
|
||||
});
|
||||
|
||||
test("false when comment is after twelveHoursAgo (too recent)", () => {
|
||||
const twelveHoursAgo = new Date("2025-01-28T12:00:00Z");
|
||||
const recentComment = new Date("2025-01-28T18:00:00Z");
|
||||
expect(isDupeCommentOldEnough(recentComment, twelveHoursAgo)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("authorDisagreedWithDupe", () => {
|
||||
test("true when issue author gave thumbs down", () => {
|
||||
const issue = { number: 1275, title: "", state: "open", user: { id: 42 }, created_at: "" };
|
||||
const reactions: GitHubReaction[] = [
|
||||
{ user: { id: 42 }, content: "-1" },
|
||||
];
|
||||
expect(authorDisagreedWithDupe(reactions, issue)).toBe(true);
|
||||
});
|
||||
|
||||
test("false when only other users reacted", () => {
|
||||
const issue = { number: 1275, title: "", state: "open", user: { id: 42 }, created_at: "" };
|
||||
const reactions: GitHubReaction[] = [
|
||||
{ user: { id: 99 }, content: "-1" },
|
||||
{ user: { id: 1 }, content: "+1" },
|
||||
];
|
||||
expect(authorDisagreedWithDupe(reactions, issue)).toBe(false);
|
||||
});
|
||||
|
||||
test("false when author gave +1 or other reaction", () => {
|
||||
const issue = { number: 1275, title: "", state: "open", user: { id: 42 }, created_at: "" };
|
||||
expect(authorDisagreedWithDupe([{ user: { id: 42 }, content: "+1" }], issue)).toBe(false);
|
||||
expect(authorDisagreedWithDupe([{ user: { id: 42 }, content: "eyes" }], issue)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getLastDupeComment", () => {
|
||||
test("returns null when no dupe comments", () => {
|
||||
expect(
|
||||
getLastDupeComment([
|
||||
{ id: 1, body: "Not a duplicate", created_at: "", user: { type: "User", id: 1 } },
|
||||
])
|
||||
).toBe(null);
|
||||
});
|
||||
|
||||
test("returns the only dupe comment when one exists", () => {
|
||||
const c: GitHubComment = {
|
||||
id: 1,
|
||||
body: "Found a possible duplicate of #1000",
|
||||
created_at: "",
|
||||
user: { type: "Bot", id: 2 },
|
||||
};
|
||||
expect(getLastDupeComment([c])).toBe(c);
|
||||
});
|
||||
|
||||
test("returns the last dupe comment when multiple exist", () => {
|
||||
const c1: GitHubComment = {
|
||||
id: 1,
|
||||
body: "Found a possible duplicate of #1000",
|
||||
created_at: "",
|
||||
user: { type: "Bot", id: 2 },
|
||||
};
|
||||
const c2: GitHubComment = {
|
||||
id: 2,
|
||||
body: "Found a possible duplicate of #1275",
|
||||
created_at: "",
|
||||
user: { type: "Bot", id: 2 },
|
||||
};
|
||||
const other: GitHubComment = {
|
||||
id: 3,
|
||||
body: "Some other comment",
|
||||
created_at: "",
|
||||
user: { type: "User", id: 3 },
|
||||
};
|
||||
expect(getLastDupeComment([other, c1, c2])).toBe(c2);
|
||||
});
|
||||
});
|
||||
|
||||
function issue(num: number, state = "open"): GitHubIssue {
|
||||
return {
|
||||
number: num,
|
||||
title: `Issue ${num}`,
|
||||
state,
|
||||
user: { id: 1 },
|
||||
created_at: new Date().toISOString(),
|
||||
};
|
||||
}
|
||||
|
||||
function comment(body: string): GitHubComment {
|
||||
return {
|
||||
id: 1,
|
||||
body,
|
||||
created_at: new Date().toISOString(),
|
||||
user: { type: "Bot", id: 2 },
|
||||
};
|
||||
}
|
||||
|
||||
describe("decideAutoClose", () => {
|
||||
test("returns null when comment has no extractable issue number", async () => {
|
||||
const result = await decideAutoClose(
|
||||
issue(1275),
|
||||
comment("Possible duplicate of something else"),
|
||||
async () => ({ state: "open" })
|
||||
);
|
||||
expect(result).toBe(null);
|
||||
});
|
||||
|
||||
test("returns null when duplicate target is self (same issue number)", async () => {
|
||||
const result = await decideAutoClose(
|
||||
issue(1275),
|
||||
comment("Found a possible duplicate of #1275: same issue"),
|
||||
async () => ({ state: "open" })
|
||||
);
|
||||
expect(result).toBe(null);
|
||||
});
|
||||
|
||||
test("returns null when target issue is closed (avoids circular closure)", async () => {
|
||||
const result = await decideAutoClose(
|
||||
issue(1275),
|
||||
comment("Found a possible duplicate of #1000"),
|
||||
async (num) => (num === 1000 ? { state: "closed" } : { state: "open" })
|
||||
);
|
||||
expect(result).toBe(null);
|
||||
});
|
||||
|
||||
test("returns null when getTargetIssue returns null", async () => {
|
||||
const result = await decideAutoClose(
|
||||
issue(1275),
|
||||
comment("Found a possible duplicate of #1000"),
|
||||
async () => null
|
||||
);
|
||||
expect(result).toBe(null);
|
||||
});
|
||||
|
||||
test("returns null when getTargetIssue throws", async () => {
|
||||
const result = await decideAutoClose(
|
||||
issue(1275),
|
||||
comment("Found a possible duplicate of #1000"),
|
||||
async () => {
|
||||
throw new Error("API error");
|
||||
}
|
||||
);
|
||||
expect(result).toBe(null);
|
||||
});
|
||||
|
||||
test("returns duplicateOf number when target is open (should close)", async () => {
|
||||
const result = await decideAutoClose(
|
||||
issue(1275),
|
||||
comment("Found a possible duplicate of #1000: same bug"),
|
||||
async (num) => (num === 1000 ? { state: "open" } : { state: "closed" })
|
||||
);
|
||||
expect(result).toBe(1000);
|
||||
});
|
||||
|
||||
test("returns null when target state is not exactly 'open' (e.g. uppercase)", async () => {
|
||||
const result = await decideAutoClose(
|
||||
issue(1275),
|
||||
comment("Found a possible duplicate of #1000"),
|
||||
async () => ({ state: "OPEN" } as { state: string })
|
||||
);
|
||||
expect(result).toBe(null);
|
||||
});
|
||||
});
|
||||
@@ -6,21 +6,22 @@ declare global {
|
||||
};
|
||||
}
|
||||
|
||||
interface GitHubIssue {
|
||||
export interface GitHubIssue {
|
||||
number: number;
|
||||
title: string;
|
||||
state: string;
|
||||
user: { id: number };
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
interface GitHubComment {
|
||||
export interface GitHubComment {
|
||||
id: number;
|
||||
body: string;
|
||||
created_at: string;
|
||||
user: { type: string; id: number };
|
||||
}
|
||||
|
||||
interface GitHubReaction {
|
||||
export interface GitHubReaction {
|
||||
user: { id: number };
|
||||
content: string;
|
||||
}
|
||||
@@ -57,7 +58,41 @@ async function githubRequest<T>(
|
||||
return response.json();
|
||||
}
|
||||
|
||||
function extractDuplicateIssueNumber(commentBody: string): number | null {
|
||||
/** True if comment is a bot "possible duplicate" detection (used for filtering). */
|
||||
export function isDupeComment(comment: GitHubComment): boolean {
|
||||
const bodyLower = comment.body.toLowerCase();
|
||||
return (
|
||||
bodyLower.includes("possible duplicate") && comment.user.type === "Bot"
|
||||
);
|
||||
}
|
||||
|
||||
/** True if the duplicate comment is old enough to auto-close (>= 12h). */
|
||||
export function isDupeCommentOldEnough(
|
||||
dupeCommentDate: Date,
|
||||
twelveHoursAgo: Date
|
||||
): boolean {
|
||||
return dupeCommentDate <= twelveHoursAgo;
|
||||
}
|
||||
|
||||
/** True if the issue author reacted with thumbs down to the duplicate comment. */
|
||||
export function authorDisagreedWithDupe(
|
||||
reactions: GitHubReaction[],
|
||||
issue: GitHubIssue
|
||||
): boolean {
|
||||
return reactions.some(
|
||||
(r) => r.user.id === issue.user.id && r.content === "-1"
|
||||
);
|
||||
}
|
||||
|
||||
/** Returns the most recent duplicate-detection comment, or null if none. */
|
||||
export function getLastDupeComment(
|
||||
comments: GitHubComment[]
|
||||
): GitHubComment | null {
|
||||
const dupeComments = comments.filter(isDupeComment);
|
||||
return dupeComments.length > 0 ? dupeComments[dupeComments.length - 1]! : null;
|
||||
}
|
||||
|
||||
export function extractDuplicateIssueNumber(commentBody: string): number | null {
|
||||
// Try to match #123 format first
|
||||
let match = commentBody.match(/#(\d+)/);
|
||||
if (match) {
|
||||
@@ -73,6 +108,30 @@ function extractDuplicateIssueNumber(commentBody: string): number | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decides whether to auto-close this issue as duplicate of another.
|
||||
* Returns the target issue number to close as duplicate of, or null to skip.
|
||||
* Used by the main loop and by tests.
|
||||
*/
|
||||
export async function decideAutoClose(
|
||||
issue: GitHubIssue,
|
||||
lastDupeComment: GitHubComment,
|
||||
getTargetIssue: (issueNumber: number) => Promise<{ state: string } | null>
|
||||
): Promise<number | null> {
|
||||
const duplicateIssueNumber = extractDuplicateIssueNumber(lastDupeComment.body);
|
||||
if (duplicateIssueNumber === null) return null;
|
||||
|
||||
if (duplicateIssueNumber === issue.number) return null;
|
||||
|
||||
try {
|
||||
const targetIssue = await getTargetIssue(duplicateIssueNumber);
|
||||
if (!targetIssue || targetIssue.state !== "open") return null;
|
||||
return duplicateIssueNumber;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function closeIssueAsDuplicate(
|
||||
owner: string,
|
||||
repo: string,
|
||||
@@ -173,25 +232,18 @@ async function autoCloseDuplicates(): Promise<void> {
|
||||
`[DEBUG] Issue #${issue.number} has ${comments.length} comments`
|
||||
);
|
||||
|
||||
const dupeComments = comments.filter((comment) => {
|
||||
const bodyLower = comment.body.toLowerCase();
|
||||
return (
|
||||
bodyLower.includes("possible duplicate") &&
|
||||
comment.user.type === "Bot"
|
||||
);
|
||||
});
|
||||
const lastDupeComment = getLastDupeComment(comments);
|
||||
const dupeCount = comments.filter(isDupeComment).length;
|
||||
console.log(
|
||||
`[DEBUG] Issue #${issue.number} has ${dupeComments.length} duplicate detection comments`
|
||||
`[DEBUG] Issue #${issue.number} has ${dupeCount} duplicate detection comments`
|
||||
);
|
||||
|
||||
if (dupeComments.length === 0) {
|
||||
if (lastDupeComment === null) {
|
||||
console.log(
|
||||
`[DEBUG] Issue #${issue.number} - no duplicate comments found, skipping`
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
const lastDupeComment = dupeComments[dupeComments.length - 1];
|
||||
const dupeCommentDate = new Date(lastDupeComment.created_at);
|
||||
console.log(
|
||||
`[DEBUG] Issue #${
|
||||
@@ -199,7 +251,7 @@ async function autoCloseDuplicates(): Promise<void> {
|
||||
} - most recent duplicate comment from: ${dupeCommentDate.toISOString()}`
|
||||
);
|
||||
|
||||
if (dupeCommentDate > twelveHoursAgo) {
|
||||
if (!isDupeCommentOldEnough(dupeCommentDate, twelveHoursAgo)) {
|
||||
console.log(
|
||||
`[DEBUG] Issue #${issue.number} - duplicate comment is too recent, skipping`
|
||||
);
|
||||
@@ -224,10 +276,7 @@ async function autoCloseDuplicates(): Promise<void> {
|
||||
`[DEBUG] Issue #${issue.number} - duplicate comment has ${reactions.length} reactions`
|
||||
);
|
||||
|
||||
const authorThumbsDown = reactions.some(
|
||||
(reaction) =>
|
||||
reaction.user.id === issue.user.id && reaction.content === "-1"
|
||||
);
|
||||
const authorThumbsDown = authorDisagreedWithDupe(reactions, issue);
|
||||
console.log(
|
||||
`[DEBUG] Issue #${issue.number} - author thumbs down reaction: ${authorThumbsDown}`
|
||||
);
|
||||
@@ -239,12 +288,19 @@ async function autoCloseDuplicates(): Promise<void> {
|
||||
continue;
|
||||
}
|
||||
|
||||
const duplicateIssueNumber = extractDuplicateIssueNumber(
|
||||
lastDupeComment.body
|
||||
const duplicateOf = await decideAutoClose(
|
||||
issue,
|
||||
lastDupeComment,
|
||||
(issueNumber) =>
|
||||
githubRequest<GitHubIssue>(
|
||||
`/repos/${owner}/${repo}/issues/${issueNumber}`,
|
||||
token
|
||||
).then((i) => ({ state: i.state }))
|
||||
);
|
||||
if (!duplicateIssueNumber) {
|
||||
|
||||
if (duplicateOf === null) {
|
||||
console.log(
|
||||
`[DEBUG] Issue #${issue.number} - could not extract duplicate issue number from comment, skipping`
|
||||
`[DEBUG] Issue #${issue.number} - skipping (invalid/self/closed target or fetch error)`
|
||||
);
|
||||
continue;
|
||||
}
|
||||
@@ -254,17 +310,17 @@ async function autoCloseDuplicates(): Promise<void> {
|
||||
|
||||
try {
|
||||
console.log(
|
||||
`[INFO] Auto-closing issue #${issue.number} as duplicate of #${duplicateIssueNumber}: ${issueUrl}`
|
||||
`[INFO] Auto-closing issue #${issue.number} as duplicate of #${duplicateOf}: ${issueUrl}`
|
||||
);
|
||||
await closeIssueAsDuplicate(
|
||||
owner,
|
||||
repo,
|
||||
issue.number,
|
||||
duplicateIssueNumber,
|
||||
duplicateOf,
|
||||
token
|
||||
);
|
||||
console.log(
|
||||
`[SUCCESS] Successfully closed issue #${issue.number} as duplicate of #${duplicateIssueNumber}`
|
||||
`[SUCCESS] Successfully closed issue #${issue.number} as duplicate of #${duplicateOf}`
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
@@ -278,6 +334,8 @@ async function autoCloseDuplicates(): Promise<void> {
|
||||
);
|
||||
}
|
||||
|
||||
autoCloseDuplicates().catch(console.error);
|
||||
if (import.meta.main) {
|
||||
autoCloseDuplicates().catch(console.error);
|
||||
}
|
||||
|
||||
export {};
|
||||
|
||||
+133
-71
@@ -2,8 +2,11 @@
|
||||
#
|
||||
# setup-python.sh - Python Environment Setup for Aden Agent Framework
|
||||
#
|
||||
# This script sets up the Python environment with all required packages
|
||||
# for building and running goal-driven agents.
|
||||
# DEPRECATED: Use ./quickstart.sh instead. It does everything this script
|
||||
# does plus verifies MCP configuration, Claude Code skills, and API keys.
|
||||
#
|
||||
# This script is kept for CI/headless environments where the extra
|
||||
# verification steps in quickstart.sh are not needed.
|
||||
#
|
||||
|
||||
set -e
|
||||
@@ -19,64 +22,89 @@ NC='\033[0m' # No Color
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
|
||||
# Python Version
|
||||
REQUIRED_PYTHON_VERSION="3.11"
|
||||
|
||||
# Python version split into Major and Minor
|
||||
IFS='.' read -r PYTHON_MAJOR_VERSION PYTHON_MINOR_VERSION <<< "$REQUIRED_PYTHON_VERSION"
|
||||
|
||||
# Available python interpreter (follows sequence)
|
||||
POSSIBLE_PYTHONS=("python3" "python" "py")
|
||||
|
||||
# Default python interpreter (initialized)
|
||||
PYTHON_CMD=()
|
||||
|
||||
|
||||
echo ""
|
||||
echo "=================================================="
|
||||
echo " Aden Agent Framework - Python Setup"
|
||||
echo "=================================================="
|
||||
echo ""
|
||||
echo -e "${YELLOW}NOTE: Consider using ./quickstart.sh instead for a complete setup.${NC}"
|
||||
echo ""
|
||||
|
||||
# Check for Python
|
||||
if ! command -v python &> /dev/null && ! command -v python3 &> /dev/null; then
|
||||
echo -e "${RED}Error: Python is not installed.${NC}"
|
||||
echo "Please install Python 3.11+ from https://python.org"
|
||||
exit 1
|
||||
fi
|
||||
# Available Python interpreter
|
||||
for cmd in "${POSSIBLE_PYTHONS[@]}"; do
|
||||
# Check for python interpreter
|
||||
if command -v "$cmd" >/dev/null 2>&1; then
|
||||
|
||||
# Use python3 if available, otherwise python
|
||||
PYTHON_CMD="python3"
|
||||
if ! command -v python3 &> /dev/null; then
|
||||
PYTHON_CMD="python"
|
||||
fi
|
||||
# Specific check for Windows 'py' launcher
|
||||
if [ "$cmd" = "py" ]; then
|
||||
CURRENT_CMD=(py -3)
|
||||
else
|
||||
CURRENT_CMD=("$cmd")
|
||||
fi
|
||||
|
||||
# Check Python version
|
||||
PYTHON_VERSION=$($PYTHON_CMD -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')
|
||||
PYTHON_MAJOR=$($PYTHON_CMD -c 'import sys; print(sys.version_info.major)')
|
||||
PYTHON_MINOR=$($PYTHON_CMD -c 'import sys; print(sys.version_info.minor)')
|
||||
# Check Python version
|
||||
if "${CURRENT_CMD[@]}" -c "import sys; sys.exit(0 if sys.version_info >= ($PYTHON_MAJOR_VERSION, $PYTHON_MINOR_VERSION) else 1)" >/dev/null 2>&1; then
|
||||
echo -e "${GREEN}✓${NC} interpreter detected: ${CURRENT_CMD[@]}"
|
||||
# Check for pip
|
||||
if "${CURRENT_CMD[@]}" -m pip --version >/dev/null 2>&1; then
|
||||
PYTHON_CMD=("${CURRENT_CMD[@]}")
|
||||
echo -e "${GREEN}✓${NC} pip detected"
|
||||
echo ""
|
||||
break
|
||||
else
|
||||
echo -e "${RED}✗${NC} pip not found"
|
||||
echo ""
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}✗${NC} ${CURRENT_CMD[@]} not found"
|
||||
echo ""
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo -e "${BLUE}Detected Python:${NC} $PYTHON_VERSION"
|
||||
|
||||
if [ "$PYTHON_MAJOR" -lt 3 ] || ([ "$PYTHON_MAJOR" -eq 3 ] && [ "$PYTHON_MINOR" -lt 11 ]); then
|
||||
echo -e "${RED}Error: Python 3.11+ is required (found $PYTHON_VERSION)${NC}"
|
||||
echo "Please upgrade your Python installation"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$PYTHON_MINOR" -lt 11 ]; then
|
||||
echo -e "${YELLOW}Warning: Python 3.11+ is recommended for best compatibility${NC}"
|
||||
echo -e "${YELLOW}You have Python $PYTHON_VERSION which may work but is not officially supported${NC}"
|
||||
# Display error message if python not found
|
||||
if [ "${#PYTHON_CMD[@]}" -eq 0 ]; then
|
||||
echo -e "${RED}Error:${NC} No suitable Python interpreter found with pip installed."
|
||||
echo ""
|
||||
echo "Requirements:"
|
||||
echo " • Python $PYTHON_MAJOR_VERSION.$PYTHON_MINOR_VERSION+"
|
||||
echo " • pip installed"
|
||||
echo ""
|
||||
echo "Tried the following commands:"
|
||||
echo " ${POSSIBLE_PYTHONS[*]}"
|
||||
echo ""
|
||||
echo "Please install Python from:"
|
||||
echo " https://www.python.org/downloads/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Display Python version
|
||||
PYTHON_VERSION=$("${PYTHON_CMD[@]}" -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')
|
||||
echo -e "${BLUE}Detected Python:${NC} $PYTHON_VERSION"
|
||||
echo -e "${GREEN}✓${NC} Python version check passed"
|
||||
echo ""
|
||||
|
||||
# Check for pip
|
||||
if ! $PYTHON_CMD -m pip --version &> /dev/null; then
|
||||
echo -e "${RED}Error: pip is not installed${NC}"
|
||||
echo "Please install pip for Python $PYTHON_VERSION"
|
||||
# Check for uv
|
||||
if ! command -v uv &> /dev/null; then
|
||||
echo -e "${RED}Error: uv is not installed${NC}"
|
||||
echo "Please install uv from https://github.com/astral-sh/uv"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}✓${NC} pip detected"
|
||||
echo ""
|
||||
|
||||
# Upgrade pip, setuptools, and wheel
|
||||
echo "Upgrading pip, setuptools, and wheel..."
|
||||
if ! $PYTHON_CMD -m pip install --upgrade pip setuptools wheel; then
|
||||
echo "Error: Failed to upgrade pip. Please check your python/venv configuration."
|
||||
exit 1
|
||||
fi
|
||||
echo -e "${GREEN}✓${NC} Core packages upgraded"
|
||||
echo -e "${GREEN}✓${NC} uv detected"
|
||||
echo ""
|
||||
|
||||
# Install core framework package
|
||||
@@ -86,10 +114,20 @@ echo "=================================================="
|
||||
echo ""
|
||||
cd "$PROJECT_ROOT/core"
|
||||
|
||||
# Create venv if it doesn't exist
|
||||
if [ ! -d ".venv" ]; then
|
||||
echo "Creating virtual environment in core/.venv..."
|
||||
uv venv
|
||||
echo -e "${GREEN}✓${NC} Virtual environment created"
|
||||
else
|
||||
echo -e "${GREEN}✓${NC} Virtual environment already exists"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
if [ -f "pyproject.toml" ]; then
|
||||
echo "Installing framework from core/ (editable mode)..."
|
||||
$PYTHON_CMD -m pip install -e . > /dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
CORE_PYTHON=".venv/bin/python"
|
||||
if uv pip install --python "$CORE_PYTHON" -e .; then
|
||||
echo -e "${GREEN}✓${NC} Framework package installed"
|
||||
else
|
||||
echo -e "${YELLOW}⚠${NC} Framework installation encountered issues (may be OK if already installed)"
|
||||
@@ -106,10 +144,20 @@ echo "=================================================="
|
||||
echo ""
|
||||
cd "$PROJECT_ROOT/tools"
|
||||
|
||||
# Create venv if it doesn't exist
|
||||
if [ ! -d ".venv" ]; then
|
||||
echo "Creating virtual environment in tools/.venv..."
|
||||
uv venv
|
||||
echo -e "${GREEN}✓${NC} Virtual environment created"
|
||||
else
|
||||
echo -e "${GREEN}✓${NC} Virtual environment already exists"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
if [ -f "pyproject.toml" ]; then
|
||||
echo "Installing aden_tools from tools/ (editable mode)..."
|
||||
$PYTHON_CMD -m pip install -e . > /dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
TOOLS_PYTHON=".venv/bin/python"
|
||||
if uv pip install --python "$TOOLS_PYTHON" -e .; then
|
||||
echo -e "${GREEN}✓${NC} Tools package installed"
|
||||
else
|
||||
echo -e "${RED}✗${NC} Tools installation failed"
|
||||
@@ -127,18 +175,20 @@ echo "Fixing Package Compatibility"
|
||||
echo "=================================================="
|
||||
echo ""
|
||||
|
||||
# Check openai version
|
||||
OPENAI_VERSION=$($PYTHON_CMD -c "import openai; print(openai.__version__)" 2>/dev/null || echo "not_installed")
|
||||
TOOLS_PYTHON="$PROJECT_ROOT/tools/.venv/bin/python"
|
||||
|
||||
# Check openai version in tools venv
|
||||
OPENAI_VERSION=$($TOOLS_PYTHON -c "import openai; print(openai.__version__)" 2>/dev/null || echo "not_installed")
|
||||
|
||||
if [ "$OPENAI_VERSION" = "not_installed" ]; then
|
||||
echo "Installing openai package..."
|
||||
$PYTHON_CMD -m pip install "openai>=1.0.0" > /dev/null 2>&1
|
||||
uv pip install --python "$TOOLS_PYTHON" "openai>=1.0.0"
|
||||
echo -e "${GREEN}✓${NC} openai package installed"
|
||||
elif [[ "$OPENAI_VERSION" =~ ^0\. ]]; then
|
||||
echo -e "${YELLOW}Found old openai version: $OPENAI_VERSION${NC}"
|
||||
echo "Upgrading to openai 1.x+ for litellm compatibility..."
|
||||
$PYTHON_CMD -m pip install --upgrade "openai>=1.0.0" > /dev/null 2>&1
|
||||
OPENAI_VERSION=$($PYTHON_CMD -c "import openai; print(openai.__version__)" 2>/dev/null)
|
||||
uv pip install --python "$TOOLS_PYTHON" --upgrade "openai>=1.0.0"
|
||||
OPENAI_VERSION=$($TOOLS_PYTHON -c "import openai; print(openai.__version__)" 2>/dev/null)
|
||||
echo -e "${GREEN}✓${NC} openai upgraded to $OPENAI_VERSION"
|
||||
else
|
||||
echo -e "${GREEN}✓${NC} openai $OPENAI_VERSION is compatible"
|
||||
@@ -153,24 +203,36 @@ echo ""
|
||||
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
# Test framework import
|
||||
if $PYTHON_CMD -c "import framework; print('framework OK')" > /dev/null 2>&1; then
|
||||
echo -e "${GREEN}✓${NC} framework package imports successfully"
|
||||
# Test framework import using core venv
|
||||
CORE_PYTHON="$PROJECT_ROOT/core/.venv/bin/python"
|
||||
if [ -f "$CORE_PYTHON" ]; then
|
||||
if $CORE_PYTHON -c "import framework; print('framework OK')" > /dev/null 2>&1; then
|
||||
echo -e "${GREEN}✓${NC} framework package imports successfully"
|
||||
else
|
||||
echo -e "${RED}✗${NC} framework package import failed"
|
||||
echo -e "${YELLOW} Note: This may be OK if you don't need the framework${NC}"
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}✗${NC} framework package import failed"
|
||||
echo -e "${YELLOW} Note: This may be OK if you don't need the framework${NC}"
|
||||
fi
|
||||
|
||||
# Test aden_tools import
|
||||
if $PYTHON_CMD -c "import aden_tools; print('aden_tools OK')" > /dev/null 2>&1; then
|
||||
echo -e "${GREEN}✓${NC} aden_tools package imports successfully"
|
||||
else
|
||||
echo -e "${RED}✗${NC} aden_tools package import failed"
|
||||
echo -e "${RED}✗${NC} core/.venv not found - venv creation may have failed${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Test litellm + openai compatibility
|
||||
if $PYTHON_CMD -c "import litellm; print('litellm OK')" > /dev/null 2>&1; then
|
||||
# Test aden_tools import using tools venv
|
||||
TOOLS_PYTHON="$PROJECT_ROOT/tools/.venv/bin/python"
|
||||
if [ -f "$TOOLS_PYTHON" ]; then
|
||||
if $TOOLS_PYTHON -c "import aden_tools; print('aden_tools OK')" > /dev/null 2>&1; then
|
||||
echo -e "${GREEN}✓${NC} aden_tools package imports successfully"
|
||||
else
|
||||
echo -e "${RED}✗${NC} aden_tools package import failed"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}✗${NC} tools/.venv not found - venv creation may have failed${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Test litellm + openai compatibility using tools venv
|
||||
if $TOOLS_PYTHON -c "import litellm; print('litellm OK')" > /dev/null 2>&1; then
|
||||
echo -e "${GREEN}✓${NC} litellm package imports successfully"
|
||||
else
|
||||
echo -e "${YELLOW}⚠${NC} litellm import had issues (may be OK if not using LLM features)"
|
||||
@@ -191,14 +253,14 @@ echo ""
|
||||
echo "To run agents, use:"
|
||||
echo ""
|
||||
echo " ${BLUE}# From project root:${NC}"
|
||||
echo " PYTHONPATH=core:exports python -m agent_name validate"
|
||||
echo " PYTHONPATH=core:exports python -m agent_name info"
|
||||
echo " PYTHONPATH=core:exports python -m agent_name run --input '{...}'"
|
||||
echo " PYTHONPATH=core:exports ${PYTHON_CMD} -m agent_name validate"
|
||||
echo " PYTHONPATH=core:exports ${PYTHON_CMD} -m agent_name info"
|
||||
echo " PYTHONPATH=core:exports ${PYTHON_CMD} -m agent_name run --input '{...}'"
|
||||
echo ""
|
||||
echo "Available commands for your new agent:"
|
||||
echo " PYTHONPATH=core:exports python -m support_ticket_agent validate"
|
||||
echo " PYTHONPATH=core:exports python -m support_ticket_agent info"
|
||||
echo " PYTHONPATH=core:exports python -m support_ticket_agent run --input '{\"ticket_content\":\"...\",\"customer_id\":\"...\",\"ticket_id\":\"...\"}'"
|
||||
echo " PYTHONPATH=core:exports ${PYTHON_CMD} -m support_ticket_agent validate"
|
||||
echo " PYTHONPATH=core:exports ${PYTHON_CMD} -m support_ticket_agent info"
|
||||
echo " PYTHONPATH=core:exports ${PYTHON_CMD} -m support_ticket_agent run --input '{\"ticket_content\":\"...\",\"customer_id\":\"...\",\"ticket_id\":\"...\"}'"
|
||||
echo ""
|
||||
echo "To build new agents, use Claude Code skills:"
|
||||
echo " • /building-agents - Build a new agent"
|
||||
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
# Legacy Web Application Setup Script
|
||||
# NOTE: This script is for the archived honeycomb/hive web application.
|
||||
# For agent development, use: ./scripts/setup-python.sh
|
||||
# For agent development, use: ./quickstart.sh
|
||||
|
||||
set -e
|
||||
|
||||
@@ -13,7 +13,7 @@ echo " Legacy Web App Setup (Archived)"
|
||||
echo "==================================="
|
||||
echo ""
|
||||
echo "⚠️ This script is for the archived web application."
|
||||
echo " For agent development, use: ./scripts/setup-python.sh"
|
||||
echo " For agent development, use: ./quickstart.sh"
|
||||
echo ""
|
||||
|
||||
# Check for Node.js
|
||||
@@ -73,7 +73,7 @@ echo ""
|
||||
echo "⚠️ NOTE: The honeycomb/hive web application has been archived."
|
||||
echo ""
|
||||
echo "For agent development, please use:"
|
||||
echo " ./scripts/setup-python.sh"
|
||||
echo " ./quickstart.sh"
|
||||
echo ""
|
||||
echo "See ENVIRONMENT_SETUP.md for complete agent development guide."
|
||||
echo ""
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
# Aden Tools Environment Variables
|
||||
# Copy this file to .env and fill in your values
|
||||
# Or export these as environment variables
|
||||
|
||||
# Required for MCP server startup (Tier 1 - validated at startup)
|
||||
# Get your key at: https://console.anthropic.com/
|
||||
ANTHROPIC_API_KEY=your-anthropic-api-key-here
|
||||
|
||||
# Required for web_search tool (Tier 2 - validated when tool is used)
|
||||
# Get your key at: https://brave.com/search/api/
|
||||
BRAVE_SEARCH_API_KEY=your-brave-search-api-key-here
|
||||
+20
-18
@@ -5,29 +5,28 @@ description = "Tools library for the Aden agent framework"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.11"
|
||||
license = { text = "Apache-2.0" }
|
||||
authors = [
|
||||
{ name = "Aden", email = "team@aden.ai" }
|
||||
]
|
||||
authors = [{ name = "Aden", email = "team@aden.ai" }]
|
||||
keywords = ["ai", "agents", "tools", "llm"]
|
||||
classifiers = [
|
||||
"Development Status :: 3 - Alpha",
|
||||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: Apache Software License",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
"Development Status :: 3 - Alpha",
|
||||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: Apache Software License",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
]
|
||||
|
||||
dependencies = [
|
||||
"pydantic>=2.0.0",
|
||||
"httpx>=0.27.0",
|
||||
"beautifulsoup4>=4.12.0",
|
||||
"pypdf>=4.0.0",
|
||||
"pandas>=2.0.0",
|
||||
"jsonpath-ng>=1.6.0",
|
||||
"fastmcp>=2.0.0",
|
||||
"diff-match-patch>=20230430",
|
||||
"python-dotenv>=1.0.0",
|
||||
"pydantic>=2.0.0",
|
||||
"httpx>=0.27.0",
|
||||
"beautifulsoup4>=4.12.0",
|
||||
"pypdf>=4.0.0",
|
||||
"pandas>=2.0.0",
|
||||
"jsonpath-ng>=1.6.0",
|
||||
"fastmcp>=2.0.0",
|
||||
"diff-match-patch>=20230430",
|
||||
"python-dotenv>=1.0.0",
|
||||
"litellm>=1.81.0",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
@@ -87,3 +86,6 @@ lint.isort.section-order = [
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
asyncio_mode = "auto"
|
||||
|
||||
[dependency-groups]
|
||||
dev = ["ty>=0.0.13", "ruff>=0.14.14"]
|
||||
|
||||
@@ -63,7 +63,8 @@ def register_tools(mcp: FastMCP) -> None:
|
||||
|
||||
# Get total row count (re-read for accurate count)
|
||||
with open(secure_path, encoding="utf-8", newline="") as f:
|
||||
total_rows = sum(1 for _ in f) - 1 # Subtract header
|
||||
reader = csv.reader(f)
|
||||
total_rows = sum(1 for row in reader if any(row)) - 1
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
@@ -189,7 +190,8 @@ def register_tools(mcp: FastMCP) -> None:
|
||||
|
||||
# Get new total row count
|
||||
with open(secure_path, encoding="utf-8", newline="") as f:
|
||||
total_rows = sum(1 for _ in f) - 1 # Subtract header
|
||||
reader = csv.reader(f)
|
||||
total_rows = sum(1 for row in reader if any(row)) - 1 # Subtract header
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
|
||||
Reference in New Issue
Block a user