ubiquitous-invention/plans/Plan-daily-driver-finish/Epic-shipping-the-shell/Task-wire-ai-chat-to-trpc.md

79 lines
3.6 KiB
Markdown
Raw Normal View History

plans: scaffold daily-driver-finish, saas-hardening, agent-coordination Three new plan trees that fill in the gaps surfaced during repo review. Together they map out what remains between the current scaffold-with-stubs state and a daily-usable, multitenant, agent-coordinated app. * Plan-daily-driver-finish (P0): turn stubs into real data. Five tasks covering the lint/shared-types breakage, hardcoded dashboard mocks, AI-page setTimeout placeholder, post-signin landing decision, and a cross-browser collab smoke test against the deployed Hocuspocus instance. * Plan-multitenant-saas-hardening (P1): everything multitenant needs beyond what Plan-multitenant-cursor-sync already covers. Invites and role management, soft-delete + append-only audit log, rate limits on the auth + mutation hot paths, and a Vitest + GitHub Actions test foundation so PRs can't ship red. * Plan-agent-coordination (P2): the layer that makes a Task-*.md runnable, not just readable. Adds workflow_prompt with task -> epic -> plan inheritance, an agent_runs table for auditable sessions, and two new MCP tools (claim_task / complete_task) that replace the freeform update_object composition agents do today. Includes an intentionally-deferred Epic-optional-orchestrator that captures the Symphony-shaped runner as a decision point rather than an immediate build. Each task is bead-scale (one focused Cursor session) with explicit in-scope, out-of-scope, and anti-goal sections so a future agent can pick up a single Task-*.md and start without scrollback context. Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-02 00:52:22 -04:00
---
kind: task
slug: wire-ai-chat-to-trpc
title: Replace AI chat setTimeout placeholder with a real provider call
plan_slug: daily-driver-finish
epic_slug: shipping-the-shell
status: ready
priority: P0
tenant_id: global
owner: unassigned
cursor_todo_id: null
updated_at: "2026-06-01"
---
# Task summary
`apps/web/app/(app)/[workspaceSlug]/ai/page.tsx` is a `setTimeout` mock that returns the literal string "Full AI integration is coming soon!". Replace with a real call through `apps/web/server/routers/ai.ts` and `packages/ai`.
## Description
The page already manages local chat state — message list, input ref, auto-scroll, loading state. All it's missing is the network call.
### Approach
1. **Inspect `routers/ai.ts`** to see what procedures exist. If there's already a `chat` / `complete` procedure, use it. Otherwise add one:
- Input: `{ messages: Array<{ role: "user" | "assistant" | "system", content: string }>, workspaceSlug: string }`
- Output: streaming text (use the Vercel AI SDK's `streamText` from `@tasks/ai`).
- Wrap with `workspaceProcedure` so workspace membership is checked.
2. **Use streaming, not request/response**. The Vercel AI SDK's `useChat` hook is the natural fit, but it expects a `/api/chat` HTTP endpoint, not tRPC. Two options:
- (a) Add a Next.js route handler at `apps/web/app/api/chat/route.ts` that calls into the same provider abstraction in `packages/ai`. Keep auth in the route handler (`auth()` from `apps/web/lib/auth.ts`). Use `useChat()` on the client.
- (b) Stream through tRPC v11's subscription support. More work; only choose this if you specifically want a single API style.
- Recommendation: (a). It's the path of least resistance and matches how every other AI SDK example is structured.
3. **Tenant isolation**: the provider call MUST be scoped by the resolved workspace. Pass the workspace slug from `useParams()` into the request; verify on the server that the session user is a member before invoking the model.
4. **Provider selection** comes from env (`packages/ai` already supports this — OpenAI, Anthropic, or Ollama on CT 108 via `OPENAI_BASE_URL`). Don't hardcode a provider in the route handler.
5. **Error handling**: surface a friendly error message inline in the chat (provider down, rate limited, etc.) rather than crashing the page. Show "AI is unavailable" if no provider env is set.
6. **Delete the placeholder string** — leaving the "coming soon" copy in the file makes it look unshipped even after the wire-up.
### Out of scope
- Tool-calling, retrieval, or letting the AI mutate workspace objects. That's `Plan-agent-coordination` work.
- Conversation persistence (storing chats in DB). Keep messages in component state for now; persistence is a follow-up.
## Subtasks
- [ ] Audit `apps/web/server/routers/ai.ts` and `packages/ai/src/` for existing primitives.
- [ ] Add `apps/web/app/api/chat/route.ts` route handler with `auth()` check and `workspace_id` scoping.
- [ ] Replace the `setTimeout` block in `[workspaceSlug]/ai/page.tsx` with `useChat()` from `@ai-sdk/react`.
- [ ] Add inline error state and unavailable state.
- [ ] Verify against at least one provider (whichever is configured in your `.env`).
## Owner or assignee
Unassigned
## Status
ready
## Estimation
M
## Acceptance criteria
- [ ] No `setTimeout` mock remains in `[workspaceSlug]/ai/page.tsx`.
- [ ] Sending a message produces a streamed response from a real provider.
- [ ] Server route validates session and workspace membership before calling the provider.
- [ ] Error and unavailable states render gracefully.
## Links to related Epic / Plan
- Epic: `./Epic-shipping-the-shell.md`
- Plan: `../Plan-daily-driver-finish.md`