Skip to content

feat(agent): Viral Tech Copywriter#6922

Open
fermano wants to merge 2 commits intoaden-hive:mainfrom
fermano:feat/agent-viral-tech-copywriter
Open

feat(agent): Viral Tech Copywriter#6922
fermano wants to merge 2 commits intoaden-hive:mainfrom
fermano:feat/agent-viral-tech-copywriter

Conversation

@fermano
Copy link
Copy Markdown
Contributor

@fermano fermano commented Apr 2, 2026

Description

Adds examples/templates/viral_tech_copywriter/, a reference goal-driven agent for tech marketing copy: conversational brief → structured JSON → hooks + per-channel copy → user-chosen HTML and/or Markdown export, using only existing hive-tools (save_data, append_data, serve_file_to_user, load_data, list_data_files, edit_data).

Graph: intake (client-facing) → normalize-briefwrite-packagedeliver-exports (terminal, client-facing; MCP tools only on deliver-exports). mcp_servers.json is required; ViralTechCopywriterAgent.load_hive_tools_registry() fails fast with a clear error if it is missing (both run and tui), and _setup() uses the same helper so MCP wiring is not duplicated. flowchart.json matches agent.py (four nodes; terminal deliver-exports).

flowchart LR
  A[intake] --> B[normalize-brief]
  B --> C[write-package]
  C --> D[deliver-exports]
Loading

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactoring (no functional changes)

Related Issues

Fixes #6821

Changes Made

  • New template examples/templates/viral_tech_copywriter/: agent.py, nodes/__init__.py, config.py, __init__.py, __main__.py, mcp_servers.json, flowchart.json (aligned with graph).
  • MCP startup: mcp_config_path(), load_hive_tools_registry() (fail-fast if config missing), used from _setup() and TUI without poking private fields from the CLI.
  • examples/templates/README.md: table row for this template.
  • Tests: tests/test_structure.py (graph, deliver-node tools, goal weights, AgentRunner.load, MCP path + missing-file error).
  • Template README: behavior, outputs, PYTHONPATH, MCP requirement, honesty constraints.

Testing

Describe the tests you ran to verify your changes:

  • Unit tests pass (cd core && pytest tests/)
  • Lint passes (cd core && ruff check .)
  • Manual testing performed

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

Screenshots (if applicable)

Add screenshots to demonstrate UI changes.

Summary by CodeRabbit

  • New Features

    • Added "Viral Tech Copywriter" template with end-to-end workflow, CLI (run/tui/info/validate), HTML vs. Markdown file-serving behavior, and clear startup failure when required MCP server config is missing.
  • Documentation

    • Comprehensive README with setup/run guidance, LLM configuration, expected outputs, and honesty constraints (no fabricated metrics/customers/quotes).
  • Tests

    • Added structural and runtime tests validating workflow, agent wiring, and MCP config behavior.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 2, 2026

📝 Walkthrough

Walkthrough

Adds a new "Viral Tech Copywriter" template under examples/templates/viral_tech_copywriter implementing a linear four-stage graph (intake → normalize-brief → write-package → deliver-exports) that converts conversational briefs into structured JSON, channel copy, and optional HTML/Markdown exports; delivery is limited to hive-tools MCP file/data APIs and prompts prohibit fabrication.

Changes

Cohort / File(s) Summary
Package entry & exports
examples/templates/viral_tech_copywriter/__init__.py, examples/templates/viral_tech_copywriter/__main__.py
Adds package exports, __version__, and a Click CLI with run, tui, info, and validate commands plus logging and TUI runtime wiring.
Agent core & config
examples/templates/viral_tech_copywriter/agent.py, examples/templates/viral_tech_copywriter/config.py
Implements ViralTechCopywriterAgent with graph construction, executor/tool registry setup (reads mcp_servers.json), async lifecycle (start/stop/run/trigger_and_wait), Goal/success criteria/constraints, and AgentMetadata/default config.
Node specs & prompts
examples/templates/viral_tech_copywriter/nodes/__init__.py
Defines four NodeSpec nodes and detailed system prompts: intake, normalize-brief, write-package, deliver-exports. deliver-exports is the only node using hive-tools delivery tools.
Workflow & MCP config
examples/templates/viral_tech_copywriter/flowchart.json, examples/templates/viral_tech_copywriter/mcp_servers.json
Adds flowchart describing nodes/edges/entry/terminal and an mcp_servers.json entry for a hive-tools stdio MCP server (executes python mcp_server.py --stdio from tools/).
Tests & test scaffolding
examples/templates/viral_tech_copywriter/tests/conftest.py, examples/templates/viral_tech_copywriter/tests/test_structure.py
Adds pytest fixtures and structural tests verifying goal, node order/flags, edge linearity, tools present only on deliver-exports, agent validation, runner loading, and MCP config path/behavior when missing.
Documentation
examples/templates/viral_tech_copywriter/README.md
New README describing end-to-end behavior, honesty constraints, run/TUI/LLM instructions, required mcp_servers.json, expected outputs, file-serving behavior for HTML vs Markdown, and example CLI/pytest commands.

