mirror of
https://github.com/nearai/ironclaw.git
synced 2026-09-03 08:06:01 +08:00
* feat(engine): add short title field to v2 threads for sidebar labels `Thread.goal` is the execution prompt — a multi-paragraph meta-prompt for missions, or the full first user message for gateway chats. Reusing it as the sidebar label makes the conversation list expand to fit the longest prompt in view. Split the two concerns: - `Thread.title: Option<String>` (with `#[serde(default)]`) for the compact human label; legacy rows without the field rehydrate cleanly as None. - Threaded a `title` parameter through `ThreadManager::spawn_thread_with_history` and added a `spawn_thread_with_title` wrapper; title is applied before `save_thread` so the executor's in-memory copy observes it atomically. - Mission-spawned threads pass `Some(mission.name)`; gateway conversation threads pass `Thread::derive_title_from_message(content)` (first non-empty line, trimmed, char-safe truncated to 60 with an ellipsis). - `EngineThreadInfo` carries the new field; `chat_threads_handler` prefers it and falls back to a derived short label for pre-existing threads. - Belt-and-braces CSS truncation on `.thread-label` so the sidebar can never bleed across the page even if a title somehow slips through long. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(engine): streaming title truncation + docstring/test-name fix Addresses review feedback on PR #2776: - Drop the unreachable `trimmed.is_empty()` guard — the `find` predicate already guarantees the line is non-empty after trim. - Replace `trimmed.chars().count()` + re-iterate with a single streaming pass: take up to MAX_CHARS-1 chars, peek the rest, and append either the final char (no ellipsis, result is MAX_CHARS) or '…'. Avoids an O(n) scan on pathological single-line input. - Correct the docstring to say "leading and trailing whitespace" so it matches `trim()`, which is the right behavior for a sidebar label. - Rename `derive_title_trims_trailing_whitespace` to `derive_title_trims_whitespace` since the test input has whitespace on both ends. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(bridge): assert thread_to_info carries title and goal separately Addresses self-review finding on PR #2776: the `EngineThreadInfo` wire contract gained a `title` field but nothing in the Rust tree directly exercised the DTO populator after upstream dropped the sidebar engine-thread merging. Adds two small tests that build a `Thread` with and without a title and assert `thread_to_info` passes both `title` and `goal` through independently — so mission DTOs can render the short label without reading the multi-paragraph meta-prompt. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(bridge): propagate title through EngineThreadInfo and archive roundtrip Addresses two medium-severity review findings on PR #2776 (same class of bug — a new `Thread.title` field was added without propagation to satellite types, per `.claude/rules/review-discipline.md`): 1. `thread_to_info` now falls back to deriving a short label from `goal` when `title` is `None`. Without this, legacy engine threads persisted before the `title` field existed flow through to frontends (TUI, mission detail views) as `title = None`, and the frontend `threadTitle()` fallback chain in `history.js` renders a UUID prefix because `EngineThreadInfo` has no `turn_count`. 2. `ThreadArchiveSummary` now carries `title` (with `#[serde(default)]` for backwards compatibility, mirroring the `total_cost_usd` precedent at #2562). `compact_thread_summary` persists it, `thread_from_archive` reads it. `backfill_archived_threads` is a live consumer — without this, workspaces that only have archived summaries still rehydrate threads with no title. Tests: - `thread_to_info_derives_title_from_goal_when_absent` - `thread_to_info_derives_from_first_line_of_long_goal` - `archive_summary_preserves_title_through_round_trip` - `archive_summary_handles_legacy_json_without_title_field` Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>