Skip to content

Commit 4ba950f

Browse files
Merge pull request #5499 from aden-hive/feat/open-hive
feat: tool call revamp, Intercom & GA integrations, credential improvements
2 parents 296aab6 + 9c3a11d commit 4ba950f

File tree

47 files changed

+3273
-767
lines changed

Some content is hidden

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

47 files changed

+3273
-767
lines changed

.claude/skills/hive-create/examples/deep_research_agent/agent.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ def _build_graph(self) -> GraphSpec:
195195
max_tokens=self.config.max_tokens,
196196
loop_config={
197197
"max_iterations": 100,
198-
"max_tool_calls_per_turn": 20,
198+
"max_tool_calls_per_turn": 30,
199199
"max_history_tokens": 32000,
200200
},
201201
conversation_mode="continuous",

.claude/skills/hive-create/examples/deep_research_agent/nodes/__init__.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,12 @@
7171
- Track which URL each finding comes from (you'll need citations later)
7272
- Call set_output for each key in a SEPARATE turn (not in the same turn as other tool calls)
7373
74+
Context management:
75+
- Your tool results are automatically saved to files. After compaction, the file \
76+
references remain in the conversation — use load_data() to recover any content you need.
77+
- Use append_data('research_notes.md', ...) to maintain a running log of key findings \
78+
as you go. This survives compaction and helps the report node produce a detailed report.
79+
7480
When done, use set_output (one key at a time, separate turns):
7581
- set_output("findings", "Structured summary: key findings with source URLs for each claim. \
7682
Include themes, contradictions, and confidence levels.")
@@ -161,6 +167,9 @@
161167
- Every factual claim must cite its source with [n] notation
162168
- Be objective — present multiple viewpoints where sources disagree
163169
- Answer the original research questions from the brief
170+
- If findings appear incomplete or summarized, call list_data_files() and load_data() \
171+
to access the detailed source material from the research phase. The research node's \
172+
tool results and research_notes.md contain the full data.
164173
165174
Save the HTML:
166175
save_data(filename="report.html", data="<html>...</html>")

core/demos/github_outreach_demo.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1768,7 +1768,7 @@ async def _run_pipeline(websocket, initial_message: str):
17681768
judge=judge,
17691769
config=LoopConfig(
17701770
max_iterations=30,
1771-
max_tool_calls_per_turn=15,
1771+
max_tool_calls_per_turn=30,
17721772
max_history_tokens=64000,
17731773
max_tool_result_chars=8_000,
17741774
spillover_dir=str(_DATA_DIR),

core/demos/handoff_demo.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,7 @@ async def forward_event(event):
751751
judge=None, # implicit judge: accept when output_keys filled
752752
config=LoopConfig(
753753
max_iterations=20,
754-
max_tool_calls_per_turn=10,
754+
max_tool_calls_per_turn=30,
755755
max_history_tokens=32_000,
756756
),
757757
conversation_store=store_a,
@@ -849,7 +849,7 @@ async def forward_event(event):
849849
judge=None, # implicit judge
850850
config=LoopConfig(
851851
max_iterations=10,
852-
max_tool_calls_per_turn=5,
852+
max_tool_calls_per_turn=30,
853853
max_history_tokens=32_000,
854854
),
855855
conversation_store=store_b,

core/demos/org_demo.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1257,7 +1257,7 @@ async def forward_event(event):
12571257
judge=judge,
12581258
config=LoopConfig(
12591259
max_iterations=30,
1260-
max_tool_calls_per_turn=25,
1260+
max_tool_calls_per_turn=30,
12611261
max_history_tokens=32_000,
12621262
),
12631263
conversation_store=store,

core/framework/agents/credential_tester/agent.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ def _configure_local_node(
453453
)
454454
loop_config = {
455455
"max_iterations": 50,
456-
"max_tool_calls_per_turn": 10,
456+
"max_tool_calls_per_turn": 30,
457457
"max_history_tokens": 32000,
458458
}
459459

@@ -539,7 +539,7 @@ def _build_graph(self) -> GraphSpec:
539539
max_tokens=self.config.max_tokens,
540540
loop_config={
541541
"max_iterations": 50,
542-
"max_tool_calls_per_turn": 10,
542+
"max_tool_calls_per_turn": 30,
543543
"max_history_tokens": 32000,
544544
},
545545
conversation_mode="continuous",

core/framework/agents/hive_coder/agent.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@
127127
)
128128
loop_config = {
129129
"max_iterations": 100,
130-
"max_tool_calls_per_turn": 20,
130+
"max_tool_calls_per_turn": 30,
131131
"max_history_tokens": 32000,
132132
}
133133

@@ -160,8 +160,8 @@
160160
edges=[],
161161
conversation_mode="continuous",
162162
loop_config={
163-
"max_iterations": 200,
164-
"max_tool_calls_per_turn": 10,
163+
"max_iterations": 999_999,
164+
"max_tool_calls_per_turn": 30,
165165
"max_history_tokens": 32000,
166166
},
167167
)

core/framework/agents/hive_coder/nodes/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@
351351
```python
352352
loop_config = {
353353
"max_iterations": 100,
354-
"max_tool_calls_per_turn": 20,
354+
"max_tool_calls_per_turn": 30,
355355
"max_history_tokens": 32000,
356356
}
357357
```
@@ -469,7 +469,7 @@
469469
terminal node that doesn't exist. Agent tests MUST be structural:
470470
- Validate graph, node specs, edges, tools, prompts
471471
- Check goal/constraints/success criteria definitions
472-
- Test `AgentRunner.load()` + `_setup()` (skip if no API key)
472+
- Test `AgentRunner.load()` succeeds (structural, no API key needed)
473473
- NEVER call `runner.run()` or `trigger_and_wait()` in tests for \
474474
forever-alive agents — they will hang and time out.
475475
When you restructure an agent (change nodes/edges), always update \

core/framework/agents/hive_coder/reference/anti_patterns.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ One client-facing node handles ALL user interaction (setup, logging, reports). O
8080
- Validate graph structure (nodes, edges, entry points)
8181
- Verify node specs (tools, prompts, client-facing flag)
8282
- Check goal/constraints/success criteria definitions
83-
- Test that `AgentRunner.load()` + `_setup()` succeeds (skip if no API key)
83+
- Test that `AgentRunner.load()` succeeds (structural, no API key needed)
8484

8585
**What NOT to do:**
8686
```python

core/framework/agents/hive_coder/reference/file_templates.md

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -235,16 +235,14 @@ class MyAgent:
235235
identity_prompt=identity_prompt,
236236
)
237237

238-
def _setup(self, mock_mode=False):
238+
def _setup(self):
239239
self._storage_path = Path.home() / ".hive" / "agents" / "my_agent"
240240
self._storage_path.mkdir(parents=True, exist_ok=True)
241241
self._tool_registry = ToolRegistry()
242242
mcp_config = Path(__file__).parent / "mcp_servers.json"
243243
if mcp_config.exists():
244244
self._tool_registry.load_mcp_config(mcp_config)
245-
llm = None
246-
if not mock_mode:
247-
llm = LiteLLMProvider(model=self.config.model, api_key=self.config.api_key, api_base=self.config.api_base)
245+
llm = LiteLLMProvider(model=self.config.model, api_key=self.config.api_key, api_base=self.config.api_base)
248246
tools = list(self._tool_registry.get_tools().values())
249247
tool_executor = self._tool_registry.get_executor()
250248
self._graph = self._build_graph()
@@ -257,9 +255,9 @@ class MyAgent:
257255
checkpoint_max_age_days=7, async_checkpoint=True),
258256
)
259257

260-
async def start(self, mock_mode=False):
258+
async def start(self):
261259
if self._agent_runtime is None:
262-
self._setup(mock_mode=mock_mode)
260+
self._setup()
263261
if not self._agent_runtime.is_running:
264262
await self._agent_runtime.start()
265263

@@ -274,8 +272,8 @@ class MyAgent:
274272
return await self._agent_runtime.trigger_and_wait(
275273
entry_point_id=entry_point, input_data=input_data or {}, session_state=session_state)
276274

277-
async def run(self, context, mock_mode=False, session_state=None):
278-
await self.start(mock_mode=mock_mode)
275+
async def run(self, context, session_state=None):
276+
await self.start()
279277
try:
280278
result = await self.trigger_and_wait("default", context, session_state=session_state)
281279
return result or ExecutionResult(success=False, error="Execution timeout")
@@ -471,19 +469,17 @@ def cli():
471469

472470
@cli.command()
473471
@click.option("--topic", "-t", required=True)
474-
@click.option("--mock", is_flag=True)
475472
@click.option("--verbose", "-v", is_flag=True)
476-
def run(topic, mock, verbose):
473+
def run(topic, verbose):
477474
"""Execute the agent."""
478475
setup_logging(verbose=verbose)
479-
result = asyncio.run(default_agent.run({"topic": topic}, mock_mode=mock))
476+
result = asyncio.run(default_agent.run({"topic": topic}))
480477
click.echo(json.dumps({"success": result.success, "output": result.output}, indent=2, default=str))
481478
sys.exit(0 if result.success else 1)
482479

483480

484481
@cli.command()
485-
@click.option("--mock", is_flag=True)
486-
def tui(mock):
482+
def tui():
487483
"""Launch TUI dashboard."""
488484
from pathlib import Path
489485
from framework.tui.app import AdenTUI
@@ -499,7 +495,7 @@ def tui(mock):
499495
storage.mkdir(parents=True, exist_ok=True)
500496
mcp_cfg = Path(__file__).parent / "mcp_servers.json"
501497
if mcp_cfg.exists(): agent._tool_registry.load_mcp_config(mcp_cfg)
502-
llm = None if mock else LiteLLMProvider(model=agent.config.model, api_key=agent.config.api_key, api_base=agent.config.api_base)
498+
llm = LiteLLMProvider(model=agent.config.model, api_key=agent.config.api_key, api_base=agent.config.api_base)
503499
runtime = create_agent_runtime(
504500
graph=agent._build_graph(), goal=agent.goal, storage_path=storage,
505501
entry_points=[EntryPointSpec(id="start", name="Start", entry_node="intake", trigger_type="manual", isolation_level="isolated")],
@@ -564,7 +560,6 @@ import sys
564560
from pathlib import Path
565561

566562
import pytest
567-
import pytest_asyncio
568563

569564
_repo_root = Path(__file__).resolve().parents[3]
570565
for _p in ["exports", "core"]:
@@ -576,18 +571,17 @@ AGENT_PATH = str(Path(__file__).resolve().parents[1])
576571

577572

578573
@pytest.fixture(scope="session")
579-
def mock_mode():
580-
return True
574+
def agent_module():
575+
"""Import the agent package for structural validation."""
576+
import importlib
577+
return importlib.import_module(Path(AGENT_PATH).name)
581578

582579

583-
@pytest_asyncio.fixture(scope="session")
584-
async def runner(tmp_path_factory, mock_mode):
580+
@pytest.fixture(scope="session")
581+
def runner_loaded():
582+
"""Load the agent through AgentRunner (structural only, no LLM needed)."""
585583
from framework.runner.runner import AgentRunner
586-
storage = tmp_path_factory.mktemp("agent_storage")
587-
r = AgentRunner.load(AGENT_PATH, mock_mode=mock_mode, storage_path=storage)
588-
r._setup()
589-
yield r
590-
await r.cleanup_async()
584+
return AgentRunner.load(AGENT_PATH)
591585
```
592586

593587
## entry_points Format

0 commit comments

Comments
 (0)