Download src/core.ts from smlflg/PromptBoost: direct link, hf CLI and curl.
- Browser
- Download file 28.8 kB
-
https://huggingface.co/smlflg/PromptBoost/resolve/main/src/core.ts
- Command line
-
hf download hf://smlflg/PromptBoost/src/core.ts
-
curl -L -o core.ts https://huggingface.co/smlflg/PromptBoost/resolve/main/src/core.ts
28.8 kB
| import { | |
| defaultRubric, | |
| evalFixtures, | |
| harnessPolicies, | |
| modelAdapterProfiles, | |
| taskTypeHints | |
| } from "./profiles.ts"; | |
| import type { | |
| BoostedPrompt, | |
| EvalCase, | |
| EvalPlan, | |
| EvalResult, | |
| GenerateOptions, | |
| HarnessPolicy, | |
| InputAdequacy, | |
| JudgeRunner, | |
| ModelAdapterProfile, | |
| PromptScore, | |
| PromptScoreDimension, | |
| PromptRunner, | |
| TaskSpec, | |
| TaskType | |
| } from "./types.ts"; | |
| const intentPreservationRule = | |
| "Preserve the user's task intent. Clarify and operationalize it, but do not add a different task."; | |
| const stopWords = new Set([ | |
| "a", | |
| "an", | |
| "and", | |
| "aus", | |
| "das", | |
| "der", | |
| "die", | |
| "ein", | |
| "eine", | |
| "einer", | |
| "einen", | |
| "for", | |
| "from", | |
| "in", | |
| "of", | |
| "the", | |
| "to", | |
| "und", | |
| "zu" | |
| ]); | |
| export function analyzeUserPrompt(rawPrompt: string, options: Pick<GenerateOptions, "taskType"> = {}): TaskSpec { | |
| const normalizedPrompt = rawPrompt.trim(); | |
| const taskType = options.taskType || inferTaskType(normalizedPrompt); | |
| const hints = taskTypeHints[taskType]; | |
| const deliverables = unique(detectDeliverables(normalizedPrompt)); | |
| const constraints = unique([...detectConstraints(normalizedPrompt), intentPreservationRule]); | |
| const successCriteria = unique(detectSuccessCriteria(normalizedPrompt)); | |
| const inputs = unique(detectInputs(normalizedPrompt)); | |
| const ambiguities = detectAmbiguities(normalizedPrompt, taskType, deliverables); | |
| const inputAdequacy = assessInputAdequacy(normalizedPrompt, taskType, { | |
| inputs, | |
| deliverables, | |
| constraints, | |
| successCriteria, | |
| ambiguities | |
| }); | |
| return { | |
| id: createStableId("task", normalizedPrompt), | |
| rawUserPrompt: normalizedPrompt, | |
| taskType, | |
| goal: normalizeGoal(normalizedPrompt), | |
| inputs, | |
| deliverables, | |
| constraints, | |
| successCriteria, | |
| ambiguities, | |
| forbiddenChanges: [ | |
| "Do not change the objective or audience implied by the user.", | |
| "Do not assume harness capabilities that were not provided.", | |
| "Do not convert uncertainty into asserted facts." | |
| ], | |
| suggestedScaffolding: { | |
| inputs: hints.inputs, | |
| deliverables: hints.deliverables, | |
| constraints: hints.constraints, | |
| successCriteria: hints.successCriteria | |
| }, | |
| inputAdequacy | |
| }; | |
| } | |
| export function buildHarnessPrompt( | |
| taskSpec: TaskSpec, | |
| adapterProfile: ModelAdapterProfile = modelAdapterProfiles[0], | |
| harnessPolicy: HarnessPolicy = harnessPolicies[0] | |
| ): BoostedPrompt { | |
| const evalPlan = createEvalPlan(taskSpec, adapterProfile); | |
| const sections = [ | |
| section("Task Spec", formatTaskSpec(taskSpec)), | |
| section("Adapter-Suggested Scaffolding", formatSuggestedScaffolding(taskSpec)), | |
| section("Harness Policy", formatHarnessPolicy(harnessPolicy)), | |
| section("Model Adapter", formatModelAdapter(adapterProfile)), | |
| section("Execution Contract", formatExecutionContract(taskSpec, adapterProfile)), | |
| section("Verification", formatVerification(taskSpec, harnessPolicy, adapterProfile)), | |
| section("Output Contract", formatOutputContract(taskSpec, adapterProfile)), | |
| section("Eval Plan", formatEvalPlan(evalPlan)) | |
| ]; | |
| const prompt = [ | |
| "# PromptBoost Harness Prompt", | |
| "", | |
| "Use this as the complete prompt for a blank harness. It is intentionally plain text and provider-neutral.", | |
| "", | |
| ...sections.flatMap((item) => [`## ${item.label}`, item.body, ""]) | |
| ] | |
| .join("\n") | |
| .trim(); | |
| const boostedPrompt = { | |
| id: `${taskSpec.id}:${adapterProfile.id}:${harnessPolicy.id}`, | |
| rawUserPrompt: taskSpec.rawUserPrompt, | |
| taskSpec, | |
| harnessPolicy, | |
| modelProfile: adapterProfile, | |
| sections, | |
| prompt, | |
| evalPlan, | |
| rationale: [ | |
| "Task intent is preserved in a stable Task Spec.", | |
| "Observed user intent is separated from adapter-suggested scaffolding.", | |
| "Harness instructions stay blank and portable.", | |
| `Model-specific rules use the ${adapterProfile.label} failure-prevention profile.`, | |
| "The prompt includes a local heuristic score and an eval plan so quality can be tested instead of assumed." | |
| ], | |
| score: emptyScore(), | |
| inputAdequacy: taskSpec.inputAdequacy | |
| }; | |
| boostedPrompt.score = scorePrompt(boostedPrompt); | |
| return boostedPrompt; | |
| } | |
| export function generateBoostedPrompt(rawPrompt: string, options: GenerateOptions = {}): BoostedPrompt { | |
| const taskSpec = analyzeUserPrompt(rawPrompt, { taskType: options.taskType }); | |
| const adapterProfile = findModelProfile(options.modelProfileId); | |
| const harnessPolicy = findHarnessPolicy(options.harnessPolicyId); | |
| return buildHarnessPrompt(taskSpec, adapterProfile, harnessPolicy); | |
| } | |
| export function scorePrompt(candidate: BoostedPrompt | string, rubric = defaultRubric): PromptScore { | |
| const text = typeof candidate === "string" ? candidate : candidate.prompt; | |
| const taskSpec = typeof candidate === "string" ? undefined : candidate.taskSpec; | |
| const lower = text.toLowerCase(); | |
| const wordCount = countWords(text); | |
| const dimensions: PromptScoreDimension[] = rubric.map((dimension) => { | |
| switch (dimension.key) { | |
| case "task_preservation": | |
| return scoreDimension(dimension.key, dimension.label, taskPreservationScore(text, taskSpec)); | |
| case "input_adequacy": | |
| return scoreDimension(dimension.key, dimension.label, inputAdequacyScore(text, taskSpec)); | |
| case "deliverable_completeness": | |
| return scoreDimension(dimension.key, dimension.label, deliverableScore(lower, taskSpec)); | |
| case "format_clarity": | |
| return scoreDimension(dimension.key, dimension.label, formatScore(text)); | |
| case "grounding": | |
| return scoreDimension(dimension.key, dimension.label, groundingScore(lower)); | |
| case "verification": | |
| return scoreDimension(dimension.key, dimension.label, verificationScore(lower)); | |
| case "harness_portability": | |
| return scoreDimension(dimension.key, dimension.label, portabilityScore(lower)); | |
| case "bloat_control": | |
| return scoreDimension(dimension.key, dimension.label, bloatScore(wordCount)); | |
| default: | |
| return scoreDimension(dimension.key, dimension.label, { | |
| value: 3, | |
| evidence: "No scorer was registered for this dimension." | |
| }); | |
| } | |
| }); | |
| const weighted = dimensions.reduce((total, dimension) => { | |
| const rubricDimension = rubric.find((item) => item.key === dimension.key); | |
| return total + dimension.value * (rubricDimension?.weight || 1); | |
| }, 0); | |
| const weightSum = rubric.reduce((total, dimension) => total + dimension.weight, 0); | |
| let overall = Math.round((weighted / (weightSum * 5)) * 100); | |
| if (taskSpec?.inputAdequacy.status === "blocked") { | |
| overall = Math.min(overall, 35); | |
| } else if (taskSpec?.inputAdequacy.status === "needs_clarification") { | |
| overall = Math.min(overall, 59); | |
| } | |
| return { | |
| overall, | |
| grade: taskSpec?.inputAdequacy.status === "blocked" ? "blocked" : overall >= 82 ? "strong" : overall >= 62 ? "usable" : "weak", | |
| source: "prompt_shape_heuristic", | |
| dimensions, | |
| findings: buildScoreFindings(dimensions, overall) | |
| }; | |
| } | |
| export async function runEvalCase( | |
| evalCase: EvalCase, | |
| runner: PromptRunner, | |
| options: GenerateOptions = {}, | |
| judgeRunner?: JudgeRunner | |
| ): Promise<EvalResult> { | |
| const startedAt = performance.now(); | |
| const boostedPrompt = generateBoostedPrompt(evalCase.rawUserPrompt, { | |
| taskType: evalCase.taskType, | |
| ...options | |
| }); | |
| const output = await runner.run(boostedPrompt.prompt, evalCase, boostedPrompt); | |
| const score = judgeRunner | |
| ? await judgeRunner.judge(output, evalCase, boostedPrompt) | |
| : scorePrompt(boostedPrompt); | |
| return { | |
| caseId: evalCase.id, | |
| boostedPromptId: boostedPrompt.id, | |
| output: output.output, | |
| score, | |
| scoreSource: judgeRunner ? "judge" : "prompt_shape_heuristic", | |
| durationMs: Math.round(performance.now() - startedAt), | |
| metadata: output.metadata | |
| }; | |
| } | |
| export function compareAdapters(rawPrompt: string, options: Omit<GenerateOptions, "modelProfileId"> = {}) { | |
| return modelAdapterProfiles | |
| .map((profile) => generateBoostedPrompt(rawPrompt, { ...options, modelProfileId: profile.id })) | |
| .sort((left, right) => right.score.overall - left.score.overall); | |
| } | |
| export function runLocalFixtureComparison() { | |
| return evalFixtures.map((fixture) => { | |
| const results = compareAdapters(fixture.rawUserPrompt, { | |
| taskType: fixture.taskType, | |
| harnessPolicyId: "blank" | |
| }); | |
| const best = results[0]; | |
| return { | |
| fixture, | |
| best, | |
| results | |
| }; | |
| }); | |
| } | |
| export function findModelProfile(id = "gpt-openai"): ModelAdapterProfile { | |
| const profile = modelAdapterProfiles.find((item) => item.id === id); | |
| if (!profile) { | |
| throw new Error(`Unknown model adapter profile: ${id}`); | |
| } | |
| return profile; | |
| } | |
| export function findHarnessPolicy(id = "blank"): HarnessPolicy { | |
| const policy = harnessPolicies.find((item) => item.id === id); | |
| if (!policy) { | |
| throw new Error(`Unknown harness policy: ${id}`); | |
| } | |
| return policy; | |
| } | |
| export function inferTaskType(prompt: string): TaskType { | |
| const lower = prompt.toLowerCase(); | |
| const wordCount = countWords(prompt); | |
| const documentCue = /\b(pdf|dokument|document|file|datei|attached|beigefuegt|beigefügt|quelle|source)\b/.test(lower); | |
| const codebaseCue = /\b(bug|fix|patch|regression|module|modul|repo|codebase|implementiere|implement|failing test|tests? fail)\b/.test(lower); | |
| const summaryCue = /\b(summarize|summary|zusammenfass|fasse)\b/.test(lower) || /总结|摘要/.test(prompt); | |
| if (/\b(json|schema|felder|fields|extrahiere|extract|structured|objekt)\b/.test(lower)) { | |
| return "structured_extraction"; | |
| } | |
| if (codebaseCue && !/\b(code fence|code block|markdown code)\b/.test(lower)) { | |
| return "coding_patch"; | |
| } | |
| if (/\b(recherch|research|aktuellen|current|quellen|sources|entscheidungsvorlage)\b/.test(lower)) { | |
| return "research_synthesis"; | |
| } | |
| if (/\b(strategy|strategie|memo|risiken|risks|produktstrategie|roadmap)\b/.test(lower)) { | |
| return "strategic_memo"; | |
| } | |
| if (documentCue && summaryCue && wordCount > 2) { | |
| return "long_document"; | |
| } | |
| return "general"; | |
| } | |
| function createEvalPlan(taskSpec: TaskSpec, profile: ModelAdapterProfile): EvalPlan { | |
| return { | |
| rubric: defaultRubric, | |
| expectedFailureModes: unique([...profile.failureModes, ...taskSpec.ambiguities]), | |
| requiredChecks: unique([ | |
| "intent preservation", | |
| ...taskSpec.successCriteria, | |
| ...taskSpec.suggestedScaffolding.successCriteria.map((criterion) => `adapter-suggested: ${criterion}`), | |
| "final answer matches requested output format", | |
| "verification happened before finalization" | |
| ]), | |
| metadataFields: [ | |
| "promptVersion", | |
| "model", | |
| "harness", | |
| "runnerId", | |
| "runnerVersion", | |
| "durationMs", | |
| "tokensIn", | |
| "tokensOut", | |
| "costUsd", | |
| "observedFailureModes", | |
| "blockedChecks" | |
| ] | |
| }; | |
| } | |
| function formatTaskSpec(taskSpec: TaskSpec): string { | |
| return [ | |
| `Goal: ${taskSpec.goal}`, | |
| "", | |
| `Input adequacy: ${taskSpec.inputAdequacy.status} (${taskSpec.inputAdequacy.score}/100)`, | |
| list("Adequacy reasons", taskSpec.inputAdequacy.reasons), | |
| list("Adequacy warnings", taskSpec.inputAdequacy.warnings), | |
| "", | |
| list("Inputs", taskSpec.inputs), | |
| list("Deliverables", taskSpec.deliverables), | |
| list("Success criteria", taskSpec.successCriteria), | |
| list("Constraints", taskSpec.constraints), | |
| list("Known ambiguities to preserve or resolve", taskSpec.ambiguities), | |
| list("Forbidden changes", taskSpec.forbiddenChanges) | |
| ].join("\n"); | |
| } | |
| function formatSuggestedScaffolding(taskSpec: TaskSpec): string { | |
| return [ | |
| "These items are adapter-suggested scaffolding for execution quality. They are not claims about what the user explicitly requested.", | |
| list("Suggested inputs to confirm", taskSpec.suggestedScaffolding.inputs), | |
| list("Suggested supporting deliverables", taskSpec.suggestedScaffolding.deliverables), | |
| list("Suggested constraints", taskSpec.suggestedScaffolding.constraints), | |
| list("Suggested success checks", taskSpec.suggestedScaffolding.successCriteria) | |
| ].join("\n"); | |
| } | |
| function formatHarnessPolicy(policy: HarnessPolicy): string { | |
| return [ | |
| `${policy.label}:`, | |
| list("Runtime assumptions", policy.runtimeAssumptions), | |
| list("Tool rules", policy.toolRules), | |
| list("Artifact rules", policy.artifactRules), | |
| list("Verification rules", policy.verificationRules), | |
| list("Portability rules", policy.portabilityRules) | |
| ].join("\n"); | |
| } | |
| function formatModelAdapter(profile: ModelAdapterProfile): string { | |
| return [ | |
| `${profile.label}: ${profile.summary}`, | |
| `Evidence level: ${profile.evidence}`, | |
| `Evidence note: ${profile.evidenceNote}`, | |
| `Prompt style: ${profile.style}`, | |
| `Prompt pattern: ${profile.promptPattern}`, | |
| list("Adapter rules", profile.adapterRules), | |
| list("Expected failure modes", profile.failureModes) | |
| ].join("\n"); | |
| } | |
| function formatExecutionContract(taskSpec: TaskSpec, profile: ModelAdapterProfile): string { | |
| const steps = [ | |
| "Restate the objective internally as the Task Spec above and keep it stable.", | |
| "Identify the minimum work needed to produce each deliverable.", | |
| "Apply the Model Adapter rules only to reduce failure risk; do not use them to change the task.", | |
| "Produce the requested artifacts in a directly reusable format." | |
| ]; | |
| if (profile.explicitness >= 88 && profile.evidence !== "hypothesis") { | |
| steps.splice(2, 0, "Keep local analysis, checks, and final synthesis as separate phases."); | |
| } | |
| if (taskSpec.taskType === "structured_extraction") { | |
| steps.push("For structured data, return valid syntax and use null for unknown required fields."); | |
| } | |
| if (taskSpec.taskType === "coding_patch") { | |
| steps.push("For code, inspect the existing implementation before proposing or applying a fix."); | |
| } | |
| return list("Steps", steps); | |
| } | |
| function formatVerification( | |
| taskSpec: TaskSpec, | |
| policy: HarnessPolicy, | |
| profile: ModelAdapterProfile | |
| ): string { | |
| return [ | |
| list("Required verification checks", [ | |
| ...policy.verificationRules, | |
| ...taskSpec.successCriteria.map((criterion) => `Check ${criterion}.`), | |
| ...profile.failureModes.map((mode) => `Look specifically for ${mode}.`) | |
| ]), | |
| "", | |
| "If a check cannot be completed in the current harness, say which check is blocked and why." | |
| ].join("\n"); | |
| } | |
| function formatOutputContract(taskSpec: TaskSpec, profile: ModelAdapterProfile): string { | |
| if (taskSpec.taskType === "structured_extraction") { | |
| return [ | |
| "Return the final artifact as structured data only.", | |
| "- If the user specified JSON, return valid JSON and no surrounding prose.", | |
| "- Use null for required fields that are missing or unknown.", | |
| "- Put assumptions and verification notes only in separate metadata if the harness explicitly supports metadata; otherwise omit prose." | |
| ].join("\n"); | |
| } | |
| const lines = [ | |
| "Return the final answer with these sections:", | |
| "- Assumptions and resolved ambiguities", | |
| "- Final deliverables", | |
| "- Verification summary" | |
| ]; | |
| if (profile.examples >= 75 || taskSpec.taskType === "structured_extraction") { | |
| lines.push( | |
| "", | |
| "Minimal output pattern:", | |
| "```text", | |
| "Assumptions:", | |
| "- ...", | |
| "", | |
| "Deliverables:", | |
| "- ...", | |
| "", | |
| "Verification:", | |
| "- checked: ...", | |
| "- remaining risk: ...", | |
| "```" | |
| ); | |
| } | |
| return lines.join("\n"); | |
| } | |
| function formatEvalPlan(evalPlan: EvalPlan): string { | |
| return [ | |
| list( | |
| "Rubric dimensions", | |
| evalPlan.rubric.map((dimension) => `${dimension.label}: ${dimension.description}`) | |
| ), | |
| list("Expected failure modes", evalPlan.expectedFailureModes), | |
| list("Log these metadata fields for real eval runs", evalPlan.metadataFields) | |
| ].join("\n"); | |
| } | |
| function assessInputAdequacy( | |
| prompt: string, | |
| taskType: TaskType, | |
| observed: Pick<TaskSpec, "inputs" | "deliverables" | "constraints" | "successCriteria" | "ambiguities"> | |
| ): InputAdequacy { | |
| const words = countWords(prompt); | |
| const reasons = []; | |
| const warnings = []; | |
| let score = 0; | |
| if (!prompt) { | |
| return { | |
| status: "blocked", | |
| score: 0, | |
| reasons: ["The raw user prompt is empty."], | |
| warnings: ["No boosted prompt should be preferred until the user provides an actual task."] | |
| }; | |
| } | |
| if (words >= 8) score += 30; | |
| else if (words >= 4) score += 18; | |
| else score += 6; | |
| if (observed.deliverables.length) score += 20; | |
| else warnings.push("No explicit deliverable was detected in the user prompt."); | |
| if (observed.inputs.length) score += 15; | |
| else warnings.push("No concrete input/source was detected."); | |
| if (observed.constraints.length > 1) score += 15; | |
| else if (observed.constraints.length) score += 8; | |
| if (observed.successCriteria.length) score += 10; | |
| else warnings.push("No explicit success criterion was detected."); | |
| if (taskType !== "general") score += 10; | |
| else warnings.push("Task type is generic; adapter defaults may be broad."); | |
| if (taskType === "structured_extraction" && !hasExplicitSchema(prompt)) { | |
| score -= 18; | |
| warnings.push("Structured extraction was detected, but the exact output schema or field list is missing."); | |
| } | |
| if (taskType === "long_document" && !/\b(pdf|document|dokument|file|datei|source|quelle)\b/i.test(prompt)) { | |
| score -= 12; | |
| warnings.push("Summary intent was detected without a concrete document/source cue."); | |
| } | |
| score = clamp(score, 0, 100); | |
| reasons.push(`${words} word(s) in raw prompt.`); | |
| reasons.push(`${observed.deliverables.length} observed deliverable(s), ${observed.inputs.length} observed input(s).`); | |
| return { | |
| status: score < 25 ? "blocked" : score < 70 ? "needs_clarification" : "sufficient", | |
| score, | |
| reasons, | |
| warnings: warnings.length ? warnings : ["No major input adequacy warning detected."] | |
| }; | |
| } | |
| function normalizeGoal(prompt: string): string { | |
| const compact = prompt.replace(/\s+/g, " ").trim(); | |
| if (!compact) return "Complete the user's requested task."; | |
| return /[.!?。!?]$/.test(compact) ? compact : `${compact}.`; | |
| } | |
| function detectInputs(prompt: string): string[] { | |
| const lower = prompt.toLowerCase(); | |
| const inputs = []; | |
| if (/\bpdf|dokument|document|file|datei\b/.test(lower)) inputs.push("provided document or file"); | |
| if (/内容|文本|段/.test(prompt)) inputs.push("provided text/content"); | |
| if (/\bcode|modul|module|repo|codebase\b/.test(lower)) inputs.push("existing codebase or module"); | |
| if (/\bstichpunkte|notes|notizen\b/.test(lower)) inputs.push("user notes"); | |
| if (/\bquellen|sources|research|recherch\b/.test(lower)) inputs.push("verified sources"); | |
| return inputs; | |
| } | |
| function detectDeliverables(prompt: string): string[] { | |
| const lower = prompt.toLowerCase(); | |
| const deliverables = []; | |
| if (/\bmarkdown|md\b/.test(lower)) deliverables.push("Markdown output"); | |
| if (/\brender|render-skript|render script|export\b/.test(lower)) { | |
| deliverables.push("render script or export instructions"); | |
| } | |
| if (/\bjson|schema|objekt|object\b/.test(lower)) deliverables.push("valid structured object"); | |
| if (/\btest|tests|regression\b/.test(lower)) deliverables.push("tests or verification commands"); | |
| if (/\bmemo|entscheidungsvorlage|strategy|strategie\b/.test(lower)) deliverables.push("decision memo"); | |
| if (/\bzusammenfass|summary|summarize|fasse\b/.test(lower) || /总结|摘要/.test(prompt)) { | |
| deliverables.push("summary"); | |
| } | |
| return deliverables; | |
| } | |
| function detectConstraints(prompt: string): string[] { | |
| const lower = prompt.toLowerCase(); | |
| const constraints = []; | |
| if (/\bsource-faithful|quellentreu|grounded|quelle\b/.test(lower)) { | |
| constraints.push("Use only source-grounded claims and mark uncertainty."); | |
| } | |
| if (/\bknapp|concise|kurz\b/.test(lower)) constraints.push("Keep the output concise."); | |
| if (/\bvalides json|valid json\b/.test(lower)) constraints.push("Return syntactically valid JSON."); | |
| if (/\bsubagent|parallel|chunk\b/.test(lower)) { | |
| constraints.push("Separate local work from merge and verification phases."); | |
| } | |
| return constraints; | |
| } | |
| function detectSuccessCriteria(prompt: string): string[] { | |
| const lower = prompt.toLowerCase(); | |
| const criteria = []; | |
| if (/\bsource-faithful|quellentreu|grounded|quelle\b/.test(lower)) criteria.push("source faithfulness"); | |
| if (/\bvalides json|valid json\b/.test(lower)) criteria.push("valid JSON"); | |
| if (/\btest|tests\b/.test(lower)) criteria.push("passing tests"); | |
| if (/\bmarkdown\b/.test(lower)) criteria.push("usable Markdown"); | |
| if (/\brender\b/.test(lower)) criteria.push("render command works"); | |
| return criteria; | |
| } | |
| function detectAmbiguities(prompt: string, taskType: TaskType, deliverables: string[]): string[] { | |
| const ambiguities = []; | |
| const lower = prompt.toLowerCase(); | |
| if (prompt.trim().length < 80) { | |
| ambiguities.push("The source material, audience, and exact output depth may need confirmation."); | |
| } | |
| if (taskType === "long_document" && !/\bseiten|pages|length|umfang|15\b/.test(lower)) { | |
| ambiguities.push("Desired output length is not specified."); | |
| } | |
| if (taskType === "structured_extraction" && !hasExplicitSchema(prompt)) { | |
| ambiguities.push("The exact field schema is not specified."); | |
| } | |
| if (deliverables.length === 0) { | |
| ambiguities.push("The final deliverable format is underspecified."); | |
| } | |
| return ambiguities.length ? ambiguities : ["No major ambiguity detected; preserve any uncertainty found during execution."]; | |
| } | |
| function hasExplicitSchema(prompt: string): boolean { | |
| const lower = prompt.toLowerCase(); | |
| if (/\{[^}]+:[^}]+\}/.test(prompt)) return true; | |
| if (/\bfields?\s*:\s*\w+/i.test(prompt)) return true; | |
| if (/\bfelder\s*:\s*\w+/i.test(prompt)) return true; | |
| return /\b(email|name|datum|date|price|amount|id|status)\b/.test(lower) && /\bjson|schema|object|objekt\b/.test(lower); | |
| } | |
| function taskPreservationScore(text: string, taskSpec?: TaskSpec) { | |
| if (!taskSpec) { | |
| return { | |
| value: /preserve|intent|task/i.test(text) ? 4 : 3, | |
| evidence: "Scored from text only because no Task Spec object was provided." | |
| }; | |
| } | |
| const goalTokens = tokenize(taskSpec.goal); | |
| const promptTokens = new Set(tokenize(text)); | |
| const retained = goalTokens.filter((token) => promptTokens.has(token)).length; | |
| const ratio = goalTokens.length ? retained / goalTokens.length : 0; | |
| const value = ratio >= 0.65 ? 5 : ratio >= 0.45 ? 4 : ratio >= 0.28 ? 3 : 2; | |
| return { | |
| value, | |
| evidence: `${Math.round(ratio * 100)}% of meaningful goal tokens appear in the boosted prompt.` | |
| }; | |
| } | |
| function inputAdequacyScore(text: string, taskSpec?: TaskSpec) { | |
| if (!taskSpec) { | |
| const words = countWords(text); | |
| return { | |
| value: words >= 8 ? 3 : 2, | |
| evidence: "Estimated from text only because no raw Task Spec was provided." | |
| }; | |
| } | |
| return { | |
| value: | |
| taskSpec.inputAdequacy.status === "sufficient" | |
| ? 5 | |
| : taskSpec.inputAdequacy.status === "needs_clarification" | |
| ? 3 | |
| : 1, | |
| evidence: `${taskSpec.inputAdequacy.status}: ${taskSpec.inputAdequacy.warnings.join(" ")}` | |
| }; | |
| } | |
| function deliverableScore(lower: string, taskSpec?: TaskSpec) { | |
| if (!taskSpec) { | |
| const hasDeliverables = /deliverables|outputs|required artifacts|output contract/.test(lower); | |
| return { | |
| value: hasDeliverables ? 4 : 2, | |
| evidence: hasDeliverables ? "The prompt names deliverables." : "Deliverables are not explicit." | |
| }; | |
| } | |
| const observedHits = taskSpec.deliverables.filter((deliverable) => { | |
| const tokens = tokenize(deliverable); | |
| return tokens.some((token) => lower.includes(token)); | |
| }); | |
| const scaffoldingLabeled = lower.includes("adapter-suggested scaffolding") || lower.includes("suggested supporting deliverables"); | |
| if (!taskSpec.deliverables.length) { | |
| return { | |
| value: scaffoldingLabeled ? 3 : 2, | |
| evidence: "No explicit user deliverable was detected; only adapter-suggested scaffolding is available." | |
| }; | |
| } | |
| const ratio = observedHits.length / taskSpec.deliverables.length; | |
| return { | |
| value: ratio >= 0.9 && scaffoldingLabeled ? 5 : ratio >= 0.65 ? 4 : ratio >= 0.4 ? 3 : 2, | |
| evidence: `${observedHits.length}/${taskSpec.deliverables.length} observed deliverables are visible; scaffolding labeled=${scaffoldingLabeled}.` | |
| }; | |
| } | |
| function formatScore(text: string) { | |
| const headingCount = (text.match(/^##?\s/gm) || []).length; | |
| const listCount = (text.match(/^- /gm) || []).length; | |
| const value = headingCount >= 5 && listCount >= 12 ? 5 : headingCount >= 3 && listCount >= 6 ? 4 : 3; | |
| return { | |
| value, | |
| evidence: `${headingCount} headings and ${listCount} bullet lines detected.` | |
| }; | |
| } | |
| function groundingScore(lower: string) { | |
| const hits = ["source", "ground", "uncertain", "unsupported", "invent", "quelle", "uncertainty"].filter( | |
| (word) => lower.includes(word) | |
| ); | |
| return { | |
| value: hits.length >= 4 ? 5 : hits.length >= 3 ? 4 : hits.length >= 2 ? 3 : 2, | |
| evidence: `Grounding markers found: ${hits.join(", ") || "none"}.` | |
| }; | |
| } | |
| function verificationScore(lower: string) { | |
| const hits = ["verification", "verify", "check", "review", "pruef", "test"].filter((word) => | |
| lower.includes(word) | |
| ); | |
| return { | |
| value: hits.length >= 4 ? 5 : hits.length >= 3 ? 4 : hits.length >= 2 ? 3 : 2, | |
| evidence: `Verification markers found: ${hits.join(", ") || "none"}.` | |
| }; | |
| } | |
| function portabilityScore(lower: string) { | |
| const risky = ["subagent", "tool call", "function call", "system prompt", "<system>", "scratchpad"].filter( | |
| (word) => lower.includes(word) | |
| ); | |
| const hasPortable = lower.includes("provider-neutral") || lower.includes("blank harness") || lower.includes("plain text"); | |
| let value = hasPortable ? 5 : 4; | |
| if (risky.length >= 3) value = 3; | |
| if (risky.length >= 5) value = 2; | |
| return { | |
| value, | |
| evidence: risky.length | |
| ? `Potential runtime assumptions detected: ${risky.join(", ")}.` | |
| : "No major provider-specific runtime assumption detected." | |
| }; | |
| } | |
| function bloatScore(wordCount: number) { | |
| let value = 5; | |
| if (wordCount < 90) value = 3; | |
| if (wordCount > 760) value = 4; | |
| if (wordCount > 1100) value = 3; | |
| if (wordCount > 1600) value = 2; | |
| return { | |
| value, | |
| evidence: `${wordCount} words in generated prompt.` | |
| }; | |
| } | |
| function buildScoreFindings(dimensions: PromptScoreDimension[], overall: number): string[] { | |
| const findings = []; | |
| const weakDimensions = dimensions.filter((dimension) => dimension.value <= 3); | |
| const inputAdequacy = dimensions.find((dimension) => dimension.key === "input_adequacy"); | |
| if (inputAdequacy?.value === 1) { | |
| findings.push("Input is insufficient; collect a real user task before preferring this boosted prompt."); | |
| } else if (overall >= 82) { | |
| findings.push("The boosted prompt has strong prompt-shape signals for a first real eval run."); | |
| } else if (overall >= 62) { | |
| findings.push("The boosted prompt has usable prompt-shape signals, but low dimensions should be tightened before production."); | |
| } else { | |
| findings.push("The boosted prompt needs more input or structure before it should be preferred over the raw prompt."); | |
| } | |
| weakDimensions.forEach((dimension) => { | |
| findings.push(`${dimension.label} needs attention: ${dimension.evidence}`); | |
| }); | |
| return findings; | |
| } | |
| function scoreDimension( | |
| key: PromptScoreDimension["key"], | |
| label: string, | |
| result: { value: number; evidence: string } | |
| ): PromptScoreDimension { | |
| return { | |
| key, | |
| label, | |
| value: clamp(result.value, 1, 5), | |
| evidence: result.evidence | |
| }; | |
| } | |
| function emptyScore(): PromptScore { | |
| return { | |
| overall: 0, | |
| grade: "blocked", | |
| source: "unscored", | |
| dimensions: [], | |
| findings: [] | |
| }; | |
| } | |
| function section(label: string, body: string) { | |
| return { label, body }; | |
| } | |
| function list(title: string, items: string[]) { | |
| return [`${title}:`, ...(items.length ? items.map((item) => `- ${item}`) : ["- none observed"])].join("\n"); | |
| } | |
| function tokenize(value: string): string[] { | |
| return value | |
| .toLowerCase() | |
| .replace(/[^\p{L}0-9]+/gu, " ") | |
| .split(/\s+/) | |
| .map((token) => token.trim()) | |
| .filter((token) => token.length > 2 && !stopWords.has(token)); | |
| } | |
| function countWords(value: string) { | |
| return value.trim().split(/\s+/).filter(Boolean).length; | |
| } | |
| function unique<T>(items: T[]): T[] { | |
| return Array.from(new Set(items.filter(Boolean))); | |
| } | |
| function clamp(value: number, min: number, max: number) { | |
| return Math.max(min, Math.min(max, value)); | |
| } | |
| function createStableId(prefix: string, value: string) { | |
| let hash = 0; | |
| for (let index = 0; index < value.length; index += 1) { | |
| hash = (hash << 5) - hash + value.charCodeAt(index); | |
| hash |= 0; | |
| } | |
| return `${prefix}-${Math.abs(hash).toString(36)}`; | |
| } | |