Sequence Diagram

sequenceDiagram
    participant Client as Client
    participant Agent as ViralTechCopywriterAgent
    participant Executor as GraphExecutor
    participant LLM as LLM Provider
    participant Tools as HiveTools MCP

    Client->>Agent: run(context)
    activate Agent
    Agent->>Agent: start()
    Agent->>Executor: initialize graph/executor

    Note over Agent,Executor: Linear node execution

    Executor->>LLM: process intake prompt
    LLM-->>Executor: raw_brief
    Executor->>LLM: process normalize-brief prompt
    LLM-->>Executor: structured_brief (JSON)
    Executor->>LLM: process write-package prompt
    LLM-->>Executor: copy_package (JSON)
    Executor->>LLM: process deliver-exports prompt
    LLM->>Tools: save_data / append_data / serve_file_to_user
    Tools-->>LLM: file URIs/paths
    LLM-->>Executor: delivered_artifacts

    Executor-->>Agent: ExecutionResult
    Agent->>Agent: stop()
    Agent-->>Client: ExecutionResult
    deactivate Agent
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰
I hopped in to tidy briefs and lines,
From chat to hooks and export signs.
Four nodes aligned, no fibs allowed,
Files saved neat—our client’s wowed.
A little rabbit cheers: well done, team!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.95% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(agent): Viral Tech Copywriter' is clear, concise, and directly summarizes the main feature addition—a new agent template.
Linked Issues check ✅ Passed The PR implements all primary coding requirements from #6821: linear flow with four nodes, Goal with success criteria and constraints, tools=[] for non-deliver nodes, hive-tools MCP only on deliver-exports with specified toolkit, HTML/Markdown delivery, mcp_servers.json, skip_credential_validation, structural tests, and proper outputs.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing the Viral Tech Copywriter template under examples/templates/viral_tech_copywriter/ with no unrelated modifications to other components.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@fermano fermano marked this pull request as draft April 2, 2026 23:17
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (9)
examples/templates/viral_tech_copywriter/config.py (1)

1-5: Add from __future__ import annotations import.

Per coding guidelines, all Python files should include this import for modern type syntax.

Proposed fix
 """Runtime configuration for Viral Tech Copywriter."""
 
+from __future__ import annotations
+
 from dataclasses import dataclass
 
 from framework.config import RuntimeConfig
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/templates/viral_tech_copywriter/config.py` around lines 1 - 5, Add
the future annotations import at the top of the module: insert "from __future__
import annotations" as the first import to enable postponed evaluation of
annotations for this module that defines the dataclass RuntimeConfig (and any
other type hints) in examples/templates/viral_tech_copywriter/config.py.
examples/templates/viral_tech_copywriter/tests/conftest.py (1)

19-30: Add return type hints to fixtures.

Per coding guidelines, functions should have type hints on all signatures.

Proposed fix
+from types import ModuleType
+
+from framework.runner.runner import AgentRunner
+
+
 `@pytest.fixture`(scope="session")
-def agent_module():
-    import importlib
-
+def agent_module() -> ModuleType:
+    import importlib
     return importlib.import_module(Path(AGENT_PATH).name)
 
 
 `@pytest.fixture`(scope="session")
-def runner_loaded():
-    from framework.runner.runner import AgentRunner
-
+def runner_loaded() -> AgentRunner:
     return AgentRunner.load(AGENT_PATH, skip_credential_validation=True)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/templates/viral_tech_copywriter/tests/conftest.py` around lines 19 -
30, Add explicit return type annotations to the pytest fixtures: annotate
agent_module to return types.ModuleType and annotate runner_loaded to return
framework.runner.runner.AgentRunner; import ModuleType (from types) and ensure
AgentRunner is imported or referenced for the type hint so signatures read with
-> ModuleType and -> AgentRunner respectively while keeping the existing
pytest.fixture decorators and behavior.
examples/templates/viral_tech_copywriter/__main__.py (3)

