mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-08-25 22:12:22 +02:00
[eric] client-pool: stop hashing the compaction cutoff, it respawned the CLI every turn past 65% context
This commit is contained in:
@@ -40,11 +40,16 @@ p_last_field_digests: Dict[str, Dict[str, str]] = {}
|
||||
def boot_fingerprint(options_kwargs: Dict, session: AgentSession) -> str:
|
||||
"""Hash of every input the CLI subprocess freezes at boot. Includes the full mcp_servers config
|
||||
(so MCPActivate / model-env changes respawn), the composed system prompt (so per-turn selection
|
||||
context respawns instead of silently not applying), branch, and the compaction cutoff (else a
|
||||
live client would keep the untrimmed transcript forever)."""
|
||||
context respawns instead of silently not applying), and the branch.
|
||||
|
||||
The compaction cutoff is deliberately NOT hashed. It only ever changes prompt_content (the
|
||||
rebuilt history prefix), which is sent per query, never frozen at boot, and on the resume path
|
||||
the CLI replays its own untrimmed transcript regardless. Every path that does rebuild history
|
||||
(needs_fresh_session / needs_fork / fork) already forces a respawn through force_respawn. Hashing
|
||||
it bought nothing and cost a full CLI respawn on EVERY turn once a session crossed
|
||||
compact_threshold_pct, measured at +1.0s TTFT per turn."""
|
||||
frozen = {k: v for k, v in options_kwargs.items() if k not in P_NON_BOOT_KEYS}
|
||||
frozen["p_branch"] = session.active_branch_id
|
||||
frozen["p_compacted_through"] = session.compacted_through_msg_id
|
||||
# Pool diagnostics (OPENSWARM_POOL_DIAG=1): on a respawn, names WHICH boot field drifted; the tool for debugging respawn churn (e.g. the thinking short/long-prompt flip) in the field.
|
||||
if os.environ.get("OPENSWARM_POOL_DIAG") == "1":
|
||||
digests = {k: hashlib.sha256(json.dumps(v, sort_keys=True, default=str).encode()).hexdigest()[:10] for k, v in frozen.items()}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
"""What the client pool's boot fingerprint does and does NOT hash.
|
||||
|
||||
Reuse is gated on this hash, so anything the CLI subprocess freezes at boot must be in it (a stale
|
||||
live client is the bug it exists to prevent), and anything sent per query must be out of it (hashing
|
||||
those respawns the CLI for nothing, which is exactly what the compaction cutoff used to do)."""
|
||||
|
||||
import pytest
|
||||
|
||||
from backend.apps.agents.core.models import AgentSession
|
||||
from backend.apps.agents.manager.run.client_pool import boot_fingerprint
|
||||
|
||||
BASE_KWARGS = {
|
||||
"model": "haiku",
|
||||
"cwd": "/tmp/ws",
|
||||
"system_prompt": {"type": "preset", "preset": "claude_code"},
|
||||
"allowed_tools": ["Read"],
|
||||
"disallowed_tools": ["mcp__claude_ai_*"],
|
||||
"mcp_servers": {"openswarm-mcp-meta": {"command": "python", "args": ["m.py"], "type": "stdio"}},
|
||||
"can_use_tool": lambda: None,
|
||||
"stderr": lambda line: None,
|
||||
"hooks": {"PreToolUse": []},
|
||||
}
|
||||
|
||||
|
||||
def make_session() -> AgentSession:
|
||||
return AgentSession(name="t", model="haiku", mode="agent")
|
||||
|
||||
|
||||
def test_fingerprint_stable_across_per_turn_keys():
|
||||
s = make_session()
|
||||
a = boot_fingerprint(dict(BASE_KWARGS), s)
|
||||
changed = dict(BASE_KWARGS)
|
||||
changed["can_use_tool"] = lambda: 1
|
||||
changed["stderr"] = lambda line: 1
|
||||
changed["hooks"] = {"PreToolUse": ["different"]}
|
||||
changed["resume"] = "sdk-session-xyz"
|
||||
changed["fork_session"] = True
|
||||
assert boot_fingerprint(changed, s) == a
|
||||
|
||||
|
||||
def test_fingerprint_ignores_the_compaction_cutoff():
|
||||
"""The cutoff only rewrites prompt_content, which is sent per query and never frozen at boot,
|
||||
and every path that rebuilds history already forces a respawn. Hashing it respawned the CLI on
|
||||
every turn past compact_threshold_pct for zero token saving (+1.0s TTFT per turn, measured)."""
|
||||
s = make_session()
|
||||
before = boot_fingerprint(dict(BASE_KWARGS), s)
|
||||
for cutoff in ("msg42", "msg43", "msg44"):
|
||||
s.compacted_through_msg_id = cutoff
|
||||
assert boot_fingerprint(dict(BASE_KWARGS), s) == before
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mutate", [
|
||||
lambda k, s: k.__setitem__("mcp_servers", {**k["mcp_servers"], "x": {"command": "node", "type": "stdio"}}),
|
||||
lambda k, s: k.__setitem__("system_prompt", {"type": "preset", "preset": "claude_code", "append": "sel"}),
|
||||
lambda k, s: k.__setitem__("model", "gpt-5-mini"),
|
||||
lambda k, s: k.__setitem__("cwd", "/tmp/other"),
|
||||
lambda k, s: k.__setitem__("allowed_tools", ["Read", "Bash"]),
|
||||
lambda k, s: k.__setitem__("tools", ["Read", "Bash", "ToolSearch"]),
|
||||
lambda k, s: setattr(s, "active_branch_id", "branch2"),
|
||||
])
|
||||
def test_fingerprint_changes_on_boot_inputs(mutate):
|
||||
s = make_session()
|
||||
kwargs = dict(BASE_KWARGS)
|
||||
kwargs["mcp_servers"] = dict(BASE_KWARGS["mcp_servers"])
|
||||
before = boot_fingerprint(kwargs, s)
|
||||
mutate(kwargs, s)
|
||||
assert boot_fingerprint(kwargs, s) != before
|
||||
@@ -1,19 +1,16 @@
|
||||
"""Invariant + seeded-simulation tests for the persistent-client pool (lever A of the TTFT work).
|
||||
Proves the red-teamed safety properties hold by construction: fingerprint-gated reuse, respawn on
|
||||
any boot-input change, pop-first disposal, never-raising teardown, and (seeded sim) that random op
|
||||
sequences never reuse a stale client, never double-boot needlessly, and always recover a dead one."""
|
||||
Proves the red-teamed safety properties hold by construction: fingerprint-gated reuse, pop-first
|
||||
disposal, never-raising teardown, idle/LRU reclaim, and (seeded sim) that random op sequences never
|
||||
reuse a stale client, never double-boot needlessly, and always recover a dead one. What the
|
||||
fingerprint itself hashes lives in test_boot_fingerprint.py."""
|
||||
|
||||
import asyncio
|
||||
import random
|
||||
from typing import Dict, List
|
||||
|
||||
import pytest
|
||||
|
||||
from backend.apps.agents.core.models import AgentSession
|
||||
from backend.apps.agents.manager.run.client_pool import (
|
||||
ClientHandle,
|
||||
acquire_client,
|
||||
boot_fingerprint,
|
||||
dispose_all_clients,
|
||||
dispose_client,
|
||||
dispose_client_soon,
|
||||
@@ -39,56 +36,6 @@ class FakeClient:
|
||||
raise RuntimeError("teardown boom")
|
||||
|
||||
|
||||
def make_session(branch: str = "main", compacted: str | None = None) -> AgentSession:
|
||||
s = AgentSession(name="t", model="haiku", mode="agent")
|
||||
s.active_branch_id = branch
|
||||
s.compacted_through_msg_id = compacted
|
||||
return s
|
||||
|
||||
|
||||
BASE_KWARGS = {
|
||||
"model": "haiku",
|
||||
"cwd": "/tmp/ws",
|
||||
"system_prompt": {"type": "preset", "preset": "claude_code"},
|
||||
"allowed_tools": ["Read"],
|
||||
"disallowed_tools": ["mcp__claude_ai_*"],
|
||||
"mcp_servers": {"openswarm-mcp-meta": {"command": "python", "args": ["m.py"], "type": "stdio"}},
|
||||
"can_use_tool": lambda: None,
|
||||
"stderr": lambda line: None,
|
||||
"hooks": {"PreToolUse": []},
|
||||
}
|
||||
|
||||
|
||||
def test_fingerprint_stable_across_per_turn_keys():
|
||||
s = make_session()
|
||||
a = boot_fingerprint(dict(BASE_KWARGS), s)
|
||||
changed = dict(BASE_KWARGS)
|
||||
changed["can_use_tool"] = lambda: 1
|
||||
changed["stderr"] = lambda line: 1
|
||||
changed["hooks"] = {"PreToolUse": ["different"]}
|
||||
changed["resume"] = "sdk-session-xyz"
|
||||
changed["fork_session"] = True
|
||||
assert boot_fingerprint(changed, s) == a
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mutate", [
|
||||
lambda k, s: k.__setitem__("mcp_servers", {**k["mcp_servers"], "x": {"command": "node", "type": "stdio"}}),
|
||||
lambda k, s: k.__setitem__("system_prompt", {"type": "preset", "preset": "claude_code", "append": "sel"}),
|
||||
lambda k, s: k.__setitem__("model", "gpt-5-mini"),
|
||||
lambda k, s: k.__setitem__("cwd", "/tmp/other"),
|
||||
lambda k, s: k.__setitem__("allowed_tools", ["Read", "Bash"]),
|
||||
lambda k, s: setattr(s, "active_branch_id", "branch2"),
|
||||
lambda k, s: setattr(s, "compacted_through_msg_id", "msg42"),
|
||||
])
|
||||
def test_fingerprint_changes_on_boot_inputs(mutate):
|
||||
s = make_session()
|
||||
kwargs = dict(BASE_KWARGS)
|
||||
kwargs["mcp_servers"] = dict(BASE_KWARGS["mcp_servers"])
|
||||
before = boot_fingerprint(kwargs, s)
|
||||
mutate(kwargs, s)
|
||||
assert boot_fingerprint(kwargs, s) != before
|
||||
|
||||
|
||||
def test_reuse_respawn_force_and_teardown():
|
||||
async def run():
|
||||
pool: Dict[str, ClientHandle] = {}
|
||||
|
||||
Reference in New Issue
Block a user