# CHUNK #9 — AI Roles & Suggestions **Duration:** ~3 days · **Prereqs:** CHUNK #8 (providers, token budget), CHUNK #4 (entities), CHUNK #3 (editor edit API) · **Follows:** CHUNK #8 · **Unblocks:** CHUNK #11 (parity: AI works in web + desktop identically) **Purpose:** Bring the four agentic roles (Editor, Reader, Publisher, Co-Author) to life with robust base prompts, a context builder that pulls from the author's own data, AI SDK tool-calls, and — the signature feature — the **suggestion protocol** that renders AI feedback as inline, adoptable/rejectable/pinnable edits anchored to exact passages. --- ## Steps ### 1. Base role prompts (`packages/ai/src/roles/`) 1. **Role type** (`packages/ai/src/roles/types.ts`): `Role = 'editor' | 'reader' | 'publisher' | 'co-author'`. Each has a `systemPrompt`, `temperature` default, and `tools[]`. 2. **Editor** (line editor): tighten prose, kill filter words, sharpen dialogue tags, fix pacing, flag weak openings/closings, check consistency against character/world data. Emits targeted structured edits with rationale. Respects the author's voice. 3. **Reader** (honest first-time reader): what was confusing, where attention dropped, what was telegraphed too early, what paid off. Reports as a reader, not in craft jargon. 4. **Publisher** (market & packaging): comps, hook, pacing vs. genre, title/cover/blurb ideas, series potential, format decisions. 5. **Co-Author** (collaborator with full project knowledge): drafts scenes/chapters in the author's voice, proposes plot turns, writes dialogue, expands world-building — always as *suggestions* the author accepts or rejects, never silently rewriting canon. 6. Prompts live in `docs/ROLE_PROMPTS.md` as the human reference; `packages/ai/src/roles/prompts.ts` imports them. ### 2. Context builder (`packages/ai/src/context.ts`) 1. `buildContext(project, { targetDoc, role, maxTokens })`: - Pull relevant characters (mentioned in target doc + top entities), world items, linked plot beats, prior chapter summaries. - Pack in priority order until the context budget (Chunk 8) is reached. - Return `{ system, contextText, sources: {entityId, title}[] }` — `sources` powers the "what I used" panel. 2. History: last N messages from the `AISession`, truncated to the history budget. ### 3. Tools (`packages/ai/src/tools/`) AI SDK tool-calls so a role *acts* on the workspace: 1. `applySuggestion({ target, before, after, rationale, kind })` — registers a suggestion (Chunk 5 model). 2. `updateEntity({ id, fields })` — edits a character/world field (pending author approval in UI). 3. `addNote({ body, linkedTo })` — creates a note. 4. `draftChapter({ title, outline })` — seeds a chapter doc. 5. `queryProject({ q })` — search entities/chapters (returns snippets for the role). ### 4. Suggestion protocol (the signature feature) 1. **Structured output**: roles emit JSON `{ target: {docId, range|nodePath}, before, after, rationale, kind: 'replace'|'insert'|'delete'|'entity-update'|'draft', status: 'pending' }`. Enforce with the provider's JSON-mode + a local zod schema validator (retry on parse failure). 2. **Inline rendering** (`packages/editor/src/decorations/suggestions.ts`): render each pending suggestion as an inline decoration over the exact passage — green for insert, yellow for replace, red for delete. Range is a **node anchor**, not a raw offset (re-resolved on every transaction — prevents drift, Chunk 3 risk). 3. **Actions**: hover a decoration → **Accept** (applies the edit via `applyEdit`), **Reject** (removes it), **Pin** (copies it into a pinned note for later). Panel lists all pending suggestions with rationale + "what I used" sources. 4. **Co-Author drafts**: render as a side-by-side diff view (original vs. draft) with accept/reject per paragraph. ### 5. Session UI (`apps/web/src/features/ai/`) 1. **AI panel** (`AiPanel.tsx`): role selector, provider/model picker, temperature/thinking/context sliders, "Ask" button, streaming response view, pending suggestions counter. 2. **Sessions** (`AiSessionsView.tsx`): list past sessions (from `AISession`), reopen to continue, export session transcript. 3. **Feedback loop**: after accepting/rejecting, log the choice → future context can deprioritize rejected styles (v1: simple counter, not ML). ### 6. Tests 1. Unit: `buildContext` packs the right entities within budget; `sources` populated. 2. Unit: zod schema rejects malformed suggestion JSON. 3. Unit: node-anchor resolution survives a doc edit (insert before range → range shifts correctly). 4. E2E: start an Editor session → suggestion appears inline → Accept → text changes → suggestion cleared; Pin → note created. 5. E2E: Co-Author draft → diff view → Reject → original intact. --- ## Acceptance criteria (all must pass) - [ ] All four roles respond with role-appropriate output; base prompts enforced. - [ ] Suggestions render inline over the exact passage; accept/reject/pin all work. - [ ] Accepting applies the edit; rejecting removes it; Pin creates a note. - [ ] "What I used" lists the entities/context the role drew from. - [ ] Node-anchored ranges stay correct across typing (no drift). - [ ] Co-Author draft shows a paragraph-level diff; accept/reject work. - [ ] Sessions persist; reopen continues the conversation. - [ ] Contract suite still green on both adapters. ## Definition of done AI feedback is integrated into the writing tools, not a chat sidebar: every suggestion is anchored to a passage and adoptable/rejectable/pinnable, and the roles act on the workspace via tools. This is the signature PubScript feature. ## Risks & fallbacks - **Range drift over live editing** → node anchors, not raw offsets; re-resolve on every transaction (built into Chunk 3's decoration pipeline). - **Scope creep in roles** → roles are prompt + tools, not new UI surfaces; the suggestion protocol is the single integration point. - **LLM JSON reliability** → strict zod validation + retry; fall back to a structured template if the model refuses JSON.