Repository navigation
feat(t3team): kill the inter-agent chatter loop + idle-aware wake policy - #202
Merged
Merged
Conversation
Extracts the launch -> settle -> resume -> fail funnel that the t3team server currently owns (controller skeleton, resume/fail closures, run registry, lifecycle interface) into @t3team-sdk so both the t3team server and external durable hosts (nexi-distribution portal, GHE #383) consume one implementation instead of re-mirroring it. No app code; broker, lifecycle, sinks and repair are injected.
createWorkflowRunController now builds the t3team broker/sinks/repair and delegates start/settle/resume/fail to @t3team/sdk createWorkflowRunHost; launchWorkflowRecipe maps the host start to the launch result. makeControllerResume/makeControllerFail (neutral duplication) deleted; race-boundary tests moved to the host level; GHE #403 retainPendingStep behavior carried into the host-fail sink.
… runsRoot Host lifecycle interface drops broker-owned pending/sleep records (hosts call those through their own broker); recordFailed detail matches the durable row shape; controller passes the full drive handles into the repair funnel; race test supplies launchThreadId.
…ive-guard LOC ceiling Split t3team-sdk.workflowHost.ts into workflowHostTypes.ts (the funnel's contract) + the two factories; split the server controller into controllerEnv.ts (broker + options plumbing) + the host binding. Verified against the additive guard with the CI sync point pinned: this branch adds zero violations beyond the fork-main baseline.
…ink-248-current' into integ/shared-workflow-host-289
…defaultRunsRoot
The 'retries a transient reply-journal failure without losing the suspended
ask' test's custom appendResolved read runsRoot from the appendReply opts,
but the resume funnel only passes {runId, correlationId, reply}. So the
retried append fell back to defaultRunsRoot() -- a different journal than the
suspended run's (runsRoot). The replay then couldn't find the reply and the
ask re-suspended, so onCompleted never fired (appendAttempts was 2).
Capture the run's journal root from the test's config (as the default
appendReply does from config.runOptions), so the retried write lands where
the run lives. The host retry logic was correct; the mock was unfaithful to
the host's appendResolved contract.
Three contradicting texts made coordinated child threads into a send/receive frenzy; align all of them on one contract: - reaction-visibility: split the user-return instruction by reason. Unanswered user message keeps the strong answer-first rule; an unreacted agent reply now gets the quiet rule - act only if the situation changed, no re-stating, no re-acknowledging standing instructions, no status recap, one short line when nothing is new. - steering context: the anti-ping line now fires for EVERY parented thread, not only while a human is steering (idle gets the standing variant: one final report when done, hard blockers only). - child kickoff frame: "report progress and results" -> stay silent while working, report the final result exactly once.
…aming - Debounce default 2000ms -> 45s idle window (env override + 0=immediate semantics unchanged); urgent pending deliveries claim the batch at window 0 (bypass) via a per-thread urgent-pending mirror in the reactor (mailbox untouched: no peek API; batch cap + requeue-on-failure kept). - Delivery tiers in startActorReaction: user interjection while queueing -> compressed pointer framing (user's message comes first); first inter-agent delivery -> full bodies; every later delivery -> header-only (sender, ~1-line summary, id, urgency) with t3team_read_message pointer. - Restart-rehydrate prefix-matching now recognizes all three bases (full / header-single / compressed-single). - Tests: 45s default window, urgent immediate claim, tier selection, rehydrate matching; existing clock-driven tests keep the 50ms pin re-pinned before each test.
Adds t3team_ask_user to the t3team MCP toolkit so any agent thread can ask the user a structured question, suspend the turn, and resume with the answer as the tool result — mirroring the provider adapters' AskUserQuestion flow for harnesses whose model ships no native question tool. - askUser.ts: appends a user-input.requested activity (same shape the provider runtime ingestion projects), suspends on the durable thread.user-input-response-requested event for its requestId, appends a user-input.resolved activity, and returns the submitted answers. Cancellation (turn interrupted or subscription ended without an answer) closes the question with a cancelled user-input.resolved activity under the same requestId so the pending panel clears. - tools.ts: T3TeamAskUserTool (question/options/multiSelect/allowFreeText), canonical map entry t3team.thread.ask_user, and askUserDependencies (McpInvocationContext + OrchestrationEngineService + ambient Scope for the cancellation finalizer). - handlers.ts: routes t3team_ask_user to t3TeamAskUser (not the broker callTool dispatch). - catalog: ASK_USER_INPUT_SCHEMA + t3team.thread.ask_user entry (defaultEnabled). - Tests: happy path, decoy-event filtering, multiSelect/allowFreeText mapping, empty-question rejection, cancellation on subscription end, and end-to-end wiring through T3TeamToolkitRegistrationLive.
- M1: first-delivery tier was unreachable - each delivery is persisted into the transcript before the drain claims the batch, so hasPriorInterAgentMessages now excludes the current batch's own message ids; regression test added. - M2: userInterjectedDuringQueueing no longer counts inter-agent reaction inputs or automated senders as user interjections; a sibling burst can no longer compress its own batch. - m1: claimed-then-requeued urgent entries re-note their urgent mirror (onRequeueUrgent on both dispatch paths, only when willRetry) so a failed dispatch does not downgrade them to the 45s idle window. - m2: restart-rehydrate prefix matching now applies the identity guards to all three tier bases, not only the full-body one. - m3: buildChildKickoffText gets first assertions. - quiet rule gains an explicit blocker/failure carve-out.
- t3team_send_message gains an optional urgent flag: urgent deliveries bypass the recipients idle coalescing window and wake immediately. The tool description restricts it to hard blockers and unblocking questions; everything else coalesces into the idle digest. - Child abnormal-stop notifications are marked urgent server-side: a child stopping unexpectedly is exactly what a parent must hear about without the 45s delay.
…ctions The restart-hold summary path reads the steering context off the thread (humanSteeringInstructionForThread -> findHandoffParentThreadId), so the idleThread fixture needs messages/activities; without them the summary turn defects out and the mailbox reacting flag sticks.
…hatter fix Main now carries the evolved delivery tiers (buildActorReactionTurnInput, modular reactor limits/events). Resolution: keep main's architecture and re-apply the chatter fixes on top - 45s idle debounce + urgent wake-bypass mirror (limits + reactor + events), M1 first-delivery exclusion and M2 interjection guards in the evolved reaction input, m1 onRequeueUrgent on both dispatch paths, m2 rehydrate identity guards on all tier bases, the UNANSWERED/QUIET instruction split with the blocker carve-out, the urgent send_message producer, and the aligned test suites.
- t3team-actorReactionInput.ts: remove a dangling comment fragment left by the de-duplication that silently swallowed buildActorReactionInput into an unclosed block comment (ReferenceError at runtime). - t3team-actorMessageReactor.test.ts: import the debounce constant + resolver from the limits module where main relocated them.
johnnyelwailer
added a commit
that referenced
this pull request
Oct 12, 2026
…eting, linked repos) (#524) * fix(web): desktop UX fixes (My Work drag, sign-in dialog, loading greeting, linked repos) - My Work pane and startup gate get the Electron drag header (nx-nexi#199) - Device-code account sign-in is a dialog, not a truncated sidebar button (#201) - My Work loading screen: time-of-day greeting + vector animation, no logo (#202) - Linked repositories: schemeless host/owner/repo gets https://, signed-in detection no longer fails on one stale host, Recheck re-probes, larger dialog (#203) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> * fix(web): sign-in code dialog spacing without restyling DialogPanel DialogPanel owns its spacing (shadcn/no-restyle failed Lint). Move the gap onto a plain wrapper, as the other dialogs do. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Philip Jonientz <philip.jonientz@nexplore.ch> Co-authored-by: Claude Sonnet 5.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.
Aligns all inter-agent prompt surfaces on one contract and changes the wake policy so coordinated child threads stop turning into a send/receive frenzy.
Verification: 75/75 across the six affected test files; tsc clean on touched files.