From e72467da50fa0026f7c3959e3bb76283c75dbc7a Mon Sep 17 00:00:00 2001 From: seb Date: Sun, 11 Oct 2026 14:23:47 +0200 Subject: [PATCH] u --- src/tools/prompts.js | 300 +++++++++++++++++-------------------------- 1 file changed, 116 insertions(+), 184 deletions(-) diff --git a/src/tools/prompts.js b/src/tools/prompts.js index 1e074ad..9e772ec 100644 --- a/src/tools/prompts.js +++ b/src/tools/prompts.js @@ -3,88 +3,71 @@ import { listSkillFiles } from './skill.js'; // #region Tool Prompts & Descriptions +const NOTE_DESC = 'Status message shown to the user during execution.'; + /** * Descriptions for all tools registered in the agent's toolbelt. * Used in defineTool({ description }) across src/tools/*. */ export const TOOL_DESCRIPTIONS = { dashback_request: - 'Call the Dashback (QuixPOS) REST API with GET, POST, PUT, PATCH or DELETE. Paths are root-relative (e.g. "/article/2").', + 'Call Dashback (QuixPOS) REST API with GET/POST/PUT/PATCH/DELETE. Root-relative paths (e.g. "/article/2").', ask_user: - 'Prompt user for missing decisions or parameters with a concise question and up to 3 options. Pauses the run until the user answers.', + 'Prompt user for missing parameters with a concise question and up to 3 options. Pauses run until answered.', javascript_execute: - 'Execute JS in an isolated worker sandbox using either inline `code` or a VFS applet. Use for computation, binary I/O and aggregation. Provide exactly one of `code` and `appletvfsfile`. ' + - 'Applets are the preferred method when the first execution may throw: save a `.applet.js` file in the VFS so it can be inspected and further edited with `patch`, then call it by VFS path. ' + - 'Applet files must start with `// @applet-input-schema {JSON Schema}` on line 1 and `// @applet-output-schema ` on line 2. ' + - 'The input schema describes the GUI form passed as `applet_input`. The output line declares the RESULT COLUMNS as typed CSV: `name:type` pairs separated by `;` (e.g. `id:integer;name:string;active:boolean`); a bare `name` defaults to string, and the allowed types are string, integer, number, boolean and date. ' + - 'Applets return typed CSV, NOT JSON: export a function that receives `applet_input` and returns a row object, or an array of row objects, whose keys are the declared columns (e.g. `return [{ id: 1, name: "Kaffee" }]`). Only declared columns are emitted, in header order; missing keys become empty cells. The tool result then carries `result` as a `;`-separated CSV string with a header row, plus `columns` (name/type) and `rows` (data row count). Returning a single object yields one data row. ' + - 'Inline code: assign `module.exports` to return value (sync value or Promise; wrap async in IIFE: `module.exports = (async () => { ... })()`). ' + - 'REST API: `await fetch("/path")` (authenticated). ' + - 'VFS: directly use global `fs.readFileSync`/`writeFileSync` for binary artifacts/buffers/images (`image/` is read-only; paths must be relative paths, root is not allowed). VFS can host a static website (HTML, CSS, JS, images, etc.). ' + - 'Embed generated images/links in markdown: `![alt](relative/path)`. Internet links use `https://...` or `hostname.com`/`hostname.com/filename`; a pure relative file with no dotted hostname is always a VFS relative path. Use find_files/read_file/patch for text. ' + - 'All APIs are pre-injected globals: `fs`/`vfs` (virtual filesystem), `sharp` (image processing), `ExcelJS`/`exceljs` (spreadsheet processing with VFS support for readFile/writeFile/writeBuffer/load), `PDFDocument`/`PDFKit`/`pdfkit` (PDF generation with VFS support for toFile/toBuffer/pipe), WebCrypto `crypto` (`subtle`, `randomUUID`), and standard web globals. Do NOT use `require()` or `import` (disabled; all necessary APIs are already in global scope).', + 'Execute JS in an isolated sandbox via inline `code` (assign to `module.exports`) or `appletvfsfile` ' + + '(.applet.js returning typed CSV per @applet-input-schema and @applet-output-schema; details in applet.SKILL). ' + + 'Pre-injected globals: fs/vfs, sharp, ExcelJS, PDFDocument, crypto, and fetch("/path"). No require/import.', find_files: - 'List VFS files. Root-relative forward-slash paths. ' + - 'Set skills=true to list root-level ".SKILL" files (reusable instructions exempt from reset_vfs; read via read_file).', + 'List VFS files (root-relative paths). Set skills=true to list root-level ".SKILL" files.', read_file: - 'Read text file (text, CSV, JSON, markdown, …) from VFS. Root-relative forward-slash paths. ' + - 'SKILL files return parsed title and markdown content. ' + - 'Windowed via seek/limit (0-indexed lines). Binary files not supported (use analyze_image for images).', + 'Read text file (text, CSV, JSON, markdown, SKILL) from VFS with seek/limit pagination. Binary not supported.', patch: - 'Create, overwrite, or search-and-replace text in VFS files (the only write path for text files). Operations apply in order. ' + - 'Mode: search null/omitted = create or overwrite (directories auto-created). ' + - 'search provided = replace first verbatim occurrence (read file with read_file first). ' + - 'SKILL files: root-only ".SKILL" (line 1 is title, or provide title field).', + 'Create, overwrite, or search-and-replace text in VFS files. Operations apply in order. Omit search to create/overwrite.', search_images: - 'Search Google Images and download candidates to VFS as AVIF. Returns VFS paths for inspection via analyze_image.', + 'Search Google Images and download candidates to VFS as AVIF. Inspect candidates via analyze_image.', analyze_image: - 'Inspect 1-9 images via vision model. Always evaluate images with this tool before using them. Multiple paths render as a labelled comparison grid. ' + - 'Paths: VFS-relative ("images/foo.avif") or DB ("image/"). Returns model evaluation.', + 'Inspect 1-9 images via vision model. Paths: VFS-relative ("images/foo.avif") or DB ("image/").', web_search: - 'Search Google via Serper.dev. Use timePeriod "day" or "week" for news/recent events. Returns 10 results per page.', + 'Search Google via Serper.dev. Use timePeriod "day" or "week" for news/recent events. 10 results/page.', url_get: - 'Fetch and scrape web page content via Serper Scrape (text, markdown, metadata).', + 'Fetch and scrape web page content (text, markdown, metadata) via Serper Scrape.', pdf_read: - 'Read PDF/text documents as layout text ("txt") or render pages to VFS PNG images ("png", stored in "images/").', + 'Read PDF/text documents as layout text ("txt") or render pages to VFS PNG images ("png").', reset_vfs: - 'Clear VFS files, images, and artifacts. Preserves SKILL files by default.', + 'Clear VFS files, images, and artifacts. Preserves SKILL files unless include_skills=true.', rm: - 'Delete single VFS file (e.g. specific artifact or SKILL file). Irreversible.', + 'Permanently delete a single VFS file or SKILL file.', apisuggestionsorissues: 'Report missing API endpoint, feature request, bug, or issue for triage.', search_articles: - 'Text search articles by name, brand, EAN, SKU, or supplier SKU. ' + - 'Returns window of full articles (default 3, max 20), offset, and total count. Ordered alphabetically by name.', + 'Search articles by name, brand, EAN, SKU, or supplier SKU (AND logic, ordered by name).', edit_image: - 'Generate or edit images using the configured company image model (modelslugimage). ' + - 'Supports reference image attachments fed in low or high quality, output size tier, ' + - 'aspect ratio, and saving directly to a specified VFS output path (always saved as AVIF).', + 'Generate or edit images via modelslugimage. Supports reference image attachments, size tier, ratio, and VFS AVIF output.', ean_checksum: - 'Validate EAN/GTIN/UPC barcode check digits or calculate the missing check digit for barcodes ' + - '(EAN-13, EAN-8, UPC-A, GTIN-14). Strips spaces and hyphens automatically.', + 'Validate or calculate check digits for EAN-13, EAN-8, UPC-A, and GTIN-14 barcodes.', net_gross_calc: - 'Convert between net and gross prices (net to gross, gross to net) with VAT/tax rate (default 19%). ' + - 'Computes 2-decimal rounded display values and 6-decimal high-precision net values for API article creation.', + 'Convert net/gross prices with VAT rate (default 19%). Returns rounded display values and 6-decimal net API values.', set_user_route: - 'Navigate the user to a frontend route. Use this when the user says "show me the article" or asks to see, open, or view a specific page or entity (e.g. an article detail page, orders, quotes, deliveries, or customer). Use a path from the ROUTE MATRIX in the system prompt.', + 'Navigate user to a frontend route when asked to view/open an entity or page (see ROUTE MATRIX in prompt).', }; // #region Tool Parameter Descriptions @@ -94,11 +77,11 @@ export const TOOL_DESCRIPTIONS = { */ export const TOOL_PARAMETER_DESCRIPTIONS = { dashback_request: { - note: 'A note explaining what this request is doing (or null). This note will be displayed to the user while the request is executing.', + note: NOTE_DESC, method: 'HTTP method.', path: 'Endpoint path (e.g. "/article/2").', query: 'Query parameters object or null.', - body: 'JSON request payload string or null.', + body: 'JSON payload string or null.', }, ask_user: { @@ -107,62 +90,60 @@ export const TOOL_PARAMETER_DESCRIPTIONS = { }, javascript_execute: { - note: 'A note explaining what this code is doing (or null). This note will be displayed to the user while the code is executing.', - code: 'Optional inline JavaScript code. Provide exactly one of this and appletvfsfile. Assign result to `module.exports`. Async code must use IIFE. Do not use require() or import.', - appletvfsfile: - 'Optional VFS-relative path to a .applet.js file. Provide exactly one of this and code. The file must begin with the two applet metadata lines (`@applet-input-schema` JSON Schema, then `@applet-output-schema` typed CSV columns like `id:integer;name:string`).', - applet_input: - 'Input values passed to the exported function when running appletvfsfile. Omit to pass an empty object. The applet returns typed CSV rows mapped onto its `@applet-output-schema` columns.', - timeout: 'Execution timeout in ms or null. Default 20000, max 60000.', - max_output: 'Max stdout chars or null. Default 20000.', + note: NOTE_DESC, + code: 'Inline JS code. Assign result to `module.exports`. Wrap async in IIFE. Mutually exclusive with appletvfsfile.', + appletvfsfile: 'VFS path to .applet.js file. Mutually exclusive with code.', + applet_input: 'Input values passed to applet export function. Returns typed CSV rows.', + timeout: 'Timeout in ms (default 20000, max 60000).', + max_output: 'Max stdout chars (default 20000).', }, find_files: { - dirname: 'VFS directory to list or null. Default "." (root). Must be "." or empty if skills=true.', - recursive: 'Walk subdirectories or null. Default false.', - skills: 'List only root SKILL files with parsed titles or null. Overrides dirname/recursive. Default false.', - seek: 'Pagination offset or null. Default 0.', - limit: 'Max entries to return or null. Default 50, max 500.', - maxDepth: 'Max recursive directory depth or null. Default 3.', + dirname: 'Directory to list (default "."). Must be "." if skills=true.', + recursive: 'Walk subdirectories (default false).', + skills: 'List only root SKILL files with parsed titles (default false).', + seek: 'Pagination offset (default 0).', + limit: 'Max entries (default 50, max 500).', + maxDepth: 'Max recursive depth (default 3).', }, read_file: { filename: 'VFS file path.', - seek: 'Line offset (0-indexed) or null. Default 0.', - limit: 'Max lines to return or null. Default 400, max 5000.', + seek: '0-indexed line offset (default 0).', + limit: 'Max lines to return (default 400, max 5000).', }, patch: { operations: 'Ordered patch operations.', - file: 'VFS path (e.g. "notes.md", "pipeline.SKILL"). SKILL files must be root-level (no "/").', - search: 'Exact text to replace. null/omitted = overwrite or create file.', + file: 'VFS path. SKILL files must be root-level.', + search: 'Exact text to replace. Omit to overwrite or create file.', replace: 'Replacement text.', - title: 'Optional line-1 title for SKILL files or null.', - skiplines: 'Lines to skip before searching or null.', + title: 'Line-1 title for SKILL files.', + skiplines: 'Lines to skip before search.', }, search_images: { - note: 'A note explaining what this image search is doing (or null). This note will be displayed to the user while executing.', + note: NOTE_DESC, query: 'Search query.', - count: 'Candidate count or null. Default 4, max 9.', - gl: 'Country code or null. Default "de".', - hl: 'Language code or null. Default "de".', + count: 'Candidate count (default 4, max 9).', + gl: 'Country code (default "de").', + hl: 'Language code (default "de").', }, analyze_image: { - note: 'A note explaining what this image inspection is doing (or null). This note will be displayed to the user while the images are being analyzed.', + note: NOTE_DESC, paths: '1–9 VFS paths or DB paths ("image/").', - prompt: 'Inspection criteria or question, or null.', + prompt: 'Inspection criteria or question.', grid: 'Grid layout or null for auto.', }, web_search: { - note: 'A note explaining what this search is doing (or null). This note will be displayed to the user while the search is executing.', + note: NOTE_DESC, query: 'Search query.', - timePeriod: 'Time filter: "day", "week", "month", or "year", or null.', - gl: 'Country code or null. Default "de".', - hl: 'Language code or null. Default "de".', - page: 'Result page number (10/page) or null. Default 1.', + timePeriod: 'Time filter: "day" | "week" | "month" | "year".', + gl: 'Country code (default "de").', + hl: 'Language code (default "de").', + page: 'Result page number (10/page, default 1).', }, url_get: { @@ -171,13 +152,13 @@ export const TOOL_PARAMETER_DESCRIPTIONS = { pdf_read: { path: 'VFS path or HTTP(S) URL.', - format: 'Output format: "txt" (layout text), "png" (page images), "both", or null. Default "txt".', - page: '1-based page number or null for all pages.', - dpi: 'PNG render DPI or null. Default 150.', + format: '"txt" (layout text), "png" (page images), or "both" (default "txt").', + page: '1-based page number, or null for all pages.', + dpi: 'Render DPI for PNG (default 150).', }, reset_vfs: { - include_skills: 'Delete SKILL files too (or null). Default false.', + include_skills: 'Delete SKILL files too (default false).', }, rm: { @@ -186,53 +167,47 @@ export const TOOL_PARAMETER_DESCRIPTIONS = { apisuggestionsorissues: { text: 'Issue or request details.', - type: 'Report category or null.', - title: 'Short summary or null.', + type: 'Report category.', + title: 'Short summary.', }, search_articles: { - searchquery: - 'Words that must all match across name, brand, EAN, SKU, or supplier SKU (AND logic, order-independent) or null.', - excludewords: - 'Words that if all match exclude the article (AND logic, order-independent) or null.', - offset: 'Pagination offset or null. Default 0.', - limit: 'Result window size (1–20) or null. Default 3.', + searchquery: 'Keywords matching name, brand, EAN, SKU, or supplier SKU (AND logic).', + excludewords: 'Keywords to exclude (AND logic).', + offset: 'Pagination offset (default 0).', + limit: 'Window size 1–20 (default 3).', }, edit_image: { - note: 'A note explaining what this image generation or edit is doing (or null). This note will be displayed to the user while the image is being generated or edited.', - prompt: 'Description of the image to generate, or edit/transformation instructions when attachments are provided.', - attachments: - 'Optional reference image(s) for editing/image-to-image or null. Omit for text-to-image generation.', - attachment_vfsfilename: - 'VFS path (e.g. "images/sample.png") or database path ("image/").', - attachment_high: - 'Feed image in high quality/resolution if true; low quality/resolution if false or null (default).', - size: 'Resolution tier (3 choices): "1K" (standard, default), "2K" (high quality), "4K" (ultra high), or null.', - ratio: 'Aspect ratio (3 choices): "1:1" (square, default), "4:3" (landscape), "3:4" (portrait), or null.', - vfsoutputfilename: - 'VFS path where the output image should be saved (e.g. "images/edited.avif") or null. Defaults to "images/generated-.avif". Output is always converted to AVIF.', + note: NOTE_DESC, + prompt: 'Prompt for text-to-image or edit/transformation instructions.', + attachments: 'Reference image attachments for img2img.', + attachment_vfsfilename: 'VFS path or DB path ("image/").', + attachment_high: 'High resolution input if true (default false).', + size: 'Resolution tier: "1K" (default), "2K", "4K".', + ratio: 'Aspect ratio: "1:1" (default), "4:3", "3:4".', + vfsoutputfilename: 'Target VFS path (always saved as AVIF). Defaults to "images/generated-.avif".', }, ean_checksum: { - note: 'A note explaining what this EAN checksum check is doing (or null). This note will be displayed to the user while executing.', - code: 'Barcode number to validate or complete (e.g. 12 digits for EAN-13 check digit calculation, or 13 digits for EAN-13 validation).', - action: 'Optional action: "auto" (default: infer from length), "validate" (check last digit), "calculate" (compute check digit for the given payload), or null.', + note: NOTE_DESC, + code: 'Barcode number to validate or complete.', + action: '"auto" (default), "validate", or "calculate".', }, net_gross_calc: { - note: 'A note explaining what this price calculation is doing. This note will be displayed to the user while executing.', - gross: 'Gross price (incl. VAT) or null. When provided, computes net price and tax amount.', - net: 'Net price (excl. VAT) or null. When provided, computes gross price and tax amount.', - taxRate: 'Tax/VAT rate percentage (e.g. 19 for 19%, 7 for 7%) or null. Default 19.', - amount: 'Generic price amount or null when used with "from" ("gross" or "net").', - from: 'Direction when using "amount": "gross" (default) or "net".', - precision: 'Decimal precision for net price API value or null (default 6, between 2 and 8).', - items: 'Optional array of prices or objects for batch calculation: [19.99, 49.95] or [{ gross: 19.99, taxRate: 7 }].', + note: NOTE_DESC, + gross: 'Gross price (incl. VAT).', + net: 'Net price (excl. VAT).', + taxRate: 'VAT percentage (default 19).', + amount: 'Price amount when paired with "from".', + from: '"gross" (default) or "net".', + precision: 'Net price API decimal precision 2–8 (default 6).', + items: 'Array of prices or calculation objects for batch processing.', }, set_user_route: { - route: 'Target frontend route path according to the Route Construction Matrix (e.g. "/artikel/ART-10042", "/kategorien/elektronik/kabel", "/auftrag/1001").', + route: 'Frontend route from Route Matrix (e.g. "/artikel/ART-10042", "/auftrag/1001").', }, }; @@ -242,70 +217,42 @@ export const PATCH_PARAM_DESCRIPTIONS = TOOL_PARAMETER_DESCRIPTIONS.patch; // #region Tool-specific Subprompts export const ANALYZE_IMAGE_VISION_COMPARE_PROMPT = - 'Compare these images, judge visual quality, flag watermarks, text overlays or defects, and say which one is best and why.'; + 'Compare these images, evaluate visual quality, flag watermarks/overlays/defects, and state the best candidate with rationale.'; export const ANALYZE_IMAGE_VISION_DESCRIBE_PROMPT = - 'Describe this image, judge its visual quality, flag any watermark, text overlay or defect, and say whether it is usable as a product or category image.'; + 'Describe this image, evaluate visual quality, flag watermarks/overlays/defects, and verify suitability as a product/category image.'; // #endregion // #endregion // #region System Prompt Components -export const SYSTEM_PROMPT_VFS_RULES = [ - 'VFS & SKILLS:', - '- Persistent per-company VFS; root-relative forward-slash paths (e.g. "labels/sheet1.png"). Can host a static website.', - '- User uploads go to "attachments/…", tagged in messages as `[ATTACHMENT name= path= type=]`. Inspect with read_file (text/csv/json), pdf_read (PDF), analyze_image (images), javascript_execute + ExcelJS (spreadsheets).', - '- Markdown links: internet links are "https://…" or dotted hostnames ("hostname.com/file"); anything else is a VFS path (`[download](report.csv)`).', - '- SKILL files: root-only ".SKILL" markdown (first line = title). Discover via find_files({ skills: true }). ALWAYS read_file the matching skill BEFORE executing a covered task. Propose saving improved procedures as new SKILL files. Exempt from reset_vfs; delete via rm.', -].join('\n'); - export const SYSTEM_PROMPT_RULES = [ - 'RULES:', - '- LABELS (/labeltemplate): Dashback JSON `{ "objects": [ ... ] }`. Do NOT use ZPL.', - '- IMAGES: flow search_images → analyze_image({ paths, prompt }) → upload via fetch in javascript_execute. `image/` is READ-ONLY; write generated images elsewhere (e.g. "images/…").', - '- OUTPUT: Markdown + emoji. Render VFS images inline `![alt](artifacts/example.png)`; other files (PDF, JSON, CSV) need download links.', - '- NAVIGATION: when the user asks to view/open a page or entity, call set-user-route with a path from the matrix.', - '- API: routes are not inlined. BEFORE dashback_request, read_file the api-
.SKILL for exact params and response shapes. `api-binary-streaming-routes.SKILL` covers fetch()-only routes.', - '- T* TYPES: `T` (e.g. T2) is shorthand for a reusable object shape. Ids are GLOBAL: the same T always means the same shape in every skill. Each api-
.SKILL only lists, in its "Reusable types" block, the T it uses (plus the ones those reference), so a skill shows a subset of the registry, and a T may appear in several skills with an identical definition.', -].join('\n'); - -export const SYSTEM_PROMPT_BINARY_UPLOAD = [ - 'BINARY IMAGE UPLOAD (fetch() in javascript_execute, image/avif buffer body):', - '- POST /article/{sku}/image -> 201 { image: { picId, sort, full: { w, h, size }, thumb: { w, h }, hash, thumbHash } }', - '- POST /category/{id}/image -> 201 { category: { id, thumbW, thumbH, thumbHash } }', - '- POST /brand/{id}/image -> 201 { brand: { id, fullHash, thumbW, thumbH, thumbHash, pics: [...] } }', + 'RULES & VFS:', + '- VFS: Persistent root-relative paths ("labels/sheet1.png"). Uploads land in "attachments/..." ([ATTACHMENT name= path= type=]); inspect via read_file, pdf_read, analyze_image, or javascript_execute + ExcelJS. Can host static sites.', + '- Links: Web links use "https://..." or domains; relative paths format as [label](relative/path). Inline images: ![alt](images/path.avif). Other files require download links.', + '- SKILLS: Flat root ".SKILL" markdown files. ALWAYS read_file matching skill BEFORE executing covered tasks. Exempt from reset_vfs.', + '- API: Routes are not inlined. BEFORE dashback_request, read_file the api-
.SKILL for parameters and response structures. api-binary-streaming-routes.SKILL covers fetch()-only upload/stream endpoints.', + '- Types: T refers to globally shared object schemas across skills.', + '- Images: Pipeline: search_images -> analyze_image -> upload via fetch() in javascript_execute. "image/" is read-only; write generated assets to "images/...".', + '- Labels: Use Dashback JSON `{ "objects": [ ... ] }` for /labeltemplate. Never use ZPL.', + '- Navigation: Call set_user_route when the user asks to open or view any page/entity.', ].join('\n'); export const SYSTEM_PROMPT_ROUTE_MATRIX = [ - 'ROUTE MATRIX (client routes German, API sections English; skills = api-
):', - '| Destination | Path | Example | API sections |', - '|:---|:---|:---|:---|', - '| Article Search | `/artikel?target={query}&filter={filter}&offset={n}` | `/artikel?target=kabel` | article, category, brand |', - '| Article Detail | `/artikel/${encodeURIComponent(sku)}` | `/artikel/ART-10042` | article, category, brand, attributename, propertyname, unit, supplier, printer, labeltemplate, ledger |', - '| Warehouse / Stock | `/artikel/lager` | `/artikel/lager` | warehouse, stock, ledger |', - '| Brands | `/artikel/marken` | `/artikel/marken` | brand |', - '| Label Templates | `/artikel/vorlagen` | `/artikel/vorlagen` | labeltemplate, printer |', - '| Attributes | `/artikel/merkmale` | `/artikel/merkmale` | attributename, attributevalue, propertyname |', - '| Category Root | `/kategorien` | `/kategorien` | category |', - '| Category Subtree | `/kategorien/${slug1}/${slug2}` (encoded slugs) | `/kategorien/elektronik/kabel` | category, article |', - '| Delivery List | `/lieferung` | `/lieferung` | delivery |', - '| New Delivery | `/lieferung/neu` | `/lieferung/neu` | delivery, supplier, article, warehouse, stock |', - '| Delivery Detail | `/lieferung/${deliveryId}` | `/lieferung/42` | delivery, supplier, ledger |', - '| Suppliers | `/lieferung/lieferanten` | `/lieferung/lieferanten` | supplier |', - '| Quote List | `/auftrag` | `/auftrag` | quote |', - '| New Quote | `/auftrag/neu` | `/auftrag/neu` | quote, entity, article |', - '| Quote Detail | `/auftrag/${quoteId}` | `/auftrag/1001` | quote, entity |', - '| Order List | `/auftrag/bestellung` | `/auftrag/bestellung` | order |', - '| New Order | `/auftrag/bestellung/neu` | `/auftrag/bestellung/neu` | order, entity, article |', - '| Order Detail | `/auftrag/bestellung/${orderId}` | `/auftrag/bestellung/2005` | order, entity, account, payment, shipping, package |', - '| Customer List | `/kunde` | `/kunde` | entity |', - '| New Customer | `/kunde/neu` | `/kunde/neu` | entity, customergroup, number |', - '| Customer Detail | `/kunde/${entityId}` | `/kunde/312` | entity, customergroup |', - '| Customer Groups | `/kunde/gruppen` | `/kunde/gruppen` | customergroup |', - '| Article History | `/infos/articlehistory` | `/infos/articlehistory` | article (`GET /article/{sku}/history`) |', - '| Global History | `/infos/globalhistory` | `/infos/globalhistory` | company (`GET /company/history`) |', - '| Statistics | `/infos/statistics` | `/infos/statistics` | none; aggregate from order, delivery, ledger |', + 'ROUTE MATRIX (client German, API skills = api-
):', + '- Search: /artikel?target={query}&filter={filter}&offset={n} -> article, category, brand', + '- Article Detail: /artikel/${sku} -> article, category, brand, attributename, propertyname, unit, supplier, printer, labeltemplate, ledger', + '- Warehouse / Stock: /artikel/lager -> warehouse, stock, ledger', + '- Brands: /artikel/marken -> brand', + '- Label Templates: /artikel/vorlagen -> labeltemplate, printer', + '- Attributes: /artikel/merkmale -> attributename, attributevalue, propertyname', + '- Categories: /kategorien | /kategorien/${slug1}/${slug2} -> category, article', + '- Deliveries: /lieferung | /lieferung/neu | /lieferung/${deliveryId} | /lieferung/lieferanten -> delivery, supplier, article, warehouse, stock, ledger', + '- Quotes: /auftrag | /auftrag/neu | /auftrag/${quoteId} -> quote, entity, article', + '- Orders: /auftrag/bestellung | /auftrag/bestellung/neu | /auftrag/bestellung/${orderId} -> order, entity, account, payment, shipping, package', + '- Customers: /kunde | /kunde/neu | /kunde/${entityId} | /kunde/gruppen -> entity, customergroup, number', + '- History & Stats: /infos/articlehistory | /infos/globalhistory | /infos/statistics -> article, company, order, delivery, ledger', ].join('\n'); // #endregion @@ -315,17 +262,12 @@ export const SYSTEM_PROMPT_ROUTE_MATRIX = [ /** * Builds the SKILL index block for the system prompt. * - * Listing the skills inline means the model knows what guidance exists BEFORE it decides what - * to do, so it can reach for `read_file` on the right skill instead of guessing a procedure - * from scratch. Only the filename, title and line count are included — the body is read on - * demand, which keeps the prompt small no matter how many skills exist. - * * @param {string} vfsRoot * @returns {string} */ export function buildSkillIndex(vfsRoot) { if (!vfsRoot) { - return 'AVAILABLE SKILLS: unknown (the virtual filesystem could not be read this turn). Call find_files({ skills: true }) to check.'; + return 'AVAILABLE SKILLS: unknown. Call find_files({ skills: true }) to verify.'; } let skills; @@ -333,21 +275,16 @@ export function buildSkillIndex(vfsRoot) { skills = listSkillFiles(vfsRoot); } catch (err) { console.warn('conversation: failed to list skill files:', err.message); - return 'AVAILABLE SKILLS: could not be read this turn. Call find_files({ skills: true }) to check.'; + return 'AVAILABLE SKILLS: unreadable this turn. Call find_files({ skills: true }) to verify.'; } if (skills.length === 0) { - return [ - 'AVAILABLE SKILLS: none. This company has no SKILL files yet.', - ].join('\n'); + return 'AVAILABLE SKILLS: none.'; } - const width = Math.max(...skills.map((s) => s.path.length)); return [ - `AVAILABLE SKILLS (${skills.length}): stored in the VFS root as flat .SKILL files.`, - 'Before starting a task that any of these cover, read the matching skill with read_file and follow it.', - '', - ...skills.map((s) => ` ${s.path.padEnd(width)} ${String(s.lines).padStart(4)} lines | ${s.title}`), + `AVAILABLE SKILLS (${skills.length}): stored in VFS root. Read with read_file before executing covered tasks.`, + ...skills.map((s) => `- ${s.path} (${s.lines} lines): ${s.title}`), ].join('\n'); } @@ -356,8 +293,7 @@ export function buildSkillIndex(vfsRoot) { // #region System Prompt /** - * System prompt: base instructions plus the generated API routes reference - * (docs/api/routes.md), read on each run so it stays current. + * System prompt: base instructions and contextual index. * * @param {string} vfsRoot Resolved VFS root for this user's company, used to list SKILL files. * @param {number} [googleAuthId] @@ -385,15 +321,11 @@ export async function buildSystemPrompt(vfsRoot, googleAuthId) { const basePrompt = [ 'QuixPOS Article Management System API Assistant', `Date: ${today}`, - '[TESTSYSTEM, destructive commands are allowed, main purpose of this system is to find bugs]', - '', - SYSTEM_PROMPT_VFS_RULES, - '', - buildSkillIndex(vfsRoot), + '[TESTSYSTEM: destructive commands allowed; primary goal is finding bugs]', '', SYSTEM_PROMPT_RULES, '', - SYSTEM_PROMPT_BINARY_UPLOAD, + buildSkillIndex(vfsRoot), '', SYSTEM_PROMPT_ROUTE_MATRIX, ].join('\n'); @@ -405,4 +337,4 @@ export async function buildSystemPrompt(vfsRoot, googleAuthId) { return sections.join('\n\n'); } -// #endregion +// #endregion \ No newline at end of file