Phase 2 and 3 of the platform rework. - Neutral request/response contract: external_id, metadata, X-AI-Key, run_id in the response; client-specific fields removed. - AI profile is a revision table: saving creates an inactive revision, activation is separate, try-run does not store a run. One chat-completions gateway serves AIHub and OpenAI-compatible profiles. - Add between and in rule operators. - Contracts moved to contracts/lead-scoring/ with a score-response fixture. - Admin Web updated for revisions, runs and the neutral fixture. - Consolidate tests; remove rewrite_architect.md and the stale handoff doc; rewrite spec, CONTEXT and ARCHITECTURE for the current design. Not verified: live AIHub/OpenAI behavior, Omni/EMS integration.
46 lines
1.7 KiB
TypeScript
46 lines
1.7 KiB
TypeScript
import { env } from '$env/dynamic/private';
|
|
import type { RequestEvent } from '@sveltejs/kit';
|
|
import type { components } from '$lib/generated/api';
|
|
import fixture from '../../../../../contracts/lead-scoring/fixtures/run-request.json';
|
|
|
|
export type RunRequest = components['schemas']['RunRequest'];
|
|
export const scoringFixture = fixture as RunRequest;
|
|
|
|
export class FixtureRunnerNotConfigured extends Error {}
|
|
|
|
export function fixtureRunnerConfigured(): boolean {
|
|
return Boolean(env.LEAD_SCORING_FIXTURE_APP_API_KEY?.trim());
|
|
}
|
|
|
|
export async function submitScoringFixture(event: RequestEvent, useAI = false): Promise<Response> {
|
|
const base = env.BACKEND_INTERNAL_URL;
|
|
const appKey = env.LEAD_SCORING_FIXTURE_APP_API_KEY?.trim();
|
|
if (!appKey) throw new FixtureRunnerNotConfigured();
|
|
if (!base || !/^https?:\/\//.test(base)) {
|
|
throw new Error('BACKEND_INTERNAL_URL must be configured on the server');
|
|
}
|
|
|
|
const request: RunRequest = {
|
|
...scoringFixture,
|
|
scoring_config: {
|
|
...scoringFixture.scoring_config,
|
|
rule_weight: useAI ? 0.5 : 1,
|
|
ai_weight: useAI ? 0.5 : 0,
|
|
},
|
|
};
|
|
const aiKey = env.LEAD_SCORING_FIXTURE_AI_KEY?.trim();
|
|
return event.fetch(`${base.replace(/\/$/, '')}/v1/lead-scoring/score`, {
|
|
method: 'POST',
|
|
cache: 'no-store',
|
|
redirect: 'error',
|
|
headers: {
|
|
accept: 'application/json',
|
|
authorization: `Bearer ${appKey}`,
|
|
'content-type': 'application/json',
|
|
'Idempotency-Key': crypto.randomUUID(),
|
|
...(useAI && aiKey ? { 'X-AI-Key': aiKey } : {}),
|
|
},
|
|
body: JSON.stringify(request),
|
|
});
|
|
}
|