149-161: Missing return type hint.

The validate function is missing the -> None return type hint. As per coding guidelines, use type hints on all function signatures.

Proposed fix
 `@cli.command`()
-def validate() -> None:
+def validate() -> None:
     """Validate graph structure."""

Wait, I see the return type is already there on line 150. Let me re-read... Yes, def validate() -> None: is correct. LGTM!

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/templates/viral_tech_copywriter/__main__.py` around lines 149 - 161,
The reviewer comment is incorrect: the function validate already includes the
return type hint (def validate() -> None:); no code changes are needed—dismiss
the comment/approve the PR as-is and keep the existing validate function and its
usage of default_agent.validate() unchanged.

133-146: Missing return type hint on info function.

The info function is missing the -> None return type hint, which is required per coding guidelines.

Proposed fix
 `@cli.command`()
 `@click.option`("--json", "output_json", is_flag=True)
-def info(output_json: bool) -> None:
+def info(output_json: bool) -> None:

Actually, I see the return type is present. LGTM!

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/templates/viral_tech_copywriter/__main__.py` around lines 133 - 146,
The review flagged a missing return type for the info function, but the function
def info(output_json: bool) -> None already includes the correct return type; no
change required—leave the info function as-is and proceed with the approval.

81-102: Code duplication with ViralTechCopywriterAgent._setup() in agent.py.

The TUI command manually constructs EventBus, ToolRegistry, loads MCP config, and creates LiteLLMProvider - this duplicates logic from the _setup() method in agent.py. Additionally, directly assigning to private attributes (agent._event_bus, agent._tool_registry) breaks encapsulation.

Consider refactoring to expose a setup method or factory that allows TUI-specific configuration without duplicating the initialization logic.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/templates/viral_tech_copywriter/__main__.py` around lines 81 - 102,
The TUI's run_with_tui currently duplicates initialization logic and mutates
private attributes (assigning agent._event_bus, agent._tool_registry, loading
MCP config and creating LiteLLMProvider) that already belong in
ViralTechCopywriterAgent._setup; refactor by adding a public setup method or
factory on ViralTechCopywriterAgent (e.g., create_for_tui or setup_for_tui) that
encapsulates EventBus and ToolRegistry creation, MCP config loading, and
LiteLLMProvider construction, then call that new method from run_with_tui and
use agent._build_graph only after setup so you stop assigning private attributes
directly and eliminate duplicated setup code.
examples/templates/viral_tech_copywriter/agent.py (4)

252-268: Missing return type hint on info method.

The info method is missing a return type hint. As per coding guidelines, use type hints on all function signatures.

Proposed fix
-    def info(self):
+    def info(self) -> dict[str, Any]:

Ensure from typing import Any is added to imports.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/templates/viral_tech_copywriter/agent.py` around lines 252 - 268,
The info method lacks a return type hint; update the signature of def info(self)
to include a return type (e.g., -> dict[str, Any]) and add the import "from
typing import Any" to the module imports so the hint resolves; locate the info
method and metadata/self.goal references in
examples/templates/viral_tech_copywriter/agent.py and apply the change to the
function signature only (no other logic modifications).

270-298: Missing return type hint on validate method.

The validate method is missing a return type hint.

Proposed fix
-    def validate(self):
+    def validate(self) -> dict[str, Any]:
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/templates/viral_tech_copywriter/agent.py` around lines 270 - 298,
The validate method lacks a return type annotation; add an explicit return type
for validate (e.g., -> Dict[str, Any] or a custom TypedDict like
ValidationResult) and import the required typing symbols (Dict, Any or
TypedDict) at the top of the file; keep the existing return shape (keys "valid",
"errors", "warnings") and apply the annotation to the validate method signature
to make its return type explicit.

219-221: Incomplete cleanup in stop() method.

The stop() method sets _executor and _event_bus to None but leaves _tool_registry and _graph intact. This inconsistency could cause issues if the agent is restarted, as _setup() would recreate all components while stale references might remain.

Proposed fix
     async def stop(self) -> None:
         self._executor = None
         self._event_bus = None
+        self._tool_registry = None
+        self._graph = None
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/templates/viral_tech_copywriter/agent.py` around lines 219 - 221,
The stop() method currently nulled only self._executor and self._event_bus but
left self._tool_registry and self._graph intact, risking stale references on
restart; update stop() to also clear or properly dispose self._tool_registry and
self._graph (e.g., set self._tool_registry = None and self._graph = None or call
their respective cleanup/shutdown methods if available) so that subsequent calls
to _setup() recreate all components from a clean state; ensure you reference and
handle any teardown APIs on the objects before nulling to avoid resource leaks.

