improvement(mothership): mothership v0.9 - #6815
Open
Sg312 wants to merge 143 commits into
Open
Conversation
…ocs, account context Squash of the feat/platform-agent branch (sim side): mounts the Sim docs corpus in the copilot VFS, wires search_docs and retires the legacy docs search tools, and syncs the generated tool catalog and trace contracts for the platform subagent.
# Conflicts: # apps/sim/lib/knowledge/application/documents.ts
Pulls the mothership tool catalog (wait_agents / tail_agent / steer_agent / interrupt_agent), trace spans (chat.async_subagent.*, chat.orchestrate.*), and trace attributes (copilot.async_subagent.*) into the generated TS contracts.
wait_agents / tail_agent / steer_agent / interrupt_agent get natural-language running titles (naming the agent id being waited on, tailed, steered, or stopped) and a Steering→Steered completed-verb rewrite.
A subagent_start whose payload data carries a name (the orchestrator's new name trigger parameter) now labels the agent group with that mission name — the agent-type icon stays. The name flows through the live stream path, the turn model (AgentNode.displayName) and its serialize/rebuild round-trip, and persisted transcripts (PersistedContentBlock.name), so reloads keep the label.
The dispatch-time subagent_start fires before the trigger args (and therefore the name parameter) have streamed; the phase-3 start re-announces the lane with the name. The block builder was dropping that duplicate wholesale, losing the name on streaming providers — now it backfills subagentName onto the existing block instead. (The home turn-model path already reconciled this case.)
The wait_agents title ignored the mode argument, so an any-mode wait over three agents read 'Waiting for 3 agents' while the model narrated waiting for the first — contradicting the transcript.
Subagents now narrate their work through <intent>3-5 words</intent> tags (a fleet-wide prompt protocol on the mothership side). The turn model streams each subagent's text through a split-safe tag parser: complete tags update the agent's currentIntent and disappear from the prose, tags split across deltas are carried until their close arrives, and a tag that never closes flushes back as plain text. The agent card renders as one line — display name (or agent label) plus the latest intent, replaced inline as the agent shifts gears — and never auto-expands; expanding to the full tool log is a deliberate click. Only an outstanding permission prompt or a browser hand-back forces a group open. Intents persist on the subagent block (and through the legacy persisted- message paths) so reloads keep the last status, and a renamed reinvocation now takes the latest name instead of pinning the first.
POST /api/copilot/tools/execute (INTERNAL_API_SECRET, Go→Sim) runs one sim-server tool through the same server tool router the resume driver uses and returns the result synchronously — no checkpoint. This is what lets background (async) subagents write files/tables/knowledge, and lets the main lane keep streaming (instead of checkpoint-pausing and killing every background run) while async agents are live.
Files/tables created through the internal execute route now register on the chat's resources exactly like the resume driver's executions — the route runs the same handleResourceSideEffects pass (persistence only; an out-of-band route has no live event sink, so mid-turn chip pushes are a follow-up).
The rails are content-sized and unequal, so the old grid (fit-content / 1fr / fit-content) skewed the middle cell toward whichever rail was narrower. The wide tier now uses the docs' geometry: a fixed 760px content column centered between two equal flexible gutters, the sidebar hugging the container's left edge and the TOC its right — rail widths can no longer move the content.
The Navigation API fires currententrychange synchronously from the history mutation that caused it, which can originate inside another component's useInsertionEffect (style libraries navigating during commit) — setState there trips React's 'useInsertionEffect must not schedule updates'. The arrow-state sync now defers to a microtask, flushing after the commit unwinds, with a disposal guard.
Fewer than two sections (and no set nav): the left rail and its filter disappear and the reserved left gutter collapses — the content column leads the container with the TOC trailing. Two or more sections, or a multi-page set, keep the full centered docs frame.
jsdom runs the real shell against compiled pages and asserts the layout decisions: both rails on a many-section page, only the left rail dropped on a one-section page.
Between 560 and 860px the frame showed the section sidebar and hid the clerk TOC — backwards by our own reasoning, since the sidebar is the redundant list on a single page. The TOC now survives at medium widths and the sidebar joins only on wide panes.
The left rail now exists only for multi-page sets — on a lone page it just repeated the TOC. A set opens its sidebar at 560px with the TOC joining on wide panes (the docs stagger); a lone page waits until 700px and then shows the TOC alone. Set-sidebar spacing tightens to the docs values, with the current page's nested sections styled as small muted entries behind a hairline instead of full chips.
On a page with no sidebar the content column stretched while the TOC hugged the far edge, leaving a field of dead space between them. The content now caps at reading width with the TOC directly beside it and the pair centered in the pane, and the TOC waits until 800px so narrow panes stay single-column a while longer.
The 560px tier selects .art-cols:not(.no-side-nav) at (0,2,0), so the 860px tier's bare .art-cols template at (0,1,0) could never win and a set page on a wide pane kept the 2-column template — wrapping the TOC to the next grid row, bottom-left. The wide template now carries the same :not() guard, the 860 block's duplicate of the 800px no-side-nav rules is gone, and a test pins every template rule to equal specificity so a future tier can't silently lose the cascade again.
Sim-side handler for the new file-agent tool: given an uploaded .pptx or .docx, unzip it (OOXML is a zip), parse theme1.xml into theme.json (color scheme as hex, major/minor fonts, slide size from presentation.xml) and write every ppt|word/media file into a "<Name> assets" folder with original bytes and real content types. Re-runs overwrite the set in place. Pure extractor unit-tested against in-test-built packages; display label "Extracting assets from <file>".
PDFs have no zip structure or declared theme, so extraction runs in the same vetted sandbox that compiles and renders documents: poppler's pdfimages dumps every embedded image in its native format (masks filtered via -list), pdfplumber contributes each image's placement rects in page points plus the document's font names, and rendered pages are sampled into an explicitly-inferred color palette. theme.json for a pdf carries fonts, page size and count, the inferred palette, and a per-asset placement map.
The left sidebar leaves the renderer and the DSL: the shell builds only the content column and the clerk TOC (pair centered at 800px, one bare .art-cols selector per tier so the cascade cannot invert), the filter box goes with it, and nav frontmatter is tolerated but no longer rendered — sidebar METHOD chips and the set-nav markup are gone. Malformed sim: blocks no longer render a reader-facing "block was skipped" card: the block is omitted and the failure is reported as a diagnostic that apply_file_edit appends to its result, so the authoring agent sees exactly which fence to fix. The lenient flag existed only to suppress those cards mid-stream and is removed. The steps timeline connector now derives its position from the marker size, so it stays centered under the number circles.
pptx: theme.json now maps every image to its slide-by-slide placements (slide rels resolve rIds to media names; each pic frame's EMU offset and extent convert to inches) plus the slide count. pdf: a second layout.json is written — per page, the text blocks with content, position, font, size, and fill color; the filled rects (backgrounds and scrims); and rect-over-image overlay detection with coverage, which is the "image opacity" effect decks fake with a tinted rect. Stream alpha is unrecoverable, so overlays name the color and the rendered page remains the reference for strength.
Two text boxes sitting at the same height merged into one wide line; a gap much wider than a space now starts a new block, so columns and label/value pairs land as distinct entries in layout.json.
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.
Summary
Mothership v0.9
Companion: https://github.com/simstudioai/mothership/pull/440
Type of Change
Testing
Manual
Checklist