Some checks failed
Monorepo Pipeline / ⚡ Prioritize Release (push) Successful in 1s
Monorepo Pipeline / 🧹 Lint (push) Failing after 35s
Monorepo Pipeline / 🧪 Test (push) Failing after 35s
Monorepo Pipeline / 🏗️ Build (push) Failing after 12s
Monorepo Pipeline / 🚀 Release (push) Has been skipped
Monorepo Pipeline / 🐳 Build Image Processor (push) Has been skipped
Monorepo Pipeline / 🐳 Build Directus (Base) (push) Has been skipped
Monorepo Pipeline / 🐳 Build Gatekeeper (Product) (push) Has been skipped
Monorepo Pipeline / 🐳 Build Build-Base (push) Has been skipped
Monorepo Pipeline / 🐳 Build Production Runtime (push) Has been skipped
111 lines
3.9 KiB
TypeScript
111 lines
3.9 KiB
TypeScript
// ============================================================================
|
|
// Step 02: Audit — Feature Auditor + Skeptical Review (Gemini Flash)
|
|
// ============================================================================
|
|
|
|
import { llmJsonRequest } from "../llm-client.js";
|
|
import type { ConceptState, StepResult, PipelineConfig } from "../types.js";
|
|
import { DEFAULT_MODELS } from "../types.js";
|
|
|
|
export async function executeAudit(
|
|
state: ConceptState,
|
|
config: PipelineConfig,
|
|
): Promise<StepResult> {
|
|
const models = { ...DEFAULT_MODELS, ...config.modelsOverride };
|
|
const startTime = Date.now();
|
|
|
|
if (!state.facts) {
|
|
return { success: false, error: "No facts from Step 01 available." };
|
|
}
|
|
|
|
const systemPrompt = `
|
|
You are a "Strict Cost Controller". Your mission is to prevent over-billing.
|
|
Review the extracted FEATURES against the BRIEFING and the EXISTING SITE ANALYSIS.
|
|
|
|
### RULE OF THUMB:
|
|
- A "Feature" (1.500 €) is ONLY justified for complex, dynamic systems (logic, database, CMS-driven management, advanced filtering).
|
|
- Simple lists, information sections, or static descriptions (e.g., "Messen", "Team", "Historie", "Jobs" as mere text) are ALWAYS "Pages" (600 €).
|
|
- If the briefing doesn't explicitly mention "Management System", "Filterable Database", or "Client Login", it is a PAGE.
|
|
|
|
### ADDITIONAL CHECKS:
|
|
1. If any feature maps to an entity that has its own external website (listed in EXTERNAL_DOMAINS), remove it entirely — it's out of scope.
|
|
2. Videos are ASSETS not pages. Remove any video-related entries from pages.
|
|
3. If the existing site has features (search, forms, etc.), ensure they are in the functions list.
|
|
|
|
### MISSION:
|
|
Return the corrected 'features', 'otherPages', and 'functions' arrays.
|
|
|
|
### OUTPUT FORMAT:
|
|
{
|
|
"features": string[],
|
|
"otherPages": string[],
|
|
"functions": string[],
|
|
"removedItems": [{ "item": string, "reason": string }],
|
|
"addedItems": [{ "item": string, "reason": string }]
|
|
}
|
|
`;
|
|
|
|
const userPrompt = `
|
|
EXTRACTED FACTS:
|
|
${JSON.stringify(state.facts, null, 2)}
|
|
|
|
BRIEFING:
|
|
${state.briefing}
|
|
|
|
EXTERNAL DOMAINS (have own websites, OUT OF SCOPE):
|
|
${state.siteProfile?.externalDomains?.join(", ") || "none"}
|
|
|
|
EXISTING FEATURES ON CURRENT SITE:
|
|
${state.siteProfile?.existingFeatures?.join(", ") || "none"}
|
|
`;
|
|
|
|
try {
|
|
const { data, usage } = await llmJsonRequest({
|
|
model: models.flash,
|
|
systemPrompt,
|
|
userPrompt,
|
|
apiKey: config.openrouterKey,
|
|
});
|
|
|
|
// Apply audit results to facts
|
|
const auditedFacts = { ...state.facts };
|
|
auditedFacts.features = data.features || [];
|
|
auditedFacts.otherPages = [
|
|
...new Set([...(auditedFacts.otherPages || []), ...(data.otherPages || [])]),
|
|
];
|
|
if (data.functions) {
|
|
auditedFacts.functions = [
|
|
...new Set([...(auditedFacts.functions || []), ...data.functions]),
|
|
];
|
|
}
|
|
|
|
// Log changes
|
|
if (data.removedItems?.length) {
|
|
console.log(" 📉 Audit removed:");
|
|
for (const item of data.removedItems) {
|
|
console.log(` - ${item.item}: ${item.reason}`);
|
|
}
|
|
}
|
|
if (data.addedItems?.length) {
|
|
console.log(" 📈 Audit added:");
|
|
for (const item of data.addedItems) {
|
|
console.log(` + ${item.item}: ${item.reason}`);
|
|
}
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
data: auditedFacts,
|
|
usage: {
|
|
step: "02-audit",
|
|
model: models.flash,
|
|
promptTokens: usage.promptTokens,
|
|
completionTokens: usage.completionTokens,
|
|
cost: usage.cost,
|
|
durationMs: Date.now() - startTime,
|
|
},
|
|
};
|
|
} catch (err) {
|
|
return { success: false, error: `Audit step failed: ${(err as Error).message}` };
|
|
}
|
|
}
|