146-158: Missing type hints on __init__ method.

The __init__ method is missing type hints for the config parameter and return type. As per coding guidelines, use type hints on all function signatures.

Proposed fix
-    def __init__(self, config=None):
+    def __init__(self, config: AgentConfig | None = None) -> None:

Note: Replace AgentConfig with the actual type from .config module.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/templates/viral_tech_copywriter/agent.py` around lines 146 - 158,
The __init__ signature in the class is missing type hints for the config
parameter and the return type; update the __init__ method to annotate config
with the appropriate config type (e.g., AgentConfig from the .config module or
the correct type imported as AgentConfig) and add the explicit return type ->
None, and ensure the AgentConfig type is imported or referenced (or use
Optional[AgentConfig] if None is allowed) so the signature reads with proper
typing for config and a None return.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@examples/templates/viral_tech_copywriter/agent.py`:
- Around line 242-250: Update the run method and trigger_and_wait usage to add
proper type hints and remove the unused timeout parameter: change the run
signature to accept context: dict[str, Any] and session_state: Optional[Any]
(import Any and Optional from typing if missing) and update any local references
to session_state accordingly; remove the timeout parameter from the
trigger_and_wait definition and all calls (including the call inside run)
because GraphExecutor.execute() does not accept a timeout; ensure
trigger_and_wait and GraphExecutor-related call sites compile after removing
timeout and adjust imports to include Any/Optional.

