@garygentry/system1-core 0.1.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/LICENSE +21 -0
- package/README.md +13 -0
- package/dist/config/consent.d.ts +11 -0
- package/dist/config/consent.d.ts.map +1 -0
- package/dist/config/consent.js +33 -0
- package/dist/config/consent.js.map +1 -0
- package/dist/config/load.d.ts +64 -0
- package/dist/config/load.d.ts.map +1 -0
- package/dist/config/load.js +216 -0
- package/dist/config/load.js.map +1 -0
- package/dist/config/session.d.ts +31 -0
- package/dist/config/session.d.ts.map +1 -0
- package/dist/config/session.js +36 -0
- package/dist/config/session.js.map +1 -0
- package/dist/config.d.ts +28 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +64 -0
- package/dist/config.js.map +1 -0
- package/dist/decide.d.ts +57 -0
- package/dist/decide.d.ts.map +1 -0
- package/dist/decide.js +87 -0
- package/dist/decide.js.map +1 -0
- package/dist/egress/exclude.d.ts +24 -0
- package/dist/egress/exclude.d.ts.map +1 -0
- package/dist/egress/exclude.js +60 -0
- package/dist/egress/exclude.js.map +1 -0
- package/dist/egress/scrub.d.ts +12 -0
- package/dist/egress/scrub.d.ts.map +1 -0
- package/dist/egress/scrub.js +84 -0
- package/dist/egress/scrub.js.map +1 -0
- package/dist/egress/size.d.ts +16 -0
- package/dist/egress/size.d.ts.map +1 -0
- package/dist/egress/size.js +25 -0
- package/dist/egress/size.js.map +1 -0
- package/dist/errors.d.ts +44 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +23 -0
- package/dist/errors.js.map +1 -0
- package/dist/fixtures/store.d.ts +34 -0
- package/dist/fixtures/store.d.ts.map +1 -0
- package/dist/fixtures/store.js +74 -0
- package/dist/fixtures/store.js.map +1 -0
- package/dist/index.d.ts +59 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/model/answers.d.ts +38 -0
- package/dist/model/answers.d.ts.map +1 -0
- package/dist/model/answers.js +48 -0
- package/dist/model/answers.js.map +1 -0
- package/dist/model/profiles.d.ts +39 -0
- package/dist/model/profiles.d.ts.map +1 -0
- package/dist/model/profiles.js +42 -0
- package/dist/model/profiles.js.map +1 -0
- package/dist/model/types.d.ts +107 -0
- package/dist/model/types.d.ts.map +1 -0
- package/dist/model/types.js +17 -0
- package/dist/model/types.js.map +1 -0
- package/dist/model/validate.d.ts +17 -0
- package/dist/model/validate.d.ts.map +1 -0
- package/dist/model/validate.js +151 -0
- package/dist/model/validate.js.map +1 -0
- package/dist/ping.d.ts +30 -0
- package/dist/ping.d.ts.map +1 -0
- package/dist/ping.js +50 -0
- package/dist/ping.js.map +1 -0
- package/dist/prepare.d.ts +39 -0
- package/dist/prepare.d.ts.map +1 -0
- package/dist/prepare.js +84 -0
- package/dist/prepare.js.map +1 -0
- package/dist/project/project.d.ts +64 -0
- package/dist/project/project.d.ts.map +1 -0
- package/dist/project/project.js +144 -0
- package/dist/project/project.js.map +1 -0
- package/dist/run/budget.d.ts +20 -0
- package/dist/run/budget.d.ts.map +1 -0
- package/dist/run/budget.js +31 -0
- package/dist/run/budget.js.map +1 -0
- package/dist/run/pool.d.ts +16 -0
- package/dist/run/pool.d.ts.map +1 -0
- package/dist/run/pool.js +35 -0
- package/dist/run/pool.js.map +1 -0
- package/dist/run/spend.d.ts +34 -0
- package/dist/run/spend.d.ts.map +1 -0
- package/dist/run/spend.js +55 -0
- package/dist/run/spend.js.map +1 -0
- package/dist/sources/read.d.ts +40 -0
- package/dist/sources/read.d.ts.map +1 -0
- package/dist/sources/read.js +294 -0
- package/dist/sources/read.js.map +1 -0
- package/dist/sources/types.d.ts +79 -0
- package/dist/sources/types.d.ts.map +1 -0
- package/dist/sources/types.js +2 -0
- package/dist/sources/types.js.map +1 -0
- package/dist/spec/expect.d.ts +39 -0
- package/dist/spec/expect.d.ts.map +1 -0
- package/dist/spec/expect.js +95 -0
- package/dist/spec/expect.js.map +1 -0
- package/dist/spec/spec.d.ts +90 -0
- package/dist/spec/spec.d.ts.map +1 -0
- package/dist/spec/spec.js +252 -0
- package/dist/spec/spec.js.map +1 -0
- package/dist/split/split.d.ts +33 -0
- package/dist/split/split.d.ts.map +1 -0
- package/dist/split/split.js +116 -0
- package/dist/split/split.js.map +1 -0
- package/dist/testdata/index.d.ts +5 -0
- package/dist/testdata/index.d.ts.map +1 -0
- package/dist/testdata/index.js +6 -0
- package/dist/testdata/index.js.map +1 -0
- package/dist/testkit/fake-model.d.ts +14 -0
- package/dist/testkit/fake-model.d.ts.map +1 -0
- package/dist/testkit/fake-model.js +57 -0
- package/dist/testkit/fake-model.js.map +1 -0
- package/dist/testkit/tmp.d.ts +6 -0
- package/dist/testkit/tmp.d.ts.map +1 -0
- package/dist/testkit/tmp.js +46 -0
- package/dist/testkit/tmp.js.map +1 -0
- package/dist/tools/ask.d.ts +32 -0
- package/dist/tools/ask.d.ts.map +1 -0
- package/dist/tools/ask.js +59 -0
- package/dist/tools/ask.js.map +1 -0
- package/dist/tools/context.d.ts +52 -0
- package/dist/tools/context.d.ts.map +1 -0
- package/dist/tools/context.js +130 -0
- package/dist/tools/context.js.map +1 -0
- package/dist/tools/doctor.d.ts +37 -0
- package/dist/tools/doctor.d.ts.map +1 -0
- package/dist/tools/doctor.js +203 -0
- package/dist/tools/doctor.js.map +1 -0
- package/dist/tools/many.d.ts +74 -0
- package/dist/tools/many.d.ts.map +1 -0
- package/dist/tools/many.js +141 -0
- package/dist/tools/many.js.map +1 -0
- package/dist/tools/schemas.d.ts +293 -0
- package/dist/tools/schemas.d.ts.map +1 -0
- package/dist/tools/schemas.js +112 -0
- package/dist/tools/schemas.js.map +1 -0
- package/dist/tools/spec-check.d.ts +48 -0
- package/dist/tools/spec-check.d.ts.map +1 -0
- package/dist/tools/spec-check.js +164 -0
- package/dist/tools/spec-check.js.map +1 -0
- package/dist/tools/usage.d.ts +11 -0
- package/dist/tools/usage.d.ts.map +1 -0
- package/dist/tools/usage.js +27 -0
- package/dist/tools/usage.js.map +1 -0
- package/dist/transport/openrouter.d.ts +38 -0
- package/dist/transport/openrouter.d.ts.map +1 -0
- package/dist/transport/openrouter.js +89 -0
- package/dist/transport/openrouter.js.map +1 -0
- package/dist/version.d.ts +4 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +5 -0
- package/dist/version.js.map +1 -0
- package/dist/wiring.d.ts +30 -0
- package/dist/wiring.d.ts.map +1 -0
- package/dist/wiring.js +31 -0
- package/dist/wiring.js.map +1 -0
- package/package.json +63 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export { assertConsent, setConsent } from "./config/consent.js";
|
|
2
|
+
export { allProfiles, DEFAULTS, findRepoRoot, loadConfig, repoConfigPath, userConfigDir, } from "./config/load.js";
|
|
3
|
+
export { detectHarness, detectSession } from "./config/session.js";
|
|
4
|
+
export { createDecider } from "./decide.js";
|
|
5
|
+
export { applyExcludes, DEFAULT_EXCLUDES, isExcluded } from "./egress/exclude.js";
|
|
6
|
+
export { scrubQuestions, scrubState, scrubText } from "./egress/scrub.js";
|
|
7
|
+
export { assertStateFits, CHARS_PER_TOKEN, estimateTokens } from "./egress/size.js";
|
|
8
|
+
export { DecisionsError, isDecisionsError, ProviderError } from "./errors.js";
|
|
9
|
+
export { canonicalJson, FIXTURE_VERSION, FixtureStore, fixtureKey } from "./fixtures/store.js";
|
|
10
|
+
export { confidenceOf, DEFAULT_UNDECIDED_FLOOR, isChoice, isNoul, isScore, isUndecided, noulConfidence, rankedProbabilities, undecidedNames, } from "./model/answers.js";
|
|
11
|
+
export { DEFAULT_MODEL_ID, PROFILES, projectCost, resolveProfile } from "./model/profiles.js";
|
|
12
|
+
export { assertQuestionSet, parseDecisionResponse } from "./model/validate.js";
|
|
13
|
+
export { ping, probeUrl } from "./ping.js";
|
|
14
|
+
export { prepare } from "./prepare.js";
|
|
15
|
+
export { matches, parseFilter, parseSort, project as projectRows } from "./project/project.js";
|
|
16
|
+
export { checkBudget, project } from "./run/budget.js";
|
|
17
|
+
export { mapWithConcurrency } from "./run/pool.js";
|
|
18
|
+
export { SpendLedger, sumUsage } from "./run/spend.js";
|
|
19
|
+
export { gitIgnored, parseFileRef, readSources, splitDiffByFile } from "./sources/read.js";
|
|
20
|
+
export { describeExpectation, meets, parseExpect } from "./spec/expect.js";
|
|
21
|
+
export { assertExamples, exampleProblems, listSpecs, loadSpec, parseQuestionSet, parseSpec, SpecSchema, specDirs, } from "./spec/spec.js";
|
|
22
|
+
export { parseSplit, split } from "./split/split.js";
|
|
23
|
+
export { runAsk } from "./tools/ask.js";
|
|
24
|
+
export { createContext, deciderFor } from "./tools/context.js";
|
|
25
|
+
export { CODEX_RULE, runDoctor, which } from "./tools/doctor.js";
|
|
26
|
+
export { runMany, summariseSkipped } from "./tools/many.js";
|
|
27
|
+
export { AskInput, ManyInput, SpecCheckInput, TOOL_SCHEMAS, UsageInput } from "./tools/schemas.js";
|
|
28
|
+
export { runSpecCheck } from "./tools/spec-check.js";
|
|
29
|
+
export { runUsage } from "./tools/usage.js";
|
|
30
|
+
export { createOpenRouterTransport, DEFAULT_TIMEOUT_MS, RETRY_STATUSES, } from "./transport/openrouter.js";
|
|
31
|
+
export { CLI_PACKAGE, VERSION } from "./version.js";
|
|
32
|
+
export { createDeciderFromEnv, DEFAULT_ENDPOINT, DEFAULT_MODEL, resolveConnection, stateDir, } from "./wiring.js";
|
|
33
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Answer, Answers, ChoiceAnswer, NoulAnswer, ScoreAnswer } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* The default confidence at or below which a choice or score answer means
|
|
4
|
+
* nothing. Profiles carry their own floor; this is Jev's.
|
|
5
|
+
*
|
|
6
|
+
* **Calibrated against live output, and wrong at first.** It started at 0.05,
|
|
7
|
+
* tuned on hand-written fixtures. Live Jev returned 0.09 for a three-level score
|
|
8
|
+
* spread 0.38 / 0.40 / 0.22, which is about as undecided as an answer gets, and
|
|
9
|
+
* it cleared a 0.05 floor. Thresholds tuned on invented data don't transfer.
|
|
10
|
+
*
|
|
11
|
+
* Not the same as a weakly held answer: 0.34 on a genuine two-way contest (0.51
|
|
12
|
+
* against 0.49) is a decided answer held weakly. Per-branch gates in policy code
|
|
13
|
+
* handle that.
|
|
14
|
+
*/
|
|
15
|
+
export declare const DEFAULT_UNDECIDED_FLOOR = 0.15;
|
|
16
|
+
/** A flat distribution: never act on the top option. */
|
|
17
|
+
export declare function isUndecided(answer: ChoiceAnswer | ScoreAnswer, floor?: number): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* A noul's distance from a coin flip, mapped onto 0–1 so it reads beside choice
|
|
20
|
+
* and score confidences. Derived here; the model returns no noul confidence.
|
|
21
|
+
*/
|
|
22
|
+
export declare function noulConfidence(answer: NoulAnswer): number;
|
|
23
|
+
/** Confidence of any answer on one 0–1 scale. */
|
|
24
|
+
export declare function confidenceOf(answer: Answer): number;
|
|
25
|
+
/**
|
|
26
|
+
* Names of the answers that are undecided. A noul is undecided when it sits
|
|
27
|
+
* within `floor / 2` of 0.5, which keeps the same 0–1 confidence scale.
|
|
28
|
+
*/
|
|
29
|
+
export declare function undecidedNames(answers: Answers, floor?: number): string[];
|
|
30
|
+
/** Distribution entries, highest probability first. */
|
|
31
|
+
export declare function rankedProbabilities(probabilities: Record<string, number>): Array<{
|
|
32
|
+
key: string;
|
|
33
|
+
probability: number;
|
|
34
|
+
}>;
|
|
35
|
+
export declare const isChoice: (answer: Answer) => answer is ChoiceAnswer;
|
|
36
|
+
export declare const isScore: (answer: Answer) => answer is ScoreAnswer;
|
|
37
|
+
export declare const isNoul: (answer: Answer) => answer is NoulAnswer;
|
|
38
|
+
//# sourceMappingURL=answers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"answers.d.ts","sourceRoot":"","sources":["../../src/model/answers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAExF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,uBAAuB,OAAO,CAAA;AAE3C,wDAAwD;AACxD,wBAAgB,WAAW,CACzB,MAAM,EAAE,YAAY,GAAG,WAAW,EAClC,KAAK,SAA0B,GAC9B,OAAO,CAET;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAEzD;AAED,iDAAiD;AACjD,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,SAA0B,GAAG,MAAM,EAAE,CAI1F;AAED,uDAAuD;AACvD,wBAAgB,mBAAmB,CACjC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACpC,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CAI7C;AAED,eAAO,MAAM,QAAQ,WAAY,MAAM,KAAG,MAAM,IAAI,YAAwC,CAAA;AAC5F,eAAO,MAAM,OAAO,WAAY,MAAM,KAAG,MAAM,IAAI,WAAsC,CAAA;AACzF,eAAO,MAAM,MAAM,WAAY,MAAM,KAAG,MAAM,IAAI,UAAoC,CAAA"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The default confidence at or below which a choice or score answer means
|
|
3
|
+
* nothing. Profiles carry their own floor; this is Jev's.
|
|
4
|
+
*
|
|
5
|
+
* **Calibrated against live output, and wrong at first.** It started at 0.05,
|
|
6
|
+
* tuned on hand-written fixtures. Live Jev returned 0.09 for a three-level score
|
|
7
|
+
* spread 0.38 / 0.40 / 0.22, which is about as undecided as an answer gets, and
|
|
8
|
+
* it cleared a 0.05 floor. Thresholds tuned on invented data don't transfer.
|
|
9
|
+
*
|
|
10
|
+
* Not the same as a weakly held answer: 0.34 on a genuine two-way contest (0.51
|
|
11
|
+
* against 0.49) is a decided answer held weakly. Per-branch gates in policy code
|
|
12
|
+
* handle that.
|
|
13
|
+
*/
|
|
14
|
+
export const DEFAULT_UNDECIDED_FLOOR = 0.15;
|
|
15
|
+
/** A flat distribution: never act on the top option. */
|
|
16
|
+
export function isUndecided(answer, floor = DEFAULT_UNDECIDED_FLOOR) {
|
|
17
|
+
return answer.confidence <= floor;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* A noul's distance from a coin flip, mapped onto 0–1 so it reads beside choice
|
|
21
|
+
* and score confidences. Derived here; the model returns no noul confidence.
|
|
22
|
+
*/
|
|
23
|
+
export function noulConfidence(answer) {
|
|
24
|
+
return Math.abs(answer.noul - 0.5) * 2;
|
|
25
|
+
}
|
|
26
|
+
/** Confidence of any answer on one 0–1 scale. */
|
|
27
|
+
export function confidenceOf(answer) {
|
|
28
|
+
return answer.type === "noul" ? noulConfidence(answer) : answer.confidence;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Names of the answers that are undecided. A noul is undecided when it sits
|
|
32
|
+
* within `floor / 2` of 0.5, which keeps the same 0–1 confidence scale.
|
|
33
|
+
*/
|
|
34
|
+
export function undecidedNames(answers, floor = DEFAULT_UNDECIDED_FLOOR) {
|
|
35
|
+
return Object.entries(answers)
|
|
36
|
+
.filter(([, answer]) => confidenceOf(answer) <= floor)
|
|
37
|
+
.map(([name]) => name);
|
|
38
|
+
}
|
|
39
|
+
/** Distribution entries, highest probability first. */
|
|
40
|
+
export function rankedProbabilities(probabilities) {
|
|
41
|
+
return Object.entries(probabilities)
|
|
42
|
+
.map(([key, probability]) => ({ key, probability }))
|
|
43
|
+
.sort((a, b) => b.probability - a.probability);
|
|
44
|
+
}
|
|
45
|
+
export const isChoice = (answer) => answer.type === "choice";
|
|
46
|
+
export const isScore = (answer) => answer.type === "score";
|
|
47
|
+
export const isNoul = (answer) => answer.type === "noul";
|
|
48
|
+
//# sourceMappingURL=answers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"answers.js","sourceRoot":"","sources":["../../src/model/answers.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,IAAI,CAAA;AAE3C,wDAAwD;AACxD,MAAM,UAAU,WAAW,CACzB,MAAkC,EAClC,KAAK,GAAG,uBAAuB;IAE/B,OAAO,MAAM,CAAC,UAAU,IAAI,KAAK,CAAA;AACnC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,MAAkB;IAC/C,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,CAAA;AACxC,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,OAAO,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAA;AAC5E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,OAAgB,EAAE,KAAK,GAAG,uBAAuB;IAC9E,OAAO,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC;SAC3B,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC;SACrD,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAA;AAC1B,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,mBAAmB,CACjC,aAAqC;IAErC,OAAO,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC;SACjC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,WAAW,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC;SACnD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,WAAW,CAAC,CAAA;AAClD,CAAC;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,MAAc,EAA0B,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAA;AAC5F,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,MAAc,EAAyB,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,OAAO,CAAA;AACzF,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,MAAc,EAAwB,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,MAAM,CAAA"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Everything the engine needs to know about one decision model, as data.
|
|
3
|
+
*
|
|
4
|
+
* A new model that shares the wire contract is a new entry here, not new code
|
|
5
|
+
* (decision 0003). `transport` names how it is reached; only
|
|
6
|
+
* `openrouter-decisions` exists so far.
|
|
7
|
+
*/
|
|
8
|
+
export interface ModelProfile {
|
|
9
|
+
/** The id sent on the wire. */
|
|
10
|
+
id: string;
|
|
11
|
+
displayName: string;
|
|
12
|
+
transport: "openrouter-decisions";
|
|
13
|
+
/** Hard cap on one state. Oversized states are refused, never truncated. */
|
|
14
|
+
maxStateTokens: number;
|
|
15
|
+
/** Most options one choice question may have (the provider refuses more). */
|
|
16
|
+
maxChoices: number;
|
|
17
|
+
/** Listed price, USD per input token. Used only for *projected* costs. */
|
|
18
|
+
usdPerInputToken: number;
|
|
19
|
+
usdPerOutputToken: number;
|
|
20
|
+
/** When the price above was read. Prices go stale; measured cost never does. */
|
|
21
|
+
priceAsOf: string;
|
|
22
|
+
/** Confidence at or below which an answer is treated as undecided. */
|
|
23
|
+
undecidedFloor: number;
|
|
24
|
+
/** Whether the probabilities are calibrated (an emulated model's are not). */
|
|
25
|
+
calibrated: boolean;
|
|
26
|
+
}
|
|
27
|
+
export declare const PROFILES: readonly ModelProfile[];
|
|
28
|
+
export declare const DEFAULT_MODEL_ID = "typesafe/jev-1.13";
|
|
29
|
+
/**
|
|
30
|
+
* Find the profile for a model id. A dated build (`typesafe/jev-1.13-20260917`)
|
|
31
|
+
* resolves to its family profile but keeps the requested id, so it is what goes
|
|
32
|
+
* on the wire.
|
|
33
|
+
*
|
|
34
|
+
* @throws DecisionsError `unknown-model` when nothing matches.
|
|
35
|
+
*/
|
|
36
|
+
export declare function resolveProfile(id: string, profiles?: readonly ModelProfile[]): ModelProfile;
|
|
37
|
+
/** Projected cost of `calls` decisions of about `tokensPerCall` input tokens. Never a measurement. */
|
|
38
|
+
export declare function projectCost(profile: ModelProfile, calls: number, tokensPerCall: number): number;
|
|
39
|
+
//# sourceMappingURL=profiles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profiles.d.ts","sourceRoot":"","sources":["../../src/model/profiles.ts"],"names":[],"mappings":"AAGA;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,+BAA+B;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,sBAAsB,CAAA;IACjC,4EAA4E;IAC5E,cAAc,EAAE,MAAM,CAAA;IACtB,6EAA6E;IAC7E,UAAU,EAAE,MAAM,CAAA;IAClB,0EAA0E;IAC1E,gBAAgB,EAAE,MAAM,CAAA;IACxB,iBAAiB,EAAE,MAAM,CAAA;IACzB,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAA;IACjB,sEAAsE;IACtE,cAAc,EAAE,MAAM,CAAA;IACtB,8EAA8E;IAC9E,UAAU,EAAE,OAAO,CAAA;CACpB;AAED,eAAO,MAAM,QAAQ,EAAE,SAAS,YAAY,EAc3C,CAAA;AAED,eAAO,MAAM,gBAAgB,sBAAsB,CAAA;AAEnD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,EAAE,EAAE,MAAM,EACV,QAAQ,GAAE,SAAS,YAAY,EAAa,GAC3C,YAAY,CAUd;AAED,sGAAsG;AACtG,wBAAgB,WAAW,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAE/F"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { DecisionsError } from "../errors.js";
|
|
2
|
+
import { DEFAULT_UNDECIDED_FLOOR } from "./answers.js";
|
|
3
|
+
export const PROFILES = [
|
|
4
|
+
{
|
|
5
|
+
id: "typesafe/jev-1.13",
|
|
6
|
+
displayName: "TypeSafe Jev 1.13",
|
|
7
|
+
transport: "openrouter-decisions",
|
|
8
|
+
maxStateTokens: 32_000,
|
|
9
|
+
// Measured 2026-09-22: 400 options is refused upstream with "at most 255 choices".
|
|
10
|
+
maxChoices: 255,
|
|
11
|
+
usdPerInputToken: 0.042 / 1_000_000,
|
|
12
|
+
usdPerOutputToken: 0,
|
|
13
|
+
priceAsOf: "2026-09-19",
|
|
14
|
+
undecidedFloor: DEFAULT_UNDECIDED_FLOOR,
|
|
15
|
+
calibrated: true,
|
|
16
|
+
},
|
|
17
|
+
];
|
|
18
|
+
export const DEFAULT_MODEL_ID = "typesafe/jev-1.13";
|
|
19
|
+
/**
|
|
20
|
+
* Find the profile for a model id. A dated build (`typesafe/jev-1.13-20260917`)
|
|
21
|
+
* resolves to its family profile but keeps the requested id, so it is what goes
|
|
22
|
+
* on the wire.
|
|
23
|
+
*
|
|
24
|
+
* @throws DecisionsError `unknown-model` when nothing matches.
|
|
25
|
+
*/
|
|
26
|
+
export function resolveProfile(id, profiles = PROFILES) {
|
|
27
|
+
const exact = profiles.find((p) => p.id === id);
|
|
28
|
+
if (exact)
|
|
29
|
+
return exact;
|
|
30
|
+
const family = profiles.find((p) => new RegExp(`^${escapeRegExp(p.id)}-\\d{8}$`).test(id));
|
|
31
|
+
if (family)
|
|
32
|
+
return { ...family, id };
|
|
33
|
+
throw new DecisionsError("unknown-model", `No profile for model "${id}". Known: ${profiles.map((p) => p.id).join(", ")}.`, { model: id, known: profiles.map((p) => p.id) });
|
|
34
|
+
}
|
|
35
|
+
/** Projected cost of `calls` decisions of about `tokensPerCall` input tokens. Never a measurement. */
|
|
36
|
+
export function projectCost(profile, calls, tokensPerCall) {
|
|
37
|
+
return calls * tokensPerCall * profile.usdPerInputToken;
|
|
38
|
+
}
|
|
39
|
+
function escapeRegExp(text) {
|
|
40
|
+
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=profiles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"profiles.js","sourceRoot":"","sources":["../../src/model/profiles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAC7C,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAA;AA6BtD,MAAM,CAAC,MAAM,QAAQ,GAA4B;IAC/C;QACE,EAAE,EAAE,mBAAmB;QACvB,WAAW,EAAE,mBAAmB;QAChC,SAAS,EAAE,sBAAsB;QACjC,cAAc,EAAE,MAAM;QACtB,mFAAmF;QACnF,UAAU,EAAE,GAAG;QACf,gBAAgB,EAAE,KAAK,GAAG,SAAS;QACnC,iBAAiB,EAAE,CAAC;QACpB,SAAS,EAAE,YAAY;QACvB,cAAc,EAAE,uBAAuB;QACvC,UAAU,EAAE,IAAI;KACjB;CACF,CAAA;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG,mBAAmB,CAAA;AAEnD;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC5B,EAAU,EACV,QAAQ,GAA4B,QAAQ;IAE5C,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;IAC/C,IAAI,KAAK;QAAE,OAAO,KAAK,CAAA;IACvB,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,IAAI,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;IAC1F,IAAI,MAAM;QAAE,OAAO,EAAE,GAAG,MAAM,EAAE,EAAE,EAAE,CAAA;IACpC,MAAM,IAAI,cAAc,CACtB,eAAe,EACf,yBAAyB,EAAE,aAAa,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAC/E,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAChD,CAAA;AACH,CAAC;AAED,sGAAsG;AACtG,MAAM,UAAU,WAAW,CAAC,OAAqB,EAAE,KAAa,EAAE,aAAqB;IACrF,OAAO,KAAK,GAAG,aAAa,GAAG,OAAO,CAAC,gBAAgB,CAAA;AACzD,CAAC;AAED,SAAS,YAAY,CAAC,IAAY;IAChC,OAAO,IAAI,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAA;AACpD,CAAC"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The decision-model wire contract, verified against OpenRouter's decisions
|
|
3
|
+
* endpoint:
|
|
4
|
+
*
|
|
5
|
+
* POST https://openrouter.ai/api/alpha/decisions
|
|
6
|
+
* {"model": "typesafe/jev-1.13", "state": ..., "questions": {...}}
|
|
7
|
+
*
|
|
8
|
+
* A decision model does not generate text. You send one `state` and a map of
|
|
9
|
+
* named `questions`, and every question is answered against that same state,
|
|
10
|
+
* in one request, with typed, calibrated answers. `/chat/completions` rejects
|
|
11
|
+
* these models outright; they are served on their own path.
|
|
12
|
+
*
|
|
13
|
+
* The names are model-neutral on purpose: Jev is the first model with this
|
|
14
|
+
* calling convention, not the only one (decision 0003).
|
|
15
|
+
*/
|
|
16
|
+
/** Anything JSON-shaped. A bare string or a structured object both work. */
|
|
17
|
+
export type State = string | Record<string, unknown> | unknown[];
|
|
18
|
+
/**
|
|
19
|
+
* One of a fixed set of options. `criteria` maps each option key to when it
|
|
20
|
+
* applies. Always include a no-match option: the model cannot choose a value
|
|
21
|
+
* you never offered, so without one it is forced to pick among wrong answers.
|
|
22
|
+
*/
|
|
23
|
+
export interface ChoiceQuestion {
|
|
24
|
+
type: "choice";
|
|
25
|
+
instructions: string;
|
|
26
|
+
criteria: Record<string, string>;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A position along a dimension you define. `criteria` is an ordered list of
|
|
30
|
+
* levels, and **levels are 0-indexed**: three criteria are levels 0, 1 and 2, so
|
|
31
|
+
* a score of 1.5 sits between the middle and top level. Describe each level as
|
|
32
|
+
* a concrete situation ("a workaround exists"), not a degree ("medium").
|
|
33
|
+
*/
|
|
34
|
+
export interface ScoreQuestion {
|
|
35
|
+
type: "score";
|
|
36
|
+
instructions: string;
|
|
37
|
+
criteria: string[];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Whether a proposition holds, as a probability. Optional `true`/`false`
|
|
41
|
+
* criteria sharpen the boundary when the proposition is at all ambiguous.
|
|
42
|
+
*/
|
|
43
|
+
export interface NoulQuestion {
|
|
44
|
+
type: "noul";
|
|
45
|
+
instructions: string;
|
|
46
|
+
criteria?: {
|
|
47
|
+
true: string;
|
|
48
|
+
false: string;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export type Question = ChoiceQuestion | ScoreQuestion | NoulQuestion;
|
|
52
|
+
export type QuestionType = Question["type"];
|
|
53
|
+
/** Named questions, all answered against one state in one request. */
|
|
54
|
+
export type QuestionSet = Record<string, Question>;
|
|
55
|
+
export interface ChoiceAnswer {
|
|
56
|
+
type: "choice";
|
|
57
|
+
/** The winning option key. */
|
|
58
|
+
choice: string;
|
|
59
|
+
/** Distribution over every option key, summing to about 1. */
|
|
60
|
+
probabilities: Record<string, number>;
|
|
61
|
+
/** How concentrated the distribution is. See `isUndecided`. */
|
|
62
|
+
confidence: number;
|
|
63
|
+
}
|
|
64
|
+
export interface ScoreAnswer {
|
|
65
|
+
type: "score";
|
|
66
|
+
/** Probability-weighted mean level. Can land between levels. */
|
|
67
|
+
score: number;
|
|
68
|
+
/** Distribution over levels. Keys are strings ("0", "1", ...), not numbers. */
|
|
69
|
+
probabilities: Record<string, number>;
|
|
70
|
+
/** Level index to its criterion text, string-keyed for the same reason. */
|
|
71
|
+
legend?: Record<string, string>;
|
|
72
|
+
confidence: number;
|
|
73
|
+
}
|
|
74
|
+
export interface NoulAnswer {
|
|
75
|
+
type: "noul";
|
|
76
|
+
/** Probability the proposition holds, 0–1. 0.5 means "cannot tell". */
|
|
77
|
+
noul: number;
|
|
78
|
+
}
|
|
79
|
+
export type Answer = ChoiceAnswer | ScoreAnswer | NoulAnswer;
|
|
80
|
+
export type Answers = Record<string, Answer>;
|
|
81
|
+
export interface Usage {
|
|
82
|
+
input_tokens: number;
|
|
83
|
+
output_tokens: number;
|
|
84
|
+
/** Upstream-reported cost in USD. Output tokens are free on Jev. */
|
|
85
|
+
cost: number;
|
|
86
|
+
/**
|
|
87
|
+
* False when the provider reported no usage (or an unreadable one), so the
|
|
88
|
+
* zeroes above are "unknown", not "free". Absent means reported.
|
|
89
|
+
*/
|
|
90
|
+
reported?: boolean;
|
|
91
|
+
}
|
|
92
|
+
/** What the decisions endpoint returns, after validation. */
|
|
93
|
+
export interface DecisionResponse {
|
|
94
|
+
/** The model build that actually served the call, e.g. `typesafe/jev-1.13-20260917`. */
|
|
95
|
+
model: string;
|
|
96
|
+
answers: Answers;
|
|
97
|
+
usage: Usage;
|
|
98
|
+
/** Upstream generation id, when present. */
|
|
99
|
+
id?: string;
|
|
100
|
+
provider?: string;
|
|
101
|
+
}
|
|
102
|
+
export interface DecisionRequest {
|
|
103
|
+
model: string;
|
|
104
|
+
state: State;
|
|
105
|
+
questions: QuestionSet;
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/model/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,4EAA4E;AAC5E,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,EAAE,CAAA;AAMhE;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,QAAQ,CAAA;IACd,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACjC;AAED;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;CAC3C;AAED,MAAM,MAAM,QAAQ,GAAG,cAAc,GAAG,aAAa,GAAG,YAAY,CAAA;AACpE,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAA;AAE3C,sEAAsE;AACtE,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;AAMlD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,QAAQ,CAAA;IACd,8BAA8B;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,8DAA8D;IAC9D,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACrC,+DAA+D;IAC/D,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,OAAO,CAAA;IACb,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAA;IACb,+EAA+E;IAC/E,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACrC,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,MAAM,MAAM,GAAG,YAAY,GAAG,WAAW,GAAG,UAAU,CAAA;AAC5D,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AAE5C,MAAM,WAAW,KAAK;IACpB,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,MAAM,CAAA;IACrB,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAA;IACZ;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,6DAA6D;AAC7D,MAAM,WAAW,gBAAgB;IAC/B,wFAAwF;IACxF,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,KAAK,CAAA;IACZ,4CAA4C;IAC5C,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,WAAW,CAAA;CACvB"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The decision-model wire contract, verified against OpenRouter's decisions
|
|
3
|
+
* endpoint:
|
|
4
|
+
*
|
|
5
|
+
* POST https://openrouter.ai/api/alpha/decisions
|
|
6
|
+
* {"model": "typesafe/jev-1.13", "state": ..., "questions": {...}}
|
|
7
|
+
*
|
|
8
|
+
* A decision model does not generate text. You send one `state` and a map of
|
|
9
|
+
* named `questions`, and every question is answered against that same state,
|
|
10
|
+
* in one request, with typed, calibrated answers. `/chat/completions` rejects
|
|
11
|
+
* these models outright; they are served on their own path.
|
|
12
|
+
*
|
|
13
|
+
* The names are model-neutral on purpose: Jev is the first model with this
|
|
14
|
+
* calling convention, not the only one (decision 0003).
|
|
15
|
+
*/
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/model/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { DecisionResponse, QuestionSet } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Reject a malformed question set before it costs a call.
|
|
4
|
+
*
|
|
5
|
+
* @throws DecisionsError `invalid-request`, listing every problem found.
|
|
6
|
+
*/
|
|
7
|
+
export declare function assertQuestionSet(questions: unknown): asserts questions is QuestionSet;
|
|
8
|
+
/**
|
|
9
|
+
* Validate a decisions-endpoint body against the request it answers.
|
|
10
|
+
*
|
|
11
|
+
* Stricter than "has answers": every question asked must come back, as the
|
|
12
|
+
* type it was asked as, with correctly typed fields. A 2xx that fails this is
|
|
13
|
+
* still a provider failure, so it surfaces as `malformed-response` and never as
|
|
14
|
+
* a partial result.
|
|
15
|
+
*/
|
|
16
|
+
export declare function parseDecisionResponse(raw: unknown, questions: QuestionSet, requestedModel: string): DecisionResponse;
|
|
17
|
+
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/model/validate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAmB,gBAAgB,EAAE,WAAW,EAAS,MAAM,YAAY,CAAA;AAEvF;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,OAAO,GAAG,OAAO,CAAC,SAAS,IAAI,WAAW,CAwDtF;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,OAAO,EACZ,SAAS,EAAE,WAAW,EACtB,cAAc,EAAE,MAAM,GACrB,gBAAgB,CA2BlB"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { DecisionsError, ProviderError } from "../errors.js";
|
|
2
|
+
/**
|
|
3
|
+
* Reject a malformed question set before it costs a call.
|
|
4
|
+
*
|
|
5
|
+
* @throws DecisionsError `invalid-request`, listing every problem found.
|
|
6
|
+
*/
|
|
7
|
+
export function assertQuestionSet(questions) {
|
|
8
|
+
const problems = [];
|
|
9
|
+
if (!isObject(questions) || Object.keys(questions).length === 0) {
|
|
10
|
+
throw new DecisionsError("invalid-request", "questions must be a non-empty object of named questions");
|
|
11
|
+
}
|
|
12
|
+
for (const [name, q] of Object.entries(questions)) {
|
|
13
|
+
if (!isObject(q)) {
|
|
14
|
+
problems.push(`${name}: must be an object`);
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
if (typeof q.instructions !== "string" || q.instructions.trim() === "") {
|
|
18
|
+
problems.push(`${name}: instructions must be a non-empty string`);
|
|
19
|
+
}
|
|
20
|
+
switch (q.type) {
|
|
21
|
+
case "choice":
|
|
22
|
+
if (!isObject(q.criteria) || Object.keys(q.criteria).length < 2) {
|
|
23
|
+
problems.push(`${name}: choice criteria must map at least two option keys to descriptions`);
|
|
24
|
+
}
|
|
25
|
+
else if (!Object.values(q.criteria).every((v) => typeof v === "string")) {
|
|
26
|
+
problems.push(`${name}: choice criteria values must be strings`);
|
|
27
|
+
}
|
|
28
|
+
break;
|
|
29
|
+
case "score":
|
|
30
|
+
if (!Array.isArray(q.criteria) ||
|
|
31
|
+
q.criteria.length < 2 ||
|
|
32
|
+
!q.criteria.every((c) => typeof c === "string")) {
|
|
33
|
+
problems.push(`${name}: score criteria must be a list of at least two level descriptions`);
|
|
34
|
+
}
|
|
35
|
+
break;
|
|
36
|
+
case "noul":
|
|
37
|
+
if (q.criteria !== undefined &&
|
|
38
|
+
(!isObject(q.criteria) ||
|
|
39
|
+
typeof q.criteria.true !== "string" ||
|
|
40
|
+
typeof q.criteria.false !== "string")) {
|
|
41
|
+
problems.push(`${name}: noul criteria, when given, must be {true: string, false: string}`);
|
|
42
|
+
}
|
|
43
|
+
break;
|
|
44
|
+
default:
|
|
45
|
+
problems.push(`${name}: type must be choice, score or noul (got ${JSON.stringify(q.type)})`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (problems.length > 0) {
|
|
49
|
+
throw new DecisionsError("invalid-request", `Invalid question set:\n ${problems.join("\n ")}`, { problems });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Validate a decisions-endpoint body against the request it answers.
|
|
54
|
+
*
|
|
55
|
+
* Stricter than "has answers": every question asked must come back, as the
|
|
56
|
+
* type it was asked as, with correctly typed fields. A 2xx that fails this is
|
|
57
|
+
* still a provider failure, so it surfaces as `malformed-response` and never as
|
|
58
|
+
* a partial result.
|
|
59
|
+
*/
|
|
60
|
+
export function parseDecisionResponse(raw, questions, requestedModel) {
|
|
61
|
+
if (!isObject(raw))
|
|
62
|
+
throw malformed("body is not a JSON object", raw);
|
|
63
|
+
if (!isObject(raw.answers))
|
|
64
|
+
throw malformed("body has no answers object", raw);
|
|
65
|
+
const answers = {};
|
|
66
|
+
for (const [name, question] of Object.entries(questions)) {
|
|
67
|
+
const answer = raw.answers[name];
|
|
68
|
+
if (answer === undefined)
|
|
69
|
+
throw malformed(`question "${name}" was not answered`, raw);
|
|
70
|
+
if (!isObject(answer) || answer.type !== question.type) {
|
|
71
|
+
throw malformed(`answer "${name}" should be type ${question.type}, got ${JSON.stringify(isObject(answer) ? answer.type : answer)}`, raw);
|
|
72
|
+
}
|
|
73
|
+
answers[name] = checkAnswer(name, answer, raw);
|
|
74
|
+
}
|
|
75
|
+
const usage = raw.usage;
|
|
76
|
+
return {
|
|
77
|
+
model: typeof raw.model === "string" ? raw.model : requestedModel,
|
|
78
|
+
answers,
|
|
79
|
+
usage: isObject(usage)
|
|
80
|
+
? checkUsage(usage)
|
|
81
|
+
: { input_tokens: 0, output_tokens: 0, cost: 0, reported: false },
|
|
82
|
+
...(typeof raw.id === "string" ? { id: raw.id } : {}),
|
|
83
|
+
...(typeof raw.provider === "string" ? { provider: raw.provider } : {}),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function checkAnswer(name, a, raw) {
|
|
87
|
+
const bad = (field) => malformed(`answer "${name}" has an invalid ${field}`, raw);
|
|
88
|
+
switch (a.type) {
|
|
89
|
+
case "choice":
|
|
90
|
+
if (typeof a.choice !== "string")
|
|
91
|
+
throw bad("choice");
|
|
92
|
+
if (!isDistribution(a.probabilities))
|
|
93
|
+
throw bad("probabilities");
|
|
94
|
+
if (!isUnit(a.confidence))
|
|
95
|
+
throw bad("confidence");
|
|
96
|
+
return {
|
|
97
|
+
type: "choice",
|
|
98
|
+
choice: a.choice,
|
|
99
|
+
probabilities: a.probabilities,
|
|
100
|
+
confidence: a.confidence,
|
|
101
|
+
};
|
|
102
|
+
case "score":
|
|
103
|
+
if (typeof a.score !== "number" || !Number.isFinite(a.score))
|
|
104
|
+
throw bad("score");
|
|
105
|
+
if (!isDistribution(a.probabilities))
|
|
106
|
+
throw bad("probabilities");
|
|
107
|
+
if (!isUnit(a.confidence))
|
|
108
|
+
throw bad("confidence");
|
|
109
|
+
return {
|
|
110
|
+
type: "score",
|
|
111
|
+
score: a.score,
|
|
112
|
+
probabilities: a.probabilities,
|
|
113
|
+
confidence: a.confidence,
|
|
114
|
+
...(isObject(a.legend) ? { legend: a.legend } : {}),
|
|
115
|
+
};
|
|
116
|
+
case "noul":
|
|
117
|
+
if (!isUnit(a.noul))
|
|
118
|
+
throw bad("noul");
|
|
119
|
+
return { type: "noul", noul: a.noul };
|
|
120
|
+
default:
|
|
121
|
+
throw bad("type");
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function checkUsage(u) {
|
|
125
|
+
// A missing or unreadable cost is unknown, not zero: an upstream change
|
|
126
|
+
// would otherwise look like free service.
|
|
127
|
+
const reported = [u.input_tokens, u.output_tokens, u.cost].every((v) => typeof v === "number" && Number.isFinite(v));
|
|
128
|
+
return {
|
|
129
|
+
input_tokens: finiteOrZero(u.input_tokens),
|
|
130
|
+
output_tokens: finiteOrZero(u.output_tokens),
|
|
131
|
+
cost: finiteOrZero(u.cost),
|
|
132
|
+
...(reported ? {} : { reported: false }),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
function malformed(reason, raw) {
|
|
136
|
+
const preview = JSON.stringify(raw)?.slice(0, 300) ?? String(raw);
|
|
137
|
+
return new ProviderError("malformed-response", `Malformed decision response: ${reason}. Body: ${preview}`);
|
|
138
|
+
}
|
|
139
|
+
function isObject(value) {
|
|
140
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
141
|
+
}
|
|
142
|
+
function isUnit(value) {
|
|
143
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 && value <= 1;
|
|
144
|
+
}
|
|
145
|
+
function isDistribution(value) {
|
|
146
|
+
return isObject(value) && Object.keys(value).length > 0 && Object.values(value).every(isUnit);
|
|
147
|
+
}
|
|
148
|
+
function finiteOrZero(value) {
|
|
149
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/model/validate.ts"],"names":[],"mappings":"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"}
|
package/dist/ping.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ConnectionConfig } from "./wiring.js";
|
|
2
|
+
/**
|
|
3
|
+
* A reachability check that spends nothing.
|
|
4
|
+
*
|
|
5
|
+
* It reads the model's public endpoint listing rather than calling the
|
|
6
|
+
* decisions endpoint, so it needs no key and makes no decision. That makes it
|
|
7
|
+
* safe to run from any harness, and a good probe for whether the agent's shell
|
|
8
|
+
* sandbox allows network access at all.
|
|
9
|
+
*/
|
|
10
|
+
export interface PingResult {
|
|
11
|
+
ok: boolean;
|
|
12
|
+
model: string;
|
|
13
|
+
endpoint: string;
|
|
14
|
+
/** The URL actually probed. */
|
|
15
|
+
probe: string;
|
|
16
|
+
keyPresent: boolean;
|
|
17
|
+
/** Measured round trip. Absent when the request never completed. */
|
|
18
|
+
latencyMs?: number;
|
|
19
|
+
httpStatus?: number;
|
|
20
|
+
/** The listing's context length for the model, when it answered. */
|
|
21
|
+
contextLength?: number;
|
|
22
|
+
error?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface PingOptions {
|
|
25
|
+
fetch?: typeof fetch;
|
|
26
|
+
timeoutMs?: number;
|
|
27
|
+
}
|
|
28
|
+
export declare function probeUrl(config: ConnectionConfig): string;
|
|
29
|
+
export declare function ping(config: ConnectionConfig, options?: PingOptions): Promise<PingResult>;
|
|
30
|
+
//# sourceMappingURL=ping.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ping.d.ts","sourceRoot":"","sources":["../src/ping.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAEnD;;;;;;;GAOG;AACH,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,OAAO,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,+BAA+B;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,OAAO,CAAA;IACnB,oEAAoE;IACpE,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,oEAAoE;IACpE,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAGzD;AAED,wBAAsB,IAAI,CACxB,MAAM,EAAE,gBAAgB,EACxB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,UAAU,CAAC,CAoCrB"}
|
package/dist/ping.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export function probeUrl(config) {
|
|
2
|
+
const origin = new URL(config.endpoint).origin;
|
|
3
|
+
return `${origin}/api/v1/models/${config.model}/endpoints`;
|
|
4
|
+
}
|
|
5
|
+
export async function ping(config, options = {}) {
|
|
6
|
+
const doFetch = options.fetch ?? fetch;
|
|
7
|
+
const probe = probeUrl(config);
|
|
8
|
+
const base = {
|
|
9
|
+
model: config.model,
|
|
10
|
+
endpoint: config.endpoint,
|
|
11
|
+
probe,
|
|
12
|
+
keyPresent: config.apiKey !== undefined,
|
|
13
|
+
};
|
|
14
|
+
const started = performance.now();
|
|
15
|
+
try {
|
|
16
|
+
const response = await doFetch(probe, {
|
|
17
|
+
signal: AbortSignal.timeout(options.timeoutMs ?? 10_000),
|
|
18
|
+
});
|
|
19
|
+
const latencyMs = Math.round(performance.now() - started);
|
|
20
|
+
if (!response.ok) {
|
|
21
|
+
return {
|
|
22
|
+
...base,
|
|
23
|
+
ok: false,
|
|
24
|
+
latencyMs,
|
|
25
|
+
httpStatus: response.status,
|
|
26
|
+
error: `HTTP ${response.status}`,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
const body = (await response.json());
|
|
30
|
+
const contextLength = body.data?.endpoints?.[0]?.context_length;
|
|
31
|
+
return {
|
|
32
|
+
...base,
|
|
33
|
+
ok: true,
|
|
34
|
+
latencyMs,
|
|
35
|
+
httpStatus: response.status,
|
|
36
|
+
...(typeof contextLength === "number" ? { contextLength } : {}),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
return { ...base, ok: false, error: describe(error) };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function describe(error) {
|
|
44
|
+
if (error instanceof Error) {
|
|
45
|
+
const cause = error.cause;
|
|
46
|
+
return cause instanceof Error ? `${error.message}: ${cause.message}` : error.message;
|
|
47
|
+
}
|
|
48
|
+
return String(error);
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=ping.js.map
|
package/dist/ping.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ping.js","sourceRoot":"","sources":["../src/ping.ts"],"names":[],"mappings":"AA8BA,MAAM,UAAU,QAAQ,CAAC,MAAwB;IAC/C,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAA;IAC9C,OAAO,GAAG,MAAM,kBAAkB,MAAM,CAAC,KAAK,YAAY,CAAA;AAC5D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,IAAI,CACxB,MAAwB,EACxB,OAAO,GAAgB,EAAE;IAEzB,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,KAAK,CAAA;IACtC,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAA;IAC9B,MAAM,IAAI,GAAG;QACX,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,KAAK;QACL,UAAU,EAAE,MAAM,CAAC,MAAM,KAAK,SAAS;KACxC,CAAA;IACD,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,CAAA;IACjC,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,KAAK,EAAE;YACpC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,IAAI,MAAM,CAAC;SACzD,CAAC,CAAA;QACF,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,CAAA;QACzD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,OAAO;gBACL,GAAG,IAAI;gBACP,EAAE,EAAE,KAAK;gBACT,SAAS;gBACT,UAAU,EAAE,QAAQ,CAAC,MAAM;gBAC3B,KAAK,EAAE,QAAQ,QAAQ,CAAC,MAAM,EAAE;aACjC,CAAA;QACH,CAAC;QACD,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAgB,CAAA;QACnD,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,cAAc,CAAA;QAC/D,OAAO;YACL,GAAG,IAAI;YACP,EAAE,EAAE,IAAI;YACR,SAAS;YACT,UAAU,EAAE,QAAQ,CAAC,MAAM;YAC3B,GAAG,CAAC,OAAO,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAChE,CAAA;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,GAAG,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAA;IACvD,CAAC;AACH,CAAC;AAMD,SAAS,QAAQ,CAAC,KAAc;IAC9B,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAI,KAA6B,CAAC,KAAK,CAAA;QAClD,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,OAAO,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAA;IACtF,CAAC;IACD,OAAO,MAAM,CAAC,KAAK,CAAC,CAAA;AACtB,CAAC"}
|