0.6.0 — framework hardening (streaming, tools, parsing, packaging, facade) - #41
Conversation
|
Backlog (remaining audit findings, deferred from this release):
|
Greptile SummaryThis PR hardens the Hive agent runtime across five well-scoped commits: streaming now falls back gracefully on interruption, tools have per-call timeouts, JSON parsing uses a proper brace-matching extractor with typed errors, optional provider extras are declared, and the
Confidence Score: 4/5Safe to merge with one pre-existing unresolved defect: run_once() dispatches tools without the asyncio.wait_for guard that run() now has, so hung tools still block the coroutine indefinitely when callers use the direct API path. The daemon path is fully protected by tool_timeout and the streaming fallback is well-guarded. However, run_once() — the main entry point for direct API callers — still calls tool.call() with no timeout wrapper, a gap noted in the previous review that this PR did not close. src/hive/runtime/agent.py — specifically the inline tool-dispatch loop inside run_once() around line 626. Important Files Changed
Reviews (2): Last reviewed commit: "fix(ci,review): format tests; estimate i..." | Re-trigger Greptile |
|
Addressed Greptile's two P2s in fa2e8c2:
Also formatted |
…arg logging - structured.py: brace-matching JSON extractor that respects string literals/ escapes (replaces naive find/rfind slice); raise typed StructuredParseError carrying raw text on validation failure - types.py/agent.py: StructuredTaskResult.parsed is T|None; FAILED results carry parsed=None instead of an unvalidated model_construct() object - openai.py: _is_response_format_unsupported() structured-first detector replaces brittle substring match; document why streaming is not retried - conversion.py/openai.py: warn (not silently drop) on malformed tool-call args Audit findings B6, B7, B8.
…ndency errors - pyproject: add [anthropic] [openai] [mcp] [cli] extras (SDKs stay in core deps so existing installs are unchanged; extras pave the way for a slimmer core) - errors.py: MissingDependencyError + require_dependency() helper that points at the matching extra (pip install 'hive-agent[openai]') - openai/anthropic/mcp toolkit: lazy imports now raise the clear error instead of a bare ImportError; top-level 'import hive' still needs no provider SDK - export StructuredParseError + MissingDependencyError from the package Audit finding C9.
…ailures - runtime/agent.py: configurable tool_timeout wraps each tool call in wait_for; a hung tool becomes a tool-error result instead of stalling the whole cycle - config.py: DaemonConfig.tool_timeout (default 60s, validated >= 0); daemon passes it into runtime agents - agent.py: memory-recall failure now warns (was debug) and states it continues without recalled memories - daemon/loop.py: corrupt suffering snapshot falls back to a fresh SufferingState (was silently unset); persona restore wrapped in try/except; plugin-init warning carries agent_id + traceback - agents/existence.py: re-check get_active_goal before saving so a generated goal isn't piled on top of one that appeared mid-cycle (delegation/schedule/concurrent) Audit findings A2, A3, A4. (A3 uses a re-check guard, not a unique index, because subgoals/delegation/schedules legitimately create multiple active goals.)
…budget overshoot - _generate_message: when a stream ends without a terminal DONE event (or errors mid-stream), keep the text already shown to on_text if any, otherwise fall back to a retried non-streaming call -- instead of failing the task with RuntimeError - close the stream (aclose) in a finally so cancellation releases the underlying HTTP connection - run_once: guard the post-loop wrap-up generation with a budget check - document that a hard budget can overshoot by at most one generation, and why a projected pre-stop was rejected (full-output-cap estimate falsely refuses small-budget agents) Audit findings A1, A5.
- api.py: with Hive() / async with Hive() context managers; Hive(path).spawn(...) now scaffolds .hive/ lazily, so init() is optional (kept for back-compat) - daemon/setup.py: split out loop-safe ensure_hive_dirs() (no asyncio.run) from initialize_hive(); export ensure_hive_dirs from the package - bump version 0.5.4 -> 0.6.0; CHANGELOG + docs/changelog 0.6.0 section - docs: tool_timeout config row, install extras + MissingDependencyError, StructuredTaskResult.parsed nullability, context-manager usage Audit finding C10 + release.
…pe extras pins - ruff format tests/ (CI checks src/ + tests/) - _synthesize_stream_result: estimate output tokens/cost from streamed text so an interrupted streaming generation stays visible to budget tracking (Greptile P2) - pyproject extras: unversioned aliases instead of duplicating the core version pins, removing drift risk; dependencies stays authoritative (Greptile P2)
|
Rebased onto
Ready for your review. |
Framework-hardening release for 0.6.0. Makes the agent runtime robust under streaming interruptions, hung tools, and corrupt state, and makes the package friendlier to import/embed. No breaking changes; DBs upgrade automatically. Poker/simulation is intentionally out of scope (separate repo).
Reviewable per-commit — each commit is one scope:
830554aStructuredParseError(no more invalidmodel_construct()); structured-first provider error heuristics; warn on malformed tool-call argsb88dde5[anthropic] [openai] [mcp] [cli]extras (core deps unchanged) + friendlyMissingDependencyError61f4709tool_timeout; surfaced silent failures (memory recall, suffering/persona restore, plugin init) with explicit fallbacks; single active generated goal per agent32d3e302c9162fwith/async with Hive()+ lazy.hiveinit; version bump 0.6.0 + CHANGELOG + docsNotable decisions
Verification
uv run pytest— 1058 passed (added tests for streaming fallback, tool timeout, memory-recall warning, corrupt-checkpoint resume, existence guard, optional extras, context managers, robust parsing)uv run ruff check src/ tests/+ruff format --check src/— cleanuv run mypy src/— cleanuv run mkdocs build --strict— cleanRemaining audit findings filed as backlog issues (see linked issues).