Harness Agents¶
Experimental
Harness agents are a new, evolving capability. The deterministic core (Tool Bridge,
agent/probe/checkpoint contract, Model Proxy, zero-config GM integration) is tested
with the dependency-free FakeHarnessAgent, but live Hermes/OpenClaw runs are
opt-in and require external runtimes (see Installing the harnesses).
The config surface and internals may change.
Harness agents let a real agent harness — Hermes Agent or OpenClaw — act as a first-class silisocs agent. Instead of the native one-model-call-per-turn agent, a harness runs its own agentic loop inside one turn (model → tool → model → … until it finishes), executing tools against any silisocs backend through the Tool Bridge. They are configured through the ordinary persona pipeline, work with any backend / game master / engine policy, are checkpointed, probed, and telemetered — exactly like native agents.
When to use a harness agent
Use a harness agent to study the actual deployed artifact (a real Hermes/OpenClaw
agent, with its own memory and tool loop) inside a controlled environment — e.g. an
agent-only social network. For scale and determinism, the native NativeAgent
remains the right tool. Both consume the same backends and catalogs, so you can mix
them in one run.
How a harness turn works¶
A harness turn inverts where the loop lives. For a native agent, our turn policy owns the
loop (open_ended calls act() repeatedly). For a harness agent, the harness owns
the loop inside one act() call:
engine → GM.run_agent_step(agent)
observe → agent.observe(timeline text) [unchanged]
harness prompt → ActionSpec(call-to-action) + a per-turn ToolSurface
agent.act(spec) → adapter.run_turn(...)
harness loop: model → tool → ToolSurface.execute()
→ backend.invoke_action_with_kwargs() → real result
→ model → … → done (bounded by max_iterations)
returns ActionOutput(text=<final message>,
structured={"harness_turn": {...}})
harness resolve → records the turn summary; signals completion
Consequences:
- The harness's
max_iterationssupersedes our turn policy; for a harness class the effective turn policy issingle_actionaround one complete harness run. - Every inner tool call still passes through the Tool Bridge individually, which
forwards to the backend's own
invoke_action_with_kwargs— so the backend'senabled_actions/excluded_actionscatalog restriction, actor-argument injection,action_events.jsonllogging, and failure counters all behave exactly as for a native turn. (The Tool Bridge relies on the backend's catalog filtering; per-flowflow_action_filters, a native-resolve feature, do not apply to harness surfaces.) - Every inner model call passes through the Model Proxy, so token usage, retries, and
prompt logs land in the same
llm_usage/prompts_and_responses.jsonlas native agents.
Configuration¶
Zero extra configuration. Point a persona class at a harness agent class — that's it.
Harness agents work with the default game master and any resolve/action-prompt
components; no harness built-ins, no special GM config:
# agents/default.yaml (@package agents)
persona_pipeline:
classes:
user:
count: ${num_agents}
class_path: silisocs.agents.harness.fake.FakeHarnessAgent # or hermes.HermesAgent / openclaw.OpenClawAgent
params:
probe_mode: model # "model" (default) or "harness"
How it works without any GM config:
- The default action-prompt component binds the per-turn Tool Bridge into the action
spec for any acting agent that declares
wants_tool_surface(harness agents do; native agents don't, so existing scenarios are byte-for-byte unchanged), regardless of the GM's tool-calling mode. - A harness turn's
ActionOutputis self-describing (it carries aharness_turnpayload), so the shared resolve base records it uniformly — any resolve (parsed_action,tool_calling, …) handles harness output. No harness resolve component, no fallback wiring, no validation.
Available harness agents¶
class_path |
Harness | Notes |
|---|---|---|
silisocs.agents.harness.fake.FakeHarnessAgent |
none (deterministic) | Dependency-free reference / dry run. Reads the feed then posts. |
silisocs.agents.harness.hermes.HermesAgent |
Hermes Agent (in-process) | Requires the hermes install (see below). |
silisocs.agents.harness.openclaw.OpenClawAgent |
OpenClaw (out-of-process) | Requires Node + the openclaw binary. |
The persona-pipeline fields (context, bio, goal, style, memories, …) are folded
into the harness's persona / SOUL.md — the same declarative data native agents use.
Mixed native + harness populations¶
One game master hosts both harness and native agents with no special config: the shared resolve base records harness output (self-describing) and passes native output through to the normal resolve, and the default action-prompt gives each agent the right spec (a Tool Bridge for harness agents, the standard prompt/tool-schemas for native agents).
Multi-GM chains¶
The Tool Bridge is rebuilt per turn from the acting game master's backend, so a harness agent hopping through a multi-GM flow chain acts on each backend in its chain automatically — no extra configuration.
Probes¶
Harness agents answer evaluation probes two ways, selected by params.probe_mode:
model(default): the probe is answered through the agent's ownLanguageModelwith a summary of the harness's state as context — fully telemetered, deterministic with a scripted model.harness: the probe is answered by the harness itself (run_probe) — higher fidelity for studies that care about the harness's actual disposition, at the cost of another harness call.
Checkpoints & determinism¶
Harness agents are snapshot-restored, never replay-restored — neither harness ships a determinism/replay story, so their inner loops are treated as stochastic. This fits the existing per-object checkpoint contract:
- Hermes: the serialized
conversation_historyround-trips throughget_state/set_state. - OpenClaw: a bounded snapshot of the agent's workspace files (
SOUL.md,MEMORY.md, …).
Resume restores each harness agent's state directly from its checkpoint block.
Telemetry — the Model Proxy¶
Both harnesses speak OpenAI-compatible HTTP to a configurable base_url. The runtime
starts a loopback Model Proxy (a thread in the runner process, loopback-only) and
points every harness agent at it. The proxy forwards each request byte-for-byte to the
upstream provider — preserving the harness's exact request — and observes everything:
- provider
usage→ the samellm_usagecounters /by_phasebuckets / pricing as native agents (one unified summary); - every call logged to
prompts_and_responses.jsonlwith agent / phase attribution; - per-agent routing tokens as the harness-side "api key", so real provider keys live only in the proxy — harness configs and workspaces never hold real credentials.
The upstream is resolved from the same per-class model config (persona_pipeline.classes.<class>.model)
native agents use, so one model-configuration language covers both. A scripted upstream
gives deterministic, no-key integration tests.
Per-call harness detail (each tool request / execution / failure, and per-turn summaries)
is written to a new harness_events.jsonl (per-GM in multi-GM runs), listed in the
run manifest and exposed on RunArtifact.iter_harness_events().
Cost
A harness turn is many model calls (its whole tool loop), so harness populations are
far more expensive than native ones. Bound cost with the harness's max_iterations,
sim.max_concurrent_actions, and per-GM gm_concurrency_caps. For large harness
populations prefer sim.engine.executor: asyncio.
Installing the harnesses¶
Hermes (in-process)¶
Hermes is pure Python but exact-pins openai==2.24.0, which conflicts with the
silisocs openai<2.0.0 pin. Install it in an isolated environment (or after a future
openai 2.x migration):
# In a separate venv / container that imports silisocs and hermes-agent together.
pip install silisocs hermes-agent
silisocs doctor reports whether run_agent (Hermes) is importable.
OpenClaw (out-of-process)¶
OpenClaw is Node/TypeScript. Install Node and the openclaw binary; the runtime writes
an openclaw.json (agents list, all real-world tools denied, our MCP tool server mounted,
model provider pointed at the Model Proxy, heartbeat/cron disabled) and drives each turn
over the gateway's WebSocket API. silisocs doctor reports Node + openclaw presence.
Live-integration boundary
The deterministic core (Tool Bridge, agent/probe/checkpoint contract, Model Proxy, GM
slots, gateway config generation, MCP tool routing) is fully unit-tested with the
dependency-free FakeHarnessAgent. Live runs against real Hermes / OpenClaw are
opt-in (they need the external runtimes) and covered by integration tests behind
HERMES_LIVE=1 / SILISOCS_OPENCLAW_BIN.