In `@examples/templates/viral_tech_copywriter/flowchart.json`:
- Around line 133-143: The flowchart_map object is missing a mapping for
"deliver-exports"; add an entry so that "deliver-exports" maps to
["deliver-exports"] within the flowchart_map (i.e., update the flowchart_map
JSON to include the "deliver-exports" key with the appropriate array value) to
keep mappings consistent with other steps like "intake", "normalize-brief", and
"write-package".
- Around line 18-93: The flowchart JSON is missing the terminal
"deliver-exports" node and the edge from "write-package" to it, and
"write-package" is incorrectly marked as terminal; add a new node object with id
"deliver-exports" (matching the agent's terminal behavior), change the
"write-package" node's "flowchart_type" from "terminal" to "process", and add an
edge (e.g., "edge-2") with source "write-package", target "deliver-exports",
condition "on_success"; finally update "terminal_nodes" to ["deliver-exports"]
so the JSON matches the agent implementation (refer to node ids "intake",
"normalize-brief", "write-package", and the new "deliver-exports").

---

Nitpick comments:
In `@examples/templates/viral_tech_copywriter/__main__.py`:
- Around line 149-161: The reviewer comment is incorrect: the function validate
already includes the return type hint (def validate() -> None:); no code changes
are needed—dismiss the comment/approve the PR as-is and keep the existing
validate function and its usage of default_agent.validate() unchanged.
- Around line 133-146: The review flagged a missing return type for the info
function, but the function def info(output_json: bool) -> None already includes
the correct return type; no change required—leave the info function as-is and
proceed with the approval.
- Around line 81-102: The TUI's run_with_tui currently duplicates initialization
logic and mutates private attributes (assigning agent._event_bus,
agent._tool_registry, loading MCP config and creating LiteLLMProvider) that
already belong in ViralTechCopywriterAgent._setup; refactor by adding a public
setup method or factory on ViralTechCopywriterAgent (e.g., create_for_tui or
setup_for_tui) that encapsulates EventBus and ToolRegistry creation, MCP config
loading, and LiteLLMProvider construction, then call that new method from
run_with_tui and use agent._build_graph only after setup so you stop assigning
private attributes directly and eliminate duplicated setup code.

In `@examples/templates/viral_tech_copywriter/agent.py`:
- Around line 252-268: The info method lacks a return type hint; update the
signature of def info(self) to include a return type (e.g., -> dict[str, Any])
and add the import "from typing import Any" to the module imports so the hint
resolves; locate the info method and metadata/self.goal references in
examples/templates/viral_tech_copywriter/agent.py and apply the change to the
function signature only (no other logic modifications).
- Around line 270-298: The validate method lacks a return type annotation; add
an explicit return type for validate (e.g., -> Dict[str, Any] or a custom
TypedDict like ValidationResult) and import the required typing symbols (Dict,
Any or TypedDict) at the top of the file; keep the existing return shape (keys
"valid", "errors", "warnings") and apply the annotation to the validate method
signature to make its return type explicit.
- Around line 219-221: The stop() method currently nulled only self._executor
and self._event_bus but left self._tool_registry and self._graph intact, risking
stale references on restart; update stop() to also clear or properly dispose
self._tool_registry and self._graph (e.g., set self._tool_registry = None and
self._graph = None or call their respective cleanup/shutdown methods if
available) so that subsequent calls to _setup() recreate all components from a
clean state; ensure you reference and handle any teardown APIs on the objects
before nulling to avoid resource leaks.
- Around line 146-158: The __init__ signature in the class is missing type hints
for the config parameter and the return type; update the __init__ method to
annotate config with the appropriate config type (e.g., AgentConfig from the
.config module or the correct type imported as AgentConfig) and add the explicit
return type -> None, and ensure the AgentConfig type is imported or referenced
(or use Optional[AgentConfig] if None is allowed) so the signature reads with
proper typing for config and a None return.

In `@examples/templates/viral_tech_copywriter/config.py`:
- Around line 1-5: Add the future annotations import at the top of the module:
insert "from __future__ import annotations" as the first import to enable
postponed evaluation of annotations for this module that defines the dataclass
RuntimeConfig (and any other type hints) in
examples/templates/viral_tech_copywriter/config.py.

In `@examples/templates/viral_tech_copywriter/tests/conftest.py`:
- Around line 19-30: Add explicit return type annotations to the pytest
fixtures: annotate agent_module to return types.ModuleType and annotate
runner_loaded to return framework.runner.runner.AgentRunner; import ModuleType
(from types) and ensure AgentRunner is imported or referenced for the type hint
so signatures read with -> ModuleType and -> AgentRunner respectively while
keeping the existing pytest.fixture decorators and behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 64ccfa95-9bcf-4e87-9d30-14b76da2edef

📥 Commits

Reviewing files that changed from the base of the PR and between 45cfae5 and 2b402bd.

📒 Files selected for processing (10)
  • examples/templates/viral_tech_copywriter/README.md
  • examples/templates/viral_tech_copywriter/__init__.py
  • examples/templates/viral_tech_copywriter/__main__.py
  • examples/templates/viral_tech_copywriter/agent.py
  • examples/templates/viral_tech_copywriter/config.py
  • examples/templates/viral_tech_copywriter/flowchart.json
  • examples/templates/viral_tech_copywriter/mcp_servers.json
  • examples/templates/viral_tech_copywriter/nodes/__init__.py
  • examples/templates/viral_tech_copywriter/tests/conftest.py
  • examples/templates/viral_tech_copywriter/tests/test_structure.py

Comment on lines +242 to +250
async def run(self, context: dict, session_state=None) -> ExecutionResult:
await self.start()
try:
result = await self.trigger_and_wait(
"start", context, session_state=session_state
)
return result or ExecutionResult(success=False, error="Execution timeout")
finally:
await self.stop()
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if GraphExecutor.execute accepts a timeout parameter
ast-grep --pattern $'class GraphExecutor {
  $$$
  async def execute($$$) {
    $$$
  }
  $$$
}'

Repository: aden-hive/hive

Length of output: 40


🏁 Script executed:

# First, locate and read the file
wc -l examples/templates/viral_tech_copywriter/agent.py

Repository: aden-hive/hive

Length of output: 111


🏁 Script executed:

# Read the run method and surrounding context
sed -n '240,260p' examples/templates/viral_tech_copywriter/agent.py

Repository: aden-hive/hive

Length of output: 741


🏁 Script executed:

# Also read the trigger_and_wait method around line 227
sed -n '220,235p' examples/templates/viral_tech_copywriter/agent.py

Repository: aden-hive/hive

Length of output: 588


🏁 Script executed:

# Search for trigger_and_wait method definition
grep -n "def trigger_and_wait" examples/templates/viral_tech_copywriter/agent.py

Repository: aden-hive/hive

Length of output: 93


🏁 Script executed:

# Search for GraphExecutor class and execute method in the repo
find . -name "*.py" -type f | xargs grep -l "class GraphExecutor" | head -5

