agent_core/llm.py:87 documents how to retrieve the terminal response:
The terminal LLMResponse (with assembled content + finalised tool_calls + usage) is accessible via :meth:last_response after the stream is exhausted.
But LLMClient declares only chat and stream. last_response appears nowhere else in the package — a grep of ApodexHarness finds no definition either, only unrelated local variables.
Consequence: a host implementing exactly the published Protocol has no such method, so a consumer typed against LLMClient either fails strict type-check or raises AttributeError at runtime. This is the half of the streaming contract a host currently has to guess at, even though StreamDelta was deliberately given usage / finish_reason / provider so an assembler can build that response.
Decision needed: either declare last_response() -> LLMResponse | None on the Protocol, or drop the reference and document the assembler as the owner of the terminal response. Blocks nothing, but should be settled before the LLM runtime slice (migration step 3) lands on top of it.
Provenance: pre-existing in ApodexHarness/miroharness/core/llm.py:92, ported verbatim by #1 — not introduced by the refactor. ApodexHarness carries the same wording; settle the contract once, then change both.
agent_core/llm.py:87documents how to retrieve the terminal response:But
LLMClientdeclares onlychatandstream.last_responseappears nowhere else in the package — a grep of ApodexHarness finds no definition either, only unrelated local variables.Consequence: a host implementing exactly the published Protocol has no such method, so a consumer typed against
LLMClienteither fails strict type-check or raisesAttributeErrorat runtime. This is the half of the streaming contract a host currently has to guess at, even thoughStreamDeltawas deliberately givenusage/finish_reason/providerso an assembler can build that response.Decision needed: either declare
last_response() -> LLMResponse | Noneon the Protocol, or drop the reference and document the assembler as the owner of the terminal response. Blocks nothing, but should be settled before the LLM runtime slice (migration step 3) lands on top of it.Provenance: pre-existing in
ApodexHarness/miroharness/core/llm.py:92, ported verbatim by #1 — not introduced by the refactor. ApodexHarness carries the same wording; settle the contract once, then change both.