feat(responses): pass conversation context and stream thinks in real time
- delegate_to_* now receives a trimmed conversation history (last ~6 turns, 500 chars/turn) as context on both live direct-delegation paths (streaming and steward non-streaming), via new build_delegation_context helper - _stream_direct_delegation restructured as an async generator: the butler 'start' think message streams BEFORE the expert runs and the success/error message right after it finishes, instead of all messages arriving after the research completed Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -15,11 +15,69 @@ from src.agents.delegation import (
|
||||
DelegationResult,
|
||||
DelegationTask,
|
||||
_detect_action_type,
|
||||
build_delegation_context,
|
||||
delegate_to_librarian,
|
||||
get_think_message,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
class TestBuildDelegationContext:
|
||||
"""Tests for trimming conversation history into expert context."""
|
||||
|
||||
def test_empty_history_returns_empty(self):
|
||||
assert build_delegation_context(None) == ""
|
||||
assert build_delegation_context([]) == ""
|
||||
|
||||
def test_recent_turns_are_formatted(self):
|
||||
history = [
|
||||
{"role": "user", "content": "Tell me about Docker"},
|
||||
{"role": "assistant", "content": "Docker is a container runtime."},
|
||||
]
|
||||
|
||||
context = build_delegation_context(history)
|
||||
|
||||
assert "Recent conversation:" in context
|
||||
assert "user: Tell me about Docker" in context
|
||||
assert "assistant: Docker is a container runtime." in context
|
||||
|
||||
def test_only_last_max_turns_kept(self):
|
||||
history = [
|
||||
{"role": "user", "content": f"message {i}"} for i in range(10)
|
||||
]
|
||||
|
||||
context = build_delegation_context(history, max_turns=6)
|
||||
|
||||
assert "message 3" not in context
|
||||
assert "message 4" in context
|
||||
assert "message 9" in context
|
||||
|
||||
def test_long_turns_are_truncated(self):
|
||||
history = [{"role": "user", "content": "x" * 2000}]
|
||||
|
||||
context = build_delegation_context(history, max_chars_per_turn=500)
|
||||
|
||||
assert "x" * 500 in context
|
||||
assert "x" * 501 not in context
|
||||
|
||||
def test_structured_content_parts_tolerated(self):
|
||||
history = [
|
||||
{"role": "user", "content": [{"type": "text", "text": "hello there"}]}
|
||||
]
|
||||
|
||||
context = build_delegation_context(history)
|
||||
|
||||
assert "hello there" in context
|
||||
|
||||
def test_non_dict_entries_skipped(self):
|
||||
history = ["garbage", {"role": "user", "content": "real message"}]
|
||||
|
||||
context = build_delegation_context(history)
|
||||
|
||||
assert "real message" in context
|
||||
assert "garbage" not in context
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
class TestDelegationTask:
|
||||
"""Tests for the DelegationTask dataclass."""
|
||||
|
||||
Reference in New Issue
Block a user