Repository: aden-hive/hive

Length of output: 92


🏁 Script executed:

# Read complete trigger_and_wait method
sed -n '223,240p' examples/templates/viral_tech_copywriter/agent.py

Repository: aden-hive/hive

Length of output: 671


🏁 Script executed:

# Check GraphExecutor.execute method signature
sed -n '1,100p' core/framework/graph/executor.py | grep -A 20 "async def execute"

Repository: aden-hive/hive

Length of output: 40


🏁 Script executed:

# Try broader search for GraphExecutor
grep -n "class GraphExecutor" core/framework/graph/executor.py

Repository: aden-hive/hive

Length of output: 82


🏁 Script executed:

# Get the execute method from GraphExecutor
grep -A 15 "async def execute" core/framework/graph/executor.py | head -20

Repository: aden-hive/hive

Length of output: 701


🏁 Script executed:

# Check imports at the top of agent.py
head -30 examples/templates/viral_tech_copywriter/agent.py

Repository: aden-hive/hive

Length of output: 1061


🏁 Script executed:

# Check if typing.Any is imported in agent.py
grep -n "from typing import" examples/templates/viral_tech_copywriter/agent.py

Repository: aden-hive/hive

Length of output: 40


🏁 Script executed:

# Check how context is used in the run method and trigger_and_wait
grep -B5 -A10 "async def run" examples/templates/viral_tech_copywriter/agent.py

Repository: aden-hive/hive

Length of output: 572


🏁 Script executed:

# Verify all uses of context parameter type
rg "context:" examples/templates/viral_tech_copywriter/agent.py

Repository: aden-hive/hive

Length of output: 136


Add missing type hints and remove unused timeout parameter.

  1. The session_state parameter at line 242 lacks a type hint. The context parameter should also be typed as dict[str, Any] instead of dict for consistency with the rest of the codebase.

  2. The timeout parameter in trigger_and_wait (line 223) is declared but never used—GraphExecutor.execute() does not accept a timeout parameter, so this parameter should be removed.

Proposed fix for type hints
-    async def run(self, context: dict, session_state=None) -> ExecutionResult:
+    async def run(self, context: dict[str, Any], session_state: dict[str, Any] | None = None) -> ExecutionResult:

Add from typing import Any to imports if not already present.

Proposed fix for unused timeout parameter
     async def trigger_and_wait(
         self,
         entry_point: str,
         input_data: dict,
-        timeout: float | None = None,
         session_state: dict | None = None,
     ) -> ExecutionResult | None:
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async def run(self, context: dict, session_state=None) -> ExecutionResult:
await self.start()
try:
result = await self.trigger_and_wait(
"start", context, session_state=session_state
)
return result or ExecutionResult(success=False, error="Execution timeout")
finally:
await self.stop()
async def run(self, context: dict[str, Any], session_state: dict[str, Any] | None = None) -> ExecutionResult:
await self.start()
try:
result = await self.trigger_and_wait(
"start", context, session_state=session_state
)
return result or ExecutionResult(success=False, error="Execution timeout")
finally:
await self.stop()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/templates/viral_tech_copywriter/agent.py` around lines 242 - 250,
Update the run method and trigger_and_wait usage to add proper type hints and
remove the unused timeout parameter: change the run signature to accept context:
dict[str, Any] and session_state: Optional[Any] (import Any and Optional from
typing if missing) and update any local references to session_state accordingly;
remove the timeout parameter from the trigger_and_wait definition and all calls
(including the call inside run) because GraphExecutor.execute() does not accept
a timeout; ensure trigger_and_wait and GraphExecutor-related call sites compile
after removing timeout and adjust imports to include Any/Optional.

@fermano
Copy link
Copy Markdown
Contributor Author

fermano commented Apr 2, 2026

Viral.Tech.Copywriter.mp4

Copy link
Copy Markdown

@JiwaniZakir JiwaniZakir left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In __main__.py, the tui command silently skips MCP config loading if mcp_servers.json is absent (if mcp_config_path.exists(): agent._tool_registry.load_mcp_config(...)) — but the README explicitly states the file "must be present." This silent no-op will cause confusing runtime failures when save_data, serve_file_to_user, or other hive-tools are called and simply aren't registered, rather than surfacing a clear error at startup. The run_cmd command has the opposite problem: it calls default_agent.run({}) with no MCP config loading at all, so it will always run without MCP tools regardless of whether mcp_servers.json exists — making the run subcommand silently broken for the intended delivery flow. Both paths should either raise early with a descriptive message when the config is missing, or share a common setup helper so the wiring isn't duplicated and inconsistent across the two entry points. Also, directly assigning agent._event_bus and agent._tool_registry via private attributes in the CLI suggests the agent's initialization interface should expose a proper factory or configuration method instead.

@fermano fermano marked this pull request as ready for review April 3, 2026 13:25
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (4)
examples/templates/viral_tech_copywriter/agent.py (3)

249-266: Remove unused timeout parameter from trigger_and_wait.

The timeout parameter is declared but never passed to self._executor.execute(). Since GraphExecutor.execute() does not accept a timeout parameter, this is dead code that misleads callers into thinking timeout functionality exists.

Proposed fix
     async def trigger_and_wait(
         self,
         entry_point: str,
         input_data: dict,
-        timeout: float | None = None,
         session_state: dict | None = None,
     ) -> ExecutionResult | None:
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/templates/viral_tech_copywriter/agent.py` around lines 249 - 266,
Remove the unused timeout parameter from the trigger_and_wait signature and any
references to it; specifically update the async method trigger_and_wait to no
longer accept timeout: float | None and ensure callers are not relying on it,
since the call to self._executor.execute (GraphExecutor.execute) does not accept
a timeout argument. Keep the method to pass graph=self._graph, goal=self.goal,
input_data=input_data, session_state=session_state to self._executor.execute
without any timeout plumbing.

