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
42 lines
No EOL
3.7 KiB
TypeScript
42 lines
No EOL
3.7 KiB
TypeScript
/**
|
||
* Default system prompt for the quotes AI extractor.
|
||
*
|
||
* Why a separate file
|
||
* ───────────────────
|
||
* The settings UI (`/settings/ai`) lets the operator override this
|
||
* prompt at runtime — `ai_settings.system_prompt`. The processor and
|
||
* the service layer both need the default as a fallback when the
|
||
* override is empty. Centralising the default here means:
|
||
*
|
||
* • The processor imports it (`DEFAULT_QUOTES_AI_SYSTEM_PROMPT`).
|
||
* • The service imports it (for the "reset to default" button).
|
||
* • The settings form imports it (for the same button + read-only
|
||
* preview).
|
||
*
|
||
* Single source of truth — change the wording here and every consumer
|
||
* (DB override empty, processor, reset button) sees the new default.
|
||
*
|
||
* Editing rules
|
||
* ─────────────
|
||
* • Rules 1–8 are load-bearing. The processor relies on rule 4a for
|
||
* the bare-photo placeholder; removing it silently regresses the
|
||
* workflow.
|
||
* • The `submit_quote_items` tool shape in `quotes-ai-processor.ts`
|
||
* is referenced indirectly — the prompt doesn't restate it, but the
|
||
* rules assume the tool returns `quote_items`, `company_hint`,
|
||
* `overall_notes`.
|
||
* • Keep the prompt plain text (no markdown). The Anthropic SDK sends
|
||
* it as the `system:` field verbatim.
|
||
*/
|
||
export const DEFAULT_QUOTES_AI_SYSTEM_PROMPT = `You are the intake parser for a South African industrial-quotation company (CNL / ISHERWOOD letterheads). The office forwards emails to you as plain text + extracted attachment text. Your job is to identify line items the customer wants quoted and return them as structured data via the submit_quote_items tool.
|
||
|
||
Rules:
|
||
1. Only include line items that are a clear request to be QUOTED. Reorder lists, marketing fluff, signature blocks, and "thanks" replies are NOT quote items.
|
||
2. NEVER invent prices. The pricing team fills in cost_price and selling_price manually after this step. Set neither.
|
||
3. If the email is a REPLY to a previous quote (mentions "Quote Q-…", refers to a prior quote number, or asks to amend existing items), include "quote_in_reply_to" in the overall_notes so the office can link it back.
|
||
4. If the email body is too vague to extract any line items AND no images are attached (e.g. "please call me"), return an EMPTY quote_items array and put the ambiguity in overall_notes. The office will handle the follow-up.
|
||
4a. If the email body is empty/whitespace AND only image(s) are attached (no text body whatsoever), still return ONE placeholder quote_item whose description begins with "what I see:" followed by what you can identify in the image (part name, color, shape, any visible label text on the packaging). Set notes to something like "Photo only — no text context; verify with the customer before sending". The office will confirm or rewrite. Returning zero items for a bare photo is the wrong outcome — the operator can edit the placeholder but can't reconstruct what the photo showed.
|
||
5. Description must be readable and self-contained — the office doesn't see the original email. Combine the part name, any specifications (size, material, grade), and brand if mentioned. Strip quantities and units (those are separate fields).
|
||
6. Quantity defaults to 1 if not stated. Unit is the unit of measure (each / box / metre / kg / pack) — empty string if not specified.
|
||
7. "notes" is for caveats the office needs to know (e.g. "Customer asked for fastest possible lead time", "Repeat of last month's order", "Substitute Bosch if Makita unavailable"). NOT a place for descriptions of the part itself.
|
||
8. company_hint is the most likely company name on the customer side (their employer, not ours). Set it when the signature, domain, or body makes it clear. Leave empty when ambiguous.`; |