Commit graph

10 commits

Author SHA1 Message Date
3091ac94de docs(quote-assistant): runbook accuracy, MCP tool listed in API docs
- Runbook: pre-migration settings don't persist (not "saves fail"),
  eligible statuses, 15 lines per quote, audit attribution, clone/template
  behaviour, supplier kept, doubts dot, confidence guidance (Medium is the
  default; raise to High if reps often change AI prices).
- quotes.assistant_fill added to docs/api-mcp-layer.md,
  docs/audit/api-mcp-coverage.md and the Giellie skill.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 23:42:44 +02:00
8d83065964 feat(giellie): tighten the agent tool policy and MCP surface
Aligns the tool policy, the system prompt, the MCP route and the skill
doc so they describe the same boundary, with tests pinning the policy
and prompt text.

The docs and the executable policy had drifted apart — the skill doc
advertised capabilities the policy does not grant, which is worse than
not documenting them: an agent reading the doc will plan around a tool
it isn't allowed to call.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-10-16 00:44:52 +02:00
Dave
6344948b0b feat: add driverless collection confirm and new order tooling
This commit adds several key features, improvements, and cleanups across the codebase:
- Add `order_items.confirm_collected` MCP/REST endpoint to mark order items as collected without requiring driver assignment
- Add standalone order creation and order split APIs for flexible order management
- Update order list sort to oldest-first to align with user workflow of working through oldest orders first
- Improve order search to show cross-tab matches and display source tab indicators on search results
- Add customer name similarity check to warn about mismatched QuickBooks customers during invoice creation
- Remove supplier name column from delivery note PDFs and clean up related data passing across delivery note routes
- Add validation and debug logging to ItemIntelPopover for missing item ID on apply actions
- Remove unused OrderItemContextPopoverTrigger component from order detail page
- Add delivery note regeneration script and update test suites for new and existing functionality
- Update documentation and add test coverage for the new collection confirm tool
2026-08-12 01:13:46 +02:00
Dave
47d58db0c9 feat(mcp): add price_list.add_items tool for agent-driven catalogue upsert
Add a new MCP tool that lets the agent read a supplier PDF, quote PDF,
or pasted supplier email with its native vision, extract the per-line
fields, and commit them to the price_list catalogue in one round-trip.

Why: the only pre-existing path was operator upload via /pricelist ->
n8n ingest -> raw_price_list -> AI extraction -> price_list. That flow
is async, human-in-the-loop, and gates on n8n being healthy. This
tool gives the agent a synchronous shortcut for ad-hoc catalogue
updates -- paste a PDF, get the catalogue updated, no async hops.

The agent does the OCR; the tool does the commit. No LLM work moves
into the MCP server.

Behaviour:

- Dedupe by (sku, supplier) -- exact match. Different suppliers with
  the same SKU get separate rows.
- Upsert policy: cost_price overwrites (latest price wins).
  Description, selling_price, unit, category, subcategory, brand,
  markup, stock_qty, search_text, sku_normalised also patched in
  place on update.
- sku_normalised auto-computed (uppercase, strip non-alphanumeric --
  same canonical form price-list-match.ts uses).
- search_text auto-computed (lowercased, space-separated concat of
  sku + description + brand + supplier + category + subcategory +
  synonyms).
- Skipped items returned with per-item reason (missing_sku,
  missing_supplier, invalid_cost_price, pb_write_failed). Never
  silent.
- Bulk cap 500 items per call; larger lists rejected with
  too_many_items reason.
- source_file_id + source_label supported so new rows can be
  traced back to a raw_price_list upload (optional).
- Supplier stored verbatim on price_list.supplier (free-text field,
  no FK resolution -- same as the live schema).

Files:

- src/lib/server/price-list-service.ts (new) -- addPriceListItems +
  buildSearchText + computeSellingPrice helpers
- src/lib/server/price-list-service.test.ts (new) -- 17 tests
  covering validation, upsert, dedupe filter shape, normalisation
- src/app/api/mcp/route.ts -- new tool definition + dispatch block
- src/app/api/mcp/route.test.ts -- 2 dispatch tests + tool-list
  assertion update
- .agents/skills/wfdash-giellie/SKILL.md -- new section "8. Price-
  list catalogue" documenting input/output shapes + failure modes

