@harperfast/harper 5.3.0 → 5.3.1
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/bin/copyDb.ts +5 -1
- package/bin/deployRenderer.ts +3 -0
- package/components/Application.ts +66 -22
- package/components/DESIGN.md +89 -36
- package/components/componentLoader.ts +2 -0
- package/components/deploymentRecorder.ts +18 -1
- package/components/installFingerprint.ts +123 -0
- package/components/mcp/DESIGN.md +4 -4
- package/components/operations.js +29 -0
- package/config/DESIGN.md +5 -5
- package/dataLayer/DESIGN.md +37 -22
- package/dataLayer/backupRepository.ts +248 -0
- package/dataLayer/restoreMarker.ts +30 -75
- package/dataLayer/rocksdbBackup.ts +253 -110
- package/dist/bin/copyDb.js +3 -0
- package/dist/bin/copyDb.js.map +1 -1
- package/dist/bin/deployRenderer.js +3 -0
- package/dist/bin/deployRenderer.js.map +1 -1
- package/dist/components/Application.d.ts +5 -0
- package/dist/components/Application.js +51 -19
- package/dist/components/Application.js.map +1 -1
- package/dist/components/componentLoader.js +2 -0
- package/dist/components/componentLoader.js.map +1 -1
- package/dist/components/deploymentRecorder.js +18 -1
- package/dist/components/deploymentRecorder.js.map +1 -1
- package/dist/components/installFingerprint.d.ts +39 -0
- package/dist/components/installFingerprint.js +113 -0
- package/dist/components/installFingerprint.js.map +1 -0
- package/dist/components/operations.d.ts +2 -0
- package/dist/components/operations.js +31 -0
- package/dist/components/operations.js.map +1 -1
- package/dist/dataLayer/backupRepository.d.ts +33 -0
- package/dist/dataLayer/backupRepository.js +232 -0
- package/dist/dataLayer/backupRepository.js.map +1 -0
- package/dist/dataLayer/restoreMarker.d.ts +4 -1
- package/dist/dataLayer/restoreMarker.js +29 -68
- package/dist/dataLayer/restoreMarker.js.map +1 -1
- package/dist/dataLayer/rocksdbBackup.js +221 -112
- package/dist/dataLayer/rocksdbBackup.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js.map +1 -1
- package/dist/json/systemSchema.json +14 -0
- package/dist/resources/DatabaseTransaction.d.ts +140 -11
- package/dist/resources/DatabaseTransaction.js +1055 -464
- package/dist/resources/DatabaseTransaction.js.map +1 -1
- package/dist/resources/IterableEventQueue.d.ts +2 -1
- package/dist/resources/IterableEventQueue.js +16 -8
- package/dist/resources/IterableEventQueue.js.map +1 -1
- package/dist/resources/LMDBTransaction.d.ts +13 -2
- package/dist/resources/LMDBTransaction.js +219 -93
- package/dist/resources/LMDBTransaction.js.map +1 -1
- package/dist/resources/RecordEncoder.js +2 -3
- package/dist/resources/RecordEncoder.js.map +1 -1
- package/dist/resources/Resource.js +5 -6
- package/dist/resources/Resource.js.map +1 -1
- package/dist/resources/ResourceInterface.d.ts +3 -1
- package/dist/resources/ResourceInterface.js.map +1 -1
- package/dist/resources/RocksIndexStore.d.ts +2 -1
- package/dist/resources/RocksIndexStore.js +3 -0
- package/dist/resources/RocksIndexStore.js.map +1 -1
- package/dist/resources/Table.js +116 -12
- package/dist/resources/Table.js.map +1 -1
- package/dist/resources/analytics/write.js +6 -2
- package/dist/resources/analytics/write.js.map +1 -1
- package/dist/resources/auditStore.d.ts +71 -17
- package/dist/resources/auditStore.js +248 -64
- package/dist/resources/auditStore.js.map +1 -1
- package/dist/resources/branchDatabase.js +2 -0
- package/dist/resources/branchDatabase.js.map +1 -1
- package/dist/resources/databases.js +8 -2
- package/dist/resources/databases.js.map +1 -1
- package/dist/resources/indexes/fullTextNativeBinding.d.ts +6 -2
- package/dist/resources/indexes/fullTextNativeBinding.js +12 -2
- package/dist/resources/indexes/fullTextNativeBinding.js.map +1 -1
- package/dist/resources/indexes/fullTextQueryIndex.d.ts +4 -0
- package/dist/resources/indexes/fullTextQueryIndex.js +207 -10
- package/dist/resources/indexes/fullTextQueryIndex.js.map +1 -1
- package/dist/resources/models/Models.d.ts +11 -0
- package/dist/resources/models/Models.js +95 -4
- package/dist/resources/models/Models.js.map +1 -1
- package/dist/resources/models/backendRegistry.d.ts +8 -0
- package/dist/resources/models/backendRegistry.js +15 -1
- package/dist/resources/models/backendRegistry.js.map +1 -1
- package/dist/resources/models/bootstrap.d.ts +2 -0
- package/dist/resources/models/bootstrap.js +6 -0
- package/dist/resources/models/bootstrap.js.map +1 -1
- package/dist/resources/models/calibration.d.ts +88 -0
- package/dist/resources/models/calibration.js +244 -0
- package/dist/resources/models/calibration.js.map +1 -0
- package/dist/resources/models/calibrationStore.d.ts +163 -0
- package/dist/resources/models/calibrationStore.js +986 -0
- package/dist/resources/models/calibrationStore.js.map +1 -0
- package/dist/resources/models/decisionStore.d.ts +24 -0
- package/dist/resources/models/decisionStore.js +45 -0
- package/dist/resources/models/decisionStore.js.map +1 -1
- package/dist/resources/models/generativeDecision.js +44 -15
- package/dist/resources/models/generativeDecision.js.map +1 -1
- package/dist/resources/models/types.d.ts +7 -0
- package/dist/resources/recordLock.d.ts +8 -5
- package/dist/resources/recordLock.js +6 -4
- package/dist/resources/recordLock.js.map +1 -1
- package/dist/resources/replayLogs.js +8 -1
- package/dist/resources/replayLogs.js.map +1 -1
- package/dist/resources/scheduler/engine.d.ts +4 -0
- package/dist/resources/scheduler/engine.js +30 -2
- package/dist/resources/scheduler/engine.js.map +1 -1
- package/dist/resources/search.d.ts +16 -4
- package/dist/resources/search.js +117 -13
- package/dist/resources/search.js.map +1 -1
- package/dist/resources/transaction.js +85 -5
- package/dist/resources/transaction.js.map +1 -1
- package/dist/resources/transactionBroadcast.d.ts +8 -0
- package/dist/resources/transactionBroadcast.js +65 -0
- package/dist/resources/transactionBroadcast.js.map +1 -1
- package/dist/security/keys.d.ts +1 -1
- package/dist/security/keys.js +170 -120
- package/dist/security/keys.js.map +1 -1
- package/dist/server/http.js +10 -0
- package/dist/server/http.js.map +1 -1
- package/dist/server/serverHelpers/Request.js +11 -2
- package/dist/server/serverHelpers/Request.js.map +1 -1
- package/dist/server/serverHelpers/contentTypes.js +8 -3
- package/dist/server/serverHelpers/contentTypes.js.map +1 -1
- package/dist/server/serverHelpers/uwsServer.js +38 -7
- package/dist/server/serverHelpers/uwsServer.js.map +1 -1
- package/dist/server/threads/manageThreads.d.ts +3 -3
- package/dist/server/threads/manageThreads.js +15 -13
- package/dist/server/threads/manageThreads.js.map +1 -1
- package/dist/server/threads/threadServer.d.ts +3 -0
- package/dist/server/threads/threadServer.js +24 -6
- package/dist/server/threads/threadServer.js.map +1 -1
- package/dist/upgrade/directives/5-3-0.js +9 -3
- package/dist/upgrade/directives/5-3-0.js.map +1 -1
- package/dist/utility/durableFile.d.ts +36 -0
- package/dist/utility/durableFile.js +106 -0
- package/dist/utility/durableFile.js.map +1 -0
- package/dist/utility/errors/hdbError.d.ts +4 -0
- package/dist/utility/errors/hdbError.js +10 -1
- package/dist/utility/errors/hdbError.js.map +1 -1
- package/dist/utility/globalSchema.d.ts +9 -0
- package/dist/utility/hdbTerms.d.ts +1 -0
- package/dist/utility/hdbTerms.js +1 -0
- package/dist/utility/hdbTerms.js.map +1 -1
- package/dist/validation/configValidator.js +29 -0
- package/dist/validation/configValidator.js.map +1 -1
- package/index.ts +7 -0
- package/json/systemSchema.json +14 -0
- package/npm-shrinkwrap.json +22 -22
- package/package.json +2 -2
- package/resources/DESIGN.md +57 -272
- package/resources/DatabaseTransaction.ts +708 -87
- package/resources/FULL_TEXT.md +6 -2
- package/resources/IterableEventQueue.ts +14 -7
- package/resources/LMDBTransaction.ts +212 -84
- package/resources/RecordEncoder.ts +2 -3
- package/resources/Resource.ts +5 -6
- package/resources/ResourceInterface.ts +3 -1
- package/resources/RocksIndexStore.ts +5 -0
- package/resources/Table.ts +118 -15
- package/resources/analytics/write.ts +6 -2
- package/resources/audit-retention.md +203 -0
- package/resources/auditStore.ts +306 -84
- package/resources/branchDatabase.ts +2 -0
- package/resources/databases.ts +6 -2
- package/resources/indexes/DESIGN.md +120 -177
- package/resources/indexes/fullTextNativeBinding.ts +22 -3
- package/resources/indexes/fullTextQueryIndex.ts +274 -11
- package/resources/models/DESIGN.md +11 -3
- package/resources/models/Models.ts +127 -4
- package/resources/models/backendRegistry.ts +17 -0
- package/resources/models/bootstrap.ts +9 -1
- package/resources/models/calibration.ts +298 -0
- package/resources/models/calibrationStore.ts +1167 -0
- package/resources/models/decisionStore.ts +57 -0
- package/resources/models/generativeDecision.ts +54 -16
- package/resources/models/types.ts +6 -0
- package/resources/record-locks.md +155 -141
- package/resources/recordLock.ts +12 -6
- package/resources/replayLogs.ts +9 -2
- package/resources/scheduler/DESIGN.md +4 -3
- package/resources/scheduler/engine.ts +35 -2
- package/resources/search.ts +154 -16
- package/resources/transaction.ts +50 -5
- package/resources/transactionBroadcast.ts +69 -0
- package/security/DESIGN.md +9 -30
- package/security/keys.ts +175 -127
- package/server/DESIGN.md +70 -36
- package/server/http.ts +10 -0
- package/server/serverHelpers/Request.ts +10 -2
- package/server/serverHelpers/contentTypes.ts +5 -3
- package/server/serverHelpers/uwsServer.ts +34 -7
- package/server/threads/manageThreads.js +16 -14
- package/server/threads/threadServer.js +24 -6
- package/studio/web/assets/{Chat-CNEKMllJ.js → Chat-4LMxI0yB.js} +1 -1
- package/studio/web/assets/{FloatingChat-CEnWhHeR.js → FloatingChat-kWHApEtF.js} +3 -3
- package/studio/web/assets/{SearchDialog-CwhJdEdY.js → SearchDialog-B7ymna97.js} +1 -1
- package/studio/web/assets/{apiToken-DC5vsaaO.js → apiToken-CE3AAt9f.js} +1 -1
- package/studio/web/assets/{applications-DQZxDy0x.js → applications-DdN7CqsB.js} +1 -1
- package/studio/web/assets/{cssMode-Dz2DxF4e.js → cssMode-BpySZUSt.js} +1 -1
- package/studio/web/assets/{editor-B3mjd3tz.js → editor-myLCVv9C.js} +1 -1
- package/studio/web/assets/{html-BsRGM7tp.js → html-DGNYO55O.js} +1 -1
- package/studio/web/assets/{htmlMode-tUKJaA3o.js → htmlMode-BUgpQr41.js} +1 -1
- package/studio/web/assets/{index-BuqFjN5K.js → index-FN4KC9va.js} +39 -39
- package/studio/web/assets/index-QLZw6xrU.css +1 -0
- package/studio/web/assets/{index.lazy-CcpfQFY_.js → index.lazy-DZFuaumG.js} +1 -1
- package/studio/web/assets/{javascript-BZ_uRGHl.js → javascript-DiBzh4pj.js} +1 -1
- package/studio/web/assets/{jsonMode-DgB-aFMj.js → jsonMode-Bm312nmu.js} +1 -1
- package/studio/web/assets/{languageServices-BleuBw17.js → languageServices-Dz2K9rZN.js} +1 -1
- package/studio/web/assets/{lspLanguageFeatures-ByVYLSsQ.js → lspLanguageFeatures-CNu1L5xn.js} +1 -1
- package/studio/web/assets/{notifications-TuzN0IMi.js → notifications--nwFLGmM.js} +1 -1
- package/studio/web/assets/{notifications-D1Nf-Edn.js → notifications-BelKw5bR.js} +1 -1
- package/studio/web/assets/{profile-D7C7Lupz.js → profile-AU5FjOBx.js} +1 -1
- package/studio/web/assets/{regions-nGQCm-v8.js → regions-C0sTSEHH.js} +1 -1
- package/studio/web/assets/{register-C3x9Ze6P.js → register-DyNR2rGk.js} +2 -2
- package/studio/web/assets/{setComponentFile-DpjrRqeG.js → setComponentFile-BkWx8AN3.js} +1 -1
- package/studio/web/assets/{setup-CGiKLZ9e.js → setup-D6LZS78d.js} +2 -2
- package/studio/web/assets/{status-CGJwrNPH.js → status-BCWnn70o.js} +1 -1
- package/studio/web/assets/{toggleHighContrast-C-Ne6P7T.js → toggleHighContrast-pyeGJ6W1.js} +1 -1
- package/studio/web/assets/{tsMode-CSreYTys.js → tsMode-CGV3iaWC.js} +1 -1
- package/studio/web/assets/{typescript-MnxBk89W.js → typescript-Ci7Khvwo.js} +1 -1
- package/studio/web/assets/{useEntityRestURL-TNrh77-s.js → useEntityRestURL-DNiz3aZ0.js} +1 -1
- package/studio/web/assets/{workers-BfZlUNVI.js → workers-byzxjbqy.js} +1 -1
- package/studio/web/assets/{xml-BHd6qGH7.js → xml-DGnHQ3CX.js} +1 -1
- package/studio/web/assets/{yaml-C53R8OQq.js → yaml-BUoTnPWb.js} +1 -1
- package/studio/web/index.html +2 -2
- package/upgrade/directives/5-3-0.ts +10 -3
- package/utility/durableFile.ts +96 -0
- package/utility/errors/hdbError.ts +9 -0
- package/utility/hdbTerms.ts +1 -0
- package/validation/configValidator.ts +31 -0
- package/studio/web/assets/index-72cEH474.css +0 -1
|
@@ -45,6 +45,16 @@ export interface DecisionRow {
|
|
|
45
45
|
fields?: DecisionRecord['fields'];
|
|
46
46
|
noMatch?: number;
|
|
47
47
|
calibrated: boolean;
|
|
48
|
+
/** The backend's scores, kept when a fitted calibration replaced them, so a refit never reads its own output. */
|
|
49
|
+
rawDistribution?: DecisionRecord['distribution'];
|
|
50
|
+
rawFields?: DecisionRecord['fields'];
|
|
51
|
+
/** The fit applied to each field (`field` absent for a leaf schema), with its parameters as applied. */
|
|
52
|
+
calibration?: Array<{ field?: string; fitId: string; t: number; epsilon: number }>;
|
|
53
|
+
/** The decision entry's source fingerprint, or `registered:<name>` for a backend registered from code. */
|
|
54
|
+
entry?: string;
|
|
55
|
+
/** The calibration population, for a decision whose score source is identified. */
|
|
56
|
+
population?: string;
|
|
57
|
+
populationRank?: string;
|
|
48
58
|
}
|
|
49
59
|
|
|
50
60
|
type Fact = 'truth' | 'action';
|
|
@@ -84,6 +94,12 @@ export const DECISION_ATTRIBUTES = [
|
|
|
84
94
|
{ name: 'fields' },
|
|
85
95
|
{ name: 'noMatch', type: 'number' },
|
|
86
96
|
{ name: 'calibrated', type: 'boolean' },
|
|
97
|
+
{ name: 'rawDistribution' },
|
|
98
|
+
{ name: 'rawFields' },
|
|
99
|
+
{ name: 'calibration' },
|
|
100
|
+
{ name: 'entry', type: 'string' },
|
|
101
|
+
{ name: 'population', type: 'string' },
|
|
102
|
+
{ name: 'populationRank', type: 'string', indexed: true },
|
|
87
103
|
];
|
|
88
104
|
|
|
89
105
|
export const OUTCOME_ATTRIBUTES = [
|
|
@@ -279,6 +295,10 @@ function visibleTo(row: DecisionRow, tenant: string | undefined): boolean {
|
|
|
279
295
|
return tenant == null || row.tenant == null || row.tenant === tenant;
|
|
280
296
|
}
|
|
281
297
|
|
|
298
|
+
export function truthKey(id: string, field?: string): string {
|
|
299
|
+
return factKey(id, 'truth', field);
|
|
300
|
+
}
|
|
301
|
+
|
|
282
302
|
function factKey(id: string, fact: Fact, field?: string): string {
|
|
283
303
|
return field == null ? `${id}/${fact}` : `${id}/${fact}/${field}`;
|
|
284
304
|
}
|
|
@@ -394,6 +414,43 @@ export function getModelsConfigHash(): string | undefined {
|
|
|
394
414
|
return modelsConfigHash;
|
|
395
415
|
}
|
|
396
416
|
|
|
417
|
+
/** A configured entry's identity without its credentials: the same fingerprint for the same visible configuration. */
|
|
418
|
+
export function sourceFingerprint(kind: string, logicalName: string | undefined, config: unknown): string {
|
|
419
|
+
return createHash('sha256')
|
|
420
|
+
.update(
|
|
421
|
+
canonicalJson({
|
|
422
|
+
kind,
|
|
423
|
+
logicalName: logicalName ?? null,
|
|
424
|
+
config: withoutNamedCredentials(withoutFallback(config)),
|
|
425
|
+
})
|
|
426
|
+
)
|
|
427
|
+
.digest('hex');
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Only fields known to hold credentials. A setting that merely ends in `key` or `token` can change what a source
|
|
432
|
+
* scores, so it stays in the fingerprint; rotating an unrecognized secret therefore starts calibration over.
|
|
433
|
+
*/
|
|
434
|
+
const NAMED_CREDENTIAL =
|
|
435
|
+
/^(apiKey|apiSecret|accessKeyId|secretAccessKey|sessionToken|authorization|password|token|bearerToken|credentials?)$/i;
|
|
436
|
+
|
|
437
|
+
function withoutNamedCredentials(value: unknown): unknown {
|
|
438
|
+
if (Array.isArray(value)) return value.map(withoutNamedCredentials);
|
|
439
|
+
if (!value || typeof value !== 'object') return value;
|
|
440
|
+
const kept: Record<string, unknown> = {};
|
|
441
|
+
for (const [key, entry] of Object.entries(value as Record<string, unknown>)) {
|
|
442
|
+
if (!NAMED_CREDENTIAL.test(key)) kept[key] = withoutNamedCredentials(entry);
|
|
443
|
+
}
|
|
444
|
+
return kept;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/** Which backend serves after this one is routing, not what produces this one's scores. */
|
|
448
|
+
function withoutFallback(config: unknown): unknown {
|
|
449
|
+
if (!config || typeof config !== 'object' || Array.isArray(config)) return config;
|
|
450
|
+
const { fallback: _fallback, ...rest } = config as Record<string, unknown>;
|
|
451
|
+
return rest;
|
|
452
|
+
}
|
|
453
|
+
|
|
397
454
|
const CREDENTIAL_KEY = /^(apiKey|accessKeyId|authorization|.*secret.*|.*password.*|.*credential.*|.*key|.*token)$/i;
|
|
398
455
|
|
|
399
456
|
function withoutCredentials(value: unknown): unknown {
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { ServerError } from '../../utility/errors/hdbError.ts';
|
|
13
13
|
import { composeSignal } from './backendHelpers.ts';
|
|
14
|
-
import { setDecision } from './backendRegistry.ts';
|
|
14
|
+
import { SERVED_SOURCE, type ServedSourceHook, setDecision } from './backendRegistry.ts';
|
|
15
|
+
import { isCalibrationEnabled } from './calibrationStore.ts';
|
|
15
16
|
import {
|
|
16
17
|
allowedValues,
|
|
17
18
|
isObjectSchema,
|
|
@@ -143,7 +144,8 @@ export function createGenerativeDecisionBackend(
|
|
|
143
144
|
state: DecideInput,
|
|
144
145
|
schema: DecisionSchema,
|
|
145
146
|
instructions: string | undefined,
|
|
146
|
-
signal: AbortSignal | undefined
|
|
147
|
+
signal: AbortSignal | undefined,
|
|
148
|
+
served: object
|
|
147
149
|
): Promise<DecisionOutput<unknown>> => {
|
|
148
150
|
const input = buildInput(
|
|
149
151
|
state,
|
|
@@ -161,6 +163,7 @@ export function createGenerativeDecisionBackend(
|
|
|
161
163
|
temperature,
|
|
162
164
|
signal: sampleSignal,
|
|
163
165
|
requires,
|
|
166
|
+
...served,
|
|
164
167
|
});
|
|
165
168
|
return parseSample(schema, result.content, logicalName);
|
|
166
169
|
}),
|
|
@@ -176,17 +179,18 @@ export function createGenerativeDecisionBackend(
|
|
|
176
179
|
field: string | undefined,
|
|
177
180
|
leaf: DecisionLeaf,
|
|
178
181
|
instructions: string | undefined,
|
|
179
|
-
signal: AbortSignal
|
|
182
|
+
signal: AbortSignal,
|
|
183
|
+
served: object
|
|
180
184
|
): Promise<LeafScore> => {
|
|
181
185
|
const values = allowedValues(leaf);
|
|
182
186
|
const choices = values.map((value) => String(value));
|
|
183
187
|
if (leaf.noMatch !== true) {
|
|
184
188
|
const input = buildInput(state, schema, instructions, SCORE_SYSTEM_PROMPT, field);
|
|
185
|
-
const scored = await score(input, choices, { model: logicalName, signal });
|
|
189
|
+
const scored = await score(input, choices, { model: logicalName, signal, ...served });
|
|
186
190
|
return { distribution: softmax(values, scored?.logLikelihoods, logicalName) };
|
|
187
191
|
}
|
|
188
192
|
const input = buildInput(state, schema, instructions, SCORE_NO_MATCH_SYSTEM_PROMPT, field);
|
|
189
|
-
const scored = await score(input, [...choices, noMatchChoice(choices)], { model: logicalName, signal });
|
|
193
|
+
const scored = await score(input, [...choices, noMatchChoice(choices)], { model: logicalName, signal, ...served });
|
|
190
194
|
const all = softmax([...values, NO_MATCH], scored?.logLikelihoods, logicalName);
|
|
191
195
|
// Normalized over the allowed values' own scores, not by dividing out the none share, which can underflow to zero.
|
|
192
196
|
const distribution = softmax(values, (scored!.logLikelihoods as number[]).slice(0, values.length), logicalName);
|
|
@@ -199,11 +203,12 @@ export function createGenerativeDecisionBackend(
|
|
|
199
203
|
state: DecideInput,
|
|
200
204
|
schema: DecisionSchema,
|
|
201
205
|
instructions: string | undefined,
|
|
202
|
-
signal: AbortSignal | undefined
|
|
206
|
+
signal: AbortSignal | undefined,
|
|
207
|
+
served: object
|
|
203
208
|
): Promise<DecisionOutput<unknown>> => {
|
|
204
209
|
if (!isObjectSchema(schema)) {
|
|
205
210
|
const [scored] = await runPool(
|
|
206
|
-
[(leafSignal: AbortSignal) => scoreLeaf(state, schema, undefined, schema, instructions, leafSignal)],
|
|
211
|
+
[(leafSignal: AbortSignal) => scoreLeaf(state, schema, undefined, schema, instructions, leafSignal, served)],
|
|
207
212
|
concurrency,
|
|
208
213
|
signal
|
|
209
214
|
);
|
|
@@ -214,7 +219,7 @@ export function createGenerativeDecisionBackend(
|
|
|
214
219
|
entries.map(
|
|
215
220
|
([name, leaf]) =>
|
|
216
221
|
(leafSignal: AbortSignal) =>
|
|
217
|
-
scoreLeaf(state, schema, name, leaf, instructions, leafSignal)
|
|
222
|
+
scoreLeaf(state, schema, name, leaf, instructions, leafSignal, served)
|
|
218
223
|
),
|
|
219
224
|
concurrency,
|
|
220
225
|
signal
|
|
@@ -225,6 +230,12 @@ export function createGenerativeDecisionBackend(
|
|
|
225
230
|
const signatureFor = (mode: ScoringMode) =>
|
|
226
231
|
`generative=${logicalName};mode=${mode};samples=${samples};temperature=${temperature ?? 'default'}`;
|
|
227
232
|
|
|
233
|
+
const signed = (mode: ScoringMode, collector: SourceCollector | undefined): string | undefined => {
|
|
234
|
+
if (!collector) return signatureFor(mode);
|
|
235
|
+
if (collector.mixed || collector.source === null) return undefined;
|
|
236
|
+
return `${signatureFor(mode)};source=${collector.source}`;
|
|
237
|
+
};
|
|
238
|
+
|
|
228
239
|
const requires = config.requireStructuredOutput === false ? undefined : (STRUCTURED_OUTPUT as Capability[]);
|
|
229
240
|
return {
|
|
230
241
|
name: 'generative',
|
|
@@ -238,23 +249,50 @@ export function createGenerativeDecisionBackend(
|
|
|
238
249
|
const mode: ScoringMode =
|
|
239
250
|
scoring === 'auto' ? (canScore(logicalName, largestLeaf(schema)) ? 'score' : 'vote') : scoring;
|
|
240
251
|
if (mode === 'score') {
|
|
252
|
+
const collector = isCalibrationEnabled() ? sourceCollector() : undefined;
|
|
241
253
|
try {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
output: { ...(await scoreAll(state, schema, opts.instructions, signal)), signature: signatureFor('score') },
|
|
245
|
-
};
|
|
254
|
+
const output = await scoreAll(state, schema, opts.instructions, signal, servedOpts(collector));
|
|
255
|
+
return { status: 'completed', output: withSignature(output, signed('score', collector)) };
|
|
246
256
|
} catch (err) {
|
|
247
257
|
if (scoring !== 'auto' || !isScoringUnsupported(err)) throw err;
|
|
248
258
|
}
|
|
249
259
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
};
|
|
260
|
+
const collector = isCalibrationEnabled() ? sourceCollector() : undefined;
|
|
261
|
+
const output = await vote(state, schema, opts.instructions, signal, servedOpts(collector));
|
|
262
|
+
return { status: 'completed', output: withSignature(output, signed('vote', collector)) };
|
|
254
263
|
},
|
|
255
264
|
};
|
|
256
265
|
}
|
|
257
266
|
|
|
267
|
+
const NOT_COLLECTING = Object.freeze({});
|
|
268
|
+
|
|
269
|
+
interface SourceCollector {
|
|
270
|
+
source: string | null;
|
|
271
|
+
mixed: boolean;
|
|
272
|
+
hook: ServedSourceHook;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function sourceCollector(): SourceCollector {
|
|
276
|
+
const collector: SourceCollector = {
|
|
277
|
+
source: null,
|
|
278
|
+
mixed: false,
|
|
279
|
+
hook: (source) => {
|
|
280
|
+
if (source === undefined) collector.mixed = true;
|
|
281
|
+
else if (collector.source === null) collector.source = source;
|
|
282
|
+
else if (collector.source !== source) collector.mixed = true;
|
|
283
|
+
},
|
|
284
|
+
};
|
|
285
|
+
return collector;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function servedOpts(collector: SourceCollector | undefined): object {
|
|
289
|
+
return collector ? { [SERVED_SOURCE]: collector.hook } : NOT_COLLECTING;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function withSignature(output: DecisionOutput<unknown>, signature: string | undefined): DecisionOutput<unknown> {
|
|
293
|
+
return signature === undefined ? output : { ...output, signature };
|
|
294
|
+
}
|
|
295
|
+
|
|
258
296
|
// A candidate that advertises scoring without implementing it counts as able, so the facade reports
|
|
259
297
|
// that contract failure instead of the decision quietly voting.
|
|
260
298
|
function routesToScorer(logicalName: string, largestLeafSize: number): boolean {
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
* Reference: planning artifact `tmp/harper-510-phase-1-detail.md` (canonical shapes).
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import type { CalibrationBudgets, CalibrationRunResult, CalibrationSummary } from './calibrationStore.ts';
|
|
11
|
+
|
|
10
12
|
export interface Models {
|
|
11
13
|
embed(input: string | string[], opts?: EmbedOpts): Promise<Float32Array[]>;
|
|
12
14
|
generate(input: GenerateInput, opts?: GenerateOpts): Promise<GenerateResult>;
|
|
@@ -22,6 +24,10 @@ export interface Models {
|
|
|
22
24
|
getDecision<T = unknown>(id: string): Promise<DecisionRecord<T> | undefined>;
|
|
23
25
|
/** Record what actually happened for a decision: its truth, the action taken, or both. See #2840. */
|
|
24
26
|
recordOutcome<T = unknown>(id: string, outcome: OutcomeReport): Promise<DecisionRecord<T>>;
|
|
27
|
+
/** Fit calibrations from recorded outcomes now, as the periodic job does. See #2841. */
|
|
28
|
+
calibrate(budgets?: CalibrationBudgets): Promise<CalibrationRunResult>;
|
|
29
|
+
/** The newest calibration of each field of each population the caller's tenant owns. See #2841. */
|
|
30
|
+
getCalibrations(filter?: { model?: string }): Promise<CalibrationSummary[]>;
|
|
25
31
|
/** Register a custom backend under a logical id, selectable via `opts.model`. See #1325. */
|
|
26
32
|
registerBackend(kind: ModelKind, id: string, backend: ModelBackend): void;
|
|
27
33
|
/** Build a `ModelBackend` from a spec; pair with `registerBackend`. See #1325. */
|