-
Notifications
You must be signed in to change notification settings - Fork 1.5k
feat(orchestration): implement document extract prompt wrapper #1201
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| export class PromptOrchestrator { | ||
| private static readonly BASE_SYSTEM_PROMPT = `You are an automated data extraction API. You must output pure, valid JSON and absolutely nothing else. | ||
| Do NOT wrap your response in markdown code fences (e.g., do not use \`\`\` or \`\`\`json). | ||
| Do NOT include greetings, explanations, thoughts, or introductory text. | ||
|
|
||
| Your task is to parse the document based strictly on the user instructions and context. | ||
| Return a single JSON object where the keys represent the requested data points and values represent the exact extracted information. | ||
| Do not hallucinate, infer, or include outside information. If a field is missing from the document, set its value to null.`; | ||
|
|
||
| public static buildPrompt(userInstructions: string, documentContext: string): string { | ||
| return [ | ||
| this.BASE_SYSTEM_PROMPT, | ||
| "--- DOCUMENT CONTEXT ---", | ||
| documentContext, | ||
| "--- INSTRUCTIONS ---", | ||
| userInstructions.trim(), | ||
| ].join('\n\n'); | ||
|
Comment on lines
+10
to
+17
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win Send shared safety rules through the system message.
Return the shared rules as the actual 🤖 Prompt for AI Agents |
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,6 +10,7 @@ import { OutputFormats } from '../../constants/output-formats'; | |
| import { parseMarkdown } from '../../markdownify/markdown'; | ||
| import { DOCX_MIME_TYPE, PDF_MIME_TYPE, XLSX_MIME_TYPE, CSV_MIME_TYPE } from '../../utils/document/documentFile'; | ||
| import { assertLlmBaseUrlAllowed, resolveOpenAiApiKey } from '../../utils/llm-endpoint'; | ||
| import { PromptOrchestrator } from '../../utils/prompt-orchestrator'; | ||
|
|
||
| import * as XLSX from 'xlsx'; | ||
|
|
||
|
|
@@ -1428,14 +1429,10 @@ export class DocumentInterpreter { | |
| 'Prefer simple flat schemas unless the prompt clearly implies nested objects or arrays.', | ||
| ].join('\n'); | ||
|
|
||
| const userPrompt = [ | ||
| `Extraction goal: ${prompt}`, | ||
| '', | ||
| 'Sample document text:', | ||
| truncate(sampleText, MAX_SCHEMA_SAMPLE_CHARS), | ||
| ].join('\n'); | ||
| const documentContext = truncate(sampleText, MAX_SCHEMA_SAMPLE_CHARS); | ||
| const orchestratedUserPrompt = PromptOrchestrator.buildPrompt(prompt, documentContext); | ||
|
|
||
| return { systemPrompt, userPrompt }; | ||
| return { systemPrompt, userPrompt: orchestratedUserPrompt }; | ||
|
Comment on lines
+1432
to
+1435
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift Keep the shared policy in the system message.
The document context is untrusted. A document can contain instruction-like text or fake delimiters. That text can compete with the shared policy and cause schema or extraction instructions to be ignored. Change the orchestrator contract so the shared policy is passed as Also applies to: 1452-1461, 1483-1493 🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
| private static buildAtomicSchemaExpansionPrompt( | ||
|
|
@@ -1452,18 +1449,16 @@ export class DocumentInterpreter { | |
| '{"schema":{"field_key":{"label":"Field Label","type":"string|number|boolean|date|array|object","description":"...","required":true}}}', | ||
| ].join('\n'); | ||
|
|
||
| const userPrompt = [ | ||
| `Extraction goal: ${prompt}`, | ||
| '', | ||
| const documentContext = [ | ||
| `Current schema: ${JSON.stringify(schemaToJsonDefinition(currentSchema), null, 2)}`, | ||
| '', | ||
| 'Sample document text:', | ||
| truncate(sampleText, MAX_SCHEMA_SAMPLE_CHARS), | ||
| '', | ||
| 'Expand the schema into specific fields that can be extracted directly from the document.', | ||
| ].join('\n'); | ||
|
|
||
| return { systemPrompt, userPrompt }; | ||
| const orchestratedUserPrompt = PromptOrchestrator.buildPrompt(prompt, documentContext); | ||
|
|
||
| return { systemPrompt, userPrompt: orchestratedUserPrompt }; | ||
| } | ||
|
|
||
| private static buildExtractionPrompt( | ||
|
|
@@ -1485,17 +1480,17 @@ export class DocumentInterpreter { | |
| ? `\nDetected tables:\n${tables.map((table, index) => `Table ${index + 1}\n${table.map((row) => row.join(' | ')).join('\n')}`).join('\n\n')}` | ||
| : ''; | ||
|
|
||
| const userPrompt = [ | ||
| `Extraction goal: ${prompt}`, | ||
| '', | ||
| const documentContext = [ | ||
| `Schema: ${JSON.stringify(schemaToJsonDefinition(schema), null, 2)}`, | ||
| '', | ||
| `Document chunk pages: ${chunk.pageRange}`, | ||
| truncate(chunk.text, MAX_CHUNK_CHARS), | ||
| tableContext, | ||
| tableContext | ||
| ].join('\n'); | ||
|
|
||
| return { systemPrompt, userPrompt }; | ||
| // Route through the new PromptOrchestrator | ||
| const orchestratedUserPrompt = PromptOrchestrator.buildPrompt(prompt, documentContext); | ||
|
|
||
| return { systemPrompt, userPrompt: orchestratedUserPrompt }; | ||
| } | ||
|
|
||
| static async extractText(buffer: Buffer, documentMimeType: string = PDF_MIME_TYPE): Promise<{ text: string; pageCount: number }> { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Use task-specific base prompts for schema generation.
BASE_SYSTEM_PROMPTinstructs the model to extract document values.DocumentInterpreter.buildSchemaPromptandbuildAtomicSchemaExpansionPromptalso use this prompt, although those methods must return schema definitions. The conflicting instructions can produce value-shaped output, whichsanitizeSchemamay interpret as incomplete string-only field definitions.Keep the shared prompt task-neutral, or use separate base prompts for schema generation, schema expansion, and data extraction.
🤖 Prompt for AI Agents