Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,23 +85,25 @@ The trigger and the lever are decoupled through a single one-line file, `~/.holo
- **Reading it (the lever):** every turn records its own `started_at` and, while running, polls the file ~4×/s. It acts **only if the file's timestamp is newer than its `started_at`** — then it pauses, then cancels at the next action boundary.
- **Clearing it:** the file is *never deleted*. It's cleared by time — the next turn starts later, so a leftover request is automatically stale and can't kill it. This is also why a `holo stop` fired *before* a run begins is ignored: nothing was running to stop.

`holo stop --force` is the exception to the step-bounded model: it reads the runtime's pid file (`~/.holo/agent-pid-<port>`) and SIGKILLs the process directly, so it doesn't wait for an action boundary.
`holo stop --force` is the exception to the step-bounded model: it discovers the runtime through the hai-agents SDK (`LocalRuntime.attach(...).force_kill()`) and SIGKILLs the process directly, so it doesn't wait for an action boundary. For one release it also honours pre-SDK pid files (`~/.holo/agent-pid-<port>`) so an upgrade mid-session can still be stopped.

## Use from Python

`holo_desktop.agent_client` is the same client every CLI surface is built on: it spawns (or attaches to) the `hai-agent-runtime` binary on loopback and drives sessions over the agent API.
`holo_desktop.agent_client` is the same client every CLI surface is built on: it spawns (or attaches to) the `hai-agent-runtime` binary on loopback via the hai-agents local runtime and drives sessions over the agent API.

```python
import asyncio

from holo_desktop.agent_client import AgentApiClient, SpawnConfig, ensure_running
from holo_desktop.agent_client import AgentApiClient, SpawnConfig, ensure_local_runtime
from holo_desktop.agent_client.requests import build_session_request
from holo_desktop.settings import load_holo_settings


async def main() -> None:
daemon = await ensure_running(SpawnConfig(port=18795))
settings = load_holo_settings()
runtime = await asyncio.to_thread(ensure_local_runtime, SpawnConfig(port=18795), settings=settings)
try:
async with AgentApiClient(daemon.base_url, daemon.token) as client:
async with AgentApiClient(runtime) as client:
request = build_session_request(
task="Tell me how many unread emails I have", max_steps=None, max_time_s=None
)
Expand All @@ -110,7 +112,8 @@ async def main() -> None:
print(event.type)
print(stream.answer)
finally:
await daemon.aclose()
if runtime.owned:
await asyncio.to_thread(runtime.shutdown)


asyncio.run(main())
Expand Down
8 changes: 8 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ dependencies = [
# Agent-API wire contract (Pydantic specs + agp_types) for talking to the closed
# hai-agent-runtime binary; the wheel vendors agent_interface + agp_types as the only source of the spec types.
"hai-agent-api>=0.1.15",
# SDK local mode (plan 002): owns runtime download/spawn/auth/discovery; Holo delegates lifecycle to it.
"hai-agents[local]>=0.1",
# CLI / serve (A2A) / acp / mcp adapter surface.
"a2a-sdk[http-server]>=1.0.3",
"agent-client-protocol>=0.10",
Expand Down Expand Up @@ -78,6 +80,12 @@ dev = [
[tool.uv.workspace]
members = ["examples/expense_report"]

[tool.uv.sources]
# SHIP-GATE: replace with the published hai-agents[local] version before merge.
# Dev-time override onto the plan-002 implementation worktree; the [local] extra
# is empty today, so the editable path install satisfies it as-is.
hai-agents = { path = "/Users/charlie.masters/.config/superpowers/worktrees/hai-agents-python/claude-sdk-local-mode", editable = true }

[tool.hatch.build.targets.wheel]
packages = ["src/holo_desktop"]

Expand Down
98 changes: 0 additions & 98 deletions scripts/bump_runtime.py

This file was deleted.

16 changes: 6 additions & 10 deletions src/holo_desktop/agent_client/__init__.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
"""Thin client to the hai-agent-runtime binary."""
"""Thin client to the hai-agent-runtime binary (lifecycle delegated to hai-agents local mode)."""

from holo_desktop.agent_client.client import AgentApiClient, SessionStream
from holo_desktop.agent_client.launcher import (
AgentDaemon,
from holo_desktop.agent_client.sdk_runtime import (
SpawnConfig,
ensure_running,
runtime_log_path,
runtime_log_tail,
ensure_local_runtime,
ensure_local_runtime_from_env,
)

__all__ = [
"AgentApiClient",
"AgentDaemon",
"SessionStream",
"SpawnConfig",
"ensure_running",
"runtime_log_path",
"runtime_log_tail",
"ensure_local_runtime",
"ensure_local_runtime_from_env",
]
Loading
Loading