updates to skills, renaming, suggested agents, remove changelog
This commit is contained in:
@@ -45,7 +45,22 @@ AskUserQuestion(questions=[{
|
||||
|
||||
**EXECUTE THESE TOOL CALLS NOW** (silent setup — no user interaction needed):
|
||||
|
||||
1. Register the hive-tools MCP server:
|
||||
1. Check for existing sessions:
|
||||
|
||||
```
|
||||
mcp__agent-builder__list_sessions()
|
||||
```
|
||||
|
||||
- If a session with this agent name already exists, load it with `mcp__agent-builder__load_session_by_id(session_id="...")` and skip to step 3.
|
||||
- If no matching session exists, proceed to step 2.
|
||||
|
||||
2. Create a build session (replace AGENT_NAME with the user's requested agent name in snake_case):
|
||||
|
||||
```
|
||||
mcp__agent-builder__create_session(name="AGENT_NAME")
|
||||
```
|
||||
|
||||
3. Register the hive-tools MCP server:
|
||||
|
||||
```
|
||||
mcp__agent-builder__add_mcp_server(
|
||||
@@ -58,19 +73,13 @@ mcp__agent-builder__add_mcp_server(
|
||||
)
|
||||
```
|
||||
|
||||
2. Create a build session (replace AGENT_NAME with the user's requested agent name in snake_case):
|
||||
|
||||
```
|
||||
mcp__agent-builder__create_session(name="AGENT_NAME")
|
||||
```
|
||||
|
||||
3. Discover available tools:
|
||||
4. Discover available tools:
|
||||
|
||||
```
|
||||
mcp__agent-builder__list_mcp_tools()
|
||||
```
|
||||
|
||||
4. Create the package directory:
|
||||
5. Create the package directory:
|
||||
|
||||
```bash
|
||||
mkdir -p exports/AGENT_NAME/nodes
|
||||
@@ -138,7 +147,22 @@ AskUserQuestion(questions=[{
|
||||
cp -r examples/templates/TEMPLATE_DIR exports/NEW_AGENT_NAME
|
||||
```
|
||||
|
||||
### 1B.4: Create session and register MCP (same as STEP 1A)
|
||||
### 1B.4: Create session and register MCP (same logic as STEP 1A)
|
||||
|
||||
First, check for existing sessions:
|
||||
|
||||
```
|
||||
mcp__agent-builder__list_sessions()
|
||||
```
|
||||
|
||||
- If a session with this agent name already exists, load it with `mcp__agent-builder__load_session_by_id(session_id="...")` and skip to `list_mcp_tools`.
|
||||
- If no matching session exists, create one:
|
||||
|
||||
```
|
||||
mcp__agent-builder__create_session(name="NEW_AGENT_NAME")
|
||||
```
|
||||
|
||||
Then register MCP and discover tools:
|
||||
|
||||
```
|
||||
mcp__agent-builder__add_mcp_server(
|
||||
@@ -151,10 +175,6 @@ mcp__agent-builder__add_mcp_server(
|
||||
)
|
||||
```
|
||||
|
||||
```
|
||||
mcp__agent-builder__create_session(name="NEW_AGENT_NAME")
|
||||
```
|
||||
|
||||
```
|
||||
mcp__agent-builder__list_mcp_tools()
|
||||
```
|
||||
@@ -177,6 +197,23 @@ This reads the agent.json and populates the builder session with the goal, all n
|
||||
|
||||
**If starting from a template**, the goal is already loaded in the builder session. Present the existing goal to the user using the format below and ask for approval. Skip the collaborative drafting questions — go straight to presenting and asking "Do you approve this goal, or would you like to modify it?"
|
||||
|
||||
**If the user has NOT already described what they want to build**, start by asking what kind of agent they have in mind:
|
||||
|
||||
```
|
||||
AskUserQuestion(questions=[{
|
||||
"question": "What kind of agent do you want to build?",
|
||||
"header": "Agent type",
|
||||
"options": [
|
||||
{"label": "Data collection", "description": "Gathers information from the web, analyzes it, and produces a report or sends outreach (e.g. market research, news digest, email campaigns, competitive analysis)"},
|
||||
{"label": "Workflow automation", "description": "Automates a multi-step business process end-to-end (e.g. lead qualification, content publishing pipeline, data entry)"},
|
||||
{"label": "Personal assistant", "description": "Handles recurring tasks or monitors for events and acts on them (e.g. daily briefings, meeting prep, file organization)"}
|
||||
],
|
||||
"multiSelect": false
|
||||
}])
|
||||
```
|
||||
|
||||
Use the user's selection (or their custom description if they chose "Other") as context when shaping the goal below. If the user already described what they want before this step, skip the question and proceed directly.
|
||||
|
||||
**DO NOT propose a complete goal on your own.** Instead, collaborate with the user to define it.
|
||||
|
||||
**START by asking the user to help shape the goal:**
|
||||
@@ -189,7 +226,7 @@ This reads the agent.json and populates the builder session with the goal, all n
|
||||
> 2. **How will we know it succeeded?** (what does "done" look like)
|
||||
> 3. **Are there any hard constraints?** (things it must never do, quality bars, etc.)
|
||||
|
||||
**WAIT for the user to respond.** Use their input to draft:
|
||||
**WAIT for the user to respond.** Use their input (and the agent type they selected) to draft:
|
||||
|
||||
- Goal ID (kebab-case)
|
||||
- Goal name
|
||||
@@ -417,7 +454,25 @@ AskUserQuestion(questions=[{
|
||||
|
||||
**NOW — and only now — write the actual code.** The user has approved the goal, nodes, and graph.
|
||||
|
||||
**If starting from a template**, the copied files will be overwritten with the approved design. The Python files must use the NEW agent name (class name, module references, storage paths, metadata), not the original template name.
|
||||
**If starting from a template**, the copied files will be overwritten with the approved design. You MUST replace every occurrence of the old template name with the new agent name. Here is the complete checklist — miss NONE of these:
|
||||
|
||||
| File | What to rename |
|
||||
|------|---------------|
|
||||
| `config.py` | `AgentMetadata.name` — the display name shown in TUI agent selection |
|
||||
| `config.py` | `AgentMetadata.description` — agent description |
|
||||
| `agent.py` | Module docstring (line 1) |
|
||||
| `agent.py` | `class OldNameAgent:` → `class NewNameAgent:` |
|
||||
| `agent.py` | `GraphSpec(id="old-name-graph")` → `GraphSpec(id="new-name-graph")` — shown in TUI status bar |
|
||||
| `agent.py` | Storage path: `Path.home() / ".hive" / "agents" / "old_name"` → `"new_name"` |
|
||||
| `__main__.py` | Module docstring (line 1) |
|
||||
| `__main__.py` | `from .agent import ... OldNameAgent` → `NewNameAgent` |
|
||||
| `__main__.py` | CLI help string in `def cli()` docstring |
|
||||
| `__main__.py` | All `OldNameAgent()` instantiations |
|
||||
| `__main__.py` | Storage path (duplicated from agent.py) |
|
||||
| `__main__.py` | Shell banner string (e.g. `"=== Old Name Agent ==="`) |
|
||||
| `__init__.py` | Package docstring |
|
||||
| `__init__.py` | `from .agent import OldNameAgent` import |
|
||||
| `__init__.py` | `__all__` list entry |
|
||||
|
||||
### 5a: Register nodes and edges with MCP
|
||||
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
### Changed
|
||||
|
||||
### Fixed
|
||||
|
||||
### Security
|
||||
|
||||
## [0.4.2] - 2026-02-08
|
||||
|
||||
### Added
|
||||
- Resumable sessions: agents now automatically save state and can resume after interruptions
|
||||
- `/resume` command in TUI to resume latest paused/failed session
|
||||
- `/resume <session_id>` command to resume specific sessions
|
||||
- `/sessions` command to list all sessions for current agent
|
||||
- `--resume-session` CLI flag for automatic session resumption on startup
|
||||
- `--checkpoint <checkpoint_id>` CLI flag for checkpoint-based recovery
|
||||
- Ctrl+Z now immediately pauses execution with full state capture
|
||||
- `/pause` command for immediate pause during execution
|
||||
- Session state persistence: memory, execution path, node positions, visit counts
|
||||
- Unified session storage at `~/.hive/agents/{agent_name}/sessions/`
|
||||
- Automatic memory restoration on resume with full conversation history
|
||||
|
||||
### Changed
|
||||
- TUI quit now pauses execution and saves state instead of cancelling
|
||||
- Pause operations now use immediate task cancellation instead of waiting for node boundaries
|
||||
- Session cleanup timeout increased from 0.5s to 5s to ensure proper state saving
|
||||
- Session status now tracked as: active, paused, completed, failed, cancelled
|
||||
|
||||
### Deprecated
|
||||
- Pause nodes (use client-facing EventLoopNodes instead)
|
||||
- `request_pause()` method (replaced with immediate task cancellation)
|
||||
|
||||
### Removed
|
||||
- N/A
|
||||
|
||||
### Fixed
|
||||
- Memory persistence: ExecutionResult.session_state["memory"] now populated at all exit points
|
||||
- Resume now starts at correct paused_at node instead of intake node
|
||||
- Visit count double-counting on resume (paused node count now properly adjusted)
|
||||
- Session selection now picks most recent session instead of oldest
|
||||
- Quit state save failures due to insufficient timeout
|
||||
- Ctrl+Z pause implementation (was only showing notification without pausing)
|
||||
- Empty memory on resume by ensuring session_state["memory"] is properly populated
|
||||
|
||||
### Security
|
||||
- N/A
|
||||
|
||||
## [0.1.0] - 2025-01-13
|
||||
|
||||
### Added
|
||||
- Initial release
|
||||
|
||||
[Unreleased]: https://github.com/adenhq/hive/compare/v0.4.2...HEAD
|
||||
[0.4.2]: https://github.com/adenhq/hive/compare/v0.4.0...v0.4.2
|
||||
[0.1.0]: https://github.com/adenhq/hive/releases/tag/v0.1.0
|
||||
@@ -23,6 +23,7 @@ if _exports_dir.is_dir() and str(_exports_dir) not in sys.path:
|
||||
del _framework_dir, _project_root, _exports_dir
|
||||
|
||||
from mcp.server import FastMCP # noqa: E402
|
||||
from pydantic import ValidationError # noqa: E402
|
||||
|
||||
from framework.graph import ( # noqa: E402
|
||||
Constraint,
|
||||
@@ -1883,39 +1884,42 @@ def import_from_export(
|
||||
except json.JSONDecodeError as e:
|
||||
return json.dumps({"success": False, "error": f"Invalid JSON: {e}"})
|
||||
|
||||
# Parse goal (same pattern as BuildSession.from_dict lines 88-99)
|
||||
goal_data = data.get("goal")
|
||||
if goal_data:
|
||||
session.goal = Goal(
|
||||
id=goal_data["id"],
|
||||
name=goal_data["name"],
|
||||
description=goal_data["description"],
|
||||
success_criteria=[
|
||||
SuccessCriterion(**sc) for sc in goal_data.get("success_criteria", [])
|
||||
],
|
||||
constraints=[Constraint(**c) for c in goal_data.get("constraints", [])],
|
||||
)
|
||||
try:
|
||||
# Parse goal (same pattern as BuildSession.from_dict lines 88-99)
|
||||
goal_data = data.get("goal")
|
||||
if goal_data:
|
||||
session.goal = Goal(
|
||||
id=goal_data["id"],
|
||||
name=goal_data["name"],
|
||||
description=goal_data["description"],
|
||||
success_criteria=[
|
||||
SuccessCriterion(**sc) for sc in goal_data.get("success_criteria", [])
|
||||
],
|
||||
constraints=[Constraint(**c) for c in goal_data.get("constraints", [])],
|
||||
)
|
||||
|
||||
# Parse nodes (same pattern as BuildSession.from_dict line 102)
|
||||
graph_data = data.get("graph", {})
|
||||
nodes_data = graph_data.get("nodes", [])
|
||||
session.nodes = [NodeSpec(**n) for n in nodes_data]
|
||||
# Parse nodes (same pattern as BuildSession.from_dict line 102)
|
||||
graph_data = data.get("graph", {})
|
||||
nodes_data = graph_data.get("nodes", [])
|
||||
session.nodes = [NodeSpec(**n) for n in nodes_data]
|
||||
|
||||
# Parse edges (same pattern as BuildSession.from_dict lines 105-118)
|
||||
edges_data = graph_data.get("edges", [])
|
||||
session.edges = []
|
||||
for e in edges_data:
|
||||
condition_str = e.get("condition")
|
||||
if isinstance(condition_str, str):
|
||||
condition_map = {
|
||||
"always": EdgeCondition.ALWAYS,
|
||||
"on_success": EdgeCondition.ON_SUCCESS,
|
||||
"on_failure": EdgeCondition.ON_FAILURE,
|
||||
"conditional": EdgeCondition.CONDITIONAL,
|
||||
"llm_decide": EdgeCondition.LLM_DECIDE,
|
||||
}
|
||||
e["condition"] = condition_map.get(condition_str, EdgeCondition.ON_SUCCESS)
|
||||
session.edges.append(EdgeSpec(**e))
|
||||
# Parse edges (same pattern as BuildSession.from_dict lines 105-118)
|
||||
edges_data = graph_data.get("edges", [])
|
||||
session.edges = []
|
||||
for e in edges_data:
|
||||
condition_str = e.get("condition")
|
||||
if isinstance(condition_str, str):
|
||||
condition_map = {
|
||||
"always": EdgeCondition.ALWAYS,
|
||||
"on_success": EdgeCondition.ON_SUCCESS,
|
||||
"on_failure": EdgeCondition.ON_FAILURE,
|
||||
"conditional": EdgeCondition.CONDITIONAL,
|
||||
"llm_decide": EdgeCondition.LLM_DECIDE,
|
||||
}
|
||||
e["condition"] = condition_map.get(condition_str, EdgeCondition.ON_SUCCESS)
|
||||
session.edges.append(EdgeSpec(**e))
|
||||
except (KeyError, TypeError, ValueError, ValidationError) as e:
|
||||
return json.dumps({"success": False, "error": f"Malformed agent.json: {e}"})
|
||||
|
||||
# Persist updated session
|
||||
_save_session(session)
|
||||
|
||||
@@ -11,6 +11,7 @@ template_name/
|
||||
├── __init__.py # Package exports
|
||||
├── __main__.py # CLI entry point
|
||||
├── agent.py # Goal, edges, graph spec, agent class
|
||||
├── agent.json # Agent definition (used by build-from-template)
|
||||
├── config.py # Runtime configuration
|
||||
├── nodes/
|
||||
│ └── __init__.py # Node definitions (NodeSpec instances)
|
||||
@@ -19,20 +20,28 @@ template_name/
|
||||
|
||||
## How to use a template
|
||||
|
||||
### Option 1: Build from template (recommended)
|
||||
|
||||
Use the `/hive-create` skill and select "From a template" to interactively pick a template, customize the goal/nodes/graph, and export a new agent.
|
||||
|
||||
### Option 2: Manual copy
|
||||
|
||||
```bash
|
||||
# 1. Copy to your exports directory
|
||||
cp -r examples/templates/marketing_agent exports/my_marketing_agent
|
||||
cp -r examples/templates/deep_research_agent exports/my_research_agent
|
||||
|
||||
# 2. Update the module references in __main__.py and __init__.py
|
||||
|
||||
# 3. Customize goal, nodes, edges, and prompts
|
||||
|
||||
# 4. Run it
|
||||
uv run python -m exports.my_marketing_agent --input '{"product_description": "..."}'
|
||||
uv run python -m exports.my_research_agent --input '{"topic": "..."}'
|
||||
```
|
||||
|
||||
## Available templates
|
||||
|
||||
| Template | Description |
|
||||
|----------|-------------|
|
||||
| [marketing_agent](marketing_agent/) | Multi-channel marketing content generator with audience analysis, content generation, and editorial review nodes |
|
||||
| [deep_research_agent](deep_research_agent/) | Interactive research agent that searches diverse sources, evaluates findings with user checkpoints, and produces a cited HTML report |
|
||||
| [tech_news_reporter](tech_news_reporter/) | Researches the latest technology and AI news from the web and produces a well-organized report |
|
||||
| [twitter_outreach](twitter_outreach/) | Researches a Twitter/X profile, crafts a personalized outreach email, and sends it after user approval |
|
||||
|
||||
Reference in New Issue
Block a user