@oscharko-dev/keiko-model-gateway 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -0
- package/dist/capabilities.d.ts +26 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.data.d.ts +3 -0
- package/dist/capabilities.data.d.ts.map +1 -0
- package/dist/capabilities.data.js +5 -0
- package/dist/capabilities.js +169 -0
- package/dist/config.d.ts +34 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +733 -0
- package/dist/embedding.d.ts +38 -0
- package/dist/embedding.d.ts.map +1 -0
- package/dist/embedding.js +118 -0
- package/dist/gateway.d.ts +23 -0
- package/dist/gateway.d.ts.map +1 -0
- package/dist/gateway.js +144 -0
- package/dist/http.d.ts +24 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +666 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/model-selection.d.ts +22 -0
- package/dist/model-selection.d.ts.map +1 -0
- package/dist/model-selection.js +59 -0
- package/dist/normalize.d.ts +9 -0
- package/dist/normalize.d.ts.map +1 -0
- package/dist/normalize.js +114 -0
- package/dist/openai-adapter.d.ts +22 -0
- package/dist/openai-adapter.d.ts.map +1 -0
- package/dist/openai-adapter.js +382 -0
- package/dist/openai-embedding-adapter.d.ts +46 -0
- package/dist/openai-embedding-adapter.d.ts.map +1 -0
- package/dist/openai-embedding-adapter.js +271 -0
- package/dist/promptEnhancer/__tests__/_support.d.ts +15 -0
- package/dist/promptEnhancer/__tests__/_support.d.ts.map +1 -0
- package/dist/promptEnhancer/__tests__/_support.js +28 -0
- package/dist/promptEnhancer/__tests__/fixtures.d.ts +8 -0
- package/dist/promptEnhancer/__tests__/fixtures.d.ts.map +1 -0
- package/dist/promptEnhancer/__tests__/fixtures.js +58 -0
- package/dist/promptEnhancer/__tests__/grounding-fixtures.d.ts +11 -0
- package/dist/promptEnhancer/__tests__/grounding-fixtures.d.ts.map +1 -0
- package/dist/promptEnhancer/__tests__/grounding-fixtures.js +84 -0
- package/dist/promptEnhancer/candidates.d.ts +32 -0
- package/dist/promptEnhancer/candidates.d.ts.map +1 -0
- package/dist/promptEnhancer/candidates.js +109 -0
- package/dist/promptEnhancer/critic.d.ts +22 -0
- package/dist/promptEnhancer/critic.d.ts.map +1 -0
- package/dist/promptEnhancer/critic.js +237 -0
- package/dist/promptEnhancer/generator.d.ts +15 -0
- package/dist/promptEnhancer/generator.d.ts.map +1 -0
- package/dist/promptEnhancer/generator.js +424 -0
- package/dist/promptEnhancer/index.d.ts +16 -0
- package/dist/promptEnhancer/index.d.ts.map +1 -0
- package/dist/promptEnhancer/index.js +15 -0
- package/dist/promptEnhancer/optimize.d.ts +27 -0
- package/dist/promptEnhancer/optimize.d.ts.map +1 -0
- package/dist/promptEnhancer/optimize.js +203 -0
- package/dist/promptEnhancer/planner.d.ts +36 -0
- package/dist/promptEnhancer/planner.d.ts.map +1 -0
- package/dist/promptEnhancer/planner.js +55 -0
- package/dist/promptEnhancer/profiles.d.ts +20 -0
- package/dist/promptEnhancer/profiles.d.ts.map +1 -0
- package/dist/promptEnhancer/profiles.js +126 -0
- package/dist/promptEnhancer/rendering.d.ts +15 -0
- package/dist/promptEnhancer/rendering.d.ts.map +1 -0
- package/dist/promptEnhancer/rendering.js +72 -0
- package/dist/promptEnhancer/validate.d.ts +31 -0
- package/dist/promptEnhancer/validate.d.ts.map +1 -0
- package/dist/promptEnhancer/validate.js +144 -0
- package/dist/qualityIntelligence/budget.d.ts +10 -0
- package/dist/qualityIntelligence/budget.d.ts.map +1 -0
- package/dist/qualityIntelligence/budget.js +38 -0
- package/dist/qualityIntelligence/cancellation.d.ts +7 -0
- package/dist/qualityIntelligence/cancellation.d.ts.map +1 -0
- package/dist/qualityIntelligence/cancellation.js +58 -0
- package/dist/qualityIntelligence/capabilityGate.d.ts +13 -0
- package/dist/qualityIntelligence/capabilityGate.d.ts.map +1 -0
- package/dist/qualityIntelligence/capabilityGate.js +51 -0
- package/dist/qualityIntelligence/capabilityMapping.d.ts +4 -0
- package/dist/qualityIntelligence/capabilityMapping.d.ts.map +1 -0
- package/dist/qualityIntelligence/capabilityMapping.js +21 -0
- package/dist/qualityIntelligence/circuitBreaker.d.ts +26 -0
- package/dist/qualityIntelligence/circuitBreaker.d.ts.map +1 -0
- package/dist/qualityIntelligence/circuitBreaker.js +78 -0
- package/dist/qualityIntelligence/dispatcher.d.ts +38 -0
- package/dist/qualityIntelligence/dispatcher.d.ts.map +1 -0
- package/dist/qualityIntelligence/dispatcher.js +116 -0
- package/dist/qualityIntelligence/index.d.ts +20 -0
- package/dist/qualityIntelligence/index.d.ts.map +1 -0
- package/dist/qualityIntelligence/index.js +15 -0
- package/dist/qualityIntelligence/promptSegmentation.d.ts +13 -0
- package/dist/qualityIntelligence/promptSegmentation.d.ts.map +1 -0
- package/dist/qualityIntelligence/promptSegmentation.js +70 -0
- package/dist/qualityIntelligence/replayCache.d.ts +11 -0
- package/dist/qualityIntelligence/replayCache.d.ts.map +1 -0
- package/dist/qualityIntelligence/replayCache.js +72 -0
- package/dist/qualityIntelligence/routing.d.ts +11 -0
- package/dist/qualityIntelligence/routing.d.ts.map +1 -0
- package/dist/qualityIntelligence/routing.js +25 -0
- package/dist/qualityIntelligence/safeError.d.ts +38 -0
- package/dist/qualityIntelligence/safeError.d.ts.map +1 -0
- package/dist/qualityIntelligence/safeError.js +63 -0
- package/dist/qualityIntelligence/taskProfiles.d.ts +15 -0
- package/dist/qualityIntelligence/taskProfiles.d.ts.map +1 -0
- package/dist/qualityIntelligence/taskProfiles.js +101 -0
- package/dist/resilience.d.ts +26 -0
- package/dist/resilience.d.ts.map +1 -0
- package/dist/resilience.js +182 -0
- package/dist/types.d.ts +59 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +3 -0
- package/package.json +47 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { OutboundHttpEgressConfig } from "./types.js";
|
|
2
|
+
export interface OpenAIEmbeddingRequest {
|
|
3
|
+
readonly endpoint: string;
|
|
4
|
+
readonly apiKey: string;
|
|
5
|
+
readonly apiKeyHeaderName?: string;
|
|
6
|
+
readonly modelId: string;
|
|
7
|
+
readonly input: string;
|
|
8
|
+
readonly signal?: AbortSignal;
|
|
9
|
+
readonly timeoutMs?: number;
|
|
10
|
+
readonly fetchImpl?: typeof fetch;
|
|
11
|
+
readonly egress?: OutboundHttpEgressConfig | undefined;
|
|
12
|
+
}
|
|
13
|
+
export interface OpenAIEmbeddingSuccess {
|
|
14
|
+
readonly vector: Float32Array;
|
|
15
|
+
readonly modelId: string;
|
|
16
|
+
readonly modelRevision?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface OpenAIEmbeddingBatchRequest {
|
|
19
|
+
readonly endpoint: string;
|
|
20
|
+
readonly apiKey: string;
|
|
21
|
+
readonly apiKeyHeaderName?: string;
|
|
22
|
+
readonly modelId: string;
|
|
23
|
+
readonly inputs: readonly string[];
|
|
24
|
+
readonly signal?: AbortSignal;
|
|
25
|
+
readonly timeoutMs?: number;
|
|
26
|
+
readonly fetchImpl?: typeof fetch;
|
|
27
|
+
readonly egress?: OutboundHttpEgressConfig | undefined;
|
|
28
|
+
}
|
|
29
|
+
export type OpenAIEmbeddingBatchOutcome = {
|
|
30
|
+
readonly ok: true;
|
|
31
|
+
readonly value: readonly OpenAIEmbeddingSuccess[];
|
|
32
|
+
} | {
|
|
33
|
+
readonly ok: false;
|
|
34
|
+
readonly kind: OpenAIEmbeddingErrorKind;
|
|
35
|
+
};
|
|
36
|
+
export type OpenAIEmbeddingOutcome = {
|
|
37
|
+
readonly ok: true;
|
|
38
|
+
readonly value: OpenAIEmbeddingSuccess;
|
|
39
|
+
} | {
|
|
40
|
+
readonly ok: false;
|
|
41
|
+
readonly kind: OpenAIEmbeddingErrorKind;
|
|
42
|
+
};
|
|
43
|
+
export type OpenAIEmbeddingErrorKind = "wrong-header" | "rate-limited" | "unsupported-model" | "timeout" | "cancelled" | "transport" | "proxy-unreachable" | "proxy-auth-required" | "proxy-egress-failed" | "proxy-blocked-by-policy" | "tls-ca-failure" | "invalid-response";
|
|
44
|
+
export declare function requestOpenAIEmbedding(request: OpenAIEmbeddingRequest): Promise<OpenAIEmbeddingOutcome>;
|
|
45
|
+
export declare function requestOpenAIEmbeddingBatch(request: OpenAIEmbeddingBatchRequest): Promise<OpenAIEmbeddingBatchOutcome>;
|
|
46
|
+
//# sourceMappingURL=openai-embedding-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-embedding-adapter.d.ts","sourceRoot":"","sources":["../src/openai-embedding-adapter.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAE3D,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IAClC,QAAQ,CAAC,MAAM,CAAC,EAAE,wBAAwB,GAAG,SAAS,CAAC;CACxD;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC;AAQD,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IAClC,QAAQ,CAAC,MAAM,CAAC,EAAE,wBAAwB,GAAG,SAAS,CAAC;CACxD;AAED,MAAM,MAAM,2BAA2B,GAEnC;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,sBAAsB,EAAE,CAAA;CAAE,GACxE;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,wBAAwB,CAAA;CAAE,CAAC;AAEpE,MAAM,MAAM,sBAAsB,GAC9B;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,sBAAsB,CAAA;CAAE,GAC7D;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,wBAAwB,CAAA;CAAE,CAAC;AAEpE,MAAM,MAAM,wBAAwB,GAChC,cAAc,GACd,cAAc,GACd,mBAAmB,GACnB,SAAS,GACT,WAAW,GACX,WAAW,GACX,mBAAmB,GACnB,qBAAqB,GACrB,qBAAqB,GACrB,yBAAyB,GACzB,gBAAgB,GAChB,kBAAkB,CAAC;AAoLvB,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,sBAAsB,CAAC,CAYjC;AAuHD,wBAAsB,2BAA2B,CAC/C,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,2BAA2B,CAAC,CAetC"}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
// OpenAI-compatible embeddings adapter. Builds on globalThis.fetch only (no SDK
|
|
2
|
+
// dependency), mirroring openai-adapter.ts. Surfaces only structural status
|
|
3
|
+
// information; the raw provider body never escapes this module.
|
|
4
|
+
import { apiKeyHeaderValue } from "./config.js";
|
|
5
|
+
import { gatewayFetch, OutboundHttpEgressError, readJsonCapped, } from "./http.js";
|
|
6
|
+
const OUTBOUND_EMBEDDING_KINDS = {
|
|
7
|
+
PROXY_UNREACHABLE: "proxy-unreachable",
|
|
8
|
+
PROXY_AUTH_REQUIRED: "proxy-auth-required",
|
|
9
|
+
PROXY_EGRESS_FAILED: "proxy-egress-failed",
|
|
10
|
+
PROXY_BLOCKED_BY_POLICY: "proxy-blocked-by-policy",
|
|
11
|
+
TLS_CA_FAILURE: "tls-ca-failure",
|
|
12
|
+
};
|
|
13
|
+
function isRecord(value) {
|
|
14
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
15
|
+
}
|
|
16
|
+
function isNumberArray(value) {
|
|
17
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === "number");
|
|
18
|
+
}
|
|
19
|
+
function extractFirstEmbedding(payload) {
|
|
20
|
+
const data = payload.data;
|
|
21
|
+
if (!Array.isArray(data) || data.length === 0) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
const first = data[0];
|
|
25
|
+
if (!isRecord(first)) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
const embedding = first.embedding;
|
|
29
|
+
if (!isNumberArray(embedding) || embedding.length === 0) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
return embedding;
|
|
33
|
+
}
|
|
34
|
+
function parseEmbeddingShape(payload) {
|
|
35
|
+
if (!isRecord(payload)) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
const embedding = extractFirstEmbedding(payload);
|
|
39
|
+
if (embedding === null) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
const model = typeof payload.model === "string" ? payload.model : undefined;
|
|
43
|
+
const modelRevision = typeof payload.model_revision === "string" ? payload.model_revision : undefined;
|
|
44
|
+
return {
|
|
45
|
+
embedding,
|
|
46
|
+
...(model !== undefined ? { model } : {}),
|
|
47
|
+
...(modelRevision !== undefined ? { modelRevision } : {}),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function joinUrl(endpoint) {
|
|
51
|
+
const trimmed = endpoint.endsWith("/") ? endpoint.slice(0, -1) : endpoint;
|
|
52
|
+
return `${trimmed}/embeddings`;
|
|
53
|
+
}
|
|
54
|
+
function headerName(name) {
|
|
55
|
+
if (name === undefined || name.trim().length === 0) {
|
|
56
|
+
return "authorization";
|
|
57
|
+
}
|
|
58
|
+
return name.toLowerCase();
|
|
59
|
+
}
|
|
60
|
+
function classifyStatus(status) {
|
|
61
|
+
if (status === 401 || status === 403)
|
|
62
|
+
return "wrong-header";
|
|
63
|
+
if (status === 429)
|
|
64
|
+
return "rate-limited";
|
|
65
|
+
if (status === 404)
|
|
66
|
+
return "unsupported-model";
|
|
67
|
+
if (status >= 400)
|
|
68
|
+
return "transport";
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
// Distinguishes our own internal-timeout abort from a caller-driven cancellation. If our
|
|
72
|
+
// internal `timeoutSignal` is aborted, it's a timeout. Otherwise, if the caller's signal is
|
|
73
|
+
// aborted (passed via `callerSignal`), it's a user cancellation. Anything else is a
|
|
74
|
+
// transport error. Without this distinction, callers cannot tell whether their user
|
|
75
|
+
// pressed Cancel or the server hung. #192 Copilot finding.
|
|
76
|
+
function classifyDispatchError(error, timeoutSignal, callerSignal) {
|
|
77
|
+
if (callerSignal?.aborted === true)
|
|
78
|
+
return "cancelled";
|
|
79
|
+
if (error instanceof OutboundHttpEgressError)
|
|
80
|
+
return OUTBOUND_EMBEDDING_KINDS[error.code];
|
|
81
|
+
if (timeoutSignal.aborted)
|
|
82
|
+
return "timeout";
|
|
83
|
+
if (error instanceof DOMException && error.name === "TimeoutError")
|
|
84
|
+
return "timeout";
|
|
85
|
+
// A bare AbortError without either of our signals being aborted is a transport error
|
|
86
|
+
// (e.g. the fetch impl tore down its own internal controller). Mapping it to `cancelled`
|
|
87
|
+
// would misattribute the failure to the caller — #192 Copilot follow-up finding.
|
|
88
|
+
return "transport";
|
|
89
|
+
}
|
|
90
|
+
function buildRequest(request) {
|
|
91
|
+
const name = headerName(request.apiKeyHeaderName);
|
|
92
|
+
// Reuse the shared Bearer-prefixing helper from config.ts so this transport handles the
|
|
93
|
+
// same `bearer ` / `x-litellm-key` / `api-key` cases the chat adapter handles, including
|
|
94
|
+
// already-prefixed inputs. #192 Copilot finding.
|
|
95
|
+
const headers = {
|
|
96
|
+
"content-type": "application/json",
|
|
97
|
+
[name]: apiKeyHeaderValue(name, request.apiKey),
|
|
98
|
+
};
|
|
99
|
+
const body = JSON.stringify({ model: request.modelId, input: request.input });
|
|
100
|
+
const timeoutSignal = AbortSignal.timeout(request.timeoutMs ?? 30_000);
|
|
101
|
+
const signal = request.signal !== undefined ? AbortSignal.any([timeoutSignal, request.signal]) : timeoutSignal;
|
|
102
|
+
return {
|
|
103
|
+
url: joinUrl(request.endpoint),
|
|
104
|
+
headers,
|
|
105
|
+
body,
|
|
106
|
+
signal,
|
|
107
|
+
timeoutSignal,
|
|
108
|
+
callerSignal: request.signal,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
async function discardBody(response) {
|
|
112
|
+
try {
|
|
113
|
+
await readJsonCapped(response);
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// ignore — body discarded intentionally
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
async function dispatch(built, fetchImpl, egress) {
|
|
120
|
+
try {
|
|
121
|
+
return await gatewayFetch(built.url, {
|
|
122
|
+
method: "POST",
|
|
123
|
+
headers: built.headers,
|
|
124
|
+
body: built.body,
|
|
125
|
+
signal: built.signal,
|
|
126
|
+
...(fetchImpl !== undefined ? { fetchImpl } : {}),
|
|
127
|
+
...(egress !== undefined ? { egress } : {}),
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
return classifyDispatchError(error, built.timeoutSignal, built.callerSignal);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
async function decodeSuccess(response, request) {
|
|
135
|
+
let payload;
|
|
136
|
+
try {
|
|
137
|
+
payload = await readJsonCapped(response);
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
return { ok: false, kind: "invalid-response" };
|
|
141
|
+
}
|
|
142
|
+
const shape = parseEmbeddingShape(payload);
|
|
143
|
+
if (shape === null) {
|
|
144
|
+
return { ok: false, kind: "invalid-response" };
|
|
145
|
+
}
|
|
146
|
+
const vector = Float32Array.from(shape.embedding);
|
|
147
|
+
const modelId = shape.model ?? request.modelId;
|
|
148
|
+
const value = shape.modelRevision !== undefined
|
|
149
|
+
? { vector, modelId, modelRevision: shape.modelRevision }
|
|
150
|
+
: { vector, modelId };
|
|
151
|
+
return { ok: true, value };
|
|
152
|
+
}
|
|
153
|
+
export async function requestOpenAIEmbedding(request) {
|
|
154
|
+
const built = buildRequest(request);
|
|
155
|
+
const dispatched = await dispatch(built, request.fetchImpl, request.egress);
|
|
156
|
+
if (typeof dispatched === "string") {
|
|
157
|
+
return { ok: false, kind: dispatched };
|
|
158
|
+
}
|
|
159
|
+
if (!dispatched.ok) {
|
|
160
|
+
const kind = classifyStatus(dispatched.status) ?? "transport";
|
|
161
|
+
await discardBody(dispatched);
|
|
162
|
+
return { ok: false, kind };
|
|
163
|
+
}
|
|
164
|
+
return decodeSuccess(dispatched, request);
|
|
165
|
+
}
|
|
166
|
+
// ─── Array-batch transport (#189 GRD-004) ────────────────────────────────────
|
|
167
|
+
function buildBatchRequest(request) {
|
|
168
|
+
const name = headerName(request.apiKeyHeaderName);
|
|
169
|
+
const headers = {
|
|
170
|
+
"content-type": "application/json",
|
|
171
|
+
[name]: apiKeyHeaderValue(name, request.apiKey),
|
|
172
|
+
};
|
|
173
|
+
// OpenAI-compatible body: `input` is the array. Identical envelope to the scalar path
|
|
174
|
+
// except the array value, so the same gateway/TLS/egress handling applies.
|
|
175
|
+
const body = JSON.stringify({ model: request.modelId, input: request.inputs });
|
|
176
|
+
const timeoutSignal = AbortSignal.timeout(request.timeoutMs ?? 30_000);
|
|
177
|
+
const signal = request.signal !== undefined ? AbortSignal.any([timeoutSignal, request.signal]) : timeoutSignal;
|
|
178
|
+
return {
|
|
179
|
+
url: joinUrl(request.endpoint),
|
|
180
|
+
headers,
|
|
181
|
+
body,
|
|
182
|
+
signal,
|
|
183
|
+
timeoutSignal,
|
|
184
|
+
callerSignal: request.signal,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
// Resolve the slot index for one `data[]` entry, or -1 if its index is missing, non-integer,
|
|
188
|
+
// out of range, or already filled (duplicate).
|
|
189
|
+
function batchSlotIndex(item, count, slots) {
|
|
190
|
+
const index = typeof item.index === "number" ? item.index : -1;
|
|
191
|
+
if (!Number.isInteger(index) || index < 0 || index >= count)
|
|
192
|
+
return -1;
|
|
193
|
+
return slots[index] === undefined ? index : -1;
|
|
194
|
+
}
|
|
195
|
+
function buildBatchSuccess(item, embedding, ctx) {
|
|
196
|
+
const modelId = (typeof item.model === "string" ? item.model : undefined) ?? ctx.topModel ?? ctx.requestModelId;
|
|
197
|
+
return {
|
|
198
|
+
vector: Float32Array.from(embedding),
|
|
199
|
+
modelId,
|
|
200
|
+
...(ctx.topRevision !== undefined ? { modelRevision: ctx.topRevision } : {}),
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
// Validate one `data[]` entry and place it at its declared `index`. Returns false on any
|
|
204
|
+
// malformed/duplicate/out-of-range item so the caller can fail the whole batch.
|
|
205
|
+
function placeBatchItem(item, ctx, slots) {
|
|
206
|
+
if (!isRecord(item))
|
|
207
|
+
return false;
|
|
208
|
+
const index = batchSlotIndex(item, ctx.count, slots);
|
|
209
|
+
if (index < 0)
|
|
210
|
+
return false;
|
|
211
|
+
const embedding = item.embedding;
|
|
212
|
+
if (!isNumberArray(embedding) || embedding.length === 0)
|
|
213
|
+
return false;
|
|
214
|
+
slots[index] = buildBatchSuccess(item, embedding, ctx);
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
217
|
+
function buildBatchContext(payload, request) {
|
|
218
|
+
return {
|
|
219
|
+
count: request.inputs.length,
|
|
220
|
+
topModel: typeof payload.model === "string" ? payload.model : undefined,
|
|
221
|
+
topRevision: typeof payload.model_revision === "string" ? payload.model_revision : undefined,
|
|
222
|
+
requestModelId: request.modelId,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
async function decodeBatchSuccess(response, request) {
|
|
226
|
+
let payload;
|
|
227
|
+
try {
|
|
228
|
+
payload = await readJsonCapped(response);
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
return { ok: false, kind: "invalid-response" };
|
|
232
|
+
}
|
|
233
|
+
if (!isRecord(payload) || !Array.isArray(payload.data)) {
|
|
234
|
+
return { ok: false, kind: "invalid-response" };
|
|
235
|
+
}
|
|
236
|
+
const ctx = buildBatchContext(payload, request);
|
|
237
|
+
if (payload.data.length !== ctx.count) {
|
|
238
|
+
return { ok: false, kind: "invalid-response" };
|
|
239
|
+
}
|
|
240
|
+
// Place each item at its declared `index` so the result is strictly aligned to `inputs`
|
|
241
|
+
// regardless of provider ordering. Any missing/duplicate/out-of-range index → invalid.
|
|
242
|
+
const slots = new Array(ctx.count);
|
|
243
|
+
for (const item of payload.data) {
|
|
244
|
+
if (!placeBatchItem(item, ctx, slots)) {
|
|
245
|
+
return { ok: false, kind: "invalid-response" };
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
const value = [];
|
|
249
|
+
for (const slot of slots) {
|
|
250
|
+
if (slot === undefined)
|
|
251
|
+
return { ok: false, kind: "invalid-response" };
|
|
252
|
+
value.push(slot);
|
|
253
|
+
}
|
|
254
|
+
return { ok: true, value };
|
|
255
|
+
}
|
|
256
|
+
export async function requestOpenAIEmbeddingBatch(request) {
|
|
257
|
+
if (request.inputs.length === 0) {
|
|
258
|
+
return { ok: true, value: [] };
|
|
259
|
+
}
|
|
260
|
+
const built = buildBatchRequest(request);
|
|
261
|
+
const dispatched = await dispatch(built, request.fetchImpl, request.egress);
|
|
262
|
+
if (typeof dispatched === "string") {
|
|
263
|
+
return { ok: false, kind: dispatched };
|
|
264
|
+
}
|
|
265
|
+
if (!dispatched.ok) {
|
|
266
|
+
const kind = classifyStatus(dispatched.status) ?? "transport";
|
|
267
|
+
await discardBody(dispatched);
|
|
268
|
+
return { ok: false, kind };
|
|
269
|
+
}
|
|
270
|
+
return decodeBatchSuccess(dispatched, request);
|
|
271
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type ClarificationOrAssumption, type EnhancedPromptId, type GroundingNeed, type OutputSchemaDescriptor, type PromptCriticality, type PromptDomain, type PromptEnhancementProfileId, type PromptRiskClass, type PromptTaskAnalysis, type PromptTaskClass } from "@oscharko-dev/keiko-contracts";
|
|
2
|
+
export interface AnalysisOverrides {
|
|
3
|
+
readonly taskClass?: PromptTaskClass;
|
|
4
|
+
readonly domain?: PromptDomain;
|
|
5
|
+
readonly criticality?: PromptCriticality;
|
|
6
|
+
readonly groundingNeed?: GroundingNeed;
|
|
7
|
+
readonly outputSchema?: OutputSchemaDescriptor;
|
|
8
|
+
readonly missingContext?: readonly ClarificationOrAssumption[];
|
|
9
|
+
readonly riskFlags?: readonly PromptRiskClass[];
|
|
10
|
+
readonly recommendedProfile?: PromptEnhancementProfileId;
|
|
11
|
+
readonly requestId?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function makeAnalysis(overrides?: AnalysisOverrides): PromptTaskAnalysis;
|
|
14
|
+
export declare function testPromptId(value?: string): EnhancedPromptId;
|
|
15
|
+
//# sourceMappingURL=_support.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_support.d.ts","sourceRoot":"","sources":["../../../src/promptEnhancer/__tests__/_support.ts"],"names":[],"mappings":"AAGA,OAAO,EAIL,KAAK,yBAAyB,EAC9B,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,0BAA0B,EAC/B,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACrB,MAAM,+BAA+B,CAAC;AAEvC,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,SAAS,CAAC,EAAE,eAAe,CAAC;IACrC,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,WAAW,CAAC,EAAE,iBAAiB,CAAC;IACzC,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC;IACvC,QAAQ,CAAC,YAAY,CAAC,EAAE,sBAAsB,CAAC;IAC/C,QAAQ,CAAC,cAAc,CAAC,EAAE,SAAS,yBAAyB,EAAE,CAAC;IAC/D,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IAChD,QAAQ,CAAC,kBAAkB,CAAC,EAAE,0BAA0B,CAAC;IACzD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAiBD,wBAAgB,YAAY,CAAC,SAAS,GAAE,iBAAsB,GAAG,kBAAkB,CAOlF;AAED,wBAAgB,YAAY,CAAC,KAAK,SAAgB,GAAG,gBAAgB,CAEpE"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Shared test helpers for the Prompt Enhancer module tests. Excluded from coverage by the vitest
|
|
2
|
+
// config (`**/_support.ts`); not a test file.
|
|
3
|
+
import { asEnhancedPromptId, asPromptEnhancementRequestId, PROMPT_ENHANCER_SCHEMA_VERSION, } from "@oscharko-dev/keiko-contracts";
|
|
4
|
+
const BASE_ANALYSIS = {
|
|
5
|
+
schemaVersion: PROMPT_ENHANCER_SCHEMA_VERSION,
|
|
6
|
+
taskClass: "factual-qa",
|
|
7
|
+
taskClassConfidence: "moderate",
|
|
8
|
+
domain: "general",
|
|
9
|
+
criticality: "standard",
|
|
10
|
+
groundingNeed: { kind: "none", volatile: false, signals: [] },
|
|
11
|
+
outputSchema: { format: "unspecified", structured: false, hints: [] },
|
|
12
|
+
missingContext: [],
|
|
13
|
+
riskFlags: [],
|
|
14
|
+
recommendedProfile: "precise",
|
|
15
|
+
normalizedInputLength: 16,
|
|
16
|
+
signals: [],
|
|
17
|
+
};
|
|
18
|
+
export function makeAnalysis(overrides = {}) {
|
|
19
|
+
const { requestId, ...rest } = overrides;
|
|
20
|
+
return {
|
|
21
|
+
...BASE_ANALYSIS,
|
|
22
|
+
...rest,
|
|
23
|
+
requestId: asPromptEnhancementRequestId(requestId ?? "test-request"),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export function testPromptId(value = "test-prompt") {
|
|
27
|
+
return asEnhancedPromptId(value);
|
|
28
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type PromptEnhancementProfileId, type PromptEnhancementRequest } from "@oscharko-dev/keiko-contracts";
|
|
2
|
+
export interface ProfileFixture {
|
|
3
|
+
readonly name: string;
|
|
4
|
+
readonly expectedProfile: PromptEnhancementProfileId;
|
|
5
|
+
readonly request: PromptEnhancementRequest;
|
|
6
|
+
}
|
|
7
|
+
export declare const PROFILE_FIXTURES: readonly ProfileFixture[];
|
|
8
|
+
//# sourceMappingURL=fixtures.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixtures.d.ts","sourceRoot":"","sources":["../../../src/promptEnhancer/__tests__/fixtures.ts"],"names":[],"mappings":"AAUA,OAAO,EAIL,KAAK,0BAA0B,EAC/B,KAAK,wBAAwB,EAC9B,MAAM,+BAA+B,CAAC;AAEvC,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,eAAe,EAAE,0BAA0B,CAAC;IACrD,QAAQ,CAAC,OAAO,EAAE,wBAAwB,CAAC;CAC5C;AAqBD,eAAO,MAAM,gBAAgB,EAAE,SAAS,cAAc,EAsDrD,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// Profile-specific fixtures for the Prompt Enhancer planner/generator (Issue #1310 deliverable 3).
|
|
2
|
+
//
|
|
3
|
+
// One representative request per generation profile (fast, precise, research, creative, technical,
|
|
4
|
+
// safety-critical, agentic). Each request is a natural prompt whose deterministic analyzer
|
|
5
|
+
// classification selects the named profile, so the fixtures exercise the real analyze → plan → generate
|
|
6
|
+
// path rather than forcing a profile. `expectedProfile` is asserted by `fixtures.test.ts`.
|
|
7
|
+
//
|
|
8
|
+
// This file lives under `__tests__/` so it is excluded from coverage instrumentation; it is test data,
|
|
9
|
+
// not production code.
|
|
10
|
+
import { asPromptEnhancementRequestId, PROMPT_ENHANCER_SCHEMA_VERSION, } from "@oscharko-dev/keiko-contracts";
|
|
11
|
+
function makeRequest(id, text, options = {}) {
|
|
12
|
+
return {
|
|
13
|
+
schemaVersion: PROMPT_ENHANCER_SCHEMA_VERSION,
|
|
14
|
+
requestId: asPromptEnhancementRequestId(id),
|
|
15
|
+
input: {
|
|
16
|
+
text,
|
|
17
|
+
hasConnectedContext: options.hasConnectedContext,
|
|
18
|
+
},
|
|
19
|
+
missingInformationStrategy: options.missingInformationStrategy ?? "clarify",
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export const PROFILE_FIXTURES = [
|
|
23
|
+
{
|
|
24
|
+
name: "fast: light editing",
|
|
25
|
+
expectedProfile: "fast",
|
|
26
|
+
request: makeRequest("fixture-fast", "Proofread this paragraph and fix any grammar mistakes."),
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: "precise: factual question",
|
|
30
|
+
expectedProfile: "precise",
|
|
31
|
+
request: makeRequest("fixture-precise", "What is the capital of Australia and roughly when did it become the capital?"),
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: "research: grounded overview",
|
|
35
|
+
expectedProfile: "research",
|
|
36
|
+
request: makeRequest("fixture-research", "Provide a comprehensive overview of advances in solid-state battery technology, with citations."),
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: "creative: short story",
|
|
40
|
+
expectedProfile: "creative",
|
|
41
|
+
request: makeRequest("fixture-creative", "Write a short story about a lighthouse keeper who befriends a whale."),
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: "technical: code generation",
|
|
45
|
+
expectedProfile: "technical",
|
|
46
|
+
request: makeRequest("fixture-technical", "Write a function in TypeScript that merges two sorted arrays into one sorted array. Return JSON describing the result."),
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: "safety-critical: medical advice",
|
|
50
|
+
expectedProfile: "safety-critical",
|
|
51
|
+
request: makeRequest("fixture-safety-critical", "I have a headache and a fever. What medication should I take and what dose is safe?"),
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: "agentic: tool automation",
|
|
55
|
+
expectedProfile: "agentic",
|
|
56
|
+
request: makeRequest("fixture-agentic", "As an agent, automate my onboarding workflow: call the API to create accounts and take actions on my behalf."),
|
|
57
|
+
},
|
|
58
|
+
];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type GroundingStrategy, type PromptEnhancementRequest } from "@oscharko-dev/keiko-contracts";
|
|
2
|
+
export interface GroundingFixture {
|
|
3
|
+
readonly name: string;
|
|
4
|
+
readonly category: "factual" | "current" | "rag" | "enterprise" | "code" | "self-contained" | "unsupported-evidence";
|
|
5
|
+
readonly expectedStrategy: GroundingStrategy;
|
|
6
|
+
readonly expectsRagHints: boolean;
|
|
7
|
+
readonly expectedRequired: boolean;
|
|
8
|
+
readonly request: PromptEnhancementRequest;
|
|
9
|
+
}
|
|
10
|
+
export declare const GROUNDING_FIXTURES: readonly GroundingFixture[];
|
|
11
|
+
//# sourceMappingURL=grounding-fixtures.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grounding-fixtures.d.ts","sourceRoot":"","sources":["../../../src/promptEnhancer/__tests__/grounding-fixtures.ts"],"names":[],"mappings":"AAUA,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,wBAAwB,EAC9B,MAAM,+BAA+B,CAAC;AAEvC,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EACb,SAAS,GACT,SAAS,GACT,KAAK,GACL,YAAY,GACZ,MAAM,GACN,gBAAgB,GAChB,sBAAsB,CAAC;IAC3B,QAAQ,CAAC,gBAAgB,EAAE,iBAAiB,CAAC;IAC7C,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,wBAAwB,CAAC;CAC5C;AAeD,eAAO,MAAM,kBAAkB,EAAE,SAAS,gBAAgB,EAsFzD,CAAC"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// Grounding-plan fixtures for the Prompt Enhancer (Issue #1311 deliverable 3).
|
|
2
|
+
//
|
|
3
|
+
// Natural prompts whose deterministic analysis (#1309) drives a specific grounding strategy, covering
|
|
4
|
+
// the six plan types named in the Expected Verification (no-grounding, supplied-context-only,
|
|
5
|
+
// local-knowledge, repository-context, hybrid, external-research-required) plus the deliverable
|
|
6
|
+
// categories: factual/current prompts, RAG prompts, enterprise-data prompts, and an
|
|
7
|
+
// unsupported-evidence case. Each fixture exercises the real analyze -> plan -> generate path.
|
|
8
|
+
//
|
|
9
|
+
// This file lives under `__tests__/` so it is excluded from coverage instrumentation; it is test data.
|
|
10
|
+
import { asPromptEnhancementRequestId, PROMPT_ENHANCER_SCHEMA_VERSION, } from "@oscharko-dev/keiko-contracts";
|
|
11
|
+
function makeRequest(id, text, hasConnectedContext) {
|
|
12
|
+
return {
|
|
13
|
+
schemaVersion: PROMPT_ENHANCER_SCHEMA_VERSION,
|
|
14
|
+
requestId: asPromptEnhancementRequestId(id),
|
|
15
|
+
input: { text, hasConnectedContext },
|
|
16
|
+
missingInformationStrategy: "clarify",
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
export const GROUNDING_FIXTURES = [
|
|
20
|
+
{
|
|
21
|
+
name: "self-contained: code generation needs no grounding",
|
|
22
|
+
category: "self-contained",
|
|
23
|
+
expectedStrategy: "no-grounding",
|
|
24
|
+
expectsRagHints: false,
|
|
25
|
+
expectedRequired: false,
|
|
26
|
+
request: makeRequest("grd-none", "Write a function to reverse a singly linked list."),
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: "rag: answer strictly from the provided text",
|
|
30
|
+
category: "rag",
|
|
31
|
+
expectedStrategy: "supplied-context-only",
|
|
32
|
+
expectsRagHints: true,
|
|
33
|
+
expectedRequired: true,
|
|
34
|
+
request: makeRequest("grd-supplied", "Based on the provided text, answer which mitigations the report recommends."),
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: "enterprise: look up an answer in the connected document store",
|
|
38
|
+
category: "enterprise",
|
|
39
|
+
expectedStrategy: "local-knowledge",
|
|
40
|
+
expectsRagHints: true,
|
|
41
|
+
expectedRequired: true,
|
|
42
|
+
request: makeRequest("grd-local", "Using the document knowledge base, look up our onboarding steps and list them."),
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: "code: debug a failure against the repository context",
|
|
46
|
+
category: "code",
|
|
47
|
+
expectedStrategy: "repository-context",
|
|
48
|
+
expectsRagHints: false,
|
|
49
|
+
expectedRequired: true,
|
|
50
|
+
request: makeRequest("grd-repo", "Debug why this function returns the wrong result when the input array is empty."),
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: "factual research: comprehensive overview with citations (hybrid)",
|
|
54
|
+
category: "factual",
|
|
55
|
+
expectedStrategy: "hybrid",
|
|
56
|
+
expectsRagHints: true,
|
|
57
|
+
expectedRequired: true,
|
|
58
|
+
request: makeRequest("grd-hybrid", "Provide a comprehensive overview of advances in solid-state battery technology, with citations."),
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: "decision-support: optional hybrid planning with parametric fallback",
|
|
62
|
+
category: "factual",
|
|
63
|
+
expectedStrategy: "hybrid",
|
|
64
|
+
expectsRagHints: false,
|
|
65
|
+
expectedRequired: false,
|
|
66
|
+
request: makeRequest("grd-hybrid-optional", "Help me decide whether to expand into the European market, weighing the main trade-offs."),
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: "current: recency-sensitive question requires external research",
|
|
70
|
+
category: "current",
|
|
71
|
+
expectedStrategy: "external-research-required",
|
|
72
|
+
expectsRagHints: false,
|
|
73
|
+
expectedRequired: true,
|
|
74
|
+
request: makeRequest("grd-current", "What are the latest developments in the EU AI Act as of today?"),
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: "unsupported-evidence: RAG question whose answer may be absent from context",
|
|
78
|
+
category: "unsupported-evidence",
|
|
79
|
+
expectedStrategy: "supplied-context-only",
|
|
80
|
+
expectsRagHints: true,
|
|
81
|
+
expectedRequired: true,
|
|
82
|
+
request: makeRequest("grd-unsupported", "Based on the provided text, what was the company's exact revenue in 1850?"),
|
|
83
|
+
},
|
|
84
|
+
];
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type EnhancedPrompt, type PromptCandidateRejectionReason, type PromptEnhancementProfileId, type PromptTaskAnalysis, type RawPromptInput } from "@oscharko-dev/keiko-contracts";
|
|
2
|
+
import { type PromptEnhancementPlan } from "./planner.js";
|
|
3
|
+
export interface PromptCandidate {
|
|
4
|
+
readonly candidateId: string;
|
|
5
|
+
readonly profile: PromptEnhancementProfileId;
|
|
6
|
+
readonly plan: PromptEnhancementPlan;
|
|
7
|
+
readonly prompt: EnhancedPrompt;
|
|
8
|
+
}
|
|
9
|
+
export interface RejectedCandidate {
|
|
10
|
+
readonly candidateId: string;
|
|
11
|
+
readonly profile: PromptEnhancementProfileId;
|
|
12
|
+
readonly reason: Extract<PromptCandidateRejectionReason, "duplicate-candidate" | "safety-floor-not-preserved">;
|
|
13
|
+
}
|
|
14
|
+
export interface PromptCandidateSet {
|
|
15
|
+
readonly candidates: readonly PromptCandidate[];
|
|
16
|
+
readonly rejected: readonly RejectedCandidate[];
|
|
17
|
+
}
|
|
18
|
+
export interface GeneratePromptCandidatesArgs {
|
|
19
|
+
readonly analysis: PromptTaskAnalysis;
|
|
20
|
+
readonly input: RawPromptInput;
|
|
21
|
+
readonly candidateCount: number;
|
|
22
|
+
readonly profilePreference?: PromptEnhancementProfileId | undefined;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Generate a bounded, ordered set of distinct, safety-preserving Enhanced Prompt candidates. Pure.
|
|
26
|
+
*
|
|
27
|
+
* Candidates are produced by planning the analysis under each profile in the slate, deduplicating by
|
|
28
|
+
* the actual selected profile (so a forced escalation does not produce repeats), rejecting any candidate
|
|
29
|
+
* that would relax the baseline safety floor, and capping the result at `candidateCount`.
|
|
30
|
+
*/
|
|
31
|
+
export declare function generatePromptCandidates(args: GeneratePromptCandidatesArgs): PromptCandidateSet;
|
|
32
|
+
//# sourceMappingURL=candidates.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"candidates.d.ts","sourceRoot":"","sources":["../../src/promptEnhancer/candidates.ts"],"names":[],"mappings":"AAoBA,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,8BAA8B,EACnC,KAAK,0BAA0B,EAC/B,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACpB,MAAM,+BAA+B,CAAC;AAGvC,OAAO,EAAyB,KAAK,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAIjF,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,0BAA0B,CAAC;IAC7C,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;CACjC;AAID,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,0BAA0B,CAAC;IAC7C,QAAQ,CAAC,MAAM,EAAE,OAAO,CACtB,8BAA8B,EAC9B,qBAAqB,GAAG,4BAA4B,CACrD,CAAC;CACH;AAED,MAAM,WAAW,kBAAkB;IAEjC,QAAQ,CAAC,UAAU,EAAE,SAAS,eAAe,EAAE,CAAC;IAEhD,QAAQ,CAAC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,CAAC;CACjD;AAED,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;IACtC,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAE/B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAEhC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,0BAA0B,GAAG,SAAS,CAAC;CACrE;AAgDD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,4BAA4B,GAAG,kBAAkB,CA8C/F"}
|