Repository navigation
feat(t3team): durable task journal + transcript search over tool activity - #206
Merged
Merged
Conversation
`t3team.thread.search` scanned only a thread's `messages`. A thread detail also carries `activities` — the tool lifecycle: every command and its output, every file read, every tool call. In a real 31-hour run that was 1319 searchable messages against 1250 invisible activities, and the invisible half is where the evidence lives: what a test printed, which file held a symbol, why a command failed. One engine now serves both `thread.search` and `thread.search_source`: - messages and activities are normalized into one stream and interleaved chronologically, so a match is ranked by when it happened rather than which stream it came from - `order` defaults to `recent`. Matches are capped, so filling them in transcript order returned the OLDEST; one real call reported `totalMatches: 70, returnedMatches: 5` — the five earliest of seventy - `offset` pages, `hasMore` reports whether more remain, and the hint names the exact next offset - `scope` narrows to one stream; `role` filters a message role or an activity kind - a multi-word query that matches nothing verbatim retries requiring every term, reported as `matchMode`. Terms under three characters are excluded so "a b" cannot match inside "bash" An activity id cannot be resolved by `thread.read_message`, so activity matches report `activity_id` rather than presenting an id under a key that invites a lookup which always fails. The messages-only helper and `search_source`'s divergent `index` result shape are removed rather than kept alongside; both tools now return the same shape. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
An agent's plan lived only in its context window, so compaction erased it. Measured over a 31-hour nexplore orchestration run: 128 turns, 22 compactions, 12 hard truncations, zero task records — and 75 `t3team_children` polls, because the orchestrator had no durable plan and re-derived its own state by interrogating its children instead. Adds `TaskRecord` (contract), migration 056 with `thread_task_records` indexed on `(thread_id, position)`, a persistence service, and two broker tools on the MCP surface: - `t3team.task.write` replaces the whole list for the thread. Whole-list replace rather than id-based patching is deliberate: the primary consumer is a weak local model, which handles re-sending a list far more reliably than addressing individual records. - `t3team.task.list` reads it back. `note` is part of the record so a failure keeps its reason — the detail compaction otherwise destroys. Also declares the thread-search arguments added in the previous commit (`offset`, `scope`, `order`, and a `role` that accepts an activity kind) on both the MCP tool schema and the tool catalog. Without that the catalog's `additionalProperties: false` rejected them, so the paging the search result advertises was unreachable through the published contract. Both search tool descriptions now also state that an activity records only the first 500 characters of a tool result. `t3team.thread.ask_user` is added to the catalog test's expected lists and to the catalog doc. It is `status: "implemented"` but was missing from both, which left three catalog tests failing before this change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two changes that share one idea: the things an agent needs to remember must live outside its context window.
Both are grounded in one real 31-hour nexplore orchestration run (thread
fbdb583b): 128 turns, 22 compactions, 12 hard mid-conversation truncations, 10 session restarts.1. Search the whole transcript, newest first (
6e51a22)t3team.thread.searchscanned onlymessages. A thread detail also carriesactivities— every command and its output, every file read, every tool call. In that run: 1319 searchable messages against 1250 invisible activities, and the invisible half is where the evidence lives.ordernow defaults torecent. Matches are capped, so transcript order returned the oldest — one real call reportedtotalMatches: 70, returnedMatches: 5, the five earliest of seventyoffsetpaging,hasMore, and a hint naming the exact next offsetscopenarrows to one stream;rolefilters a message role or an activity kindmatchMode); terms under 3 chars are excluded so"a b"cannot match inside"bash"activity_id, notmessage_id— an activity id can never be resolved bythread.read_message, and offering it under that key invites a lookup that always failsThe messages-only helper and
search_source's divergentindexresult shape are removed rather than kept alongside. Both tools return the same shape now.2. Durable per-thread task journal (
b77b219)That run made zero task records — no such tool existed — and 75
t3team_childrenpolls, because the orchestrator had no durable plan and re-derived its own state by interrogating its children.TaskRecordcontract, migration 056 (thread_task_records, indexed on(thread_id, position)), a persistence service, and two broker tools.t3team.task.writereplaces the whole list rather than patching by id — deliberate, because the primary consumer is a weak local model that handles re-sending a list far more reliably than addressing individual records.noteis part of the record so a failure keeps its reason.Review
Ran a refute-first adversarial pass. It found 4 real defects in the first draft of the search work, all fixed here: stream-ordered instead of time-ordered ranking, unreachable arguments (schemas never declared
offset/scope/order), activity ids masquerading as message ids, and 1–2 char terms driving the fallback.One finding was not fixable here and is worth knowing: the nexplore pack records only the first 500 characters of a tool result, so activity search finds which command ran and its first 500 chars, not full output. Both tool descriptions now say so. A distro-side change raises that budget separately.
Verification
Additive guard: no errors from these files; one warning (
t3team-ThreadTaskRecords.ts, 161 lines, under the 200 cap). Remaining guard/lint/typecheck failures reproduce at cleanfork/main.Also fixes three catalog tests that were already red on
main:t3team.thread.ask_userisstatus: "implemented"but was missing from both expected lists and the catalog doc.Not included: web UI, and the pack-side capability policy that would auto-enable the journal per provider.
🤖 Generated with Claude Code