276-292: Consider adding return type hints for info() and validate().

Both methods return dictionaries with well-defined structures. Adding type hints would improve discoverability and IDE support.

Example
-    def info(self):
+    def info(self) -> dict[str, Any]:
-    def validate(self):
+    def validate(self) -> dict[str, bool | list[str]]:
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/templates/viral_tech_copywriter/agent.py` around lines 276 - 292,
Add explicit return type annotations for the info() and validate() methods to
improve discoverability and IDE support; update the signature of info() (in the
Agent class/function where info is defined) to return a typed mapping such as
dict[str, Any] or, better, a specific TypedDict describing keys
("name","version","description","goal","nodes","edges","entry_node","entry_points","pause_nodes","terminal_nodes","client_facing_nodes"),
and similarly annotate validate() with its appropriate return type (e.g.,
dict[str, Any] or a validation TypedDict/Protocol). Import typing primitives
(TypedDict, dict, Any) as needed and keep the types consistent with the actual
returned structures in info() and validate().

175-187: Add type hint for config parameter.

The config parameter lacks a type annotation. As per coding guidelines, use type hints on all function signatures.

Proposed fix
-    def __init__(self, config=None):
+    def __init__(self, config: RuntimeConfig | None = None):

You'll need to import RuntimeConfig from the config module.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/templates/viral_tech_copywriter/agent.py` around lines 175 - 187,
The __init__ signature is missing a type hint for the config parameter; import
RuntimeConfig from the config module and annotate the parameter as config:
RuntimeConfig | None in the __init__ method (the constructor shown) so the
parameter has a proper type, while keeping the existing default fallback (config
or default_config) and leaving all assignments to self.config, self._executor,
self._graph, etc. unchanged.
examples/templates/viral_tech_copywriter/__main__.py (1)

96-96: Accessing private method _build_graph() from outside the class.

