Skip to content

Commit c17ac9c

Browse files
committed
fix(soul): resolve merge duplicates from blackbox port integration
Drop duplicate budget-nudge, ToolUseSkipped emit paths, and conflicting tests introduced when merging feat/blackbox-agent-loop-port into main.
1 parent 4ab8682 commit c17ac9c

6 files changed

Lines changed: 1 addition & 111 deletions

File tree

src/pythinker_code/prompts/__init__.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,6 @@
99
GOAL_SET = (Path(__file__).parent / "goal_set.md").read_text(encoding="utf-8")
1010
GOAL_CONTINUATION = (Path(__file__).parent / "goal_continuation.md").read_text(encoding="utf-8")
1111
GOAL_WRAP_UP = (Path(__file__).parent / "goal_wrap_up.md").read_text(encoding="utf-8")
12-
BUDGET_CONTINUATION_NUDGE = (
13-
"You have used ~{pct:.0f}% of this session's configured spend ceiling "
14-
"(${spent:.2f} of ${ceiling:.2f}). Pause new work and finish the current request. "
15-
"If you need more, raise `loop_control.max_session_cost_usd` in config."
16-
)
17-
1812
BUDGET_CONTINUATION_NUDGE = (
1913
"The session has crossed {ratio:.0%} of its configured spend ceiling "
2014
"(estimated ${spent:.2f} of ${ceiling:.2f}). Continue only if the remaining work is "

src/pythinker_code/soul/pythinkersoul.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ def _budget_nudge_message(*, session_cost_usd: float, ceiling: float, ratio: flo
309309
spent=session_cost_usd,
310310
ceiling=ceiling,
311311
)
312-
return Message(role="user", content=[system_reminder(text[:450])])
312+
return Message(role="user", content=[system_reminder(text[:500])])
313313

314314

315315
def _user_message_with_hook_context(

tests/core/test_config.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ def test_default_config_dump():
6161
"prune_protect_last": 20,
6262
"prune_min_chars": 2000,
6363
"prune_tool_result_max_chars": 0,
64-
"budget_nudge_ratio": 0.75,
6564
},
6665
"background": {
6766
"max_running_tasks": 4,

tests/core/test_pythinkersoul_turn_balance.py

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -358,36 +358,3 @@ async def fake_checkpoint() -> None:
358358
await soul.turn(Message(role="user", content=[TextPart(text="hello")]))
359359
assert len(soul.context.history) == before + 1
360360
assert not any("spend ceiling" in message.extract_text(" ") for message in soul.context.history)
361-
362-
363-
@pytest.mark.asyncio
364-
async def test_token_budget_nudge_appends_user_message_when_over_threshold(
365-
runtime: Runtime,
366-
tmp_path: Path,
367-
monkeypatch: pytest.MonkeyPatch,
368-
) -> None:
369-
runtime.config.loop_control.max_session_cost_usd = 1.0
370-
runtime.config.goal.auto_continue = False
371-
soul = _make_soul(runtime, tmp_path)
372-
soul._session_cost_usd = 2.0
373-
374-
async def fake_agent_loop() -> TurnOutcome:
375-
return TurnOutcome(
376-
stop_reason="no_tool_calls",
377-
final_message=Message(role="assistant", content=[TextPart(text="done")]),
378-
step_count=1,
379-
)
380-
381-
async def fake_checkpoint() -> None:
382-
return None
383-
384-
monkeypatch.setattr(soul, "_agent_loop", fake_agent_loop)
385-
monkeypatch.setattr(soul, "_checkpoint", fake_checkpoint)
386-
387-
await soul.turn(Message(role="user", content=[TextPart(text="hello")]))
388-
reminder_messages = [
389-
message
390-
for message in soul.context.history
391-
if message.role == "user" and "spend ceiling" in message.extract_text(" ")
392-
]
393-
assert len(reminder_messages) == 1

tests/core/test_toolset.py

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -751,15 +751,6 @@ def test_tool_defers_execution_started_reads_flag_only() -> None:
751751
# --- ToolUseSkipped wire event (opt-in per tool) ---
752752

753753

754-
class _RecordingWire:
755-
def __init__(self, captured: list[object]) -> None:
756-
self.soul_side = self
757-
self._captured = captured
758-
759-
def send(self, msg: object) -> None:
760-
self._captured.append(msg)
761-
762-
763754
class DummyToolEmitsSkipped(DummyToolA):
764755
emits_tool_use_skipped: ClassVar[bool] = True
765756

@@ -808,39 +799,3 @@ async def call(self, arguments: object) -> ToolReturnValue:
808799
("exit", "Shell"),
809800
]
810801
assert not any(isinstance(e, type) and e.__name__ == "ToolUseSkipped" for e in captured)
811-
812-
813-
async def test_cross_step_dedup_emits_tool_use_skipped_when_opted_in(tmp_path: Path) -> None:
814-
"""Cross-step duplicate calls emit ToolUseSkipped only when the tool opts in."""
815-
from unittest.mock import patch
816-
817-
from pythinker_code.hooks.engine import HookEngine
818-
from pythinker_code.wire.types import ToolUseSkipped
819-
820-
ts = PythinkerToolset()
821-
ts.add(DummyToolEmitsSkipped())
822-
ts._hook_engine = HookEngine([], cwd=str(tmp_path))
823-
captured: list[object] = []
824-
args = '{"a":1}'
825-
826-
with patch("pythinker_code.soul.get_wire_or_none", return_value=_RecordingWire(captured)):
827-
ts.begin_step([])
828-
task1 = ts.handle(
829-
ToolCall(id="tc1", function=ToolCall.FunctionBody(name="ToolA", arguments=args))
830-
)
831-
assert isinstance(task1, asyncio.Task)
832-
await task1
833-
prev = ts.end_step()
834-
ts.begin_step(prev)
835-
task2 = ts.handle(
836-
ToolCall(id="tc2", function=ToolCall.FunctionBody(name="ToolA", arguments=args))
837-
)
838-
assert isinstance(task2, asyncio.Task)
839-
await task2
840-
ts.end_step()
841-
842-
skipped = [e for e in captured if isinstance(e, ToolUseSkipped)]
843-
assert len(skipped) == 1
844-
assert skipped[0].tool_call_id == "tc2"
845-
assert skipped[0].tool_name == "ToolA"
846-
assert skipped[0].reason == "dedup"

tests/tools/test_agent_tool.py

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2723,28 +2723,3 @@ async def __call__(self, params):
27232723
assert result.output.count("Shared cache key may collide.") >= 1
27242724
assert "reviewer-0, reviewer-1" in result.output
27252725
assert "batch_blockers:" not in result.output
2726-
2727-
2728-
class _RecordingWire:
2729-
def __init__(self, captured: list[object]) -> None:
2730-
self.soul_side = self
2731-
self._captured = captured
2732-
2733-
def send(self, msg: object) -> None:
2734-
self._captured.append(msg)
2735-
2736-
2737-
async def test_unknown_subagent_type_emits_fallback_wire_event(runtime: Runtime) -> None:
2738-
from unittest.mock import patch
2739-
2740-
from pythinker_code.tools.agent import AgentTool, Params
2741-
2742-
captured: list[object] = []
2743-
tool = AgentTool(runtime)
2744-
with (
2745-
tool_call_context("Agent"),
2746-
patch("pythinker_code.soul.get_wire_or_none", return_value=_RecordingWire(captured)),
2747-
):
2748-
result = await tool(Params(description="x", prompt="y", subagent_type="does-not-exist"))
2749-
assert result.is_error
2750-
assert any(type(e).__name__ == "SubagentToolFallback" for e in captured)

0 commit comments

Comments
 (0)