Remove repeated Plant, Financial and Workforce shortcut cards. Add site-scoped Plant and Financial sidebar attention status with automatic refresh. Include accumulated delivery processing, purchase order recovery, supplier reconciliation, plant data and user management changes and audit records.
78 lines
5.4 KiB
Markdown
78 lines
5.4 KiB
Markdown
# How "Ask" works (MEGA) — brief for building the same thing in Healy
|
|
|
|
## Correction first
|
|
The in-app chat does NOT use MCP. It calls tool functions directly inside the Next.js server.
|
|
MCP (`src/mcp/server.ts`) is a separate, optional, read-only wrapper over the same tools, run locally
|
|
over stdio for Claude Desktop/Code. Build the tool layer first; treat MCP as a thin extra.
|
|
|
|
## Stack
|
|
- Next.js 16 (App Router), React 19, TypeScript, Tailwind 4, vitest
|
|
- PocketBase via `pocketbase` SDK, superuser client on the server only (`pbAdmin()`)
|
|
- Model: MiniMax M3 via OpenAI-compatible endpoint (`https://api.minimax.io/v1`); Anthropic `claude-opus-5`
|
|
behind the same interface. `CHAT_PROVIDER` selects.
|
|
- Streaming: SSE from `POST /api/chat` (plain `ReadableStream`; browser reads with `fetch`)
|
|
- Tool schemas: `zod` -> `zod-to-json-schema`
|
|
- UI markdown: `react-markdown` + `remark-gfm` mapped onto the app's own table styles
|
|
|
|
## Architecture
|
|
1. `src/lib/chat/` — provider-neutral core: `types.ts` (no SDK imports), `loop.ts` (model -> tools -> model,
|
|
with max-iterations valve), `provider-anthropic.ts`, `provider-openai.ts` (one SDK each),
|
|
`system-prompt.ts` (built per request: date + user memories), `think-filter.ts`.
|
|
2. `src/lib/agent/` — tools: `tools.ts` (read tools), `tools-actions.ts` (write tools), `load.ts` (fetching),
|
|
`format.ts` (shaping + `display` strings), `resolve.ts` (name -> id), `query.ts` (generic `query_records`),
|
|
`gateway.ts` (the write seam), `schema-cache.ts`.
|
|
3. `src/lib/metrics/` — ALL business calculations as pure tested functions, shared by dashboard and agent.
|
|
4. `/api/chat` — env gate, identify user, persist thread, run loop, stream events.
|
|
5. `/dashboard/chat` — client SSE reader, threads, attachments, confirm cards, charts, PDF.
|
|
|
|
## Rules that make it trustworthy
|
|
- The model never does arithmetic. Tools return finished numbers + preformatted `display`. Prompt bans
|
|
sum/average/percent/"combined" and says what to do instead (list rows, say aggregate not available).
|
|
The first wording failed a live probe — keep "combined value of top three" as a regression probe.
|
|
- Name resolution returns ambiguity lists instead of guessing.
|
|
- `query_records`: typed generic read, filters bound with `pb.filter()`, grouping/aggregation in JS.
|
|
- Tool failures go back to the model as error results and are logged server-side.
|
|
|
|
## Writes
|
|
Model calls `propose_changes` -> pending row in `ask_log` -> confirm card -> human presses Confirm ->
|
|
`applyAction` writes -> each op keeps a `before` snapshot -> Undo. Ops validated against live schema.
|
|
`authorize()` is the single permission seam with a `NEVER_WRITABLE` set (`_superusers`, `users`, chat tables).
|
|
Ops run sequentially so `$ref:` can reference records created earlier in the batch.
|
|
**For Healy: remove the `delete` op kind entirely** (union type, planner, apply). Decide deliberately
|
|
whether Undo may delete records the agent itself just created (recommended: yes, and nothing else).
|
|
|
|
## Gotchas
|
|
MiniMax
|
|
- M2/M2.7 are text-only. M3 is the first accepting BOTH `tools` and images. Test both together.
|
|
- Use the OpenAI-compatible route; the `/anthropic` shim mangles tool-call args.
|
|
- Reasoning streams inline in `<think>…</think>`; strip it with a stateful filter (tags split across chunks).
|
|
- Tool-call args arrive as string fragments per index; concatenate before `JSON.parse`.
|
|
- Key must be an Open Platform API key (not Token Plan subscription key, not Hailuo/MiniMax Agent).
|
|
- Image endpoint: `{base minus /v1}/v1/image_generation` (appending /v1 to base gave /v1/v1).
|
|
Anthropic
|
|
- `budget_tokens` and assistant prefill are removed (400). Use `thinking: {type: "adaptive"}`.
|
|
PocketBase
|
|
- `sort=-created` / `-updated` can 400 with an empty body. Sort a real field or use autodate fields.
|
|
- `getList(1, 500)` silently truncates; use `getFullList`.
|
|
- `fields:` that omits a date field makes later date logic silently skip rows.
|
|
- A detail-less 400 is usually a bad filter/sort; reproduce with a direct `getFullList`.
|
|
Chat plumbing
|
|
- History crosses JSON; types guarantee nothing. Normalise in the route (assistant turns arrive without `toolCalls`).
|
|
- Compare `Origin` to the `Host` header, not `request.url`.
|
|
- Agent loop needs more than 8 iterations for "read file -> match -> propose".
|
|
|
|
## Brief to give the Healy agent
|
|
> Build a chat agent for Healy shaped like MEGA's "Ask". Next.js + PocketBase, SSE from `POST /api/chat`.
|
|
> Provider-neutral loop with two adapters (MiniMax M3 via OpenAI-compatible endpoint; Anthropic fallback).
|
|
> Tools are zod-schema'd functions; all business maths lives in pure tested functions shared with the UI.
|
|
> Reads: typed tools per domain + generic `query_records`; model never does arithmetic; tools return `display`.
|
|
> Writes: create and update only, NO delete. Propose -> pending log row -> human confirm -> apply, with
|
|
> `before` snapshot and undo; validate against live schema; keep a never-writable list.
|
|
> API access: expose the same handlers as REST and as an MCP server, both authenticated.
|
|
> Also: strip `<think>`, reassemble fragmented tool args, normalise history at the route, log tool failures.
|
|
|
|
## Decide deliberately (API + MCP + writes)
|
|
- Auth: Ask used an `x-ask-user` header + shared PIN during testing. A create/update API or MCP surface needs
|
|
real per-user authentication.
|
|
- MCP is headless (no human to confirm). Either keep MCP read-only, or let it only create PENDING actions a
|
|
person confirms in the app (recommended).
|