steerable-agent-runtime 0.6.7__tar.gz → 0.6.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/PKG-INFO +1 -1
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/pyproject.toml +1 -1
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/compaction.py +48 -2
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime.egg-info/PKG-INFO +1 -1
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_compaction.py +82 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/README.md +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/setup.cfg +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/__init__.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/antihallucination.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/approval.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/approval_policy.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/ask_user.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/branch.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/cache_control.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/calibration.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/config.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/default.harness.json +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/default.harness.yaml +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/errors.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/gateway_catalog.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/handoff.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/harness.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/harness_spec.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/history.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/hooks.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/llm/__init__.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/llm/anthropic_native.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/llm/compat.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/llm/errors.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/llm/google_genai.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/llm/openai_compat.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/llm/openai_responses.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/llm/parts.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/llm/presets.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/llm/system_proxy.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/loop.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/maintenance.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/mcp.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/mcp_server.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/model_catalog.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/model_info.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/model_resolve.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/observation_aging.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/orchestration.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/otel.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/plugins.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/pool.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/pricing.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/pseudo.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/recording.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/reminders.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/replay.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/resume.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/retry.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/sandboxed.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/skills.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/spill.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/storage/__init__.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/storage/in_memory.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/storage/sqlalchemy_store.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/storage/sqlite_store.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/storage/write_lease.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/subagent.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/todo.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/tokens.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/tool_schema.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/tool_search.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/tools.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/tracing.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/transport/__init__.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/transport/fastapi_sse.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/transport/stdio_jsonrpc.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/world_state.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime.egg-info/SOURCES.txt +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime.egg-info/dependency_links.txt +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime.egg-info/requires.txt +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime.egg-info/top_level.txt +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_antihallucination.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_approval.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_approval_policy.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_ask_user.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_branch.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_cache_control.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_cache_instrumentation.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_calibration.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_config.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_content_parts.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_error_taxonomy.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_fragment_bounds.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_gateway_catalog.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_golden.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_handoff.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_harness.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_harness_spec.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_history.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_history_persistence.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_hooks.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_in_memory_storage.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_llm_gemini_wire.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_llm_responses_wire.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_llm_stream_e2e.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_llm_wire_helpers.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_long_session.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_loop.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_loop_cancellation.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_loop_replay.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_loop_sandbox_event.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_maintenance.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_mcp.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_mcp_server.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_model_catalog.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_model_equivalence.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_model_info.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_model_resolve.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_observation_aging.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_orchestration.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_otel.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_parallel_tools.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_plugins.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_provider_compat.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_provider_presets.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_pseudo.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_recording.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_reminders.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_replay_crosslang.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_resume.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_retry_hooks.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_safety_gate.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_sandboxed.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_skills.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_soft_timeout.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_spill.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_sqlite_storage.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_steer.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_storage_contract.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_stream_strip.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_subagent.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_system_proxy.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_todo.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_todo_gate.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_tokens.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_tool_exposure.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_tool_hygiene.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_tool_router.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_tool_schema.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_tool_timeout.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_trace_recorder.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_transport_jsonrpc.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_transport_sse.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_usage_attribution.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_world_state.py +0 -0
- {steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_write_lease.py +0 -0
|
@@ -22,7 +22,9 @@ Strategy (deterministic first, LLM optional):
|
|
|
22
22
|
message; otherwise drop the middle span behind a marker.
|
|
23
23
|
|
|
24
24
|
System messages and the first user message (the goal) are always kept; the
|
|
25
|
-
most recent ``keep_last_messages`` are never touched
|
|
25
|
+
most recent ``keep_last_messages`` are never touched, and the kept tail is
|
|
26
|
+
widened when that count would cut a tool-call group in half (an orphan
|
|
27
|
+
``tool`` message is a provider-level 400). Between compactions
|
|
26
28
|
the transcript is append-only, so provider prompt caches keep hitting; a
|
|
27
29
|
rewrite invalidates the cache once, then the prefix is stable again.
|
|
28
30
|
|
|
@@ -440,6 +442,50 @@ class CompactionHooks(NoopHooks):
|
|
|
440
442
|
for i, m in enumerate(transcript)
|
|
441
443
|
]
|
|
442
444
|
|
|
445
|
+
@staticmethod
|
|
446
|
+
def _orphan_tool_ids(tail: Sequence[LLMMessage]) -> set[str]:
|
|
447
|
+
"""``tool_call_id``s answered inside ``tail`` but issued before it."""
|
|
448
|
+
issued: set[str] = set()
|
|
449
|
+
orphans: set[str] = set()
|
|
450
|
+
for m in tail:
|
|
451
|
+
for call in m.tool_calls or ():
|
|
452
|
+
issued.add(call.id)
|
|
453
|
+
if (
|
|
454
|
+
m.role == "tool"
|
|
455
|
+
and m.tool_call_id is not None
|
|
456
|
+
and m.tool_call_id not in issued
|
|
457
|
+
):
|
|
458
|
+
orphans.add(m.tool_call_id)
|
|
459
|
+
return orphans
|
|
460
|
+
|
|
461
|
+
def _tail_start(self, transcript: list[LLMMessage], head_end: int) -> int:
|
|
462
|
+
"""Where the untouched tail begins: ``keep_last_messages`` back, then
|
|
463
|
+
widened until the tail answers no tool call it does not also issue.
|
|
464
|
+
|
|
465
|
+
OpenAI-compatible providers reject a ``tool`` message whose
|
|
466
|
+
``tool_call_id`` was never issued by a preceding ``assistant``
|
|
467
|
+
message (DeepSeek answers HTTP 400 ``invalid_request``). A count-only
|
|
468
|
+
cut can land inside a tool-call group, summarizing the issuing
|
|
469
|
+
assistant away while its results stay in the tail. Widening only ever
|
|
470
|
+
keeps more, and is bounded by one round's tool calls — including the
|
|
471
|
+
``user`` image messages the read path interleaves between results.
|
|
472
|
+
|
|
473
|
+
Only orphans this cut created are worth widening for. A transcript
|
|
474
|
+
that arrives already missing an issuer (a host that resumed from a
|
|
475
|
+
truncated log) would otherwise widen to ``head_end`` and disable
|
|
476
|
+
summarization for the rest of the run, trading a provider 400 for a
|
|
477
|
+
context overflow.
|
|
478
|
+
"""
|
|
479
|
+
tail_start = max(head_end, len(transcript) - self._keep_last)
|
|
480
|
+
issuable = {
|
|
481
|
+
call.id for m in transcript[head_end:] for call in m.tool_calls or ()
|
|
482
|
+
}
|
|
483
|
+
while tail_start > head_end and (
|
|
484
|
+
self._orphan_tool_ids(transcript[tail_start:]) & issuable
|
|
485
|
+
):
|
|
486
|
+
tail_start -= 1
|
|
487
|
+
return tail_start
|
|
488
|
+
|
|
443
489
|
async def _summarize_middle(self, transcript: list[LLMMessage]) -> list[LLMMessage]:
|
|
444
490
|
# Keep every system message plus the first user message (the goal) as
|
|
445
491
|
# the head; keep the recent tail untouched; summarize the middle.
|
|
@@ -451,7 +497,7 @@ class CompactionHooks(NoopHooks):
|
|
|
451
497
|
head_end = i + 1
|
|
452
498
|
else:
|
|
453
499
|
break
|
|
454
|
-
tail_start =
|
|
500
|
+
tail_start = self._tail_start(transcript, head_end)
|
|
455
501
|
middle = transcript[head_end:tail_start]
|
|
456
502
|
if not middle:
|
|
457
503
|
return transcript
|
|
@@ -437,6 +437,88 @@ async def test_compaction_preserves_system_and_first_user_message() -> None:
|
|
|
437
437
|
assert call[1].role == "user" and call[1].content_text == "the original goal"
|
|
438
438
|
|
|
439
439
|
|
|
440
|
+
def tool_result(call_id: str) -> LLMMessage:
|
|
441
|
+
return LLMMessage.text_of("tool", "ok", name="emit", tool_call_id=call_id)
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
@pytest.mark.asyncio
|
|
445
|
+
async def test_summarize_middle_widens_the_tail_off_an_orphan_tool_result() -> None:
|
|
446
|
+
# A count-only tail cut can land inside a tool-call group: the issuing
|
|
447
|
+
# assistant goes into the summarized middle while its results stay in the
|
|
448
|
+
# tail, and the request opens on a `tool` message nothing answered.
|
|
449
|
+
# DeepSeek rejects that with HTTP 400 invalid_request.
|
|
450
|
+
calls = [
|
|
451
|
+
ToolCall(id="call_a", name="emit", arguments={}),
|
|
452
|
+
ToolCall(id="call_b", name="emit", arguments={}),
|
|
453
|
+
]
|
|
454
|
+
transcript = [
|
|
455
|
+
LLMMessage.text_of("system", "you are helpful"),
|
|
456
|
+
LLMMessage.text_of("user", "make a deck"),
|
|
457
|
+
LLMMessage.text_of("assistant", "reading the skill files"),
|
|
458
|
+
LLMMessage.text_of("assistant", "", tool_calls=calls),
|
|
459
|
+
tool_result("call_a"),
|
|
460
|
+
# the read path interleaves image messages between tool results
|
|
461
|
+
LLMMessage.text_of("user", "slide.png:"),
|
|
462
|
+
tool_result("call_b"),
|
|
463
|
+
LLMMessage.text_of("assistant", "wrapping up"),
|
|
464
|
+
]
|
|
465
|
+
hooks = CompactionHooks(max_context_tokens=1_000, keep_last_messages=3)
|
|
466
|
+
|
|
467
|
+
out = await hooks._summarize_middle(transcript)
|
|
468
|
+
|
|
469
|
+
assert CompactionHooks._orphan_tool_ids(out) == set()
|
|
470
|
+
assert any("[context compacted" in m.content_text for m in out)
|
|
471
|
+
# the group survived whole, in order, with its interleaved image message
|
|
472
|
+
assert [m.role for m in out[-5:]] == [
|
|
473
|
+
"assistant",
|
|
474
|
+
"tool",
|
|
475
|
+
"user",
|
|
476
|
+
"tool",
|
|
477
|
+
"assistant",
|
|
478
|
+
]
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
@pytest.mark.asyncio
|
|
482
|
+
async def test_summarize_middle_still_compacts_an_already_orphaned_transcript() -> None:
|
|
483
|
+
# The issuer is missing from the input (a host resuming from a truncated
|
|
484
|
+
# log), so widening could never repair the tail. Compaction proceeds
|
|
485
|
+
# rather than widening to the head and going silent for the rest of the
|
|
486
|
+
# run — the alternative to the provider 400 is a context overflow.
|
|
487
|
+
transcript = [
|
|
488
|
+
LLMMessage.text_of("user", "make a deck"),
|
|
489
|
+
LLMMessage.text_of("assistant", "first"),
|
|
490
|
+
tool_result("call_gone_a"),
|
|
491
|
+
tool_result("call_gone_b"),
|
|
492
|
+
LLMMessage.text_of("assistant", "wrapping up"),
|
|
493
|
+
]
|
|
494
|
+
hooks = CompactionHooks(max_context_tokens=1_000, keep_last_messages=2)
|
|
495
|
+
|
|
496
|
+
out = await hooks._summarize_middle(transcript)
|
|
497
|
+
|
|
498
|
+
assert len(out) < len(transcript)
|
|
499
|
+
assert any("[context compacted" in m.content_text for m in out)
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
@pytest.mark.asyncio
|
|
503
|
+
async def test_summarize_middle_keeps_an_aligned_tail_at_keep_last() -> None:
|
|
504
|
+
# No tool-call group is cut, so the tail stays exactly keep_last long —
|
|
505
|
+
# widening must not cost compaction on a clean boundary.
|
|
506
|
+
transcript = [
|
|
507
|
+
LLMMessage.text_of("system", "you are helpful"),
|
|
508
|
+
LLMMessage.text_of("user", "make a deck"),
|
|
509
|
+
LLMMessage.text_of("assistant", "first"),
|
|
510
|
+
LLMMessage.text_of("assistant", "second"),
|
|
511
|
+
LLMMessage.text_of("user", "keep going"),
|
|
512
|
+
LLMMessage.text_of("assistant", "third"),
|
|
513
|
+
]
|
|
514
|
+
hooks = CompactionHooks(max_context_tokens=1_000, keep_last_messages=3)
|
|
515
|
+
|
|
516
|
+
out = await hooks._summarize_middle(transcript)
|
|
517
|
+
|
|
518
|
+
assert [m.content_text for m in out[-3:]] == ["second", "keep going", "third"]
|
|
519
|
+
assert len(out) == 6 # system + goal + summary + 3 kept
|
|
520
|
+
|
|
521
|
+
|
|
440
522
|
@pytest.mark.asyncio
|
|
441
523
|
async def test_micro_compact_trigger_schedule() -> None:
|
|
442
524
|
"""Periodic prune fires on interval multiples (never round 0), and an
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/hooks.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/loop.py
RENAMED
|
File without changes
|
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/mcp.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/otel.py
RENAMED
|
File without changes
|
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/pool.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/retry.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/spill.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/todo.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/src/steerable_agent_runtime/tools.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_antihallucination.py
RENAMED
|
File without changes
|
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_approval_policy.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_cache_instrumentation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_error_taxonomy.py
RENAMED
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_fragment_bounds.py
RENAMED
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_gateway_catalog.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_history_persistence.py
RENAMED
|
File without changes
|
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_in_memory_storage.py
RENAMED
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_llm_gemini_wire.py
RENAMED
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_llm_responses_wire.py
RENAMED
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_llm_stream_e2e.py
RENAMED
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_llm_wire_helpers.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_loop_cancellation.py
RENAMED
|
File without changes
|
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_loop_sandbox_event.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_model_equivalence.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_observation_aging.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_parallel_tools.py
RENAMED
|
File without changes
|
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_provider_compat.py
RENAMED
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_provider_presets.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_replay_crosslang.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_sqlite_storage.py
RENAMED
|
File without changes
|
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_storage_contract.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_trace_recorder.py
RENAMED
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_transport_jsonrpc.py
RENAMED
|
File without changes
|
|
File without changes
|
{steerable_agent_runtime-0.6.7 → steerable_agent_runtime-0.6.8}/tests/test_usage_attribution.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|