Add the room assistant as a local-operator client - #8
Merged
Conversation
Give the user a peer operator for dispatch and room control without adding a roster agent, and keep reset a hard floor for later compaction. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Pull request overview
This PR introduces a “room assistant” implemented as a local-operator client (user:assistant) with a dedicated side-chat surface, plus supporting protocol/storage changes so operator dispatch and context reset are durable, replayable, and kept out of the main room composer flow.
Changes:
- Add Assistant UI surfaces: setup card for configuring the assistant, and an in-room drawer for side-chat with
/api/assistant*. - Add an Operator MCP entrypoint (
/mcp/operator) and operator broker API/tools so the assistant can control the room (dispatch/cancel/compact/reset/memory/setup) without needing an Agent Turn. - Extend storage/protocol to persist
operator.dispatchevents, recordcontext.resetboundaries, and store assistant side-chat messages separately.
Reviewed changes
Copilot reviewed 57 out of 57 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| web/styles.css | Styles for assistant toggle and assistant drawer UI. |
| web/setup.ts | Setup-page state + serialization for top-level assistant configuration. |
| web/setup.html | Adds assistant configuration card to setup page; bumps asset version query strings. |
| web/setup.css | Styling for the assistant configuration card. |
| web/index.html | Adds assistant toggle button + assistant drawer markup; bumps asset version query strings. |
| web/app.ts | Implements assistant drawer behaviors, /api/assistant* calls, and operator.dispatch timeline rendering. |
| tests/unit/web/server/server.test.ts | Verifies assistant side-chat stays off /api/messages and calls assistant API instead. |
| tests/unit/storage/supervision.test.ts | Updates schema version expectation. |
| tests/unit/storage/sqlite-store.test.ts | Adds tests for context reset/summary supersede, operator.dispatch persistence, and assistant conversation message storage; updates schema version expectations. |
| tests/unit/memory/supervision-context.test.ts | Adds test ensuring watch brief current-event packets build correctly. |
| tests/unit/memory/context-engine.test.ts | Ensures operator.dispatch participates in usage/compaction; enforces reset boundary behavior. |
| tests/unit/core/envelope.test.ts | Validates new built-in user:assistant actor. |
| tests/unit/core/assistant.test.ts | Tests assistant prompt injection rules and sender-field rejection on operator writes. |
| tests/unit/contracts/web-schema.test.ts | Extends schema to accept sourceKind: operator on memory records. |
| tests/unit/contracts/setup.test.ts | Validates reserved assistant roster IDs and accepts top-level assistant setup card. |
| tests/unit/contracts/memory-identity.test.ts | Updates identity/memory contract expectations for operator sourceKind. |
| tests/unit/config.test.ts | Validates config loading for top-level assistant and reserved roster IDs. |
| tests/unit/broker/broker.test.ts | Adds reset single-flight/replay test and updates fixture context controller. |
| tests/unit/app/record-mappers.test.ts | Tests record mapper projection for operator-authored records. |
| tests/unit/app/operator-runtime.test.ts | Tests assistant host single-flight/replay behavior and orphan user-row reprompt. |
| tests/unit/app/operator-broker-api.test.ts | Tests operator-only access, operator.dispatch dispatching, public send authoring, and operator restrictions. |
| tests/unit/app/cli.test.ts | Verifies setup snapshot includes assistant and various assistant draft preservation behaviors. |
| src/web/server/types.ts | Adds AssistantApi + operator MCP handler options to HTTP server types. |
| src/web/server/server.ts | Adds /mcp/operator and /api/assistant* endpoints with contract validation. |
| src/web/server/index.ts | Re-exports AssistantApi. |
| src/storage/types.ts | Adds assistant conversation, context reset, and operator.dispatch-related storage interfaces. |
| src/storage/sqlite-store.ts | Implements assistant conversation tables + context reset tracking; adds operator.dispatch support in accept flow; adds operator provenance mapping; adds supervision correlation lookup. |
| src/storage/schema.ts | Bumps schema to v9 and adds assistant_conversation_messages + context_resets. |
| src/memory/types.ts | Adds reset boundary to context usage/types. |
| src/memory/context-packet.ts | Applies reset-through floor when computing transcript/summary inclusion. |
| src/memory/context-messages.ts | Extends room context message definition to include operator.dispatch; adds content helpers. |
| src/memory/context-engine.ts | Enforces reset boundary in usage/compaction and adds explicit reset operation. |
| src/mcp/server/operator-tools.ts | New operator MCP tool surface (no Agent Turn required). |
| src/mcp/server/index.ts | Exports operator MCP server creation. |
| src/mcp/server/http.ts | Allows custom MCP server creation per request (operator vs member surfaces). |
| src/core/envelope.ts | Adds new event types + operator provenance source kind; adds built-in assistant actor. |
| src/core/assistant.ts | Defines assistant/operator constants, reserved IDs, and assistant prompt builder. |
| src/contracts/setup.ts | Adds setup-level assistant schema; rejects reserved roster IDs. |
| src/contracts/rest.ts | Extends REST contracts to include operator as valid sourceKind and adds resetThroughSeq to context usage. |
| src/contracts/operator.ts | New operator tool input/output schemas and parsing helpers. |
| src/contracts/index.ts | Exports assistant + operator contracts. |
| src/contracts/events.ts | Adds operator to provenance sourceKind schema. |
| src/contracts/assistant.ts | New assistant REST contracts for snapshot/messages/cancel flows. |
| src/config.ts | Adds assistant config schema, reserved-id validation, and path resolution for assistant brain. |
| src/broker/types.ts | Adds reset command types and operator message metadata fields. |
| src/broker/broker.ts | Adds reset command single-flight + persistence/audit event; supports operator provenance kind; supports operator.dispatch metadata on accept. |
| src/app/runtime.ts | Wires operator binding, operator MCP handler, and assistant host into runtime start/close + HTTP server. |
| src/app/record-mappers.ts | Allows operator sourceKind to be projected to REST contracts. |
| src/app/operator-runtime.ts | New assistant host + brain harness implementation (CLI brain + persistent side-chat). |
| src/app/operator-broker-api.ts | New operator broker API implementing operator behaviors (dispatch/send/reset/etc.). |
| src/app/init-config.ts | Adds default and preserved assistant draft handling for setup flow. |
| src/app/index.ts | Exports operator broker/runtime modules. |
| docs/STORAGE_AND_MEMORY.md | Documents assistant actor, operator sourceKind, v9 tables, operator.dispatch semantics, and reset boundary rules. |
| docs/PROTOCOL.md | Updates protocol docs for operator provenance, operator.dispatch/context.reset events, assistant actor, and assistant REST surface. |
| docs/IMPLEMENTATION.md | Updates architecture and UI docs to include assistant/operator surfaces. |
| docs/DECISIONS.md | Adds/updates decision entries for assistant as operator client and related invariants. |
| docs/ACCEPTANCE_TESTS.md | Adds acceptance cases for assistant/operator behaviors and updates UI constraints. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+138
to
+148
| const server = | ||
| options.createServer === undefined | ||
| ? createGroupXMcpServer({ | ||
| broker: options.broker!, | ||
| binding, | ||
| ...(options.knownTargets === undefined ? {} : { knownTargets: options.knownTargets }) | ||
| }) | ||
| : options.createServer({ | ||
| binding, | ||
| ...(options.knownTargets === undefined ? {} : { knownTargets: options.knownTargets }) | ||
| }); |
Comment on lines
+18
to
+26
| export function contentFromRoomContextMessage(event: StoredEventRecord): string { | ||
| if (!isRoomContextMessage(event)) { | ||
| throw new GroupXError( | ||
| "INVALID_ENVELOPE", | ||
| `Context message ${event.eventId} is not a current-task source event` | ||
| ); | ||
| } | ||
| return (event.body as { content: string }).content; | ||
| } |
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
user:assistantas a peer operator client (local-operator//mcp/operator), not a roster agent, so side chat stays off the Broker composer.operator.dispatch, acceptsourceKind: operatoron memory/identity, and keepcontext.reseta hard floor for later usage/compact.Test plan
npx tsc --noEmitMade with Cursor