12 Commits
Author SHA1 Message Date
chengyongruandchengyongru dfc3919b52 fix: stop masking runtime failures 2026-07-21 11:44:52 +08:00
chengyongruandchengyongru cf00f537bd fix(agent): guide recovery from oversized tool results
Use the existing in-flight context governor to replace tool output that cannot fit the next model request with a bounded, actionable instruction. The model can retry with narrower arguments, use another tool, or explain the context limit without a second recovery state machine.
2026-07-19 01:08:36 +08:00
chengyongruandXubin Ren b4f069800e refactor(agent): make runner consume required runtime 2026-07-10 17:54:34 +08:00
chengyongruandXubin Ren aecb5fbc33 fix(agent): avoid tool compaction echo loops 2026-07-03 00:36:22 +08:00
8248d075db fix(agent): harden tool-call handling against malformed upstream relays
Combine malformed tool-call handling with placeholder filtering and a
no-tools fallback so a relay that returns tool_use blocks with null
id/name/input can no longer crash a turn or permanently wedge a session.

Adapted to the ContextGovernor architecture (context governance now lives
in nanobot/agent/context_governance.py, not runner.py):

- ToolCallRequest.has_valid_name(): single source of truth for "usable
  name" (non-empty string).
- tool_hints.format_tool_hints(): skip tool calls with a non-string/empty
  name instead of raising AttributeError on the whole turn.
- ContextGovernor.strip_placeholder_assistant_messages() and
  strip_malformed_tool_calls() (plus the _tool_call_name_is_valid helper):
  history-cleaning staticmethods invoked at the START of
  prepare_for_model() — strip_placeholder, then strip_malformed, then the
  existing drop_orphan/backfill chain. Both only repair the model-facing
  copy and leave persisted history untouched (return a copy, or the same
  list when nothing changes). Also wired into runner's minimal-repair path.
- AgentRunner._drop_malformed_tool_calls(): returns
  (dropped, all_dropped, original_finish_reason); clears finish_reason to
  "stop" when all calls are dropped.
- AgentRunner._malformed_tool_call_retry_messages() + _request_model
  malformed_retry flag: when an all-dropped tool_calls response comes back,
  retry once with a corrective note; if the retry STILL comes back
  all-dropped, fall back to _request_no_tools for graceful text degradation.

Tests for the history-cleaning methods live with ContextGovernor in
tests/agent/test_runner_governance.py; response-layer and tool-hint tests
stay on AgentRunner / tool_hints.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 19:46:59 +08:00
chengyongruandXubin Ren 3460ca3cb9 fix(agent): gate microcompaction on context pressure
Extract model-facing context governance from AgentRunner.

Only compact in-flight tool results when the model request is over budget, keep compacted IDs stable within a turn, and allow the newest result to be compacted as a last resort when it is the remaining source of overflow.
2026-06-27 11:04:41 +08:00
chengyongruandXubin Ren 0e9861558a fix: keep duplicate id repair in Anthropic provider
maintainer edit: move duplicate tool_use history repair out of AgentRunner and into Anthropic message conversion, reusing the OpenAI-compatible queue-mapping approach locally without broadening the shared runner path.
2026-06-24 10:21:48 +08:00
chengyongruandXubin Ren 853aecdb97 fix: preserve duplicate-id tool calls
maintainer edit: remap duplicate tool_use/tool_call ids instead of dropping later calls, so Anthropic-compatible providers that reuse ids for distinct parallel tool calls keep all requested work while still sending unique ids.
2026-06-24 10:21:48 +08:00
Teddy YanandXubin Ren 6b8e832ba5 fix: address PR review comments - rename _dedup to _dedupe and fix ID storage consistency 2026-06-24 10:21:48 +08:00
6689e2d377 fix(providers): dedupe tool_use ids to prevent Anthropic 400s
Anthropic rejects any request where two tool_use blocks share an id
("messages.N.content.M: tool_use ids must be unique"). A mis-assembled
stream could surface the same tool_use block twice in one assistant turn;
the runner persisted it verbatim, so the malformed message was re-sent on
every subsequent turn and permanently bricked the session — the agent
silently stopped replying.

Fix at two layers:
- AnthropicProvider._parse_response: drop duplicate tool_use ids (keep
  first) as the response enters nanobot, so corruption is never persisted.
- AgentRunner._dedup_tool_calls: a new context-governance pass that dedupes
  assistant tool_calls and tool results by id before each send, healing any
  history that was already corrupted.

Add regression tests covering both the dedup and the no-op fast path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 10:21:48 +08:00
hamb1yandXubin Ren 0df60416ba fix(agent): address session and streaming concurrency bugs 2026-05-28 22:54:46 +08:00
chengyongruandXubin Ren 99cc6ee808 test(agent): expand coverage and refactor test structure
- Add 42 tests for ContextBuilder (context.py: 0→42 tests)
- Add 37 tests for SubagentManager lifecycle (subagent.py: 2→37 tests)
- Add 42 unit tests for AutoCompact in isolation
- Split monolithic test_runner.py (3313 lines) into 9 focused files:
  test_runner_core, test_runner_hooks, test_runner_errors,
  test_runner_safety, test_runner_persistence, test_runner_governance,
  test_runner_tool_execution, test_runner_injections,
  test_loop_runner_integration
- Add 3 config passthrough tests (temperature/max_tokens/reasoning_effort)
- Fix fragile patch.object(__init__) in test_stop_preserves_context
- Create shared conftest.py with make_provider/make_loop factories

Total: 934 tests passing, 0 regressions
2026-05-13 12:49:17 +08:00