Tests:

- 134/134 pass across the affected files
- 1775/1778 in the full suite (3 pre-existing failures unrelated
  to this change: pocketbase-admin.test.ts PB mock mismatch,
  quotes/items/[id]/attachments/upload/route.test.ts timeout,
  supplier-form.test.tsx race -- all reproducible on main)
- npm run build clean
2026-08-10 12:45:05 +02:00
SJCoetz
87cead1bcf feat(mcp): expand stock purchase invoice matching service with 5 phases
Build out the buyer-side PO reconciliation workflow that landed in
60d3204 ('stock purchase invoice reconciliation tool') into a full
3-document × 2-PO-kind matching service. The tool now covers every
real-life supplier document the buyer can receive.

Renamed the service entry point from matchAndReceiveFromInvoice to
matchAndReceiveFromPoDocument (old name kept as a back-compat alias).
The MCP tool name stays stock_purchases.match_and_receive_from_invoice
so existing callers don't break; the input arg shape changed from
'invoice:' to 'document:' (old 'invoice:' arg still accepted for
back-compat).

Phase 1 — supplier_sku backfill (prep work, not in service code)
Phase 2 — auto-detect stock vs customer POs (single tool, both kinds)
Phase 3 — GRN (delivery-note) mode via new mode: 'grn' flag
Phase 4 — pack-size inference (Orapi case: per-unit vs per-pack)
Phase 5 — PO reference normalisation (PO202608017 vs PO-2026-08-017)

Also adds 3 new MCP tools for the collection-confirm buyer workflow:
collection_confirm.list, collection_confirm.upload_invoice,
collection_confirm.confirm_order_items.

Docs: updated .agents/skills/wfdash-giellie/SKILL.md and
src/app/api/mcp/FEATURE-REQUESTS.md to describe the new modes and
shape. 1,661/1,664 vitest tests pass; the 3 failing tests are
pre-existing (PocketBase SDK mock mismatch in pocketbase-admin.test,
5s timeout in quotes/items/[id]/attachments/upload/route.test —
both reproducible on main without this change).
2026-08-09 20:23:36 +02:00
SJCoetz
60d320411d feat(mcp): add stock purchase invoice reconciliation tool
Add the full buyer-side supplier invoice reconciliation workflow:
- Include the new `stock_purchases.match_and_receive_from_invoice` MCP tool for deterministic PO-invoice matching
- Create core matching service with strict, rule-based line matching (sku → supplier_sku → description overlap)
- Support dry-run default mode to validate matches before committing
- Add automatic attachment handling with standard `supplier_invoice_*` naming convention
- Add full test suite for the matching logic
- Update documentation and agent skill profile to document the new tool and workflow

Pre-existing test failures (3 total) are unrelated to this change.
2026-08-09 16:59:44 +02:00
SJCoetz
63048e51c9 feat: add AI quote processing pipeline and admin settings UI
Add complete end-to-end AI-powered quote extraction workflow:
- Disable PB SDK auto-cancellation to support parallel batch requests
- Add required runtime dependencies for AI processing and document parsing
- Implement AI settings backend, operator UI, and REST API routes
- Add quote ingestion, insight population, and manual re-run AI endpoints
- Build service layers for quote items, AI settings, and structured item insights
- Fix attachment upload handling and quote item history blob parsing
- Add supporting migrations, smoke tests, and shared utility functions
- Export previously private helper functions for cross-service reuse
2026-08-09 16:17:29 +02:00
SJCoetz
c41908f4b7 feat(quote-items): CRUD via REST + MCP for AI auto-fill agents
Closes architectural gap #1 from the Giellie skill (the operator's AI
agent could ingest quotes via /api/mcp but had no way to enumerate,
add, or patch the resulting line items - every auto-price flow had to
stop and ask a human for the item IDs).

Adds:
  - GET  /api/v1/quote_items        (list w/ filter, sort, expand)
  - POST /api/v1/quote_items        (create on existing quote)
  - GET  /api/v1/quote_items/[id]   (fetch one)
  - PATCH /api/v1/quote_items/[id]  (whitelisted patch)
  - quote_items.list  MCP tool
  - quote_items.get   MCP tool
  - quote_items.create MCP tool
  - quote_items.update MCP tool

