diff --git a/solstone/think/cortex_client.py b/solstone/think/cortex_client.py index 116b11e46..34652d8f3 100644 --- a/solstone/think/cortex_client.py +++ b/solstone/think/cortex_client.py @@ -19,9 +19,18 @@ logger = logging.getLogger(__name__) # while Callosum events remain the fast wake path. Monkeypatched small in tests. _POLL_INTERVAL_S = 0.5 _CLAIM_POLL_INTERVAL_S = 0.1 -_CLAIM_WINDOW_S = 1.0 -# Total sends including the initial broadcast. -_CLAIM_MAX_BROADCASTS = 3 + +# Claim-wait schedules. len(windows) is the total number of sends, including the +# initial broadcast; element i is how long to poll for a claim after send i. +# A delivered request claims in milliseconds, so these windows exist to survive +# a *lost* broadcast, not a slow one. +# +# Fast-fail (~3s): the default, for interactive callers who would rather fail +# than make a person wait. +_DEFAULT_CLAIM_WINDOWS: tuple[float, ...] = (1.0, 1.0, 1.0) +# Patient (~30s): for the think orchestrator, whose units are re-walked hours +# later if a request is lost during a broadcast burst. +PATIENT_CLAIM_WINDOWS: tuple[float, ...] = (1.0, 2.0, 4.0, 8.0, 15.0) class CortexSpawnUnavailable(Exception): @@ -60,12 +69,32 @@ def _find_use_file(talents_dir: Path, use_id: str) -> tuple[Path | None, str]: return None, "not_found" +def _check_claimed(use_id: str, window: float) -> bool: + """Poll for a durable Cortex claim on ``use_id`` for up to ``window`` seconds.""" + if get_use_log_status(use_id) in ("running", "completed"): + return True + + deadline = time.monotonic() + window + while True: + remaining = deadline - time.monotonic() + if remaining <= 0: + return False + sleep_for = min(_CLAIM_POLL_INTERVAL_S, remaining) + if sleep_for <= 0: + return False + time.sleep(sleep_for) + if get_use_log_status(use_id) in ("running", "completed"): + return True + + def cortex_request( prompt: str, name: str, provider: Optional[str] = None, config: Optional[Dict[str, Any]] = None, use_id: Optional[str] = None, + *, + claim_windows: Optional[tuple[float, ...]] = None, ) -> str: """Create a Cortex talent request via Callosum broadcast. @@ -75,6 +104,9 @@ def cortex_request( provider: AI provider - openai, google, or anthropic config: Provider-specific configuration (model, max_output_tokens, thinking_budget, etc.) use_id: Optional pre-reserved use_id. When omitted, a unique timestamp is allocated. + claim_windows: Claim-wait schedule. Defaults to the fast-fail + _DEFAULT_CLAIM_WINDOWS; the think orchestrator passes + PATIENT_CLAIM_WINDOWS. Returns: Use ID (timestamp-based string). @@ -83,6 +115,7 @@ def cortex_request( CortexSpawnUnavailable: If the request cannot reach Callosum. CortexNotClaimed: If Cortex does not claim the request. """ + windows = claim_windows if claim_windows is not None else _DEFAULT_CLAIM_WINDOWS # Get journal path (for use_id uniqueness check) journal_path = get_journal() @@ -134,35 +167,21 @@ def cortex_request( logger.info("Failed to send cortex request for talent '%s'", name) raise CortexSpawnUnavailable(detail=unavailable_detail) - broadcasts = 1 - while True: - if get_use_log_status(use_id) in ("running", "completed"): + # The initial broadcast above is send 0; each later window rebroadcasts first, + # so the total send count is exactly len(windows). + for index, window in enumerate(windows): + if index: + unavailable_detail = callosum_send_classified( + "cortex", "request", **request_fields + ) + if unavailable_detail: + logger.info("Failed to send cortex request for talent '%s'", name) + raise CortexSpawnUnavailable(detail=unavailable_detail) + + if _check_claimed(use_id, window): return use_id - deadline = time.monotonic() + _CLAIM_WINDOW_S - while True: - remaining = deadline - time.monotonic() - if remaining <= 0: - break - sleep_for = min(_CLAIM_POLL_INTERVAL_S, remaining) - if sleep_for <= 0: - break - time.sleep(sleep_for) - if get_use_log_status(use_id) in ("running", "completed"): - return use_id - - if broadcasts >= _CLAIM_MAX_BROADCASTS: - break - - broadcasts += 1 - unavailable_detail = callosum_send_classified( - "cortex", "request", **request_fields - ) - if unavailable_detail: - logger.info("Failed to send cortex request for talent '%s'", name) - raise CortexSpawnUnavailable(detail=unavailable_detail) - - detail = f"cortex did not claim use_id {use_id} after {broadcasts} broadcasts" + detail = f"cortex did not claim use_id {use_id} after {len(windows)} broadcasts" raise CortexNotClaimed(use_id=use_id, detail=detail) diff --git a/solstone/think/thinking.py b/solstone/think/thinking.py index b6ce7727a..bcff61c2f 100644 --- a/solstone/think/thinking.py +++ b/solstone/think/thinking.py @@ -39,6 +39,7 @@ from solstone.think.change_detection import detect_segment_change, resolve_prede from solstone.think.cluster import cluster_segments, read_segment_data_state from solstone.think.cogitate_policy import DETERMINISTIC_FAILURE_THRESHOLD from solstone.think.cortex_client import ( + PATIENT_CLAIM_WINDOWS, CortexNotClaimed, CortexSpawnUnavailable, cortex_request, @@ -897,9 +898,14 @@ class _NotClaimed: def _dispatch_cortex_request(**kwargs) -> str | None | _NotClaimed: - """Call cortex_request and classify dispatch failures for orchestrators.""" + """Call cortex_request and classify dispatch failures for orchestrators. + + Orchestrated units are re-walked hours later when a request is lost, so they + wait out a broadcast burst on the patient claim schedule rather than + fast-failing the way interactive callers do. + """ try: - return cortex_request(**kwargs) + return cortex_request(**kwargs, claim_windows=PATIENT_CLAIM_WINDOWS) except CortexSpawnUnavailable as exc: logging.info("cortex_request unavailable: %s", exc.detail or "unknown") return None diff --git a/tests/test_bad_media_corpus.py b/tests/test_bad_media_corpus.py index 7f1ded83f..86c23ad27 100644 --- a/tests/test_bad_media_corpus.py +++ b/tests/test_bad_media_corpus.py @@ -366,7 +366,9 @@ def _run_idle_gate( monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: spawned.append(name) or f"agent-{name}", + lambda prompt, name, config=None, **kwargs: ( + spawned.append(name) or f"agent-{name}" + ), ) monkeypatch.setattr( think, diff --git a/tests/test_cortex_client.py b/tests/test_cortex_client.py index efe44ae14..f047ae718 100644 --- a/tests/test_cortex_client.py +++ b/tests/test_cortex_client.py @@ -193,7 +193,12 @@ def test_cortex_request_empty_journal(tmp_path, monkeypatch): assert len(use_id) > 0 -def _install_fake_claim_clock(monkeypatch): +def _install_fake_claim_clock(monkeypatch, poll_interval=0.01, windows=(0.02,) * 3): + """Fake the claim loop's clock so schedules run without real sleeps. + + Returns the cortex_client module and the mutable fake-monotonic clock, so + tests can read elapsed time and timestamp individual sends. + """ import solstone.think.cortex_client as cc now = {"value": 0.0} @@ -203,14 +208,14 @@ def _install_fake_claim_clock(monkeypatch): now["value"] += seconds monkeypatch.setattr(cc.time, "sleep", fake_sleep) - monkeypatch.setattr(cc, "_CLAIM_POLL_INTERVAL_S", 0.01) - monkeypatch.setattr(cc, "_CLAIM_WINDOW_S", 0.02) - return cc + monkeypatch.setattr(cc, "_CLAIM_POLL_INTERVAL_S", poll_interval) + monkeypatch.setattr(cc, "_DEFAULT_CLAIM_WINDOWS", tuple(windows)) + return cc, now def test_cortex_request_returns_when_claim_appears_after_poll(tmp_path, monkeypatch): monkeypatch.setenv("SOLSTONE_JOURNAL", str(tmp_path)) - cc = _install_fake_claim_clock(monkeypatch) + cc, _ = _install_fake_claim_clock(monkeypatch) monkeypatch.setattr(cc, "callosum_send_classified", lambda *a, **kw: "") statuses = iter(["not_found", "running"]) @@ -226,7 +231,7 @@ def test_cortex_request_returns_when_claim_appears_after_poll(tmp_path, monkeypa def test_cortex_request_rebroadcast_reuses_same_use_id(tmp_path, monkeypatch): monkeypatch.setenv("SOLSTONE_JOURNAL", str(tmp_path)) - cc = _install_fake_claim_clock(monkeypatch) + cc, _ = _install_fake_claim_clock(monkeypatch) send_calls = [] def fake_send(*args, **kwargs): @@ -248,8 +253,9 @@ def test_cortex_request_rebroadcast_reuses_same_use_id(tmp_path, monkeypatch): def test_cortex_request_raises_when_not_claimed(tmp_path, monkeypatch): + """Default schedule fast-fails: three sends, one window each, then raises.""" monkeypatch.setenv("SOLSTONE_JOURNAL", str(tmp_path)) - cc = _install_fake_claim_clock(monkeypatch) + cc, clock = _install_fake_claim_clock(monkeypatch) send_calls = [] def fake_send(*args, **kwargs): @@ -264,6 +270,92 @@ def test_cortex_request_raises_when_not_claimed(tmp_path, monkeypatch): assert excinfo.value.use_id == "1713629000003" assert len(send_calls) == 3 + assert "after 3 broadcasts" in excinfo.value.detail + assert clock["value"] == pytest.approx(sum(cc._DEFAULT_CLAIM_WINDOWS), abs=1e-6) + + +def test_cortex_request_patient_windows_are_non_decreasing(tmp_path, monkeypatch): + """An explicit schedule drives send count, gaps, and total budget.""" + monkeypatch.setenv("SOLSTONE_JOURNAL", str(tmp_path)) + cc, clock = _install_fake_claim_clock(monkeypatch, poll_interval=0.001) + windows = (0.01, 0.02, 0.04, 0.08, 0.15) + send_times = [] + + def fake_send(*args, **kwargs): + send_times.append(clock["value"]) + return "" + + monkeypatch.setattr(cc, "callosum_send_classified", fake_send) + monkeypatch.setattr(cc, "get_use_log_status", lambda use_id: "not_found") + + with pytest.raises(CortexNotClaimed) as excinfo: + cortex_request( + "test", "chat", "openai", use_id="1713629000005", claim_windows=windows + ) + + assert len(send_times) == len(windows) + assert "after 5 broadcasts" in excinfo.value.detail + + gaps = [b - a for a, b in zip(send_times, send_times[1:])] + assert gaps == pytest.approx(list(windows[:-1]), abs=1e-6) + assert gaps == sorted(gaps), "rebroadcast windows must be non-decreasing" + assert clock["value"] == pytest.approx(sum(windows), abs=1e-6) + + +def test_cortex_request_raises_spawn_unavailable_on_failed_rebroadcast( + tmp_path, monkeypatch +): + """A send failure on a rebroadcast is CortexSpawnUnavailable, not NotClaimed.""" + monkeypatch.setenv("SOLSTONE_JOURNAL", str(tmp_path)) + cc, _ = _install_fake_claim_clock(monkeypatch) + send_calls = [] + + def fake_send(*args, **kwargs): + send_calls.append(kwargs) + return "FileNotFoundError" if len(send_calls) >= 2 else "" + + monkeypatch.setattr(cc, "callosum_send_classified", fake_send) + monkeypatch.setattr(cc, "get_use_log_status", lambda use_id: "not_found") + + with pytest.raises(CortexSpawnUnavailable) as excinfo: + cortex_request("test", "chat", "openai", use_id="1713629000006") + + assert excinfo.value.detail == "FileNotFoundError" + assert len(send_calls) == 2 + + +def test_dispatch_cortex_request_patient_schedule_claims_after_default_would_fail( + tmp_path, monkeypatch +): + """The orchestrator survives a claim that lands past the fast-fail budget.""" + import solstone.think.thinking as think + + monkeypatch.setenv("SOLSTONE_JOURNAL", str(tmp_path)) + default_windows = (0.01, 0.01, 0.01) # budget 0.03 + patient_windows = (0.01, 0.02, 0.04, 0.08, 0.15) # budget 0.30 + cc, clock = _install_fake_claim_clock( + monkeypatch, poll_interval=0.001, windows=default_windows + ) + monkeypatch.setattr(think, "PATIENT_CLAIM_WINDOWS", patient_windows) + monkeypatch.setattr(cc, "callosum_send_classified", lambda *a, **kw: "") + + # Claim lands after the default budget expires but well inside the patient one. + claim_at = 0.05 + monkeypatch.setattr( + cc, + "get_use_log_status", + lambda use_id: "running" if clock["value"] >= claim_at else "not_found", + ) + + with pytest.raises(CortexNotClaimed): + cortex_request("test", "chat", "openai", use_id="1713629000007") + + clock["value"] = 0.0 + result = think._dispatch_cortex_request( + prompt="test", name="chat", provider="openai", use_id="1713629000008" + ) + + assert result == "1713629000008" def test_cortex_request_immediate_claim_does_not_sleep(tmp_path, monkeypatch): diff --git a/tests/test_pipeline_smoke.py b/tests/test_pipeline_smoke.py index e40f6936a..6b1b4ec73 100644 --- a/tests/test_pipeline_smoke.py +++ b/tests/test_pipeline_smoke.py @@ -189,7 +189,7 @@ class TestPipelineSmokeTest: monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: f"agent-{name}", + lambda prompt, name, config=None, **kwargs: f"agent-{name}", ) monkeypatch.setattr( think, diff --git a/tests/test_think_activity.py b/tests/test_think_activity.py index f69049c48..35acb7168 100644 --- a/tests/test_think_activity.py +++ b/tests/test_think_activity.py @@ -110,7 +110,7 @@ class TestRunActivityPrompts: spawned_requests = [] - def mock_cortex_request(prompt, name, config): + def mock_cortex_request(prompt, name, config, **kwargs): spawned_requests.append((name, config)) return f"agent-{name}" @@ -168,7 +168,7 @@ class TestRunActivityPrompts: spawned = [] - def mock_cortex_request(prompt, name, config): + def mock_cortex_request(prompt, name, config, **kwargs): spawned.append(name) return f"agent-{name}" @@ -220,7 +220,7 @@ class TestRunActivityPrompts: captured_config = {} - def mock_cortex_request(prompt, name, config): + def mock_cortex_request(prompt, name, config, **kwargs): captured_config.update(config) return "agent-1" @@ -287,7 +287,7 @@ class TestRunActivityPrompts: ) monkeypatch.setattr( "solstone.think.thinking.cortex_request", - lambda prompt, name, config: "agent-1", + lambda prompt, name, config, **kwargs: "agent-1", ) monkeypatch.setattr( "solstone.think.thinking.wait_for_uses", @@ -397,7 +397,7 @@ class TestRunActivityPrompts: ) monkeypatch.setattr( "solstone.think.thinking.cortex_request", - lambda prompt, name, config: "agent-1", + lambda prompt, name, config, **kwargs: "agent-1", ) monkeypatch.setattr( "solstone.think.thinking.wait_for_uses", @@ -504,7 +504,7 @@ class TestRunActivityPrompts: spawned: list[str] = [] - def mock_cortex_request(prompt, name, config): + def mock_cortex_request(prompt, name, config, **kwargs): spawned.append(name) return f"agent-{name}" @@ -572,7 +572,7 @@ class TestRunActivityPrompts: spawned: list[str] = [] - def mock_cortex_request(prompt, name, config): + def mock_cortex_request(prompt, name, config, **kwargs): spawned.append(config["activity"]["id"]) return f"agent-{config['activity']['id']}" @@ -664,7 +664,9 @@ class TestRunActivityPrompts: ) monkeypatch.setattr( "solstone.think.thinking.cortex_request", - lambda prompt, name, config: pytest.fail("should not dispatch"), + lambda prompt, name, config, **kwargs: pytest.fail( + "should not dispatch" + ), ) result = run_activity_prompts( diff --git a/tests/test_think_no_activity_prompts.py b/tests/test_think_no_activity_prompts.py index d33b2d747..14acac143 100644 --- a/tests/test_think_no_activity_prompts.py +++ b/tests/test_think_no_activity_prompts.py @@ -94,7 +94,7 @@ def _patch_segment_dependencies( monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: f"agent-{name}", + lambda prompt, name, config=None, **kwargs: f"agent-{name}", ) monkeypatch.setattr( think, diff --git a/tests/test_think_segment.py b/tests/test_think_segment.py index 7c3f5eba1..4f3d1c01b 100644 --- a/tests/test_think_segment.py +++ b/tests/test_think_segment.py @@ -220,7 +220,9 @@ def _patch_segment_cortex(monkeypatch, think, spawned: list[str]) -> None: monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: spawned.append(name) or f"agent-{name}", + lambda prompt, name, config=None, **kwargs: ( + spawned.append(name) or f"agent-{name}" + ), ) monkeypatch.setattr( think, @@ -344,7 +346,9 @@ class TestRunSegmentSense: monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: spawned.append(name) or f"agent-{name}", + lambda prompt, name, config=None, **kwargs: ( + spawned.append(name) or f"agent-{name}" + ), ) monkeypatch.setattr(think, "_callosum", None) monkeypatch.setattr(think, "_jsonl", writer) @@ -414,7 +418,9 @@ class TestRunSegmentSense: monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: spawned.append(name) or f"agent-{name}", + lambda prompt, name, config=None, **kwargs: ( + spawned.append(name) or f"agent-{name}" + ), ) monkeypatch.setattr( think, @@ -465,7 +471,9 @@ class TestRunSegmentSense: monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: spawned.append(name) or f"agent-{name}", + lambda prompt, name, config=None, **kwargs: ( + spawned.append(name) or f"agent-{name}" + ), ) monkeypatch.setattr( think, @@ -540,7 +548,9 @@ class TestRunSegmentSense: monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: spawned.append(name) or f"agent-{name}", + lambda prompt, name, config=None, **kwargs: ( + spawned.append(name) or f"agent-{name}" + ), ) monkeypatch.setattr( think, @@ -628,7 +638,9 @@ class TestRunSegmentSense: monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: spawned.append(name) or f"agent-{name}", + lambda prompt, name, config=None, **kwargs: ( + spawned.append(name) or f"agent-{name}" + ), ) monkeypatch.setattr( think, @@ -675,7 +687,9 @@ class TestRunSegmentSense: monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: spawned.append(name) or f"agent-{name}", + lambda prompt, name, config=None, **kwargs: ( + spawned.append(name) or f"agent-{name}" + ), ) monkeypatch.setattr( think, @@ -737,7 +751,9 @@ class TestRunSegmentSense: monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: spawned.append(name) or f"agent-{name}", + lambda prompt, name, config=None, **kwargs: ( + spawned.append(name) or f"agent-{name}" + ), ) monkeypatch.setattr( think, @@ -797,7 +813,9 @@ class TestRunSegmentSense: monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: spawned.append(name) or f"agent-{name}", + lambda prompt, name, config=None, **kwargs: ( + spawned.append(name) or f"agent-{name}" + ), ) monkeypatch.setattr( think, @@ -853,7 +871,9 @@ class TestRunSegmentSense: monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: spawned.append(name) or f"agent-{name}", + lambda prompt, name, config=None, **kwargs: ( + spawned.append(name) or f"agent-{name}" + ), ) monkeypatch.setattr( think, @@ -907,7 +927,9 @@ class TestRunSegmentSense: monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: spawned.append(name) or f"agent-{name}", + lambda prompt, name, config=None, **kwargs: ( + spawned.append(name) or f"agent-{name}" + ), ) monkeypatch.setattr( think, @@ -971,7 +993,9 @@ class TestRunSegmentSense: monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: spawned.append(name) or f"agent-{name}", + lambda prompt, name, config=None, **kwargs: ( + spawned.append(name) or f"agent-{name}" + ), ) monkeypatch.setattr( think, @@ -1063,7 +1087,9 @@ class TestRunSegmentSense: monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: spawned.append(name) or f"agent-{name}", + lambda prompt, name, config=None, **kwargs: ( + spawned.append(name) or f"agent-{name}" + ), ) monkeypatch.setattr( think, @@ -1131,7 +1157,9 @@ class TestRunSegmentSense: monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: spawned.append(name) or f"agent-{name}", + lambda prompt, name, config=None, **kwargs: ( + spawned.append(name) or f"agent-{name}" + ), ) monkeypatch.setattr( think, @@ -1180,7 +1208,9 @@ class TestRunSegmentSense: monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: spawned.append(name) or f"agent-{name}", + lambda prompt, name, config=None, **kwargs: ( + spawned.append(name) or f"agent-{name}" + ), ) monkeypatch.setattr( think, @@ -1247,7 +1277,9 @@ class TestRunSegmentSense: monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: spawned.append(name) or f"agent-{name}", + lambda prompt, name, config=None, **kwargs: ( + spawned.append(name) or f"agent-{name}" + ), ) monkeypatch.setattr( think, @@ -1300,7 +1332,9 @@ class TestRunSegmentSense: monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: spawned.append(name) or f"agent-{name}", + lambda prompt, name, config=None, **kwargs: ( + spawned.append(name) or f"agent-{name}" + ), ) monkeypatch.setattr( think, @@ -1587,7 +1621,9 @@ class TestRunSegmentSense: monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: spawned.append(name) or f"agent-{name}", + lambda prompt, name, config=None, **kwargs: ( + spawned.append(name) or f"agent-{name}" + ), ) monkeypatch.setattr( think, @@ -1633,7 +1669,9 @@ class TestRunSegmentSense: monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: spawned.append(name) or f"agent-{name}", + lambda prompt, name, config=None, **kwargs: ( + spawned.append(name) or f"agent-{name}" + ), ) monkeypatch.setattr( think, @@ -1678,7 +1716,9 @@ class TestRunSegmentSense: monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: spawned.append(name) or f"agent-{name}", + lambda prompt, name, config=None, **kwargs: ( + spawned.append(name) or f"agent-{name}" + ), ) monkeypatch.setattr( think, @@ -1728,7 +1768,9 @@ class TestRunSegmentSense: monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: spawned.append(name) or f"agent-{name}", + lambda prompt, name, config=None, **kwargs: ( + spawned.append(name) or f"agent-{name}" + ), ) monkeypatch.setattr( think, @@ -1779,7 +1821,9 @@ class TestRunSegmentSense: monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: spawned.append(name) or f"agent-{name}", + lambda prompt, name, config=None, **kwargs: ( + spawned.append(name) or f"agent-{name}" + ), ) monkeypatch.setattr( think, @@ -1825,7 +1869,9 @@ class TestRunSegmentSense: monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: spawned.append(name) or f"agent-{name}", + lambda prompt, name, config=None, **kwargs: ( + spawned.append(name) or f"agent-{name}" + ), ) monkeypatch.setattr( think, @@ -1863,7 +1909,9 @@ class TestRunSegmentSense: monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: spawned.append(name) or f"agent-{name}", + lambda prompt, name, config=None, **kwargs: ( + spawned.append(name) or f"agent-{name}" + ), ) monkeypatch.setattr( think, @@ -1904,7 +1952,9 @@ class TestRunSegmentSense: monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: spawned.append(name) or f"agent-{name}", + lambda prompt, name, config=None, **kwargs: ( + spawned.append(name) or f"agent-{name}" + ), ) def mock_wait_for_agents(agent_ids, timeout=600): @@ -1984,7 +2034,7 @@ class TestRunSegmentSense: monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: f"agent-{name}", + lambda prompt, name, config=None, **kwargs: f"agent-{name}", ) monkeypatch.setattr( think, @@ -2073,7 +2123,7 @@ class TestRunSegmentSense: monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: f"agent-{name}", + lambda prompt, name, config=None, **kwargs: f"agent-{name}", ) monkeypatch.setattr( think, @@ -2114,7 +2164,7 @@ class TestRunSegmentSense: }, ) - def mock_cortex_request(prompt, name, config=None): + def mock_cortex_request(prompt, name, config=None, **kwargs): calls.append(name) if name == "sense": return "agent-sense" @@ -2163,7 +2213,7 @@ class TestRunSegmentSense: jsonl_events = [] emitted_events = [] - def mock_cortex_request(prompt, name, config=None): + def mock_cortex_request(prompt, name, config=None, **kwargs): if name == "sense": return "agent-sense" raise think.CortexNotClaimed(use_id="lost-1") @@ -2488,7 +2538,7 @@ class TestThinkJSONLEvents: monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: "agent-sense", + lambda prompt, name, config=None, **kwargs: "agent-sense", ) monkeypatch.setattr( think, @@ -2551,7 +2601,7 @@ class TestThinkJSONLEvents: monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: f"agent-{name}", + lambda prompt, name, config=None, **kwargs: f"agent-{name}", ) monkeypatch.setattr( think, diff --git a/tests/test_think_segment_prephase.py b/tests/test_think_segment_prephase.py index ecb456e2d..3985873ab 100644 --- a/tests/test_think_segment_prephase.py +++ b/tests/test_think_segment_prephase.py @@ -451,7 +451,7 @@ def test_segment_health_log_receives_segment_talent_events(tmp_path, monkeypatch monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: f"agent-{name}", + lambda prompt, name, config=None, **kwargs: f"agent-{name}", ) monkeypatch.setattr( think, @@ -1069,7 +1069,7 @@ def test_activity_replay_dedupes_records_and_preserves_non_refresh( monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: f"agent-{name}", + lambda prompt, name, config=None, **kwargs: f"agent-{name}", ) monkeypatch.setattr( think, @@ -1243,7 +1243,7 @@ def test_run_segment_sense_reports_invalid_sense_output( monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: f"agent-{name}", + lambda prompt, name, config=None, **kwargs: f"agent-{name}", ) monkeypatch.setattr( think, diff --git a/tests/test_think_skip_talents.py b/tests/test_think_skip_talents.py index 06da874e8..581073c48 100644 --- a/tests/test_think_skip_talents.py +++ b/tests/test_think_skip_talents.py @@ -125,7 +125,9 @@ def _patch_segment_dependencies( monkeypatch.setattr( think, "cortex_request", - lambda prompt, name, config=None: spawned.append(name) or f"agent-{name}", + lambda prompt, name, config=None, **kwargs: ( + spawned.append(name) or f"agent-{name}" + ), ) monkeypatch.setattr( think,