Skip to content

Commit 132d84c

Browse files
Merge pull request #5058 from adenhq/fix/deprecation
fix(arch): remove all deprecated concepts and deadcodes
2 parents 893053e + a03b378 commit 132d84c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+511
-6533
lines changed

.claude/skills/hive-create/SKILL.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,7 @@ AskUserQuestion(questions=[{
492492
- node_id (kebab-case)
493493
- name
494494
- description
495-
- node_type: `"event_loop"` (recommended for all LLM work) or `"function"` (deterministic, no LLM)
495+
- node_type: `"event_loop"` (the only valid type; use `client_facing: True` for HITL)
496496
- input_keys (what data this node receives)
497497
- output_keys (what data this node produces)
498498
- tools (ONLY tools that exist from Step 1 — empty list if no tools needed)
@@ -852,8 +852,7 @@ cd /home/timothy/oss/hive && PYTHONPATH=exports uv run python -m AGENT_NAME vali
852852

853853
| Type | tools param | Use when |
854854
| ------------ | ----------------------- | --------------------------------------- |
855-
| `event_loop` | `'["tool1"]'` or `'[]'` | LLM-powered work with or without tools |
856-
| `function` | N/A | Deterministic Python operations, no LLM |
855+
| `event_loop` | `'["tool1"]'` or `'[]'` | All agent work (with or without tools, HITL via client_facing) |
857856

858857
---
859858

@@ -1008,7 +1007,7 @@ Use this reference during STEP 2 to give accurate, honest assessments.
10081007
| Sub-second responses | LLM latency is inherent | Traditional code, no LLM |
10091008
| Processing millions of items | Context windows and rate limits | Batch processing + sampling |
10101009
| Real-time streaming data | No built-in pub/sub or streaming input | Custom MCP server + agent |
1011-
| Guaranteed determinism | LLM outputs vary | Function nodes for deterministic parts |
1010+
| Guaranteed determinism | LLM outputs vary | Traditional code for deterministic parts |
10121011
| Offline/air-gapped | Requires LLM API access | Local models (not currently supported) |
10131012
| Multi-user concurrency | Single-user session model | Separate agent instances per user |
10141013

core/MCP_BUILDER_TOOLS_GUIDE.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ Register an MCP server as a tool source for your agent.
8282
"example_tool"
8383
],
8484
"total_mcp_servers": 1,
85-
"note": "MCP server 'tools' registered with 6 tools. These tools can now be used in llm_tool_use nodes."
85+
"note": "MCP server 'tools' registered with 6 tools. These tools can now be used in event_loop nodes."
8686
}
8787
```
8888

@@ -149,7 +149,7 @@ List tools available from registered MCP servers.
149149
]
150150
},
151151
"total_tools": 6,
152-
"note": "Use these tool names in the 'tools' parameter when adding llm_tool_use nodes"
152+
"note": "Use these tool names in the 'tools' parameter when adding event_loop nodes"
153153
}
154154
```
155155

@@ -246,7 +246,7 @@ Here's a complete workflow for building an agent with MCP tools:
246246
"node_id": "web-searcher",
247247
"name": "Web Search",
248248
"description": "Search the web for information",
249-
"node_type": "llm_tool_use",
249+
"node_type": "event_loop",
250250
"input_keys": "[\"query\"]",
251251
"output_keys": "[\"search_results\"]",
252252
"system_prompt": "Search for {query} using the web_search tool",

core/MCP_INTEGRATION_GUIDE.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ builder = WorkflowBuilder()
119119
builder.add_node(
120120
node_id="researcher",
121121
name="Web Researcher",
122-
node_type="llm_tool_use",
122+
node_type="event_loop",
123123
system_prompt="Research the topic using web_search",
124124
tools=["web_search"], # Tool from tools MCP server
125125
input_keys=["topic"],
@@ -137,7 +137,7 @@ Tools from MCP servers can be referenced in your agent.json just like built-in t
137137
{
138138
"id": "searcher",
139139
"name": "Web Searcher",
140-
"node_type": "llm_tool_use",
140+
"node_type": "event_loop",
141141
"system_prompt": "Search for information about {topic}",
142142
"tools": ["web_search", "web_scrape"],
143143
"input_keys": ["topic"],

core/MCP_SERVER_GUIDE.md

Lines changed: 17 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -103,39 +103,28 @@ Add a processing node to the agent graph.
103103
- `node_id` (string, required): Unique node identifier
104104
- `name` (string, required): Human-readable name
105105
- `description` (string, required): What this node does
106-
- `node_type` (string, required): One of: `llm_generate`, `llm_tool_use`, `router`, `function`
106+
- `node_type` (string, required): Must be `event_loop` (the only valid type)
107107
- `input_keys` (string, required): JSON array of input variable names
108108
- `output_keys` (string, required): JSON array of output variable names
109-
- `system_prompt` (string, optional): System prompt for LLM nodes
110-
- `tools` (string, optional): JSON array of tool names for tool_use nodes
111-
- `routes` (string, optional): JSON object of route mappings for router nodes
109+
- `system_prompt` (string, optional): System prompt for the LLM
110+
- `tools` (string, optional): JSON array of tool names
111+
- `client_facing` (boolean, optional): Set to true for human-in-the-loop interaction
112112

113-
**Node Types:**
113+
**Node Type:**
114114

115-
1. **llm_generate**: Uses LLM to generate output from inputs
116-
- Requires: `system_prompt`
117-
- Tools: Not used
118-
119-
2. **llm_tool_use**: Uses LLM with tools to accomplish tasks
120-
- Requires: `system_prompt`, `tools`
121-
- Tools: Array of tool names (e.g., `["web_search", "web_fetch"]`)
122-
123-
3. **router**: LLM-powered routing to different paths
124-
- Requires: `system_prompt`, `routes`
125-
- Routes: Object mapping route names to target node IDs
126-
- Example: `{"pass": "success_node", "fail": "retry_node"}`
127-
128-
4. **function**: Executes a pre-defined function
129-
- System prompt describes the function behavior
130-
- No LLM calls, pure computation
115+
**event_loop**: LLM-powered node with self-correction loop
116+
- Requires: `system_prompt`
117+
- Optional: `tools` (array of tool names, e.g., `["web_search", "web_fetch"]`)
118+
- Optional: `client_facing` (set to true for HITL / user interaction)
119+
- Supports: iterative refinement, judge-based evaluation, tool use, streaming
131120

132121
**Example:**
133122
```json
134123
{
135124
"node_id": "search_sources",
136125
"name": "Search Sources",
137126
"description": "Searches for relevant sources on the topic",
138-
"node_type": "llm_tool_use",
127+
"node_type": "event_loop",
139128
"input_keys": "[\"topic\", \"search_queries\"]",
140129
"output_keys": "[\"sources\", \"source_count\"]",
141130
"system_prompt": "Search for sources using the provided queries...",
@@ -198,7 +187,7 @@ Export the validated graph as an agent specification.
198187

199188
**What it does:**
200189
1. Validates the graph
201-
2. Auto-generates missing edges from router routes
190+
2. Validates edge connectivity
202191
3. Writes files to disk:
203192
- `exports/{agent-name}/agent.json` - Full agent specification
204193
- `exports/{agent-name}/README.md` - Auto-generated documentation
@@ -252,47 +241,6 @@ Test the complete agent graph with sample inputs.
252241

253242
---
254243

255-
### Evaluation Rules
256-
257-
#### `add_evaluation_rule`
258-
Add a rule for the HybridJudge to evaluate node outputs.
259-
260-
**Parameters:**
261-
- `rule_id` (string, required): Unique rule identifier
262-
- `description` (string, required): What this rule checks
263-
- `condition` (string, required): Python expression to evaluate
264-
- `action` (string, required): Action to take: `accept`, `retry`, `escalate`
265-
- `priority` (integer, optional): Rule priority (default: 0)
266-
- `feedback_template` (string, optional): Feedback message template
267-
268-
**Condition Examples:**
269-
- `'result.get("success") == True'` - Check for success flag
270-
- `'result.get("error_type") == "timeout"'` - Check error type
271-
- `'len(result.get("data", [])) > 0'` - Check for non-empty data
272-
273-
**Example:**
274-
```json
275-
{
276-
"rule_id": "timeout_retry",
277-
"description": "Retry on timeout errors",
278-
"condition": "result.get('error_type') == 'timeout'",
279-
"action": "retry",
280-
"priority": 10,
281-
"feedback_template": "Timeout occurred, retrying..."
282-
}
283-
```
284-
285-
#### `list_evaluation_rules`
286-
List all configured evaluation rules.
287-
288-
#### `remove_evaluation_rule`
289-
Remove an evaluation rule.
290-
291-
**Parameters:**
292-
- `rule_id` (string, required): Rule to remove
293-
294-
---
295-
296244
## Example Workflow
297245

298246
Here's a complete workflow for building a research agent:
@@ -320,7 +268,7 @@ add_node(
320268
node_id="planner",
321269
name="Research Planner",
322270
description="Creates research strategy",
323-
node_type="llm_generate",
271+
node_type="event_loop",
324272
input_keys='["topic"]',
325273
output_keys='["strategy", "queries"]',
326274
system_prompt="Analyze topic and create research plan..."
@@ -330,7 +278,7 @@ add_node(
330278
node_id="searcher",
331279
name="Search Sources",
332280
description="Find relevant sources",
333-
node_type="llm_tool_use",
281+
node_type="event_loop",
334282
input_keys='["queries"]',
335283
output_keys='["sources"]',
336284
system_prompt="Search for sources...",
@@ -359,10 +307,9 @@ The exported agent will be saved to `exports/research-agent/`.
359307

360308
1. **Start with the goal**: Define clear success criteria before building nodes
361309
2. **Test nodes individually**: Use `test_node` to verify each node works
362-
3. **Use router nodes for branching**: Don't create edges manually for routers - define routes and they'll be auto-generated
363-
4. **Add evaluation rules**: Help the judge evaluate outputs deterministically
364-
5. **Validate early, validate often**: Run `validate_graph` after adding nodes/edges
365-
6. **Check exports**: Review the generated README.md to verify your agent structure
310+
3. **Use conditional edges for branching**: Define condition_expr on edges for decision points
311+
4. **Validate early, validate often**: Run `validate_graph` after adding nodes/edges
312+
5. **Check exports**: Review the generated README.md to verify your agent structure
366313

367314
---
368315

core/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ To use the agent builder with Claude Desktop or other MCP clients, add this to y
7373
The MCP server provides tools for:
7474
- Creating agent building sessions
7575
- Defining goals with success criteria
76-
- Adding nodes (llm_generate, llm_tool_use, router, function)
76+
- Adding nodes (event_loop only)
7777
- Connecting nodes with edges
7878
- Validating and exporting agent graphs
7979
- Testing nodes and full agent graphs

core/demos/github_outreach_demo.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
)
6969
from framework.graph.executor import GraphExecutor # noqa: E402
7070
from framework.graph.goal import Goal # noqa: E402
71-
from framework.graph.node import NodeSpec # noqa: E402
71+
from framework.graph.node import NodeContext, NodeProtocol, NodeResult, NodeSpec # noqa: E402
7272
from framework.llm.litellm import LiteLLMProvider # noqa: E402
7373
from framework.runner.tool_registry import ToolRegistry # noqa: E402
7474
from framework.runtime.core import Runtime # noqa: E402
@@ -654,7 +654,7 @@ def list_data_files() -> dict:
654654
id="sender",
655655
name="Sender",
656656
description="Send approved campaign emails",
657-
node_type="function",
657+
node_type="event_loop",
658658
input_keys=["approved_emails"],
659659
output_keys=["send_results"],
660660
),
@@ -823,11 +823,20 @@ def _send_email_via_resend(
823823
return {"error": f"Network error: {e}"}
824824

825825

826+
class SenderNode(NodeProtocol):
827+
"""Node wrapper for send_emails function."""
828+
829+
async def execute(self, ctx: NodeContext) -> NodeResult:
830+
approved = ctx.input_data.get("approved_emails", "")
831+
result_str = send_emails(approved_emails=approved)
832+
ctx.memory.write("send_results", result_str)
833+
return NodeResult(success=True, output={"send_results": result_str})
834+
835+
826836
def send_emails(approved_emails: str = "") -> str:
827837
"""Send approved campaign emails via Resend, or log if unconfigured.
828838
829-
Called by FunctionNode which unpacks input_keys as kwargs.
830-
Returns a JSON string (FunctionNode wraps it in NodeResult).
839+
Returns a JSON string.
831840
"""
832841
approved = approved_emails
833842
if not approved:
@@ -1780,7 +1789,7 @@ async def _run_pipeline(websocket, initial_message: str):
17801789
)
17811790
for nid, impl in nodes.items():
17821791
executor.register_node(nid, impl)
1783-
executor.register_function("sender", send_emails)
1792+
executor.register_node("sender", SenderNode())
17841793

17851794
# --- Event forwarding: bus → WebSocket ---
17861795

core/examples/manual_agent.py

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
This example demonstrates how to build and run an agent programmatically
55
without using the Claude Code CLI or external LLM APIs.
66
7-
It uses 'function' nodes to define logic in pure Python, making it perfect
8-
for understanding the core runtime loop:
7+
It uses custom NodeProtocol implementations to define logic in pure Python,
8+
making it perfect for understanding the core runtime loop:
99
Setup -> Graph definition -> Execution -> Result
1010
1111
Run with:
@@ -16,22 +16,33 @@
1616

1717
from framework.graph import EdgeCondition, EdgeSpec, Goal, GraphSpec, NodeSpec
1818
from framework.graph.executor import GraphExecutor
19+
from framework.graph.node import NodeContext, NodeProtocol, NodeResult
1920
from framework.runtime.core import Runtime
2021

2122

22-
# 1. Define Node Logic (Pure Python Functions)
23-
def greet(name: str) -> str:
23+
# 1. Define Node Logic (Custom NodeProtocol implementations)
24+
class GreeterNode(NodeProtocol):
2425
"""Generate a simple greeting."""
25-
return f"Hello, {name}!"
2626

27+
async def execute(self, ctx: NodeContext) -> NodeResult:
28+
name = ctx.input_data.get("name", "World")
29+
greeting = f"Hello, {name}!"
30+
ctx.memory.write("greeting", greeting)
31+
return NodeResult(success=True, output={"greeting": greeting})
2732

28-
def uppercase(greeting: str) -> str:
33+
34+
class UppercaserNode(NodeProtocol):
2935
"""Convert text to uppercase."""
30-
return greeting.upper()
36+
37+
async def execute(self, ctx: NodeContext) -> NodeResult:
38+
greeting = ctx.input_data.get("greeting") or ctx.memory.read("greeting") or ""
39+
result = greeting.upper()
40+
ctx.memory.write("final_greeting", result)
41+
return NodeResult(success=True, output={"final_greeting": result})
3142

3243

3344
async def main():
34-
print("🚀 Setting up Manual Agent...")
45+
print("Setting up Manual Agent...")
3546

3647
# 2. Define the Goal
3748
# Every agent needs a goal with success criteria
@@ -55,8 +66,7 @@ async def main():
5566
id="greeter",
5667
name="Greeter",
5768
description="Generates a simple greeting",
58-
node_type="function",
59-
function="greet", # Matches the registered function name
69+
node_type="event_loop",
6070
input_keys=["name"],
6171
output_keys=["greeting"],
6272
)
@@ -65,8 +75,7 @@ async def main():
6575
id="uppercaser",
6676
name="Uppercaser",
6777
description="Converts greeting to uppercase",
68-
node_type="function",
69-
function="uppercase",
78+
node_type="event_loop",
7079
input_keys=["greeting"],
7180
output_keys=["final_greeting"],
7281
)
@@ -98,23 +107,23 @@ async def main():
98107
runtime = Runtime(storage_path=Path("./agent_logs"))
99108
executor = GraphExecutor(runtime=runtime)
100109

101-
# 7. Register Function Implementations
102-
# Connect string names in NodeSpecs to actual Python functions
103-
executor.register_function("greeter", greet)
104-
executor.register_function("uppercaser", uppercase)
110+
# 7. Register Node Implementations
111+
# Connect node IDs in the graph to actual Python implementations
112+
executor.register_node("greeter", GreeterNode())
113+
executor.register_node("uppercaser", UppercaserNode())
105114

106115
# 8. Execute Agent
107-
print("Executing agent with input: name='Alice'...")
116+
print("Executing agent with input: name='Alice'...")
108117

109118
result = await executor.execute(graph=graph, goal=goal, input_data={"name": "Alice"})
110119

111120
# 9. Verify Results
112121
if result.success:
113-
print("\n✅ Success!")
122+
print("\nSuccess!")
114123
print(f"Path taken: {' -> '.join(result.path)}")
115124
print(f"Final output: {result.output.get('final_greeting')}")
116125
else:
117-
print(f"\n❌ Failed: {result.error}")
126+
print(f"\nFailed: {result.error}")
118127

119128

120129
if __name__ == "__main__":

core/examples/mcp_integration_example.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ async def example_4_custom_agent_with_mcp_tools():
122122
node_id="web-searcher",
123123
name="Web Search",
124124
description="Search the web for information",
125-
node_type="llm_tool_use",
125+
node_type="event_loop",
126126
system_prompt="Search for {query} and return the top results. Use the web_search tool.",
127127
tools=["web_search"], # This tool comes from tools MCP server
128128
input_keys=["query"],
@@ -133,7 +133,7 @@ async def example_4_custom_agent_with_mcp_tools():
133133
node_id="summarizer",
134134
name="Summarize Results",
135135
description="Summarize the search results",
136-
node_type="llm_generate",
136+
node_type="event_loop",
137137
system_prompt="Summarize the following search results in 2-3 sentences: {search_results}",
138138
input_keys=["search_results"],
139139
output_keys=["summary"],

0 commit comments

Comments
 (0)