@warmdrift/kgauto-compiler 2.0.0-alpha.56 → 2.0.0-alpha.58
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/chunk-B4INZ32V.mjs +185 -0
- package/dist/glassbox/index.d.mts +3 -3
- package/dist/glassbox/index.d.ts +3 -3
- package/dist/glassbox-routes/format.d.mts +2 -2
- package/dist/glassbox-routes/format.d.ts +2 -2
- package/dist/glassbox-routes/index.d.mts +4 -4
- package/dist/glassbox-routes/index.d.ts +4 -4
- package/dist/glassbox-routes/react/index.d.mts +2 -2
- package/dist/glassbox-routes/react/index.d.ts +2 -2
- package/dist/index.d.mts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +191 -1
- package/dist/index.mjs +11 -1
- package/dist/{ir-BiXAMyji.d.ts → ir-B2h0GAEL.d.ts} +33 -1
- package/dist/{ir-CAlLBu5d.d.mts → ir-BC4uDL98.d.mts} +33 -1
- package/dist/key-health.d.mts +121 -0
- package/dist/key-health.d.ts +121 -0
- package/dist/key-health.js +209 -0
- package/dist/key-health.mjs +6 -0
- package/dist/profiles.d.mts +1 -1
- package/dist/profiles.d.ts +1 -1
- package/dist/{types-Dj5FLhBV.d.mts → types-B-pzBJKf.d.mts} +1 -1
- package/dist/{types-DsA8JFOp.d.ts → types-CKuu7Clz.d.ts} +1 -1
- package/dist/{types-C_dkNMA_.d.mts → types-CRy90cjp.d.mts} +1 -1
- package/dist/{types-hEDGehpz.d.ts → types-CsB2YASc.d.ts} +1 -1
- package/package.json +7 -2
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
// src/key-health.ts
|
|
2
|
+
var JSON_HEADERS = { "Content-Type": "application/json" };
|
|
3
|
+
function jsonResponse(status, body) {
|
|
4
|
+
return new Response(JSON.stringify(body), { status, headers: JSON_HEADERS });
|
|
5
|
+
}
|
|
6
|
+
function bearerOf(req) {
|
|
7
|
+
const header = req.headers.get("Authorization") ?? "";
|
|
8
|
+
const match = /^Bearer\s+(.+)$/i.exec(header);
|
|
9
|
+
return match?.[1]?.trim() ?? "";
|
|
10
|
+
}
|
|
11
|
+
function requireString(name, value) {
|
|
12
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
13
|
+
throw new Error(`createKeyHealthRoute: ${name} is required`);
|
|
14
|
+
}
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
function envKey(env, name) {
|
|
18
|
+
const v = env[name];
|
|
19
|
+
if (typeof v !== "string") return void 0;
|
|
20
|
+
const trimmed = v.trim();
|
|
21
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
22
|
+
}
|
|
23
|
+
var PROBE_SPECS = [
|
|
24
|
+
{
|
|
25
|
+
provider: "anthropic",
|
|
26
|
+
canonicalEnvName: "ANTHROPIC_API_KEY",
|
|
27
|
+
buildRequest: (key) => ({
|
|
28
|
+
url: "https://api.anthropic.com/v1/models?limit=1",
|
|
29
|
+
headers: { "x-api-key": key, "anthropic-version": "2023-06-01" }
|
|
30
|
+
})
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
provider: "deepseek",
|
|
34
|
+
canonicalEnvName: "DEEPSEEK_API_KEY",
|
|
35
|
+
buildRequest: (key) => ({
|
|
36
|
+
url: "https://api.deepseek.com/user/balance",
|
|
37
|
+
headers: { Authorization: `Bearer ${key}` }
|
|
38
|
+
}),
|
|
39
|
+
parseBalanceUsd: (body) => {
|
|
40
|
+
const infos = body?.balance_infos;
|
|
41
|
+
if (!Array.isArray(infos) || infos.length === 0) return void 0;
|
|
42
|
+
const first = infos[0];
|
|
43
|
+
if (first?.currency !== "USD") return void 0;
|
|
44
|
+
const n = Number(first.total_balance);
|
|
45
|
+
return Number.isFinite(n) ? n : void 0;
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
provider: "google",
|
|
50
|
+
canonicalEnvName: "GEMINI_API_KEY",
|
|
51
|
+
buildRequest: (key) => ({
|
|
52
|
+
url: `https://generativelanguage.googleapis.com/v1beta/models?pageSize=1&key=${encodeURIComponent(key)}`,
|
|
53
|
+
headers: {}
|
|
54
|
+
})
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
provider: "openai",
|
|
58
|
+
canonicalEnvName: "OPENAI_API_KEY",
|
|
59
|
+
buildRequest: (key) => ({
|
|
60
|
+
url: "https://api.openai.com/v1/models",
|
|
61
|
+
headers: { Authorization: `Bearer ${key}` }
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
];
|
|
65
|
+
function createKeyHealthRoute(config) {
|
|
66
|
+
const appId = requireString("appId", config.appId);
|
|
67
|
+
const ingestSecret = requireString("ingestSecret", config.ingestSecret);
|
|
68
|
+
const fetchFn = config.fetchImpl ?? fetch;
|
|
69
|
+
const timeoutMs = config.timeoutMs ?? 3e3;
|
|
70
|
+
async function probeProvider(spec, env) {
|
|
71
|
+
let key;
|
|
72
|
+
let envName = spec.canonicalEnvName;
|
|
73
|
+
if (spec.provider === "google") {
|
|
74
|
+
const gemini = envKey(env, "GEMINI_API_KEY");
|
|
75
|
+
const google = envKey(env, "GOOGLE_API_KEY");
|
|
76
|
+
const aiSdk = envKey(env, "GOOGLE_GENERATIVE_AI_API_KEY");
|
|
77
|
+
key = gemini ?? google ?? aiSdk;
|
|
78
|
+
envName = gemini ? "GEMINI_API_KEY" : google ? "GOOGLE_API_KEY" : aiSdk ? "GOOGLE_GENERATIVE_AI_API_KEY" : "GEMINI_API_KEY";
|
|
79
|
+
} else {
|
|
80
|
+
key = envKey(env, spec.canonicalEnvName);
|
|
81
|
+
}
|
|
82
|
+
if (!key) {
|
|
83
|
+
return {
|
|
84
|
+
provider: spec.provider,
|
|
85
|
+
env: envName,
|
|
86
|
+
present: false,
|
|
87
|
+
valid: null,
|
|
88
|
+
detail: "key_absent"
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
const base = {
|
|
92
|
+
provider: spec.provider,
|
|
93
|
+
env: envName,
|
|
94
|
+
present: true,
|
|
95
|
+
valid: null
|
|
96
|
+
};
|
|
97
|
+
const { url, headers } = spec.buildRequest(key);
|
|
98
|
+
const started = Date.now();
|
|
99
|
+
let res;
|
|
100
|
+
try {
|
|
101
|
+
res = await fetchFn(url, {
|
|
102
|
+
method: "GET",
|
|
103
|
+
headers,
|
|
104
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
105
|
+
});
|
|
106
|
+
} catch (err) {
|
|
107
|
+
const isTimeout = err instanceof Error && (err.name === "TimeoutError" || err.name === "AbortError");
|
|
108
|
+
return {
|
|
109
|
+
...base,
|
|
110
|
+
latency_ms: Date.now() - started,
|
|
111
|
+
// NEVER echo err.message — provider errors could theoretically carry
|
|
112
|
+
// request context; a fixed vocabulary keeps key material impossible.
|
|
113
|
+
detail: isTimeout ? "timeout" : "network_error"
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
const latencyMs = Date.now() - started;
|
|
117
|
+
if (res.ok) {
|
|
118
|
+
const result = {
|
|
119
|
+
...base,
|
|
120
|
+
valid: true,
|
|
121
|
+
status: res.status,
|
|
122
|
+
latency_ms: latencyMs
|
|
123
|
+
};
|
|
124
|
+
if (spec.parseBalanceUsd) {
|
|
125
|
+
try {
|
|
126
|
+
const body = await res.json();
|
|
127
|
+
const balance = spec.parseBalanceUsd(body);
|
|
128
|
+
if (balance !== void 0) result.balance_usd = balance;
|
|
129
|
+
} catch {
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return result;
|
|
133
|
+
}
|
|
134
|
+
if (res.status === 401 || res.status === 403) {
|
|
135
|
+
return { ...base, valid: false, status: res.status, latency_ms: latencyMs };
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
...base,
|
|
139
|
+
valid: null,
|
|
140
|
+
status: res.status,
|
|
141
|
+
latency_ms: latencyMs,
|
|
142
|
+
detail: `http_${res.status}`
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
async function handle(req) {
|
|
146
|
+
try {
|
|
147
|
+
if (req.method !== "GET") {
|
|
148
|
+
return jsonResponse(405, { error: "method_not_allowed" });
|
|
149
|
+
}
|
|
150
|
+
if (bearerOf(req) !== ingestSecret) {
|
|
151
|
+
return jsonResponse(401, { error: "unauthorized" });
|
|
152
|
+
}
|
|
153
|
+
const env = config.env ?? process.env;
|
|
154
|
+
const settled = await Promise.allSettled(
|
|
155
|
+
PROBE_SPECS.map((spec) => probeProvider(spec, env))
|
|
156
|
+
);
|
|
157
|
+
const keys = settled.map((s, i) => {
|
|
158
|
+
if (s.status === "fulfilled") return s.value;
|
|
159
|
+
const spec = PROBE_SPECS[i];
|
|
160
|
+
return {
|
|
161
|
+
provider: spec.provider,
|
|
162
|
+
env: spec.canonicalEnvName,
|
|
163
|
+
present: true,
|
|
164
|
+
valid: null,
|
|
165
|
+
detail: "probe_failed"
|
|
166
|
+
};
|
|
167
|
+
});
|
|
168
|
+
keys.sort((a, b) => a.provider.localeCompare(b.provider));
|
|
169
|
+
const body = {
|
|
170
|
+
app_id: appId,
|
|
171
|
+
checked_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
172
|
+
keys
|
|
173
|
+
};
|
|
174
|
+
return jsonResponse(200, body);
|
|
175
|
+
} catch (err) {
|
|
176
|
+
void err;
|
|
177
|
+
return jsonResponse(500, { error: "key_health_internal_error" });
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return { handle };
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export {
|
|
184
|
+
createKeyHealthRoute
|
|
185
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { G as GlassboxEvent } from '../types-
|
|
2
|
-
export { A as AdvisoryFiredData, C as CompileDoneData, a as CompileStartData, E as ExecuteAttemptData, b as ExecuteSuccessData, F as FallbackWalkedData, c as GLASSBOX_STREAM_TTL_MS, d as GlassboxEventKind, e as GlassboxPubSub } from '../types-
|
|
3
|
-
import '../ir-
|
|
1
|
+
import { G as GlassboxEvent } from '../types-CRy90cjp.mjs';
|
|
2
|
+
export { A as AdvisoryFiredData, C as CompileDoneData, a as CompileStartData, E as ExecuteAttemptData, b as ExecuteSuccessData, F as FallbackWalkedData, c as GLASSBOX_STREAM_TTL_MS, d as GlassboxEventKind, e as GlassboxPubSub } from '../types-CRy90cjp.mjs';
|
|
3
|
+
import '../ir-BC4uDL98.mjs';
|
|
4
4
|
import '../dialect.mjs';
|
|
5
5
|
|
|
6
6
|
/**
|
package/dist/glassbox/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { G as GlassboxEvent } from '../types-
|
|
2
|
-
export { A as AdvisoryFiredData, C as CompileDoneData, a as CompileStartData, E as ExecuteAttemptData, b as ExecuteSuccessData, F as FallbackWalkedData, c as GLASSBOX_STREAM_TTL_MS, d as GlassboxEventKind, e as GlassboxPubSub } from '../types-
|
|
3
|
-
import '../ir-
|
|
1
|
+
import { G as GlassboxEvent } from '../types-CsB2YASc.js';
|
|
2
|
+
export { A as AdvisoryFiredData, C as CompileDoneData, a as CompileStartData, E as ExecuteAttemptData, b as ExecuteSuccessData, F as FallbackWalkedData, c as GLASSBOX_STREAM_TTL_MS, d as GlassboxEventKind, e as GlassboxPubSub } from '../types-CsB2YASc.js';
|
|
3
|
+
import '../ir-B2h0GAEL.js';
|
|
4
4
|
import '../dialect.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { G as GlassboxEvent } from '../types-
|
|
2
|
-
import { a as TraceDetail, b as TraceSummary, c as TraceCounterfactual } from '../types-
|
|
3
|
-
export { A as AdvisoryRecord, T as TraceHealth, d as TraceSectionRewrite } from '../types-
|
|
4
|
-
import '../ir-
|
|
1
|
+
import { G as GlassboxEvent } from '../types-CRy90cjp.mjs';
|
|
2
|
+
import { a as TraceDetail, b as TraceSummary, c as TraceCounterfactual } from '../types-B-pzBJKf.mjs';
|
|
3
|
+
export { A as AdvisoryRecord, T as TraceHealth, d as TraceSectionRewrite } from '../types-B-pzBJKf.mjs';
|
|
4
|
+
import '../ir-BC4uDL98.mjs';
|
|
5
5
|
import '../dialect.mjs';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { G as GlassboxEvent } from '../types-
|
|
2
|
-
import { a as TraceDetail, b as TraceSummary, c as TraceCounterfactual } from '../types-
|
|
3
|
-
export { A as AdvisoryRecord, T as TraceHealth, d as TraceSectionRewrite } from '../types-
|
|
4
|
-
import '../ir-
|
|
1
|
+
import { G as GlassboxEvent } from '../types-CsB2YASc.js';
|
|
2
|
+
import { a as TraceDetail, b as TraceSummary, c as TraceCounterfactual } from '../types-CKuu7Clz.js';
|
|
3
|
+
export { A as AdvisoryRecord, T as TraceHealth, d as TraceSectionRewrite } from '../types-CKuu7Clz.js';
|
|
4
|
+
import '../ir-B2h0GAEL.js';
|
|
5
5
|
import '../dialect.js';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { a as TraceDetail } from '../../types-
|
|
3
|
-
import '../../ir-
|
|
2
|
+
import { a as TraceDetail } from '../../types-B-pzBJKf.mjs';
|
|
3
|
+
import '../../ir-BC4uDL98.mjs';
|
|
4
4
|
import '../../dialect.mjs';
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { a as TraceDetail } from '../../types-
|
|
3
|
-
import '../../ir-
|
|
2
|
+
import { a as TraceDetail } from '../../types-CKuu7Clz.js';
|
|
3
|
+
import '../../ir-B2h0GAEL.js';
|
|
4
4
|
import '../../dialect.js';
|
|
5
5
|
|
|
6
6
|
/**
|
package/dist/index.d.mts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { C as CompilePolicy, N as NormalizedResponse, A as ApiKeys, P as ProviderOverrides, a as CompiledRequest, b as PromptIR, c as CallOptions, d as CallResult, S as SystemModelMessage, e as CompileResult, B as BestPracticeAdvisory, f as SectionRewrite, R as RecordInput, g as RecordOutcomeInput, O as OutcomeResult, h as OracleScore, i as Adapter, j as PerAxisMetrics, k as Provider, l as ChainEntry, G as Grounding } from './ir-
|
|
2
|
-
export { m as CallAttempt, n as CallError, o as ChainModelEntry, p as ChainWithGrounding, q as Constraints, F as FallbackReason, H as HistoryCachePolicy, I as IntentDeclaration, M as Message, r as MutationApplied, s as NormalizedTokens, t as OutcomeKind, u as PerAxisMetricsByModel, v as PromptSection, w as SectionKind, x as ShadowProbeConfig, T as ToolCall, y as ToolDefinition } from './ir-
|
|
1
|
+
import { C as CompilePolicy, N as NormalizedResponse, A as ApiKeys, P as ProviderOverrides, a as CompiledRequest, b as PromptIR, c as CallOptions, d as CallResult, S as SystemModelMessage, e as CompileResult, B as BestPracticeAdvisory, f as SectionRewrite, R as RecordInput, g as RecordOutcomeInput, O as OutcomeResult, h as OracleScore, i as Adapter, j as PerAxisMetrics, k as Provider, l as ChainEntry, G as Grounding } from './ir-BC4uDL98.mjs';
|
|
2
|
+
export { m as CallAttempt, n as CallError, o as ChainModelEntry, p as ChainWithGrounding, q as Constraints, E as EffortLevel, F as FallbackReason, H as HistoryCachePolicy, I as IntentDeclaration, M as Message, r as MutationApplied, s as NormalizedTokens, t as OutcomeKind, u as PerAxisMetricsByModel, v as PromptSection, w as SectionKind, x as ShadowProbeConfig, T as ToolCall, y as ToolDefinition } from './ir-BC4uDL98.mjs';
|
|
3
3
|
import { ModelProfile, ArchetypeConvention } from './profiles.mjs';
|
|
4
4
|
export { ALIASES, CacheStrategy, CliffRule, LATENCY_TIER_MS, LatencyTier, LoweringSpec, RecoveryRule, StructuredOutputCapability, SystemPromptMode, allProfiles, getProfile, latencyTierOf, profilesByProvider, tryGetProfile } from './profiles.mjs';
|
|
5
5
|
export { BrainForwardConfig, BrainForwardRoutes, createBrainForwardRoutes } from './brain-proxy.mjs';
|
|
6
|
+
export { KeyHealthConfig, KeyHealthProvider, KeyHealthResponseBody, KeyHealthResult, KeyHealthRoute, createKeyHealthRoute } from './key-health.mjs';
|
|
6
7
|
import { IntentArchetypeName } from './dialect.mjs';
|
|
7
8
|
export { ALL_ARCHETYPES, ContextBucket, DIALECT_VERSION, HistoryDepth, INTENT_ARCHETYPES, OutputMode, ShapeSignature, ToolCountBucket, bucketContext, bucketHistory, bucketToolCount, hashShape, isArchetype, learningKey } from './dialect.mjs';
|
|
8
9
|
|
|
@@ -463,6 +464,7 @@ interface OutcomePayload {
|
|
|
463
464
|
cost_usd_actual?: number;
|
|
464
465
|
ttft_ms?: number;
|
|
465
466
|
history_cacheable_tokens?: number;
|
|
467
|
+
effort?: string;
|
|
466
468
|
history_tokens_at_compile?: number;
|
|
467
469
|
/**
|
|
468
470
|
* Mirrors `ir.constraints.toolOrchestration` from compile time. NULL when
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { C as CompilePolicy, N as NormalizedResponse, A as ApiKeys, P as ProviderOverrides, a as CompiledRequest, b as PromptIR, c as CallOptions, d as CallResult, S as SystemModelMessage, e as CompileResult, B as BestPracticeAdvisory, f as SectionRewrite, R as RecordInput, g as RecordOutcomeInput, O as OutcomeResult, h as OracleScore, i as Adapter, j as PerAxisMetrics, k as Provider, l as ChainEntry, G as Grounding } from './ir-
|
|
2
|
-
export { m as CallAttempt, n as CallError, o as ChainModelEntry, p as ChainWithGrounding, q as Constraints, F as FallbackReason, H as HistoryCachePolicy, I as IntentDeclaration, M as Message, r as MutationApplied, s as NormalizedTokens, t as OutcomeKind, u as PerAxisMetricsByModel, v as PromptSection, w as SectionKind, x as ShadowProbeConfig, T as ToolCall, y as ToolDefinition } from './ir-
|
|
1
|
+
import { C as CompilePolicy, N as NormalizedResponse, A as ApiKeys, P as ProviderOverrides, a as CompiledRequest, b as PromptIR, c as CallOptions, d as CallResult, S as SystemModelMessage, e as CompileResult, B as BestPracticeAdvisory, f as SectionRewrite, R as RecordInput, g as RecordOutcomeInput, O as OutcomeResult, h as OracleScore, i as Adapter, j as PerAxisMetrics, k as Provider, l as ChainEntry, G as Grounding } from './ir-B2h0GAEL.js';
|
|
2
|
+
export { m as CallAttempt, n as CallError, o as ChainModelEntry, p as ChainWithGrounding, q as Constraints, E as EffortLevel, F as FallbackReason, H as HistoryCachePolicy, I as IntentDeclaration, M as Message, r as MutationApplied, s as NormalizedTokens, t as OutcomeKind, u as PerAxisMetricsByModel, v as PromptSection, w as SectionKind, x as ShadowProbeConfig, T as ToolCall, y as ToolDefinition } from './ir-B2h0GAEL.js';
|
|
3
3
|
import { ModelProfile, ArchetypeConvention } from './profiles.js';
|
|
4
4
|
export { ALIASES, CacheStrategy, CliffRule, LATENCY_TIER_MS, LatencyTier, LoweringSpec, RecoveryRule, StructuredOutputCapability, SystemPromptMode, allProfiles, getProfile, latencyTierOf, profilesByProvider, tryGetProfile } from './profiles.js';
|
|
5
5
|
export { BrainForwardConfig, BrainForwardRoutes, createBrainForwardRoutes } from './brain-proxy.js';
|
|
6
|
+
export { KeyHealthConfig, KeyHealthProvider, KeyHealthResponseBody, KeyHealthResult, KeyHealthRoute, createKeyHealthRoute } from './key-health.js';
|
|
6
7
|
import { IntentArchetypeName } from './dialect.js';
|
|
7
8
|
export { ALL_ARCHETYPES, ContextBucket, DIALECT_VERSION, HistoryDepth, INTENT_ARCHETYPES, OutputMode, ShapeSignature, ToolCountBucket, bucketContext, bucketHistory, bucketToolCount, hashShape, isArchetype, learningKey } from './dialect.js';
|
|
8
9
|
|
|
@@ -463,6 +464,7 @@ interface OutcomePayload {
|
|
|
463
464
|
cost_usd_actual?: number;
|
|
464
465
|
ttft_ms?: number;
|
|
465
466
|
history_cacheable_tokens?: number;
|
|
467
|
+
effort?: string;
|
|
466
468
|
history_tokens_at_compile?: number;
|
|
467
469
|
/**
|
|
468
470
|
* Mirrors `ir.constraints.toolOrchestration` from compile time. NULL when
|
package/dist/index.js
CHANGED
|
@@ -52,6 +52,7 @@ __export(index_exports, {
|
|
|
52
52
|
configureBrain: () => configureBrain,
|
|
53
53
|
countTokens: () => countTokens,
|
|
54
54
|
createBrainForwardRoutes: () => createBrainForwardRoutes,
|
|
55
|
+
createKeyHealthRoute: () => createKeyHealthRoute,
|
|
55
56
|
deriveFamilyFromModelId: () => deriveFamilyFromModelId,
|
|
56
57
|
deriveOwnership: () => deriveOwnership,
|
|
57
58
|
execute: () => execute,
|
|
@@ -4509,7 +4510,9 @@ function registerCompile(appId, archetype, ir, result) {
|
|
|
4509
4510
|
// alpha.29: translator activity — persisted on the brain row so
|
|
4510
4511
|
// cross-app aggregates can answer "Sonnet narration rule fired N times,
|
|
4511
4512
|
// outcome quality lifted to M."
|
|
4512
|
-
sectionRewritesApplied: result.sectionRewritesApplied
|
|
4513
|
+
sectionRewritesApplied: result.sectionRewritesApplied,
|
|
4514
|
+
// alpha.57: cache the declared effort tier for record()'s auto-enrich.
|
|
4515
|
+
effortFromCompile: ir.constraints?.effort
|
|
4513
4516
|
});
|
|
4514
4517
|
}
|
|
4515
4518
|
function estimateSystemPromptChars(sections) {
|
|
@@ -4664,6 +4667,10 @@ function buildPayload(input, reg) {
|
|
|
4664
4667
|
cost_usd_actual: costUsdActual,
|
|
4665
4668
|
ttft_ms: input.ttftMs,
|
|
4666
4669
|
history_cacheable_tokens: reg?.historyCacheableTokens,
|
|
4670
|
+
// alpha.57 (data-first): input wins over compile-declared; undefined
|
|
4671
|
+
// end-to-end -> key absent from the JSON body entirely (safe against
|
|
4672
|
+
// brains that haven't applied migration 033 yet).
|
|
4673
|
+
effort: input.effort ?? reg?.effortFromCompile,
|
|
4667
4674
|
history_tokens_at_compile: reg?.historyTokensTotal,
|
|
4668
4675
|
// alpha.20 E3: mirror consumer's declared tool-orchestration mode so
|
|
4669
4676
|
// the brain can measure per-mode model perf separately (DeepSeek in
|
|
@@ -6929,6 +6936,188 @@ function createBrainForwardRoutes(config) {
|
|
|
6929
6936
|
return { handle, segments: KNOWN_SEGMENTS };
|
|
6930
6937
|
}
|
|
6931
6938
|
|
|
6939
|
+
// src/key-health.ts
|
|
6940
|
+
var JSON_HEADERS2 = { "Content-Type": "application/json" };
|
|
6941
|
+
function jsonResponse2(status, body) {
|
|
6942
|
+
return new Response(JSON.stringify(body), { status, headers: JSON_HEADERS2 });
|
|
6943
|
+
}
|
|
6944
|
+
function bearerOf2(req) {
|
|
6945
|
+
const header = req.headers.get("Authorization") ?? "";
|
|
6946
|
+
const match = /^Bearer\s+(.+)$/i.exec(header);
|
|
6947
|
+
return match?.[1]?.trim() ?? "";
|
|
6948
|
+
}
|
|
6949
|
+
function requireString2(name, value) {
|
|
6950
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
6951
|
+
throw new Error(`createKeyHealthRoute: ${name} is required`);
|
|
6952
|
+
}
|
|
6953
|
+
return value;
|
|
6954
|
+
}
|
|
6955
|
+
function envKey(env, name) {
|
|
6956
|
+
const v = env[name];
|
|
6957
|
+
if (typeof v !== "string") return void 0;
|
|
6958
|
+
const trimmed = v.trim();
|
|
6959
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
6960
|
+
}
|
|
6961
|
+
var PROBE_SPECS = [
|
|
6962
|
+
{
|
|
6963
|
+
provider: "anthropic",
|
|
6964
|
+
canonicalEnvName: "ANTHROPIC_API_KEY",
|
|
6965
|
+
buildRequest: (key) => ({
|
|
6966
|
+
url: "https://api.anthropic.com/v1/models?limit=1",
|
|
6967
|
+
headers: { "x-api-key": key, "anthropic-version": "2023-06-01" }
|
|
6968
|
+
})
|
|
6969
|
+
},
|
|
6970
|
+
{
|
|
6971
|
+
provider: "deepseek",
|
|
6972
|
+
canonicalEnvName: "DEEPSEEK_API_KEY",
|
|
6973
|
+
buildRequest: (key) => ({
|
|
6974
|
+
url: "https://api.deepseek.com/user/balance",
|
|
6975
|
+
headers: { Authorization: `Bearer ${key}` }
|
|
6976
|
+
}),
|
|
6977
|
+
parseBalanceUsd: (body) => {
|
|
6978
|
+
const infos = body?.balance_infos;
|
|
6979
|
+
if (!Array.isArray(infos) || infos.length === 0) return void 0;
|
|
6980
|
+
const first = infos[0];
|
|
6981
|
+
if (first?.currency !== "USD") return void 0;
|
|
6982
|
+
const n = Number(first.total_balance);
|
|
6983
|
+
return Number.isFinite(n) ? n : void 0;
|
|
6984
|
+
}
|
|
6985
|
+
},
|
|
6986
|
+
{
|
|
6987
|
+
provider: "google",
|
|
6988
|
+
canonicalEnvName: "GEMINI_API_KEY",
|
|
6989
|
+
buildRequest: (key) => ({
|
|
6990
|
+
url: `https://generativelanguage.googleapis.com/v1beta/models?pageSize=1&key=${encodeURIComponent(key)}`,
|
|
6991
|
+
headers: {}
|
|
6992
|
+
})
|
|
6993
|
+
},
|
|
6994
|
+
{
|
|
6995
|
+
provider: "openai",
|
|
6996
|
+
canonicalEnvName: "OPENAI_API_KEY",
|
|
6997
|
+
buildRequest: (key) => ({
|
|
6998
|
+
url: "https://api.openai.com/v1/models",
|
|
6999
|
+
headers: { Authorization: `Bearer ${key}` }
|
|
7000
|
+
})
|
|
7001
|
+
}
|
|
7002
|
+
];
|
|
7003
|
+
function createKeyHealthRoute(config) {
|
|
7004
|
+
const appId = requireString2("appId", config.appId);
|
|
7005
|
+
const ingestSecret = requireString2("ingestSecret", config.ingestSecret);
|
|
7006
|
+
const fetchFn = config.fetchImpl ?? fetch;
|
|
7007
|
+
const timeoutMs = config.timeoutMs ?? 3e3;
|
|
7008
|
+
async function probeProvider(spec, env) {
|
|
7009
|
+
let key;
|
|
7010
|
+
let envName = spec.canonicalEnvName;
|
|
7011
|
+
if (spec.provider === "google") {
|
|
7012
|
+
const gemini = envKey(env, "GEMINI_API_KEY");
|
|
7013
|
+
const google = envKey(env, "GOOGLE_API_KEY");
|
|
7014
|
+
const aiSdk = envKey(env, "GOOGLE_GENERATIVE_AI_API_KEY");
|
|
7015
|
+
key = gemini ?? google ?? aiSdk;
|
|
7016
|
+
envName = gemini ? "GEMINI_API_KEY" : google ? "GOOGLE_API_KEY" : aiSdk ? "GOOGLE_GENERATIVE_AI_API_KEY" : "GEMINI_API_KEY";
|
|
7017
|
+
} else {
|
|
7018
|
+
key = envKey(env, spec.canonicalEnvName);
|
|
7019
|
+
}
|
|
7020
|
+
if (!key) {
|
|
7021
|
+
return {
|
|
7022
|
+
provider: spec.provider,
|
|
7023
|
+
env: envName,
|
|
7024
|
+
present: false,
|
|
7025
|
+
valid: null,
|
|
7026
|
+
detail: "key_absent"
|
|
7027
|
+
};
|
|
7028
|
+
}
|
|
7029
|
+
const base = {
|
|
7030
|
+
provider: spec.provider,
|
|
7031
|
+
env: envName,
|
|
7032
|
+
present: true,
|
|
7033
|
+
valid: null
|
|
7034
|
+
};
|
|
7035
|
+
const { url, headers } = spec.buildRequest(key);
|
|
7036
|
+
const started = Date.now();
|
|
7037
|
+
let res;
|
|
7038
|
+
try {
|
|
7039
|
+
res = await fetchFn(url, {
|
|
7040
|
+
method: "GET",
|
|
7041
|
+
headers,
|
|
7042
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
7043
|
+
});
|
|
7044
|
+
} catch (err) {
|
|
7045
|
+
const isTimeout = err instanceof Error && (err.name === "TimeoutError" || err.name === "AbortError");
|
|
7046
|
+
return {
|
|
7047
|
+
...base,
|
|
7048
|
+
latency_ms: Date.now() - started,
|
|
7049
|
+
// NEVER echo err.message — provider errors could theoretically carry
|
|
7050
|
+
// request context; a fixed vocabulary keeps key material impossible.
|
|
7051
|
+
detail: isTimeout ? "timeout" : "network_error"
|
|
7052
|
+
};
|
|
7053
|
+
}
|
|
7054
|
+
const latencyMs = Date.now() - started;
|
|
7055
|
+
if (res.ok) {
|
|
7056
|
+
const result = {
|
|
7057
|
+
...base,
|
|
7058
|
+
valid: true,
|
|
7059
|
+
status: res.status,
|
|
7060
|
+
latency_ms: latencyMs
|
|
7061
|
+
};
|
|
7062
|
+
if (spec.parseBalanceUsd) {
|
|
7063
|
+
try {
|
|
7064
|
+
const body = await res.json();
|
|
7065
|
+
const balance = spec.parseBalanceUsd(body);
|
|
7066
|
+
if (balance !== void 0) result.balance_usd = balance;
|
|
7067
|
+
} catch {
|
|
7068
|
+
}
|
|
7069
|
+
}
|
|
7070
|
+
return result;
|
|
7071
|
+
}
|
|
7072
|
+
if (res.status === 401 || res.status === 403) {
|
|
7073
|
+
return { ...base, valid: false, status: res.status, latency_ms: latencyMs };
|
|
7074
|
+
}
|
|
7075
|
+
return {
|
|
7076
|
+
...base,
|
|
7077
|
+
valid: null,
|
|
7078
|
+
status: res.status,
|
|
7079
|
+
latency_ms: latencyMs,
|
|
7080
|
+
detail: `http_${res.status}`
|
|
7081
|
+
};
|
|
7082
|
+
}
|
|
7083
|
+
async function handle(req) {
|
|
7084
|
+
try {
|
|
7085
|
+
if (req.method !== "GET") {
|
|
7086
|
+
return jsonResponse2(405, { error: "method_not_allowed" });
|
|
7087
|
+
}
|
|
7088
|
+
if (bearerOf2(req) !== ingestSecret) {
|
|
7089
|
+
return jsonResponse2(401, { error: "unauthorized" });
|
|
7090
|
+
}
|
|
7091
|
+
const env = config.env ?? process.env;
|
|
7092
|
+
const settled = await Promise.allSettled(
|
|
7093
|
+
PROBE_SPECS.map((spec) => probeProvider(spec, env))
|
|
7094
|
+
);
|
|
7095
|
+
const keys = settled.map((s, i) => {
|
|
7096
|
+
if (s.status === "fulfilled") return s.value;
|
|
7097
|
+
const spec = PROBE_SPECS[i];
|
|
7098
|
+
return {
|
|
7099
|
+
provider: spec.provider,
|
|
7100
|
+
env: spec.canonicalEnvName,
|
|
7101
|
+
present: true,
|
|
7102
|
+
valid: null,
|
|
7103
|
+
detail: "probe_failed"
|
|
7104
|
+
};
|
|
7105
|
+
});
|
|
7106
|
+
keys.sort((a, b) => a.provider.localeCompare(b.provider));
|
|
7107
|
+
const body = {
|
|
7108
|
+
app_id: appId,
|
|
7109
|
+
checked_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7110
|
+
keys
|
|
7111
|
+
};
|
|
7112
|
+
return jsonResponse2(200, body);
|
|
7113
|
+
} catch (err) {
|
|
7114
|
+
void err;
|
|
7115
|
+
return jsonResponse2(500, { error: "key_health_internal_error" });
|
|
7116
|
+
}
|
|
7117
|
+
}
|
|
7118
|
+
return { handle };
|
|
7119
|
+
}
|
|
7120
|
+
|
|
6932
7121
|
// src/oracle.ts
|
|
6933
7122
|
var DEFAULT_DIMENSIONS = ["correctness", "completeness", "conciseness", "format"];
|
|
6934
7123
|
var judgeCallTimes = [];
|
|
@@ -7389,6 +7578,7 @@ function compile2(ir, opts) {
|
|
|
7389
7578
|
configureBrain,
|
|
7390
7579
|
countTokens,
|
|
7391
7580
|
createBrainForwardRoutes,
|
|
7581
|
+
createKeyHealthRoute,
|
|
7392
7582
|
deriveFamilyFromModelId,
|
|
7393
7583
|
deriveOwnership,
|
|
7394
7584
|
execute,
|
package/dist/index.mjs
CHANGED
|
@@ -12,6 +12,9 @@ import {
|
|
|
12
12
|
isArchetype,
|
|
13
13
|
learningKey
|
|
14
14
|
} from "./chunk-5TI6PNSK.mjs";
|
|
15
|
+
import {
|
|
16
|
+
createKeyHealthRoute
|
|
17
|
+
} from "./chunk-B4INZ32V.mjs";
|
|
15
18
|
import {
|
|
16
19
|
ABSOLUTE_FLOOR,
|
|
17
20
|
ARCHETYPE_FLOOR_DEFAULT,
|
|
@@ -2665,7 +2668,9 @@ function registerCompile(appId, archetype, ir, result) {
|
|
|
2665
2668
|
// alpha.29: translator activity — persisted on the brain row so
|
|
2666
2669
|
// cross-app aggregates can answer "Sonnet narration rule fired N times,
|
|
2667
2670
|
// outcome quality lifted to M."
|
|
2668
|
-
sectionRewritesApplied: result.sectionRewritesApplied
|
|
2671
|
+
sectionRewritesApplied: result.sectionRewritesApplied,
|
|
2672
|
+
// alpha.57: cache the declared effort tier for record()'s auto-enrich.
|
|
2673
|
+
effortFromCompile: ir.constraints?.effort
|
|
2669
2674
|
});
|
|
2670
2675
|
}
|
|
2671
2676
|
function estimateSystemPromptChars(sections) {
|
|
@@ -2820,6 +2825,10 @@ function buildPayload(input, reg) {
|
|
|
2820
2825
|
cost_usd_actual: costUsdActual,
|
|
2821
2826
|
ttft_ms: input.ttftMs,
|
|
2822
2827
|
history_cacheable_tokens: reg?.historyCacheableTokens,
|
|
2828
|
+
// alpha.57 (data-first): input wins over compile-declared; undefined
|
|
2829
|
+
// end-to-end -> key absent from the JSON body entirely (safe against
|
|
2830
|
+
// brains that haven't applied migration 033 yet).
|
|
2831
|
+
effort: input.effort ?? reg?.effortFromCompile,
|
|
2823
2832
|
history_tokens_at_compile: reg?.historyTokensTotal,
|
|
2824
2833
|
// alpha.20 E3: mirror consumer's declared tool-orchestration mode so
|
|
2825
2834
|
// the brain can measure per-mode model perf separately (DeepSeek in
|
|
@@ -4667,6 +4676,7 @@ export {
|
|
|
4667
4676
|
configureBrain,
|
|
4668
4677
|
countTokens,
|
|
4669
4678
|
createBrainForwardRoutes,
|
|
4679
|
+
createKeyHealthRoute,
|
|
4670
4680
|
deriveFamilyFromModelId,
|
|
4671
4681
|
deriveOwnership,
|
|
4672
4682
|
execute,
|
|
@@ -111,11 +111,34 @@ interface IntentDeclaration {
|
|
|
111
111
|
/** Canonical dialect-v1 archetype. Required for cross-app learning. */
|
|
112
112
|
archetype: IntentArchetypeName;
|
|
113
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* alpha.57 — dialect-level reasoning-effort tier (data-first).
|
|
116
|
+
*
|
|
117
|
+
* Vocabulary is a portfolio-level tier ladder (low → max), NOT any provider's
|
|
118
|
+
* wire value — mapping to `reasoning_effort` (OpenAI) / thinking budgets
|
|
119
|
+
* (Anthropic) / `thinkingConfig` (Gemini) stays consumer-side until
|
|
120
|
+
* routing-on-effort ships. Declaring it records the tier on the brain row
|
|
121
|
+
* (`compile_outcomes.effort`, migration 033) so effort×archetype quality
|
|
122
|
+
* evidence accumulates BEFORE any routing logic exists — same data-first
|
|
123
|
+
* sequencing as `tool_orchestration` (alpha.20).
|
|
124
|
+
*/
|
|
125
|
+
type EffortLevel = 'low' | 'medium' | 'high' | 'xhigh' | 'max';
|
|
114
126
|
interface Constraints {
|
|
115
127
|
/** Hard latency ceiling — compiler will down-rank slow models. Advisory. */
|
|
116
128
|
maxLatencyMs?: number;
|
|
117
129
|
/** Hard cost ceiling per call (USD). Advisory. */
|
|
118
130
|
maxCostUsd?: number;
|
|
131
|
+
/**
|
|
132
|
+
* alpha.57 (data-first): the reasoning-effort tier the consumer ran (or
|
|
133
|
+
* intends to run) this call at. RECORDED, NOT APPLIED — the compiler does
|
|
134
|
+
* not emit provider thinking/effort params from this field and does not
|
|
135
|
+
* route on it yet; it flows to `compile_outcomes.effort` via record()'s
|
|
136
|
+
* registry auto-enrich (same pattern as `mutationsApplied`/advisories).
|
|
137
|
+
* Declare it truthfully: this is consumer-reported ground truth, like
|
|
138
|
+
* `tokensIn`/`latencyMs`. Does NOT enter the shape key (no learning-key
|
|
139
|
+
* fragmentation).
|
|
140
|
+
*/
|
|
141
|
+
effort?: EffortLevel;
|
|
119
142
|
/** Caller wants structured (JSON) output. */
|
|
120
143
|
structuredOutput?: boolean;
|
|
121
144
|
/** Hint: caller expects a short response (used to disable thinking on Gemini). */
|
|
@@ -1145,6 +1168,15 @@ interface RecordInput {
|
|
|
1145
1168
|
* surfaces it. Distinct from `latencyMs` (end-to-end wall clock).
|
|
1146
1169
|
*/
|
|
1147
1170
|
ttftMs?: number;
|
|
1171
|
+
/**
|
|
1172
|
+
* alpha.57 (data-first) — the reasoning-effort tier this call actually ran
|
|
1173
|
+
* at. Overrides the compile-declared `constraints.effort` when both are
|
|
1174
|
+
* present (input wins — same precedence as `mutationsApplied`/`advisories`).
|
|
1175
|
+
* When omitted, record() auto-enriches from the registry-cached compile
|
|
1176
|
+
* declaration. Undefined end-to-end → the `effort` key is absent from the
|
|
1177
|
+
* outcome payload entirely (safe against pre-migration-033 brains).
|
|
1178
|
+
*/
|
|
1179
|
+
effort?: EffortLevel;
|
|
1148
1180
|
/**
|
|
1149
1181
|
* alpha.20 — advisories fired at compile() time. Persisted to the brain's
|
|
1150
1182
|
* `compile_outcome_advisories` sibling table via a second POST that fires
|
|
@@ -1343,4 +1375,4 @@ interface PerAxisMetrics {
|
|
|
1343
1375
|
/** Per-axis metrics keyed by model — used for chain-comparison views. */
|
|
1344
1376
|
type PerAxisMetricsByModel = Record<string, PerAxisMetrics>;
|
|
1345
1377
|
|
|
1346
|
-
export { type ApiKeys as A, type BestPracticeAdvisory as B, type CompilePolicy as C, type FallbackReason as F, type Grounding as G, type HistoryCachePolicy as H, type IntentDeclaration as I, type Message as M, type NormalizedResponse as N, type OutcomeResult as O, type ProviderOverrides as P, type RecordInput as R, type SystemModelMessage as S, type ToolCall as T, type CompiledRequest as a, type PromptIR as b, type CallOptions as c, type CallResult as d, type CompileResult as e, type SectionRewrite as f, type RecordOutcomeInput as g, type OracleScore as h, type Adapter as i, type PerAxisMetrics as j, type Provider as k, type ChainEntry as l, type CallAttempt as m, CallError as n, type ChainModelEntry as o, type ChainWithGrounding as p, type Constraints as q, type MutationApplied as r, type NormalizedTokens as s, type OutcomeKind as t, type PerAxisMetricsByModel as u, type PromptSection as v, type SectionKind as w, type ShadowProbeConfig as x, type ToolDefinition as y };
|
|
1378
|
+
export { type ApiKeys as A, type BestPracticeAdvisory as B, type CompilePolicy as C, type EffortLevel as E, type FallbackReason as F, type Grounding as G, type HistoryCachePolicy as H, type IntentDeclaration as I, type Message as M, type NormalizedResponse as N, type OutcomeResult as O, type ProviderOverrides as P, type RecordInput as R, type SystemModelMessage as S, type ToolCall as T, type CompiledRequest as a, type PromptIR as b, type CallOptions as c, type CallResult as d, type CompileResult as e, type SectionRewrite as f, type RecordOutcomeInput as g, type OracleScore as h, type Adapter as i, type PerAxisMetrics as j, type Provider as k, type ChainEntry as l, type CallAttempt as m, CallError as n, type ChainModelEntry as o, type ChainWithGrounding as p, type Constraints as q, type MutationApplied as r, type NormalizedTokens as s, type OutcomeKind as t, type PerAxisMetricsByModel as u, type PromptSection as v, type SectionKind as w, type ShadowProbeConfig as x, type ToolDefinition as y };
|
|
@@ -111,11 +111,34 @@ interface IntentDeclaration {
|
|
|
111
111
|
/** Canonical dialect-v1 archetype. Required for cross-app learning. */
|
|
112
112
|
archetype: IntentArchetypeName;
|
|
113
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* alpha.57 — dialect-level reasoning-effort tier (data-first).
|
|
116
|
+
*
|
|
117
|
+
* Vocabulary is a portfolio-level tier ladder (low → max), NOT any provider's
|
|
118
|
+
* wire value — mapping to `reasoning_effort` (OpenAI) / thinking budgets
|
|
119
|
+
* (Anthropic) / `thinkingConfig` (Gemini) stays consumer-side until
|
|
120
|
+
* routing-on-effort ships. Declaring it records the tier on the brain row
|
|
121
|
+
* (`compile_outcomes.effort`, migration 033) so effort×archetype quality
|
|
122
|
+
* evidence accumulates BEFORE any routing logic exists — same data-first
|
|
123
|
+
* sequencing as `tool_orchestration` (alpha.20).
|
|
124
|
+
*/
|
|
125
|
+
type EffortLevel = 'low' | 'medium' | 'high' | 'xhigh' | 'max';
|
|
114
126
|
interface Constraints {
|
|
115
127
|
/** Hard latency ceiling — compiler will down-rank slow models. Advisory. */
|
|
116
128
|
maxLatencyMs?: number;
|
|
117
129
|
/** Hard cost ceiling per call (USD). Advisory. */
|
|
118
130
|
maxCostUsd?: number;
|
|
131
|
+
/**
|
|
132
|
+
* alpha.57 (data-first): the reasoning-effort tier the consumer ran (or
|
|
133
|
+
* intends to run) this call at. RECORDED, NOT APPLIED — the compiler does
|
|
134
|
+
* not emit provider thinking/effort params from this field and does not
|
|
135
|
+
* route on it yet; it flows to `compile_outcomes.effort` via record()'s
|
|
136
|
+
* registry auto-enrich (same pattern as `mutationsApplied`/advisories).
|
|
137
|
+
* Declare it truthfully: this is consumer-reported ground truth, like
|
|
138
|
+
* `tokensIn`/`latencyMs`. Does NOT enter the shape key (no learning-key
|
|
139
|
+
* fragmentation).
|
|
140
|
+
*/
|
|
141
|
+
effort?: EffortLevel;
|
|
119
142
|
/** Caller wants structured (JSON) output. */
|
|
120
143
|
structuredOutput?: boolean;
|
|
121
144
|
/** Hint: caller expects a short response (used to disable thinking on Gemini). */
|
|
@@ -1145,6 +1168,15 @@ interface RecordInput {
|
|
|
1145
1168
|
* surfaces it. Distinct from `latencyMs` (end-to-end wall clock).
|
|
1146
1169
|
*/
|
|
1147
1170
|
ttftMs?: number;
|
|
1171
|
+
/**
|
|
1172
|
+
* alpha.57 (data-first) — the reasoning-effort tier this call actually ran
|
|
1173
|
+
* at. Overrides the compile-declared `constraints.effort` when both are
|
|
1174
|
+
* present (input wins — same precedence as `mutationsApplied`/`advisories`).
|
|
1175
|
+
* When omitted, record() auto-enriches from the registry-cached compile
|
|
1176
|
+
* declaration. Undefined end-to-end → the `effort` key is absent from the
|
|
1177
|
+
* outcome payload entirely (safe against pre-migration-033 brains).
|
|
1178
|
+
*/
|
|
1179
|
+
effort?: EffortLevel;
|
|
1148
1180
|
/**
|
|
1149
1181
|
* alpha.20 — advisories fired at compile() time. Persisted to the brain's
|
|
1150
1182
|
* `compile_outcome_advisories` sibling table via a second POST that fires
|
|
@@ -1343,4 +1375,4 @@ interface PerAxisMetrics {
|
|
|
1343
1375
|
/** Per-axis metrics keyed by model — used for chain-comparison views. */
|
|
1344
1376
|
type PerAxisMetricsByModel = Record<string, PerAxisMetrics>;
|
|
1345
1377
|
|
|
1346
|
-
export { type ApiKeys as A, type BestPracticeAdvisory as B, type CompilePolicy as C, type FallbackReason as F, type Grounding as G, type HistoryCachePolicy as H, type IntentDeclaration as I, type Message as M, type NormalizedResponse as N, type OutcomeResult as O, type ProviderOverrides as P, type RecordInput as R, type SystemModelMessage as S, type ToolCall as T, type CompiledRequest as a, type PromptIR as b, type CallOptions as c, type CallResult as d, type CompileResult as e, type SectionRewrite as f, type RecordOutcomeInput as g, type OracleScore as h, type Adapter as i, type PerAxisMetrics as j, type Provider as k, type ChainEntry as l, type CallAttempt as m, CallError as n, type ChainModelEntry as o, type ChainWithGrounding as p, type Constraints as q, type MutationApplied as r, type NormalizedTokens as s, type OutcomeKind as t, type PerAxisMetricsByModel as u, type PromptSection as v, type SectionKind as w, type ShadowProbeConfig as x, type ToolDefinition as y };
|
|
1378
|
+
export { type ApiKeys as A, type BestPracticeAdvisory as B, type CompilePolicy as C, type EffortLevel as E, type FallbackReason as F, type Grounding as G, type HistoryCachePolicy as H, type IntentDeclaration as I, type Message as M, type NormalizedResponse as N, type OutcomeResult as O, type ProviderOverrides as P, type RecordInput as R, type SystemModelMessage as S, type ToolCall as T, type CompiledRequest as a, type PromptIR as b, type CallOptions as c, type CallResult as d, type CompileResult as e, type SectionRewrite as f, type RecordOutcomeInput as g, type OracleScore as h, type Adapter as i, type PerAxisMetrics as j, type Provider as k, type ChainEntry as l, type CallAttempt as m, CallError as n, type ChainModelEntry as o, type ChainWithGrounding as p, type Constraints as q, type MutationApplied as r, type NormalizedTokens as s, type OutcomeKind as t, type PerAxisMetricsByModel as u, type PromptSection as v, type SectionKind as w, type ShadowProbeConfig as x, type ToolDefinition as y };
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@warmdrift/kgauto-compiler/key-health` — per-consumer provider-key health
|
|
3
|
+
* endpoint factory (alpha.58, KG-fleet-v1 phase 1).
|
|
4
|
+
*
|
|
5
|
+
* ## Why this exists
|
|
6
|
+
*
|
|
7
|
+
* Consumers (playbacksam, inspire-central, tt-intelligence, global-expansion)
|
|
8
|
+
* hold their own provider API keys in their own Vercel envs — the library
|
|
9
|
+
* never sees keys centrally, by design. That means the operator dashboard has
|
|
10
|
+
* no way to answer "is PB's DeepSeek key still valid?" without a per-consumer
|
|
11
|
+
* probe surface. This factory is that surface: the consumer mounts ONE route,
|
|
12
|
+
* the dashboard polls it with the consumer's existing `KGAUTO_INGEST_SECRET`
|
|
13
|
+
* bearer, and gets back a validity grid for every canonical provider key.
|
|
14
|
+
*
|
|
15
|
+
* Probes are the cheapest authenticated GETs each provider offers (model
|
|
16
|
+
* listings; DeepSeek's balance endpoint) — never a completion call, zero
|
|
17
|
+
* token cost. Keys themselves NEVER appear in any response: only presence,
|
|
18
|
+
* validity, HTTP status, latency, and (DeepSeek only) account balance.
|
|
19
|
+
*
|
|
20
|
+
* Same design contract as `createBrainForwardRoutes` (brain-proxy.ts):
|
|
21
|
+
* web-standard Request→Response, never throws (every path returns a
|
|
22
|
+
* `Response`), bearer gate, runs on Edge/Workers/Node.
|
|
23
|
+
*
|
|
24
|
+
* ## Mounting recipes
|
|
25
|
+
*
|
|
26
|
+
* ### (a) Next.js app-router route handler — ONE file
|
|
27
|
+
*
|
|
28
|
+
* // app/api/kgauto/v2/keyhealth/route.ts
|
|
29
|
+
* import { createKeyHealthRoute } from '@warmdrift/kgauto-compiler/key-health';
|
|
30
|
+
* const routes = createKeyHealthRoute({
|
|
31
|
+
* appId: 'playbacksam',
|
|
32
|
+
* ingestSecret: process.env.KGAUTO_INGEST_SECRET!,
|
|
33
|
+
* });
|
|
34
|
+
* export const GET = (req: Request) => routes.handle(req);
|
|
35
|
+
*
|
|
36
|
+
* // middleware.ts — if the app gates routes behind auth middleware, the
|
|
37
|
+
* // existing brain-proxy public-path prefix ('/api/kgauto/v2/') already
|
|
38
|
+
* // covers this route. If the allowlist is per-path, add
|
|
39
|
+
* // '/api/kgauto/v2/keyhealth' or server-to-server GETs 307 to /login
|
|
40
|
+
* // (the tt-intel middleware-drift shape — see brain-proxy.ts).
|
|
41
|
+
*
|
|
42
|
+
* ### (b) Plain per-file Vercel function
|
|
43
|
+
*
|
|
44
|
+
* // api/kgauto/keyhealth.ts
|
|
45
|
+
* export const config = { runtime: 'edge' };
|
|
46
|
+
* import { createKeyHealthRoute } from '@warmdrift/kgauto-compiler/key-health';
|
|
47
|
+
* const routes = createKeyHealthRoute({
|
|
48
|
+
* appId: 'inspire-central',
|
|
49
|
+
* ingestSecret: process.env.KGAUTO_INGEST_SECRET!,
|
|
50
|
+
* });
|
|
51
|
+
* export default (req: Request) => routes.handle(req);
|
|
52
|
+
*
|
|
53
|
+
* ## Wire shape (LOCKED CONTRACT with the operator dashboard — do not rename)
|
|
54
|
+
*
|
|
55
|
+
* 200 {
|
|
56
|
+
* app_id: string,
|
|
57
|
+
* checked_at: string, // ISO timestamp
|
|
58
|
+
* keys: [ // sorted by provider name
|
|
59
|
+
* {
|
|
60
|
+
* provider: 'anthropic' | 'deepseek' | 'google' | 'openai',
|
|
61
|
+
* env: string, // canonical env var name probed
|
|
62
|
+
* present: boolean, // key present (non-empty after trim)
|
|
63
|
+
* valid: boolean | null, // true 2xx / false 401·403 / null unknown
|
|
64
|
+
* status?: number, // probe HTTP status when a response landed
|
|
65
|
+
* latency_ms?: number, // probe round-trip
|
|
66
|
+
* balance_usd?: number, // DeepSeek only, when currency is USD
|
|
67
|
+
* detail?: string, // e.g. 'timeout', 'http_500', 'key_absent'
|
|
68
|
+
* }
|
|
69
|
+
* ]
|
|
70
|
+
* }
|
|
71
|
+
*/
|
|
72
|
+
type KeyHealthProvider = 'anthropic' | 'deepseek' | 'google' | 'openai';
|
|
73
|
+
interface KeyHealthConfig {
|
|
74
|
+
/** Consumer app id echoed as `app_id` in the response (e.g. 'playbacksam'). */
|
|
75
|
+
appId: string;
|
|
76
|
+
/** Bearer token the poller must present (consumer's existing KGAUTO_INGEST_SECRET). */
|
|
77
|
+
ingestSecret: string;
|
|
78
|
+
/** Optional fetch impl for tests. */
|
|
79
|
+
fetchImpl?: typeof fetch;
|
|
80
|
+
/** Env source; defaults to process.env. Test injection point. */
|
|
81
|
+
env?: Record<string, string | undefined>;
|
|
82
|
+
/** Per-provider probe timeout in ms. Default 3000. */
|
|
83
|
+
timeoutMs?: number;
|
|
84
|
+
}
|
|
85
|
+
interface KeyHealthResult {
|
|
86
|
+
provider: KeyHealthProvider;
|
|
87
|
+
/** Canonical env var name probed (the resolved one for Google). */
|
|
88
|
+
env: string;
|
|
89
|
+
/** Key present (non-empty after trim) in env. */
|
|
90
|
+
present: boolean;
|
|
91
|
+
/** true = provider accepted the key (2xx); false = rejected (401/403); null = unknown (absent / timeout / 5xx / 429 / network). */
|
|
92
|
+
valid: boolean | null;
|
|
93
|
+
/** HTTP status of the probe, when a response landed. */
|
|
94
|
+
status?: number;
|
|
95
|
+
/** Probe round-trip in ms, when a probe ran. */
|
|
96
|
+
latency_ms?: number;
|
|
97
|
+
/** DeepSeek only: account balance in USD when the balance API reports USD. */
|
|
98
|
+
balance_usd?: number;
|
|
99
|
+
/** Failure class when valid is null with a probe attempted (e.g. 'timeout', 'http_500') or 'key_absent'. */
|
|
100
|
+
detail?: string;
|
|
101
|
+
}
|
|
102
|
+
interface KeyHealthResponseBody {
|
|
103
|
+
app_id: string;
|
|
104
|
+
checked_at: string;
|
|
105
|
+
keys: KeyHealthResult[];
|
|
106
|
+
}
|
|
107
|
+
interface KeyHealthRoute {
|
|
108
|
+
/**
|
|
109
|
+
* Web-standard handler. GET only. Never throws — every error path returns
|
|
110
|
+
* a `Response`.
|
|
111
|
+
*/
|
|
112
|
+
handle(req: Request): Promise<Response>;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Create the per-consumer key-health route. See module docstring for the
|
|
116
|
+
* mounting recipes ((a) Next.js route handler, (b) per-file Vercel function)
|
|
117
|
+
* and the locked wire shape.
|
|
118
|
+
*/
|
|
119
|
+
declare function createKeyHealthRoute(config: KeyHealthConfig): KeyHealthRoute;
|
|
120
|
+
|
|
121
|
+
export { type KeyHealthConfig, type KeyHealthProvider, type KeyHealthResponseBody, type KeyHealthResult, type KeyHealthRoute, createKeyHealthRoute };
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@warmdrift/kgauto-compiler/key-health` — per-consumer provider-key health
|
|
3
|
+
* endpoint factory (alpha.58, KG-fleet-v1 phase 1).
|
|
4
|
+
*
|
|
5
|
+
* ## Why this exists
|
|
6
|
+
*
|
|
7
|
+
* Consumers (playbacksam, inspire-central, tt-intelligence, global-expansion)
|
|
8
|
+
* hold their own provider API keys in their own Vercel envs — the library
|
|
9
|
+
* never sees keys centrally, by design. That means the operator dashboard has
|
|
10
|
+
* no way to answer "is PB's DeepSeek key still valid?" without a per-consumer
|
|
11
|
+
* probe surface. This factory is that surface: the consumer mounts ONE route,
|
|
12
|
+
* the dashboard polls it with the consumer's existing `KGAUTO_INGEST_SECRET`
|
|
13
|
+
* bearer, and gets back a validity grid for every canonical provider key.
|
|
14
|
+
*
|
|
15
|
+
* Probes are the cheapest authenticated GETs each provider offers (model
|
|
16
|
+
* listings; DeepSeek's balance endpoint) — never a completion call, zero
|
|
17
|
+
* token cost. Keys themselves NEVER appear in any response: only presence,
|
|
18
|
+
* validity, HTTP status, latency, and (DeepSeek only) account balance.
|
|
19
|
+
*
|
|
20
|
+
* Same design contract as `createBrainForwardRoutes` (brain-proxy.ts):
|
|
21
|
+
* web-standard Request→Response, never throws (every path returns a
|
|
22
|
+
* `Response`), bearer gate, runs on Edge/Workers/Node.
|
|
23
|
+
*
|
|
24
|
+
* ## Mounting recipes
|
|
25
|
+
*
|
|
26
|
+
* ### (a) Next.js app-router route handler — ONE file
|
|
27
|
+
*
|
|
28
|
+
* // app/api/kgauto/v2/keyhealth/route.ts
|
|
29
|
+
* import { createKeyHealthRoute } from '@warmdrift/kgauto-compiler/key-health';
|
|
30
|
+
* const routes = createKeyHealthRoute({
|
|
31
|
+
* appId: 'playbacksam',
|
|
32
|
+
* ingestSecret: process.env.KGAUTO_INGEST_SECRET!,
|
|
33
|
+
* });
|
|
34
|
+
* export const GET = (req: Request) => routes.handle(req);
|
|
35
|
+
*
|
|
36
|
+
* // middleware.ts — if the app gates routes behind auth middleware, the
|
|
37
|
+
* // existing brain-proxy public-path prefix ('/api/kgauto/v2/') already
|
|
38
|
+
* // covers this route. If the allowlist is per-path, add
|
|
39
|
+
* // '/api/kgauto/v2/keyhealth' or server-to-server GETs 307 to /login
|
|
40
|
+
* // (the tt-intel middleware-drift shape — see brain-proxy.ts).
|
|
41
|
+
*
|
|
42
|
+
* ### (b) Plain per-file Vercel function
|
|
43
|
+
*
|
|
44
|
+
* // api/kgauto/keyhealth.ts
|
|
45
|
+
* export const config = { runtime: 'edge' };
|
|
46
|
+
* import { createKeyHealthRoute } from '@warmdrift/kgauto-compiler/key-health';
|
|
47
|
+
* const routes = createKeyHealthRoute({
|
|
48
|
+
* appId: 'inspire-central',
|
|
49
|
+
* ingestSecret: process.env.KGAUTO_INGEST_SECRET!,
|
|
50
|
+
* });
|
|
51
|
+
* export default (req: Request) => routes.handle(req);
|
|
52
|
+
*
|
|
53
|
+
* ## Wire shape (LOCKED CONTRACT with the operator dashboard — do not rename)
|
|
54
|
+
*
|
|
55
|
+
* 200 {
|
|
56
|
+
* app_id: string,
|
|
57
|
+
* checked_at: string, // ISO timestamp
|
|
58
|
+
* keys: [ // sorted by provider name
|
|
59
|
+
* {
|
|
60
|
+
* provider: 'anthropic' | 'deepseek' | 'google' | 'openai',
|
|
61
|
+
* env: string, // canonical env var name probed
|
|
62
|
+
* present: boolean, // key present (non-empty after trim)
|
|
63
|
+
* valid: boolean | null, // true 2xx / false 401·403 / null unknown
|
|
64
|
+
* status?: number, // probe HTTP status when a response landed
|
|
65
|
+
* latency_ms?: number, // probe round-trip
|
|
66
|
+
* balance_usd?: number, // DeepSeek only, when currency is USD
|
|
67
|
+
* detail?: string, // e.g. 'timeout', 'http_500', 'key_absent'
|
|
68
|
+
* }
|
|
69
|
+
* ]
|
|
70
|
+
* }
|
|
71
|
+
*/
|
|
72
|
+
type KeyHealthProvider = 'anthropic' | 'deepseek' | 'google' | 'openai';
|
|
73
|
+
interface KeyHealthConfig {
|
|
74
|
+
/** Consumer app id echoed as `app_id` in the response (e.g. 'playbacksam'). */
|
|
75
|
+
appId: string;
|
|
76
|
+
/** Bearer token the poller must present (consumer's existing KGAUTO_INGEST_SECRET). */
|
|
77
|
+
ingestSecret: string;
|
|
78
|
+
/** Optional fetch impl for tests. */
|
|
79
|
+
fetchImpl?: typeof fetch;
|
|
80
|
+
/** Env source; defaults to process.env. Test injection point. */
|
|
81
|
+
env?: Record<string, string | undefined>;
|
|
82
|
+
/** Per-provider probe timeout in ms. Default 3000. */
|
|
83
|
+
timeoutMs?: number;
|
|
84
|
+
}
|
|
85
|
+
interface KeyHealthResult {
|
|
86
|
+
provider: KeyHealthProvider;
|
|
87
|
+
/** Canonical env var name probed (the resolved one for Google). */
|
|
88
|
+
env: string;
|
|
89
|
+
/** Key present (non-empty after trim) in env. */
|
|
90
|
+
present: boolean;
|
|
91
|
+
/** true = provider accepted the key (2xx); false = rejected (401/403); null = unknown (absent / timeout / 5xx / 429 / network). */
|
|
92
|
+
valid: boolean | null;
|
|
93
|
+
/** HTTP status of the probe, when a response landed. */
|
|
94
|
+
status?: number;
|
|
95
|
+
/** Probe round-trip in ms, when a probe ran. */
|
|
96
|
+
latency_ms?: number;
|
|
97
|
+
/** DeepSeek only: account balance in USD when the balance API reports USD. */
|
|
98
|
+
balance_usd?: number;
|
|
99
|
+
/** Failure class when valid is null with a probe attempted (e.g. 'timeout', 'http_500') or 'key_absent'. */
|
|
100
|
+
detail?: string;
|
|
101
|
+
}
|
|
102
|
+
interface KeyHealthResponseBody {
|
|
103
|
+
app_id: string;
|
|
104
|
+
checked_at: string;
|
|
105
|
+
keys: KeyHealthResult[];
|
|
106
|
+
}
|
|
107
|
+
interface KeyHealthRoute {
|
|
108
|
+
/**
|
|
109
|
+
* Web-standard handler. GET only. Never throws — every error path returns
|
|
110
|
+
* a `Response`.
|
|
111
|
+
*/
|
|
112
|
+
handle(req: Request): Promise<Response>;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Create the per-consumer key-health route. See module docstring for the
|
|
116
|
+
* mounting recipes ((a) Next.js route handler, (b) per-file Vercel function)
|
|
117
|
+
* and the locked wire shape.
|
|
118
|
+
*/
|
|
119
|
+
declare function createKeyHealthRoute(config: KeyHealthConfig): KeyHealthRoute;
|
|
120
|
+
|
|
121
|
+
export { type KeyHealthConfig, type KeyHealthProvider, type KeyHealthResponseBody, type KeyHealthResult, type KeyHealthRoute, createKeyHealthRoute };
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/key-health.ts
|
|
21
|
+
var key_health_exports = {};
|
|
22
|
+
__export(key_health_exports, {
|
|
23
|
+
createKeyHealthRoute: () => createKeyHealthRoute
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(key_health_exports);
|
|
26
|
+
var JSON_HEADERS = { "Content-Type": "application/json" };
|
|
27
|
+
function jsonResponse(status, body) {
|
|
28
|
+
return new Response(JSON.stringify(body), { status, headers: JSON_HEADERS });
|
|
29
|
+
}
|
|
30
|
+
function bearerOf(req) {
|
|
31
|
+
const header = req.headers.get("Authorization") ?? "";
|
|
32
|
+
const match = /^Bearer\s+(.+)$/i.exec(header);
|
|
33
|
+
return match?.[1]?.trim() ?? "";
|
|
34
|
+
}
|
|
35
|
+
function requireString(name, value) {
|
|
36
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
37
|
+
throw new Error(`createKeyHealthRoute: ${name} is required`);
|
|
38
|
+
}
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
function envKey(env, name) {
|
|
42
|
+
const v = env[name];
|
|
43
|
+
if (typeof v !== "string") return void 0;
|
|
44
|
+
const trimmed = v.trim();
|
|
45
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
46
|
+
}
|
|
47
|
+
var PROBE_SPECS = [
|
|
48
|
+
{
|
|
49
|
+
provider: "anthropic",
|
|
50
|
+
canonicalEnvName: "ANTHROPIC_API_KEY",
|
|
51
|
+
buildRequest: (key) => ({
|
|
52
|
+
url: "https://api.anthropic.com/v1/models?limit=1",
|
|
53
|
+
headers: { "x-api-key": key, "anthropic-version": "2023-06-01" }
|
|
54
|
+
})
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
provider: "deepseek",
|
|
58
|
+
canonicalEnvName: "DEEPSEEK_API_KEY",
|
|
59
|
+
buildRequest: (key) => ({
|
|
60
|
+
url: "https://api.deepseek.com/user/balance",
|
|
61
|
+
headers: { Authorization: `Bearer ${key}` }
|
|
62
|
+
}),
|
|
63
|
+
parseBalanceUsd: (body) => {
|
|
64
|
+
const infos = body?.balance_infos;
|
|
65
|
+
if (!Array.isArray(infos) || infos.length === 0) return void 0;
|
|
66
|
+
const first = infos[0];
|
|
67
|
+
if (first?.currency !== "USD") return void 0;
|
|
68
|
+
const n = Number(first.total_balance);
|
|
69
|
+
return Number.isFinite(n) ? n : void 0;
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
provider: "google",
|
|
74
|
+
canonicalEnvName: "GEMINI_API_KEY",
|
|
75
|
+
buildRequest: (key) => ({
|
|
76
|
+
url: `https://generativelanguage.googleapis.com/v1beta/models?pageSize=1&key=${encodeURIComponent(key)}`,
|
|
77
|
+
headers: {}
|
|
78
|
+
})
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
provider: "openai",
|
|
82
|
+
canonicalEnvName: "OPENAI_API_KEY",
|
|
83
|
+
buildRequest: (key) => ({
|
|
84
|
+
url: "https://api.openai.com/v1/models",
|
|
85
|
+
headers: { Authorization: `Bearer ${key}` }
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
];
|
|
89
|
+
function createKeyHealthRoute(config) {
|
|
90
|
+
const appId = requireString("appId", config.appId);
|
|
91
|
+
const ingestSecret = requireString("ingestSecret", config.ingestSecret);
|
|
92
|
+
const fetchFn = config.fetchImpl ?? fetch;
|
|
93
|
+
const timeoutMs = config.timeoutMs ?? 3e3;
|
|
94
|
+
async function probeProvider(spec, env) {
|
|
95
|
+
let key;
|
|
96
|
+
let envName = spec.canonicalEnvName;
|
|
97
|
+
if (spec.provider === "google") {
|
|
98
|
+
const gemini = envKey(env, "GEMINI_API_KEY");
|
|
99
|
+
const google = envKey(env, "GOOGLE_API_KEY");
|
|
100
|
+
const aiSdk = envKey(env, "GOOGLE_GENERATIVE_AI_API_KEY");
|
|
101
|
+
key = gemini ?? google ?? aiSdk;
|
|
102
|
+
envName = gemini ? "GEMINI_API_KEY" : google ? "GOOGLE_API_KEY" : aiSdk ? "GOOGLE_GENERATIVE_AI_API_KEY" : "GEMINI_API_KEY";
|
|
103
|
+
} else {
|
|
104
|
+
key = envKey(env, spec.canonicalEnvName);
|
|
105
|
+
}
|
|
106
|
+
if (!key) {
|
|
107
|
+
return {
|
|
108
|
+
provider: spec.provider,
|
|
109
|
+
env: envName,
|
|
110
|
+
present: false,
|
|
111
|
+
valid: null,
|
|
112
|
+
detail: "key_absent"
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
const base = {
|
|
116
|
+
provider: spec.provider,
|
|
117
|
+
env: envName,
|
|
118
|
+
present: true,
|
|
119
|
+
valid: null
|
|
120
|
+
};
|
|
121
|
+
const { url, headers } = spec.buildRequest(key);
|
|
122
|
+
const started = Date.now();
|
|
123
|
+
let res;
|
|
124
|
+
try {
|
|
125
|
+
res = await fetchFn(url, {
|
|
126
|
+
method: "GET",
|
|
127
|
+
headers,
|
|
128
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
129
|
+
});
|
|
130
|
+
} catch (err) {
|
|
131
|
+
const isTimeout = err instanceof Error && (err.name === "TimeoutError" || err.name === "AbortError");
|
|
132
|
+
return {
|
|
133
|
+
...base,
|
|
134
|
+
latency_ms: Date.now() - started,
|
|
135
|
+
// NEVER echo err.message — provider errors could theoretically carry
|
|
136
|
+
// request context; a fixed vocabulary keeps key material impossible.
|
|
137
|
+
detail: isTimeout ? "timeout" : "network_error"
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
const latencyMs = Date.now() - started;
|
|
141
|
+
if (res.ok) {
|
|
142
|
+
const result = {
|
|
143
|
+
...base,
|
|
144
|
+
valid: true,
|
|
145
|
+
status: res.status,
|
|
146
|
+
latency_ms: latencyMs
|
|
147
|
+
};
|
|
148
|
+
if (spec.parseBalanceUsd) {
|
|
149
|
+
try {
|
|
150
|
+
const body = await res.json();
|
|
151
|
+
const balance = spec.parseBalanceUsd(body);
|
|
152
|
+
if (balance !== void 0) result.balance_usd = balance;
|
|
153
|
+
} catch {
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return result;
|
|
157
|
+
}
|
|
158
|
+
if (res.status === 401 || res.status === 403) {
|
|
159
|
+
return { ...base, valid: false, status: res.status, latency_ms: latencyMs };
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
...base,
|
|
163
|
+
valid: null,
|
|
164
|
+
status: res.status,
|
|
165
|
+
latency_ms: latencyMs,
|
|
166
|
+
detail: `http_${res.status}`
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
async function handle(req) {
|
|
170
|
+
try {
|
|
171
|
+
if (req.method !== "GET") {
|
|
172
|
+
return jsonResponse(405, { error: "method_not_allowed" });
|
|
173
|
+
}
|
|
174
|
+
if (bearerOf(req) !== ingestSecret) {
|
|
175
|
+
return jsonResponse(401, { error: "unauthorized" });
|
|
176
|
+
}
|
|
177
|
+
const env = config.env ?? process.env;
|
|
178
|
+
const settled = await Promise.allSettled(
|
|
179
|
+
PROBE_SPECS.map((spec) => probeProvider(spec, env))
|
|
180
|
+
);
|
|
181
|
+
const keys = settled.map((s, i) => {
|
|
182
|
+
if (s.status === "fulfilled") return s.value;
|
|
183
|
+
const spec = PROBE_SPECS[i];
|
|
184
|
+
return {
|
|
185
|
+
provider: spec.provider,
|
|
186
|
+
env: spec.canonicalEnvName,
|
|
187
|
+
present: true,
|
|
188
|
+
valid: null,
|
|
189
|
+
detail: "probe_failed"
|
|
190
|
+
};
|
|
191
|
+
});
|
|
192
|
+
keys.sort((a, b) => a.provider.localeCompare(b.provider));
|
|
193
|
+
const body = {
|
|
194
|
+
app_id: appId,
|
|
195
|
+
checked_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
196
|
+
keys
|
|
197
|
+
};
|
|
198
|
+
return jsonResponse(200, body);
|
|
199
|
+
} catch (err) {
|
|
200
|
+
void err;
|
|
201
|
+
return jsonResponse(500, { error: "key_health_internal_error" });
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return { handle };
|
|
205
|
+
}
|
|
206
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
207
|
+
0 && (module.exports = {
|
|
208
|
+
createKeyHealthRoute
|
|
209
|
+
});
|
package/dist/profiles.d.mts
CHANGED
package/dist/profiles.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as MutationApplied, B as BestPracticeAdvisory, F as FallbackReason, m as CallAttempt } from './ir-
|
|
1
|
+
import { r as MutationApplied, B as BestPracticeAdvisory, F as FallbackReason, m as CallAttempt } from './ir-BC4uDL98.mjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Glass-Box observability types (alpha.17).
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as MutationApplied, B as BestPracticeAdvisory, F as FallbackReason, m as CallAttempt } from './ir-
|
|
1
|
+
import { r as MutationApplied, B as BestPracticeAdvisory, F as FallbackReason, m as CallAttempt } from './ir-B2h0GAEL.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Glass-Box observability types (alpha.17).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@warmdrift/kgauto-compiler",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.58",
|
|
4
4
|
"description": "Prompt compiler + central learning brain for multi-model AI apps. Swap models without rewriting prompts.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -26,6 +26,11 @@
|
|
|
26
26
|
"import": "./dist/brain-proxy.mjs",
|
|
27
27
|
"require": "./dist/brain-proxy.js"
|
|
28
28
|
},
|
|
29
|
+
"./key-health": {
|
|
30
|
+
"types": "./dist/key-health.d.ts",
|
|
31
|
+
"import": "./dist/key-health.mjs",
|
|
32
|
+
"require": "./dist/key-health.js"
|
|
33
|
+
},
|
|
29
34
|
"./glassbox": {
|
|
30
35
|
"types": "./dist/glassbox/index.d.ts",
|
|
31
36
|
"import": "./dist/glassbox/index.mjs",
|
|
@@ -52,7 +57,7 @@
|
|
|
52
57
|
"README.md"
|
|
53
58
|
],
|
|
54
59
|
"scripts": {
|
|
55
|
-
"build": "tsup src/index.ts src/dialect.ts src/profiles.ts src/brain-proxy.ts src/glassbox/index.ts src/glassbox-routes/index.ts src/glassbox-routes/format.ts src/glassbox-routes/react/index.ts --format cjs,esm --dts --clean --external react --external react-dom",
|
|
60
|
+
"build": "tsup src/index.ts src/dialect.ts src/profiles.ts src/brain-proxy.ts src/key-health.ts src/glassbox/index.ts src/glassbox-routes/index.ts src/glassbox-routes/format.ts src/glassbox-routes/react/index.ts --format cjs,esm --dts --clean --external react --external react-dom",
|
|
56
61
|
"test": "vitest run",
|
|
57
62
|
"test:watch": "vitest",
|
|
58
63
|
"typecheck": "tsc --noEmit",
|