_build_graph() is prefixed with underscore indicating it's a private implementation detail. Consider either making it public (rename to build_graph()) or exposing the graph through a public property/method on the agent class.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@examples/templates/viral_tech_copywriter/__main__.py` at line 96, The code
calls the private method _build_graph() on agent from outside the class; change
this to use a public API by either adding a public wrapper method build_graph()
on the agent class that returns self._build_graph() (or renaming _build_graph to
build_graph) and then replace agent._build_graph() with agent.build_graph(), or
expose the graph via a public property like graph on the agent and call
agent.graph; update all external call sites to use the new public symbol
(build_graph or graph) and keep the original internal implementation name if you
prefer to preserve backward compatibility.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@examples/templates/viral_tech_copywriter/__main__.py`:
- Line 96: The code calls the private method _build_graph() on agent from
outside the class; change this to use a public API by either adding a public
wrapper method build_graph() on the agent class that returns self._build_graph()
(or renaming _build_graph to build_graph) and then replace agent._build_graph()
with agent.build_graph(), or expose the graph via a public property like graph
on the agent and call agent.graph; update all external call sites to use the new
public symbol (build_graph or graph) and keep the original internal
implementation name if you prefer to preserve backward compatibility.

In `@examples/templates/viral_tech_copywriter/agent.py`:
- Around line 249-266: Remove the unused timeout parameter from the
trigger_and_wait signature and any references to it; specifically update the
async method trigger_and_wait to no longer accept timeout: float | None and
ensure callers are not relying on it, since the call to self._executor.execute
(GraphExecutor.execute) does not accept a timeout argument. Keep the method to
pass graph=self._graph, goal=self.goal, input_data=input_data,
session_state=session_state to self._executor.execute without any timeout
plumbing.
- Around line 276-292: Add explicit return type annotations for the info() and
validate() methods to improve discoverability and IDE support; update the
signature of info() (in the Agent class/function where info is defined) to
return a typed mapping such as dict[str, Any] or, better, a specific TypedDict
describing keys
("name","version","description","goal","nodes","edges","entry_node","entry_points","pause_nodes","terminal_nodes","client_facing_nodes"),
and similarly annotate validate() with its appropriate return type (e.g.,
dict[str, Any] or a validation TypedDict/Protocol). Import typing primitives
(TypedDict, dict, Any) as needed and keep the types consistent with the actual
returned structures in info() and validate().
- Around line 175-187: The __init__ signature is missing a type hint for the
config parameter; import RuntimeConfig from the config module and annotate the
parameter as config: RuntimeConfig | None in the __init__ method (the
constructor shown) so the parameter has a proper type, while keeping the
existing default fallback (config or default_config) and leaving all assignments
to self.config, self._executor, self._graph, etc. unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: db317e66-abc7-4308-99cc-16195cafb3e6

📥 Commits

Reviewing files that changed from the base of the PR and between 2b402bd and a7f410d.

📒 Files selected for processing (5)
  • examples/templates/viral_tech_copywriter/README.md
  • examples/templates/viral_tech_copywriter/__main__.py
  • examples/templates/viral_tech_copywriter/agent.py
  • examples/templates/viral_tech_copywriter/flowchart.json
  • examples/templates/viral_tech_copywriter/tests/test_structure.py
✅ Files skipped from review due to trivial changes (1)
  • examples/templates/viral_tech_copywriter/README.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • examples/templates/viral_tech_copywriter/flowchart.json

@fermano
Copy link
Copy Markdown
Contributor Author

fermano commented Apr 3, 2026

@JiwaniZakir thank you very much for your comments. 3 of them (out of 4) have been addressed. Just one of them was not addressed: The note that run never loads MCP isn’t accurate: run goes through default_agent.run() → start() → _setup(), which always calls load_hive_tools_registry() when mcp_servers.json is present, same as the delivery path.

@JiwaniZakir
Copy link
Copy Markdown

The fulfillment_status correction looks good — using null for unfulfilled orders is the right approach since Shopify returns null rather than a string value, and that distinction matters when doing conditional checks. The "unshipped" example would have caused silent bugs for anyone copying it. Would want to see the full Docker Hub change to confirm that section is complete before approving.

@fermano
Copy link
Copy Markdown
Contributor Author

fermano commented Apr 3, 2026

Are you sure you are commenting at the PR you intended? This agent has nothing to do with Shopify and shipments.

@JiwaniZakir
Copy link
Copy Markdown

The PR description still has placeholder changes ("Change 1, Change 2, Change 3") which makes it hard to review what was actually implemented — can you fill that out with the real diff summary? Also, the checklist item for adding tests is unchecked; if this agent has any prompt templating or output formatting logic, that should have coverage before merge.

@fermano
Copy link
Copy Markdown
Contributor Author

fermano commented Apr 3, 2026

@JiwaniZakir added some description there. Please let me know if you need anything else for this PR.

@JiwaniZakir
Copy link
Copy Markdown

The graph topology looks correct — four nodes with deliver-exports as the only terminal, and MCP tools scoped only there keeps the earlier nodes lean. One thing worth verifying: if load_hive_tools_registry() is called in both run and tui entry points, make sure the fast-fail error surfaces cleanly in TUI mode and doesn't get swallowed by a curses/rich rendering layer before the user sees it. Also, the normalize-brief step converting freeform input to structured JSON is doing meaningful validation work — would be good to see what happens when the brief is ambiguous or underspecified.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Agent - Viral Tech Copywriter

2 participants