- direction: Literal["backward","forward","both"] in service and manager
- HistoriesService.graph annotated -> HistoryGraphResponse
- Pin 404 for missing seed_scope and missing history (was loose 4xx)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The orchestrator was passing prior agent output to the next agent by
text-concatenating "Previous analysis from {name}: ..." onto the user's
query, capped at 2000 chars. error_analysis then sniffed for the literal
string "Previous analysis" to know it had upstream context. That coupling
is brittle, lossy, and hides what's flowing between agents.
This adds a small AgentRunState dataclass (prior_responses dict plus
record/get_prior helpers) that the orchestrator instantiates per user
query and threads through each sequential agent's context. Each agent
gets the original query verbatim and reads upstream AgentResponses
structurally from run_state. error_analysis now pulls the prior history
response from run_state and appends its full content as "Context from
history analysis:" alongside the existing job_id-driven augmentation.
Parallel execution doesn't need run_state and isn't touched.
Tests cover the dataclass round-trip, that sequential agents share one
run_state instance and see the original query (no "Previous analysis
from..." mutation), and that error_analysis incorporates a recorded
history response into its prompt.
Owner dispatch only delivers history_update events to the user who owns
the changed history. Watching a shared or pinned non-owned history
(e.g. via the multi-history view) silently received nothing under SSE
because the dispatch path keys on history ownership and there was no
way for a viewer to opt in.
Add an additive viewer-subscription channel: the client POSTs the
history ids it wants pushes for to /api/events/history-subscriptions,
the dispatcher fans the record out to every webapp worker over Kombu,
and history_update fanout pushes to subscribed viewers in addition to
the owner. Subscriptions are refcounted on the client and replayed on
every EventSource onopen so reconnects don't drop them. Per-worker
subscription state is purged when a user's last connection on that
worker closes; the client's onopen replay re-asserts the desired set.
No authorization check on the dispatch path: SSE events only carry
history ids, the client follows up with a normal access-controlled
REST fetch, and leaking "history changed at T" pings is acceptable.
MultipleViewItem now subscribes whenever it renders a history the
current user does not own and SSE is enabled; owned histories continue
through owner dispatch with zero subscribe round-trip.
Tests: integration test exercising subscribe -> mutate -> receive ->
unsubscribe -> stop receiving end-to-end, plus vitest for the client
refcount and replay logic.
The earlier rename commit replaced 'WinBox' with 'scratchbook' in the
selenium helper docstrings and the frame() context manager, which just
swapped one inconsistent name for another. Converge on 'window manager'
for everything I'm touching here.
Drop the winbox npm package, delete window-manager.js and windows.scss,
remove the SCSS import from base.scss. Update navigation YAML selectors
and Selenium test helpers to use the new .scratchbook-window class
names. The core.windows.yaml tour still references #winbox-1 which
will need a follow-up update.
Negative limits silently sliced from the tail (tools[:-5]) and very large
limits would have happily echoed thousands of results. Treat anything <= 0
as "use the default of 10," and cap at 50 to bound the per-turn payload
the router ships back to the model.
Inventory/availability questions like "is FastQC installed?" or "do I
have an RNA-seq workflow?" don't need specialist routing -- they're
single-call lookups against the toolbox or workflow index. The router
handling them directly avoids a handoff round-trip.
Boundary stays tight: these are availability/inventory only. "What tool
should I use for my analysis?" still routes to the tool_recommendation
specialist, and IWC catalog search is deliberately out of scope (different
data source, different ranking semantics) -- left for a follow-up.
ops.search_tools doesn't accept a limit, so the router wrapper slices
oversized result lists and flags the truncation back to the model.
Server metadata (version, brand, URL, capability flags) is a stateless
single-call lookup that doesn't need a specialist. Adds the tool to the
router, lists it in the prompt's fast-path section, and adds focused
unit-test coverage.