Patch whitelist on update is identical to bulk_update_quote_items:
  cost_price, selling_price, description, sku, unit, supplier, markup,
  pricing_source, pricing_notes, matched_price_list_id, user_edited
Everything else (id, quote, created, updated, quantity, is_processed)
returns 400 / MCP error with the allow-list echoed back so the agent
can self-correct.

quote_items.update does NOT enforce the already_priced skip - that's
the safety-net for bulk_update_quote_items. Single-row patches are
explicit writes.

Newly created rows have is_processed=false forced server-side; Giellie
still cannot flip the flag (architectural gap #2 unchanged - that's a
UI gate by design).

Also: removed "JEI" from quotes.company_letterhead select values on
the live PB - valid values are now ["CNL", "ISHERWOOD"]. Use the
uppercase form when setting this field.

Giellie skill doc refreshed: tool count 69 to 73, new "quote_items
CRUD" subsection, three new REST rows, architectural gap #1 marked
RESOLVED, hard rule #1 updated to cover the new endpoint, new worked
example for "add a missing line item + price it", change-log entry.

Tests: 82 passing across the three touched files (was 63 before).
Type-check: zero new errors (pre-existing 29 in
orders-service-review.test.ts unchanged).

Deployment: pending operator rebuild + redeploy. Until then
POST /api/v1/quote_items returns 404 and the new tools don't appear
in tools/list.

Co-authored-by: Orca <help@stably.ai>
2026-08-05 02:40:09 +02:00
SJCoetz
0455ddd346 docs(giellie): correct tool count (70 → 69) + add post-redeploy verification
The earlier change log claimed the catalog went 69 → 70 after wiring
tools.discovery, but tools.discovery was already in the catalog from
the start — only its runtime behavior changed from 'Unknown tool' to
functional. Live post-redeploy smoke test confirms 69 tools.

Fix all six '70' references in the doc to '69', and append a second
change-log entry recording what was verified live after the redeploy:
  - tools.discovery returns the flat 69-tool catalog via JSON-RPC ✅
  - GET /api/mcp still works ✅
  - 5 other bugs reproduce exactly as documented (validates the doc) ✅
  - ISHERWOOD + CNL letterhead PDF regeneration on Q000087 still works ✅

Co-authored-by: Orca <help@stably.ai>
2026-08-04 22:53:46 +02:00
SJCoetz
8fe80fefc8 docs(giellie): refresh skill doc — corrected host, all tokens, smoke-test findings
Bring the Giellie agent's operating manual in line with the live production
state after the 2026-08-04 smoke test against https://wfdash.apphub.co.za.

Bugs / quirks documented (with workarounds):
  - tools.discovery was unwired; now fixed in code (separate commit),
    live server needs redeploy before response changes
  - orders.list silently ignores 'filter'; only 'search' is honoured
  - quotes.lookup returns opaque 'fetch failed' — use quotes.list instead
  - collection_pool.list + sprint.list return 'Missing collection context'
  - orders.get 'not found' for at least one valid id
  - quotes.items.rewrite was incorrectly listed as an MCP tool (it's REST)

Architectural gaps documented:
  - No quote_items.list MCP tool; quotes.create_from_email returns item
    count only, so a freshly-ingested quote's item IDs can't be recovered
    via the agent API
  - is_processed is intentionally NOT in bulk_update_quote_items whitelist;
    end-to-end create→price→render pipeline requires human in the UI

Credentials & endpoints now include every token the agent might need:
AGENT_API_KEY, PB admin email/password, n8n base URL + API key, six
n8n webhook URLs (rewriter, price-list match, PO send, AI insights,
markup approval, customer list, QB invoice creator), TomTom map key.

Other updates:
  - Replaced stale base URL wfdash.davidels.dev with wfdash.apphub.co.za
  - Bumped tool count 69 → 70 (tools.discovery added to catalog)
  - Added three-way tool discovery guide (tools/list, tools.discovery,
    GET /api/mcp)
  - Added 'Quote PDF rendering' guide explaining the 422 gates,
    status transitions, and letterhead codes
  - Added change log at the bottom
  - All worked examples updated to the correct host

Co-authored-by: Orca <help@stably.ai>
2026-08-04 22:47:55 +02:00