rotate chat TUI conversation id per launch / clear-chat

This commit is contained in:
Yiorgis Gozadinos 2026-05-21 14:21:51 +03:00
parent 80e3ae0280
commit 188d35023f
No known key found for this signature in database
3 changed files with 11 additions and 2 deletions

View file

@ -5,6 +5,7 @@
- Bump `haiku.skills>=0.17.1` and `pydantic-ai-slim>=1.100.0` (the last pre-2.0 release). Migrate off two APIs slated for removal in pydantic-ai 2.0: `Agent(tool_retries=, output_retries=)``Agent(retries={"tools": …, "output": …})` in the LLM-as-judge evaluator, and `Evaluator.evaluation_name` class attribute → overriding `get_default_evaluation_name()` on `CitationMRREvaluator` / `CitationMAPEvaluator`.
- Drop the `item.annotations` fallback in `_picture_description_text`. Docling's `PictureItem` runs a `@model_validator(mode="after")` on load that migrates the deprecated `annotations` field into `meta.description`, so reading `meta.description.text` covers both legacy and current blobs. Tests in `test_converters.py` switched to `meta.description.text` for the same reason.
- Chat TUI now generates a stable per-launch `thread_id` (rotated on "Clear chat") instead of hardcoding `"tui"`. AGUIAdapter forwards it as the `gen_ai.conversation.id` OTel attribute, so multi-turn TUI sessions group into one Logfire conversation instead of collapsing every launch into a single bucket.
- Documentation generator swapped from `mkdocs-material` to `zensical`. Drops `mkdocs` / `mkdocs-material` dev deps, replaces `mkdocs.yml` with `zensical.toml`, adds `overrides/main.html` (OG/Twitter share meta) and `docs/stylesheets/extra.css`. `build-docs` workflow now runs `uv run zensical build` and publishes via the GitHub Pages artifact actions instead of `mkdocs gh-deploy`.
### Fixed

View file

@ -108,6 +108,10 @@ class ChatApp(App):
self._is_processing = False
self._current_worker: Worker[None] | None = None
self._document_filter: list[str] = []
# Stable per-launch id so multi-turn chats land in one Logfire
# conversation. AGUIAdapter reads run_input.thread_id and exports it
# as the `gen_ai.conversation.id` OTel attribute on every agent run.
self._conversation_id = str(uuid.uuid4())
def compose(self) -> "ComposeResult":
"""Compose the UI layout."""
@ -207,7 +211,7 @@ class ChatApp(App):
await chat_history.show_thinking()
run_input = RunAgentInput(
thread_id="tui",
thread_id=self._conversation_id,
run_id=str(uuid.uuid4()),
messages=self._messages,
state=self._state,
@ -375,6 +379,8 @@ class ChatApp(App):
# Reset state
if self._toolset:
self._state = self._toolset.build_state_snapshot()
# Cleared chat starts a fresh Logfire conversation.
self._conversation_id = str(uuid.uuid4())
def action_focus_input(self) -> None:
"""Focus the input field, or cancel if processing."""

View file

@ -219,7 +219,7 @@ async def test_chat_history_thinking_indicator(temp_db_path: Path):
@pytest.mark.asyncio
async def test_clear_chat_resets_state(temp_db_path: Path):
"""Test that clearing chat resets state and messages."""
"""Test that clearing chat resets state, messages, and conversation id."""
from haiku.rag.chat.widgets.chat_history import ChatHistory
app, mock_client = _make_app(temp_db_path)
@ -232,10 +232,12 @@ async def test_clear_chat_resets_state(temp_db_path: Path):
await chat_history.add_message("assistant", "Hi there")
assert len(chat_history.messages) == 2
previous_conversation_id = app._conversation_id
await app.action_clear_chat()
await pilot.pause()
assert len(chat_history.messages) == 0
assert app._conversation_id != previous_conversation_id
@pytest.mark.asyncio