@hourslabs/domovoi 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 +201 -0
- package/NOTICE +4 -0
- package/README.md +312 -0
- package/dist/cache.d.ts +102 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/calibration/index.d.ts +45 -0
- package/dist/calibration/index.d.ts.map +1 -0
- package/dist/calibration/index.js +95 -0
- package/dist/calibration/index.js.map +1 -0
- package/dist/engine/abort.d.ts +43 -0
- package/dist/engine/abort.d.ts.map +1 -0
- package/dist/engine/config.d.ts +79 -0
- package/dist/engine/config.d.ts.map +1 -0
- package/dist/engine/decide.d.ts +18 -0
- package/dist/engine/decide.d.ts.map +1 -0
- package/dist/engine/distribution.d.ts +18 -0
- package/dist/engine/distribution.d.ts.map +1 -0
- package/dist/engine/error-recording.d.ts +35 -0
- package/dist/engine/error-recording.d.ts.map +1 -0
- package/dist/engine/finalize.d.ts +12 -0
- package/dist/engine/finalize.d.ts.map +1 -0
- package/dist/engine/hooks.d.ts +12 -0
- package/dist/engine/hooks.d.ts.map +1 -0
- package/dist/engine/index.d.ts +7 -0
- package/dist/engine/index.d.ts.map +1 -0
- package/dist/engine/meta.d.ts +37 -0
- package/dist/engine/meta.d.ts.map +1 -0
- package/dist/engine/threshold.d.ts +31 -0
- package/dist/engine/threshold.d.ts.map +1 -0
- package/dist/env.d.ts +46 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/errors.d.ts +66 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/hash.d.ts +27 -0
- package/dist/hash.d.ts.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1263 -0
- package/dist/index.js.map +1 -0
- package/dist/prompt.d.ts +14 -0
- package/dist/prompt.d.ts.map +1 -0
- package/dist/providers/index.d.ts +6 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +301 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/openai/adapter.d.ts +25 -0
- package/dist/providers/openai/adapter.d.ts.map +1 -0
- package/dist/providers/openai/distribution.d.ts +26 -0
- package/dist/providers/openai/distribution.d.ts.map +1 -0
- package/dist/providers/openai/factory.d.ts +76 -0
- package/dist/providers/openai/factory.d.ts.map +1 -0
- package/dist/providers/openai/index.d.ts +6 -0
- package/dist/providers/openai/index.d.ts.map +1 -0
- package/dist/providers/provider.d.ts +50 -0
- package/dist/providers/provider.d.ts.map +1 -0
- package/dist/testing/index.d.ts +40 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +34 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/tokenizer.d.ts +56 -0
- package/dist/tokenizer.d.ts.map +1 -0
- package/dist/types.d.ts +180 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/validate.d.ts +47 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/verbs/boolean.d.ts +26 -0
- package/dist/verbs/boolean.d.ts.map +1 -0
- package/dist/verbs/classifier.d.ts +63 -0
- package/dist/verbs/classifier.d.ts.map +1 -0
- package/dist/verbs/classify.d.ts +24 -0
- package/dist/verbs/classify.d.ts.map +1 -0
- package/dist/verdict.d.ts +38 -0
- package/dist/verdict.d.ts.map +1 -0
- package/package.json +108 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// src/testing/index.ts
|
|
2
|
+
var DEFAULT_CAPABILITIES = {
|
|
3
|
+
distributionSource: "logprobs",
|
|
4
|
+
coverageMeasurement: "exact",
|
|
5
|
+
// Higher than OpenAI's 20 so users don't trip the chain-min cap unexpectedly
|
|
6
|
+
// in tests of large decision spaces.
|
|
7
|
+
maxTopLogprobs: 100
|
|
8
|
+
};
|
|
9
|
+
function mockProvider(options) {
|
|
10
|
+
const id = options.id ?? "mock/test";
|
|
11
|
+
const modelId = options.modelId ?? "test";
|
|
12
|
+
const tokenizerId = options.tokenizerId ?? "mock";
|
|
13
|
+
const capabilities = options.capabilities ?? DEFAULT_CAPABILITIES;
|
|
14
|
+
const erased = options.behavior;
|
|
15
|
+
return {
|
|
16
|
+
id,
|
|
17
|
+
modelId,
|
|
18
|
+
tokenizerId,
|
|
19
|
+
capabilities,
|
|
20
|
+
async sample(input, space, opts) {
|
|
21
|
+
if (opts.signal?.aborted) {
|
|
22
|
+
const reason = opts.signal.reason;
|
|
23
|
+
if (reason instanceof Error) throw reason;
|
|
24
|
+
throw new Error(typeof reason === "string" ? reason : "aborted");
|
|
25
|
+
}
|
|
26
|
+
const result = await erased(input, space, opts);
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export { mockProvider };
|
|
33
|
+
//# sourceMappingURL=index.js.map
|
|
34
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/testing/index.ts"],"names":[],"mappings":";AAWA,IAAM,oBAAA,GAA6C;AAAA,EACjD,kBAAA,EAAoB,UAAA;AAAA,EACpB,mBAAA,EAAqB,OAAA;AAAA;AAAA;AAAA,EAGrB,cAAA,EAAgB;AAClB,CAAA;AAoCO,SAAS,aAAwC,OAAA,EAA2C;AACjG,EAAA,MAAM,EAAA,GAAK,QAAQ,EAAA,IAAM,WAAA;AACzB,EAAA,MAAM,OAAA,GAAU,QAAQ,OAAA,IAAW,MAAA;AACnC,EAAA,MAAM,WAAA,GAAc,QAAQ,WAAA,IAAe,MAAA;AAC3C,EAAA,MAAM,YAAA,GAAe,QAAQ,YAAA,IAAgB,oBAAA;AAU7C,EAAA,MAAM,SAAS,OAAA,CAAQ,QAAA;AAEvB,EAAA,OAAO;AAAA,IACL,EAAA;AAAA,IACA,OAAA;AAAA,IACA,WAAA;AAAA,IACA,YAAA;AAAA,IACA,MAAM,MAAA,CACJ,KAAA,EACA,KAAA,EACA,IAAA,EAC0B;AAE1B,MAAA,IAAI,IAAA,CAAK,QAAQ,OAAA,EAAS;AACxB,QAAA,MAAM,MAAA,GAAS,KAAK,MAAA,CAAO,MAAA;AAC3B,QAAA,IAAI,MAAA,YAAkB,OAAO,MAAM,MAAA;AACnC,QAAA,MAAM,IAAI,KAAA,CAAM,OAAO,MAAA,KAAW,QAAA,GAAW,SAAS,SAAS,CAAA;AAAA,MACjE;AACA,MAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,KAAA,EAAO,OAA4B,IAAI,CAAA;AACnE,MAAA,OAAO,MAAA;AAAA,IACT;AAAA,GACF;AACF","file":"index.js","sourcesContent":["/**\n * Public test helpers exposed via `@hourslabs/domovoi/testing` subpath.\n *\n * `mockProvider({ behavior, capabilities?, id? })` builds a Provider for\n * tests without hitting a real LLM. Defaults work out-of-the-box for unit\n * tests of engine logic, threshold semantics, and fallback chains.\n */\n\nimport type { Provider, SampleOptions } from \"../providers/provider.js\";\nimport type { Distribution, ProviderCapabilities } from \"../types.js\";\n\nconst DEFAULT_CAPABILITIES: ProviderCapabilities = {\n distributionSource: \"logprobs\",\n coverageMeasurement: \"exact\",\n // Higher than OpenAI's 20 so users don't trip the chain-min cap unexpectedly\n // in tests of large decision spaces.\n maxTopLogprobs: 100,\n};\n\nexport type MockProviderOptions<T extends string = string> = {\n /**\n * Function that produces the Distribution for a given input + space + opts.\n * May be sync or async; engine awaits the result.\n */\n readonly behavior: (\n input: string,\n space: readonly T[],\n opts: SampleOptions,\n ) => Distribution<T> | Promise<Distribution<T>>;\n /** Override default capabilities (for testing capability-mismatch logic). */\n readonly capabilities?: ProviderCapabilities;\n /** Override the provider id; defaults to \"mock/test\". */\n readonly id?: string;\n /** Override the model id; defaults to \"test\". */\n readonly modelId?: string;\n /** Override the tokenizer id; defaults to \"mock\". */\n readonly tokenizerId?: string;\n};\n\n/**\n * Construct a mock Provider for testing.\n *\n * @example\n * const c = domovoi.classifier({\n * space: [\"a\",\"b\",\"c\"] as const,\n * thresholds: { high: 0.7, coverageMin: 0.5 },\n * providers: [\n * mockProvider({\n * behavior: () => ({ probs: { a: 0.8, b: 0.1, c: 0.1 }, coverage: 0.95 }),\n * }),\n * ],\n * });\n */\nexport function mockProvider<T extends string = string>(options: MockProviderOptions<T>): Provider {\n const id = options.id ?? \"mock/test\";\n const modelId = options.modelId ?? \"test\";\n const tokenizerId = options.tokenizerId ?? \"mock\";\n const capabilities = options.capabilities ?? DEFAULT_CAPABILITIES;\n\n // Cast the behavior to the generic Provider.sample shape. Tests typically\n // pin `T` via the classifier they pass the mock to, so the type erasure here\n // is safe in practice.\n type AnyBehavior = (\n i: string,\n s: readonly string[],\n o: SampleOptions,\n ) => Distribution<string> | Promise<Distribution<string>>;\n const erased = options.behavior as unknown as AnyBehavior;\n\n return {\n id,\n modelId,\n tokenizerId,\n capabilities,\n async sample<U extends string>(\n input: string,\n space: readonly U[],\n opts: SampleOptions,\n ): Promise<Distribution<U>> {\n // Pre-aborted check: producers should respect cancellation.\n if (opts.signal?.aborted) {\n const reason = opts.signal.reason;\n if (reason instanceof Error) throw reason;\n throw new Error(typeof reason === \"string\" ? reason : \"aborted\");\n }\n const result = await erased(input, space as readonly string[], opts);\n return result as Distribution<U>;\n },\n };\n}\n"]}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tokenizer abstraction (internal — not exported from the public surface).
|
|
3
|
+
*
|
|
4
|
+
* Supports first-token-id resolution for decision-space collision detection
|
|
5
|
+
* and logit_bias construction. Backed by tiktoken (`cl100k_base` for OpenAI
|
|
6
|
+
* models). Adapters that need different tokenizers can build their own
|
|
7
|
+
* implementation of the same internal interface.
|
|
8
|
+
*
|
|
9
|
+
* Contract:
|
|
10
|
+
* - `encode(label)` returns the token ids for the leading whitespace + label
|
|
11
|
+
* (matches OpenAI's tokenization of an emitted output token).
|
|
12
|
+
* - `firstTokenId(label)` returns the first token id of the encoded label.
|
|
13
|
+
*
|
|
14
|
+
* Note: OpenAI's tokenizer often prepends a leading space to emitted tokens
|
|
15
|
+
* (`" yes"` vs `"yes"`). We detect first-token id with the leading-space
|
|
16
|
+
* variant since that's what the model emits at the first content position.
|
|
17
|
+
*/
|
|
18
|
+
type TokenizerId = "openai/cl100k_base";
|
|
19
|
+
export interface Tokenizer {
|
|
20
|
+
readonly id: TokenizerId;
|
|
21
|
+
/** Token ids for `label` as it would appear at a generation boundary. */
|
|
22
|
+
encode(label: string): number[];
|
|
23
|
+
/** First token id of `label` at a generation boundary. */
|
|
24
|
+
firstTokenId(label: string): number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* cl100k_base tokenizer, used by GPT-4o family + most OpenAI Chat models.
|
|
28
|
+
* Lazy-initialized; the underlying tiktoken native module is heavy.
|
|
29
|
+
*/
|
|
30
|
+
export declare function cl100kTokenizer(): Tokenizer;
|
|
31
|
+
/**
|
|
32
|
+
* Detect first-token-id collisions across a decision space. Returns the
|
|
33
|
+
* conflicting label pair if any two labels resolve to the same first token,
|
|
34
|
+
* or `undefined` if the space is collision-free.
|
|
35
|
+
*
|
|
36
|
+
* Used by the OpenAI adapter (and other tokenizer-aware adapters) at
|
|
37
|
+
* construction time to throw `ConfigError({ code: "decision_space_collision" })`
|
|
38
|
+
* before any network I/O.
|
|
39
|
+
*
|
|
40
|
+
* Imperative form (rather than `reduce`) chosen for readability: the early
|
|
41
|
+
* return on first collision short-circuits naturally without the bookkeeping
|
|
42
|
+
* that a `reduce` accumulator would require.
|
|
43
|
+
*/
|
|
44
|
+
export declare function findFirstTokenCollision(tokenizer: Tokenizer, space: readonly string[]): {
|
|
45
|
+
a: string;
|
|
46
|
+
b: string;
|
|
47
|
+
tokenId: number;
|
|
48
|
+
} | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* Build a logit_bias map for OpenAI Chat Completions: positive bias on each
|
|
51
|
+
* in-space first-token id. Negative biases are deliberately avoided so the
|
|
52
|
+
* coverage signal stays honest — positive bias nudges, doesn't force.
|
|
53
|
+
*/
|
|
54
|
+
export declare function buildLogitBias(tokenizer: Tokenizer, space: readonly string[], bias?: number): Record<string, number>;
|
|
55
|
+
export {};
|
|
56
|
+
//# sourceMappingURL=tokenizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokenizer.d.ts","sourceRoot":"","sources":["../src/tokenizer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,KAAK,WAAW,GAAG,oBAAoB,CAAC;AAExC,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,EAAE,EAAE,WAAW,CAAC;IACzB,yEAAyE;IACzE,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAChC,0DAA0D;IAC1D,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;CACrC;AAID;;;GAGG;AACH,wBAAgB,eAAe,IAAI,SAAS,CAuB3C;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,SAAS,MAAM,EAAE,GACvB;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAWvD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,IAAI,SAAM,GACT,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAIxB"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core types for domovoi: typed-uncertainty classification.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Capabilities a Provider declares about its sampling behavior. The engine
|
|
6
|
+
* uses these to decide how to interpret the returned `Distribution` and
|
|
7
|
+
* which providers in a chain produce comparable Verdict metadata.
|
|
8
|
+
*/
|
|
9
|
+
export type ProviderCapabilities = {
|
|
10
|
+
readonly distributionSource: "logprobs" | "multi_sample";
|
|
11
|
+
readonly coverageMeasurement: "exact" | "approximate" | "none";
|
|
12
|
+
/** Max top-K logprobs returned by the provider; 0 for `multi_sample`. */
|
|
13
|
+
readonly maxTopLogprobs: number;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* The label-type domain a Verdict can range over: string for multi-class
|
|
17
|
+
* spaces, boolean for the binary `domovoi.boolean()` verb.
|
|
18
|
+
*/
|
|
19
|
+
export type Label = string | boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Probability distribution over the labels of a decision space, plus a
|
|
22
|
+
* coverage signal that measures how much probability mass the model put
|
|
23
|
+
* on labels outside the space.
|
|
24
|
+
*/
|
|
25
|
+
export type Distribution<T extends Label> = {
|
|
26
|
+
/**
|
|
27
|
+
* Probability per label, renormalized to sum to 1 over the space. Labels
|
|
28
|
+
* the model didn't express any opinion on are present with value 0.
|
|
29
|
+
*/
|
|
30
|
+
readonly probs: [T] extends [string] ? {
|
|
31
|
+
readonly [K in T]: number;
|
|
32
|
+
} : {
|
|
33
|
+
readonly [K in `${T & boolean}`]: number;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Pre-renormalization mass on in-space labels, ∈ [0, 1]. Low coverage
|
|
37
|
+
* means the model wanted to answer with something outside the space.
|
|
38
|
+
*/
|
|
39
|
+
readonly coverage: number;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Plain-object error shape. `Verdict.meta.providerErrors[i].error` carries
|
|
43
|
+
* this so `JSON.stringify(verdict)` round-trips cleanly. Live `Error`
|
|
44
|
+
* instances are still passed to the `onProviderError` hook for callers
|
|
45
|
+
* that need `instanceof` semantics.
|
|
46
|
+
*/
|
|
47
|
+
export type SerializableError = {
|
|
48
|
+
readonly name: string;
|
|
49
|
+
readonly message: string;
|
|
50
|
+
readonly code?: string;
|
|
51
|
+
readonly cause?: SerializableError;
|
|
52
|
+
readonly stack?: string;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Per-Verdict metadata recorded by the engine. Present on every variant —
|
|
56
|
+
* gives observability into which provider answered, how long it took, and
|
|
57
|
+
* what failed along the way without separate instrumentation.
|
|
58
|
+
*/
|
|
59
|
+
export type VerdictMeta = {
|
|
60
|
+
/** Provider that produced this Verdict, in `factory/model` form. */
|
|
61
|
+
readonly providerUsed: string;
|
|
62
|
+
/** Every provider attempted, in chain order. */
|
|
63
|
+
readonly providersAttempted: readonly string[];
|
|
64
|
+
/** Errors swallowed during fallback. Empty when no errors occurred. */
|
|
65
|
+
readonly providerErrors: ReadonlyArray<{
|
|
66
|
+
readonly providerId: string;
|
|
67
|
+
readonly error: SerializableError;
|
|
68
|
+
}>;
|
|
69
|
+
/** Wall-clock latency from engine entry to this Verdict. */
|
|
70
|
+
readonly latencyMs: number;
|
|
71
|
+
/** True when this Verdict was served from cache. */
|
|
72
|
+
readonly cacheHit: boolean;
|
|
73
|
+
/** OOD-signal quality from the answering provider. */
|
|
74
|
+
readonly coverageQuality: "exact" | "approximate" | "none";
|
|
75
|
+
/** How the answering provider constructed its Distribution. */
|
|
76
|
+
readonly distributionSource: "logprobs" | "multi_sample";
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Why a Verdict came back as `Unknown`. Each variant carries the data
|
|
80
|
+
* relevant to its mode — surface it for routing, alerting, or retry logic.
|
|
81
|
+
*/
|
|
82
|
+
export type UnknownVerdictCause<T extends Label> = {
|
|
83
|
+
readonly type: "out_of_distribution";
|
|
84
|
+
readonly coverage: number;
|
|
85
|
+
readonly topIfRenormalized: T;
|
|
86
|
+
readonly probabilityIfRenormalized: number;
|
|
87
|
+
} | {
|
|
88
|
+
readonly type: "chain_exhausted";
|
|
89
|
+
readonly lastDistribution: Distribution<T>;
|
|
90
|
+
readonly providersAttempted: number;
|
|
91
|
+
} | {
|
|
92
|
+
readonly type: "predicate_rejected";
|
|
93
|
+
readonly previousKind: "classified" | "uncertain";
|
|
94
|
+
} | {
|
|
95
|
+
readonly type: "provider_failure";
|
|
96
|
+
readonly errors: readonly SerializableError[];
|
|
97
|
+
} | {
|
|
98
|
+
readonly type: "budget_exhausted";
|
|
99
|
+
readonly scope: "per_call_timeout" | "chain_timeout" | "max_calls";
|
|
100
|
+
} | {
|
|
101
|
+
readonly type: "cancelled";
|
|
102
|
+
readonly reason?: string;
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* Confident result. `value` cleared the `high` threshold (and the margin
|
|
106
|
+
* requirement, if any) over the decision space.
|
|
107
|
+
*/
|
|
108
|
+
export type Classified<T extends Label> = {
|
|
109
|
+
readonly kind: "classified";
|
|
110
|
+
readonly value: T;
|
|
111
|
+
/** Calibrated probability of `value`, ∈ [0, 1]. */
|
|
112
|
+
readonly probability: number;
|
|
113
|
+
readonly meta: VerdictMeta;
|
|
114
|
+
};
|
|
115
|
+
/**
|
|
116
|
+
* Top candidate found, but below the `high` threshold (or the margin
|
|
117
|
+
* requirement was not met). Carries `runnerUp` so callers can fall back,
|
|
118
|
+
* confirm with the user, or escalate to a stronger model with both
|
|
119
|
+
* candidates in scope.
|
|
120
|
+
*/
|
|
121
|
+
export type Uncertain<T extends Label> = {
|
|
122
|
+
readonly kind: "uncertain";
|
|
123
|
+
readonly top: T;
|
|
124
|
+
/** Calibrated probability of `top`, ∈ [0, 1]. */
|
|
125
|
+
readonly probability: number;
|
|
126
|
+
readonly runnerUp: T;
|
|
127
|
+
readonly distribution: Distribution<T>;
|
|
128
|
+
readonly meta: VerdictMeta;
|
|
129
|
+
};
|
|
130
|
+
/** No usable classification. `reason.type` discriminates the cause. */
|
|
131
|
+
export type Unknown<T extends Label> = {
|
|
132
|
+
readonly kind: "unknown";
|
|
133
|
+
readonly reason: UnknownVerdictCause<T>;
|
|
134
|
+
readonly meta: VerdictMeta;
|
|
135
|
+
};
|
|
136
|
+
/**
|
|
137
|
+
* The discriminated union returned by every classifier call. Narrow with
|
|
138
|
+
* `kind`, the type guards (`isClassified` / `isUncertain` / `isUnknown`),
|
|
139
|
+
* or `match` for exhaustive handling.
|
|
140
|
+
*/
|
|
141
|
+
export type Verdict<T extends Label> = Classified<T> | Uncertain<T> | Unknown<T>;
|
|
142
|
+
/** Verdict variants that carry a top-class candidate. */
|
|
143
|
+
export type Filterable<T extends Label> = Classified<T> | Uncertain<T>;
|
|
144
|
+
/**
|
|
145
|
+
* Threshold rules, discriminated by space length. Binary spaces use a
|
|
146
|
+
* deadband (`high` / `low`); multi-class spaces use a top-confidence rule
|
|
147
|
+
* with optional margin. Values must lie in `[0, 1]` and binary `high` must
|
|
148
|
+
* exceed `low` strictly.
|
|
149
|
+
*/
|
|
150
|
+
export type Thresholds<Space extends readonly string[]> = Space["length"] extends 2 ? {
|
|
151
|
+
readonly high: number;
|
|
152
|
+
readonly low: number;
|
|
153
|
+
readonly coverageMin?: number;
|
|
154
|
+
} : {
|
|
155
|
+
readonly high: number;
|
|
156
|
+
readonly margin?: number;
|
|
157
|
+
readonly coverageMin?: number;
|
|
158
|
+
};
|
|
159
|
+
/** Caps on time and provider calls. Defaults applied if a field is omitted. */
|
|
160
|
+
export type Budget = {
|
|
161
|
+
/** Per-provider-call wall-clock timeout. Default 10_000ms. */
|
|
162
|
+
readonly perCallTimeoutMs?: number;
|
|
163
|
+
/** Across-the-chain wall-clock budget. Default 30_000ms. */
|
|
164
|
+
readonly chainTimeoutMs?: number;
|
|
165
|
+
/** Hard cap on provider calls per classification. Default = chain length. */
|
|
166
|
+
readonly maxCalls?: number;
|
|
167
|
+
};
|
|
168
|
+
/**
|
|
169
|
+
* Prompt template applied to every classification call. Override only when
|
|
170
|
+
* the default doesn't fit; supply your own `templateHash` so cache keys
|
|
171
|
+
* stay correct.
|
|
172
|
+
*/
|
|
173
|
+
export type PromptTemplate = {
|
|
174
|
+
readonly systemPrompt?: string;
|
|
175
|
+
/** Renders the user message. `{labels_csv}` is filled in user-given order. */
|
|
176
|
+
readonly userTemplate: (input: string, space: readonly string[], question?: string) => string;
|
|
177
|
+
/** Stable hash for cache-key composition. */
|
|
178
|
+
readonly templateHash: string;
|
|
179
|
+
};
|
|
180
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Construction-time validators throw `ConfigError`; the runtime
|
|
3
|
+
* `validateDistribution` (called by the engine after `Provider.sample` returns)
|
|
4
|
+
* throws `ProviderError`.
|
|
5
|
+
*/
|
|
6
|
+
import type { Distribution, ProviderCapabilities, Thresholds } from "./types.js";
|
|
7
|
+
/**
|
|
8
|
+
* Throws if the decision space contains: empty labels (post-NFC + trim),
|
|
9
|
+
* duplicates (post-NFC), whitespace-padded labels, or fewer than 2 entries.
|
|
10
|
+
*
|
|
11
|
+
* The empty-array case is also rejected at the type level via the
|
|
12
|
+
* `readonly [T, ...T[]]` shape on classifier configs.
|
|
13
|
+
*/
|
|
14
|
+
export declare function validateSpace(space: readonly string[]): void;
|
|
15
|
+
/**
|
|
16
|
+
* Validate threshold values at construction. Inclusive [0, 1] range; binary
|
|
17
|
+
* requires `high > low` strict; `margin >= 0` if present.
|
|
18
|
+
*/
|
|
19
|
+
export declare function validateThresholds<S extends readonly string[]>(thresholds: Thresholds<S>, spaceLength: number): void;
|
|
20
|
+
export declare function validateClassifierName(name: string): void;
|
|
21
|
+
/**
|
|
22
|
+
* Validates the provider chain. Throws if the array is empty, or if the
|
|
23
|
+
* decision space exceeds the smallest `maxTopLogprobs` across all
|
|
24
|
+
* `distributionSource: "logprobs"` providers in the chain (multi-sample
|
|
25
|
+
* providers have no top-K constraint and are exempt).
|
|
26
|
+
*/
|
|
27
|
+
export declare function validateProviderChain(providers: ReadonlyArray<{
|
|
28
|
+
readonly id: string;
|
|
29
|
+
readonly capabilities: ProviderCapabilities;
|
|
30
|
+
}>, spaceLength: number): void;
|
|
31
|
+
/**
|
|
32
|
+
* Validate calibrator vs provider chain capabilities at construction.
|
|
33
|
+
* Multi-sample providers reject non-identity calibrators.
|
|
34
|
+
*/
|
|
35
|
+
export declare function validateCalibratorCompatibility(calibratorIsIdentity: boolean, providers: ReadonlyArray<{
|
|
36
|
+
readonly id: string;
|
|
37
|
+
readonly capabilities: ProviderCapabilities;
|
|
38
|
+
}>): void;
|
|
39
|
+
/**
|
|
40
|
+
* Engine-side check on every Distribution returned by `Provider.sample`,
|
|
41
|
+
* before calibration. Verifies coverage and per-prob range, fills missing
|
|
42
|
+
* in-space labels with `0` (mutates `probs`), and asserts sum-to-one within
|
|
43
|
+
* a fixed tolerance. Throws `ProviderError` on violation — surfaces buggy
|
|
44
|
+
* custom Provider implementations.
|
|
45
|
+
*/
|
|
46
|
+
export declare function validateDistribution<T extends string>(d: Distribution<T>, space: readonly T[]): void;
|
|
47
|
+
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEjF;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CA4B5D;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,SAAS,MAAM,EAAE,EAC5D,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,EACzB,WAAW,EAAE,MAAM,GAClB,IAAI,CAiCN;AAYD,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAOzD;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,aAAa,CAAC;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,YAAY,EAAE,oBAAoB,CAAA;CAAE,CAAC,EAC9F,WAAW,EAAE,MAAM,GAClB,IAAI,CAwBN;AAED;;;GAGG;AACH,wBAAgB,+BAA+B,CAC7C,oBAAoB,EAAE,OAAO,EAC7B,SAAS,EAAE,aAAa,CAAC;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,YAAY,EAAE,oBAAoB,CAAA;CAAE,CAAC,GAC7F,IAAI,CASN;AAID;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,MAAM,EACnD,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,EAClB,KAAK,EAAE,SAAS,CAAC,EAAE,GAClB,IAAI,CAmCN"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Binary one-shot classifier — returns `Verdict<boolean>`.
|
|
3
|
+
*
|
|
4
|
+
* The engine internally classifies over the string space `["yes", "no"]` to
|
|
5
|
+
* match LLM first-token tokenization cleanly; a small transform at the verb
|
|
6
|
+
* boundary maps the result to `boolean` so the public surface is idiomatic.
|
|
7
|
+
*
|
|
8
|
+
* Default deadband `{ high: 0.7, low: 0.3, coverageMin: 0.3 }` is
|
|
9
|
+
* illustrative — tune for your workload.
|
|
10
|
+
*/
|
|
11
|
+
import { type Cache } from "../cache.js";
|
|
12
|
+
import { type Calibrator } from "../calibration/index.js";
|
|
13
|
+
import type { Provider } from "../providers/provider.js";
|
|
14
|
+
import type { Budget, Thresholds, Verdict } from "../types.js";
|
|
15
|
+
declare const YES_NO_SPACE: readonly ["yes", "no"];
|
|
16
|
+
export type BooleanOptions = {
|
|
17
|
+
readonly providers?: readonly Provider[];
|
|
18
|
+
readonly calibrator?: Calibrator;
|
|
19
|
+
readonly cache?: Cache;
|
|
20
|
+
readonly budget?: Budget;
|
|
21
|
+
readonly thresholds?: Thresholds<typeof YES_NO_SPACE>;
|
|
22
|
+
readonly signal?: AbortSignal;
|
|
23
|
+
};
|
|
24
|
+
export declare function boolean(input: string, question: string, opts?: BooleanOptions): Promise<Verdict<boolean>>;
|
|
25
|
+
export {};
|
|
26
|
+
//# sourceMappingURL=boolean.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boolean.d.ts","sourceRoot":"","sources":["../../src/verbs/boolean.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,KAAK,KAAK,EAAe,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,KAAK,UAAU,EAAY,MAAM,yBAAyB,CAAC;AAIpE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,KAAK,EAAE,MAAM,EAAgB,UAAU,EAAuB,OAAO,EAAE,MAAM,aAAa,CAAC;AAMlG,QAAA,MAAM,YAAY,wBAA2D,CAAC;AAE9E,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;IACzC,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;IACjC,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;IACtD,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B,CAAC;AAEF,wBAAsB,OAAO,CAC3B,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,IAAI,CAAC,EAAE,cAAc,GACpB,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CA+B3B"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* domovoi.classifier({...}) — reusable configured classifier factory.
|
|
3
|
+
*
|
|
4
|
+
* Returns a `Classifier<T, I>`: a callable that takes an input, returns
|
|
5
|
+
* `Promise<Verdict<T>>`. Also exposes `.batch(items, opts?)` and `.classify`
|
|
6
|
+
* alias for discoverability.
|
|
7
|
+
*
|
|
8
|
+
* Validates configuration at construction time (validate.ts) and resolves
|
|
9
|
+
* env-driven providers if `providers` is omitted (env.ts).
|
|
10
|
+
*
|
|
11
|
+
* Note: full callable+method shape requires assigning methods to a function
|
|
12
|
+
* object. We use `Object.assign` to achieve this with type safety.
|
|
13
|
+
*/
|
|
14
|
+
import { type Cache } from "../cache.js";
|
|
15
|
+
import { type Calibrator } from "../calibration/index.js";
|
|
16
|
+
import type { Provider } from "../providers/provider.js";
|
|
17
|
+
import type { Budget, PromptTemplate, Thresholds, Verdict } from "../types.js";
|
|
18
|
+
/**
|
|
19
|
+
* Configuration accepted by `domovoi.classifier({...})`.
|
|
20
|
+
*
|
|
21
|
+
* `format` is required when `I` is not assignable to `string`. When `I = string`
|
|
22
|
+
* (default), `format` is optional and defaults to identity.
|
|
23
|
+
*/
|
|
24
|
+
export type ClassifierConfig<T extends string, I> = {
|
|
25
|
+
/** /^[a-z][a-z0-9_]*$/; uppercased for env-binding lookup. */
|
|
26
|
+
readonly name?: string;
|
|
27
|
+
readonly space: readonly [T, ...T[]];
|
|
28
|
+
readonly question?: string;
|
|
29
|
+
readonly format?: (x: I) => string;
|
|
30
|
+
readonly thresholds: Thresholds<readonly [T, ...T[]]>;
|
|
31
|
+
readonly providers?: readonly Provider[];
|
|
32
|
+
readonly calibrator?: Calibrator;
|
|
33
|
+
readonly cache?: Cache;
|
|
34
|
+
readonly budget?: Budget;
|
|
35
|
+
readonly template?: PromptTemplate;
|
|
36
|
+
readonly hooks?: {
|
|
37
|
+
onCall?: (...args: unknown[]) => void | Promise<void>;
|
|
38
|
+
onResult?: (...args: unknown[]) => void | Promise<void>;
|
|
39
|
+
};
|
|
40
|
+
readonly onProviderError?: (err: Error, ctx: {
|
|
41
|
+
providerId: string;
|
|
42
|
+
attempt: number;
|
|
43
|
+
}) => void | Promise<void>;
|
|
44
|
+
readonly onErrorPolicy?: "fallback" | "throw";
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* The configured runtime instance. Callable with an input; returns
|
|
48
|
+
* `Promise<Verdict<T>>`.
|
|
49
|
+
*
|
|
50
|
+
* Methods:
|
|
51
|
+
* - `.batch(items, opts?)`: per-item Verdicts in input order.
|
|
52
|
+
*/
|
|
53
|
+
export interface Classifier<T extends string, I> {
|
|
54
|
+
(input: I, opts?: {
|
|
55
|
+
signal?: AbortSignal;
|
|
56
|
+
}): Promise<Verdict<T>>;
|
|
57
|
+
batch(items: readonly I[], opts?: {
|
|
58
|
+
concurrency?: number;
|
|
59
|
+
signal?: AbortSignal;
|
|
60
|
+
}): Promise<Verdict<T>[]>;
|
|
61
|
+
}
|
|
62
|
+
export declare function classifier<const T extends string, I = string>(config: ClassifierConfig<T, I>): Classifier<T, I>;
|
|
63
|
+
//# sourceMappingURL=classifier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classifier.d.ts","sourceRoot":"","sources":["../../src/verbs/classifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,KAAK,KAAK,EAAe,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,KAAK,UAAU,EAAY,MAAM,yBAAyB,CAAC;AAIpE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE/E;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,IAAI;IAClD,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IACrC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC;IACnC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACtD,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;IACzC,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;IACjC,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,cAAc,CAAC;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE;QACf,MAAM,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QACtD,QAAQ,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KACzD,CAAC;IACF,QAAQ,CAAC,eAAe,CAAC,EAAE,CACzB,GAAG,EAAE,KAAK,EACV,GAAG,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,KACzC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,QAAQ,CAAC,aAAa,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC;CAC/C,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,WAAW,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC;IAC7C,CAAC,KAAK,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IACjE,KAAK,CACH,KAAK,EAAE,SAAS,CAAC,EAAE,EACnB,IAAI,CAAC,EAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GACpD,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;CAC1B;AAID,wBAAgB,UAAU,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,GAAG,MAAM,EAC3D,MAAM,EAAE,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,GAC7B,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,CA8ElB"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-class one-shot classifier — returns `Verdict<T>` where `T` is the
|
|
3
|
+
* literal union of labels in `space`.
|
|
4
|
+
*
|
|
5
|
+
* Reads providers from `DOMOVOI_PROVIDERS` env unless the caller supplies
|
|
6
|
+
* `{ providers }`. Default thresholds `{ high: 0.5, coverageMin: 0.3 }` are
|
|
7
|
+
* illustrative — production code should construct `classifier({ ... })`
|
|
8
|
+
* with thresholds tuned to the workload.
|
|
9
|
+
*/
|
|
10
|
+
import { type Cache } from "../cache.js";
|
|
11
|
+
import { type Calibrator } from "../calibration/index.js";
|
|
12
|
+
import type { Provider } from "../providers/provider.js";
|
|
13
|
+
import type { Budget, Thresholds, Verdict } from "../types.js";
|
|
14
|
+
export type ClassifyOptions<T extends string> = {
|
|
15
|
+
readonly question?: string;
|
|
16
|
+
readonly providers?: readonly Provider[];
|
|
17
|
+
readonly calibrator?: Calibrator;
|
|
18
|
+
readonly cache?: Cache;
|
|
19
|
+
readonly budget?: Budget;
|
|
20
|
+
readonly thresholds?: Thresholds<readonly [T, ...T[]]>;
|
|
21
|
+
readonly signal?: AbortSignal;
|
|
22
|
+
};
|
|
23
|
+
export declare function classify<const T extends string>(input: string, space: readonly [T, ...T[]], opts?: ClassifyOptions<T>): Promise<Verdict<T>>;
|
|
24
|
+
//# sourceMappingURL=classify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classify.d.ts","sourceRoot":"","sources":["../../src/verbs/classify.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,KAAK,KAAK,EAAe,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,KAAK,UAAU,EAAY,MAAM,yBAAyB,CAAC;AAIpE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAI/D,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,MAAM,IAAI;IAC9C,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;IACzC,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC;IACjC,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACvD,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B,CAAC;AAEF,wBAAsB,QAAQ,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,EACnD,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,EAC3B,IAAI,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,GACxB,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAgCrB"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verdict combinators and type guards. The library ships only `match`,
|
|
3
|
+
* `filter`, and the three type guards; richer combinators (tap, getOrElse,
|
|
4
|
+
* etc.) compose cleanly in userspace.
|
|
5
|
+
*/
|
|
6
|
+
import type { Classified, Filterable, Label, Uncertain, Unknown, Verdict } from "./types.js";
|
|
7
|
+
export declare function isClassified<T extends Label>(v: Verdict<T>): v is Classified<T>;
|
|
8
|
+
export declare function isUncertain<T extends Label>(v: Verdict<T>): v is Uncertain<T>;
|
|
9
|
+
export declare function isUnknown<T extends Label>(v: Verdict<T>): v is Unknown<T>;
|
|
10
|
+
/**
|
|
11
|
+
* Pattern-match against a Verdict. All three branches are required;
|
|
12
|
+
* omitting one is a compile-time error.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* const result = match(verdict, {
|
|
16
|
+
* classified: ({ value }) => save(value),
|
|
17
|
+
* uncertain: ({ top, runnerUp }) => queue.review(top, runnerUp),
|
|
18
|
+
* unknown: ({ reason }) => routeUnknown(reason),
|
|
19
|
+
* });
|
|
20
|
+
*/
|
|
21
|
+
export declare function match<T extends Label, R>(v: Verdict<T>, handlers: {
|
|
22
|
+
classified: (v: Classified<T>) => R;
|
|
23
|
+
uncertain: (v: Uncertain<T>) => R;
|
|
24
|
+
unknown: (v: Unknown<T>) => R;
|
|
25
|
+
}): R;
|
|
26
|
+
/**
|
|
27
|
+
* Domain-validity filter. The predicate sees `Filterable<T>` — Classified or
|
|
28
|
+
* Uncertain only. When it returns `false`, the Verdict becomes
|
|
29
|
+
* `Unknown { predicate_rejected }`. Unknown inputs pass through unchanged.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* const safe = filter<MyLabels>((v) => {
|
|
33
|
+
* const pick = v.kind === "classified" ? v.value : v.top;
|
|
34
|
+
* return !DEPRECATED.has(pick);
|
|
35
|
+
* })(verdict);
|
|
36
|
+
*/
|
|
37
|
+
export declare function filter<T extends Label>(pred: (v: Filterable<T>) => boolean): (v: Verdict<T>) => Verdict<T>;
|
|
38
|
+
//# sourceMappingURL=verdict.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verdict.d.ts","sourceRoot":"","sources":["../src/verdict.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE7F,wBAAgB,YAAY,CAAC,CAAC,SAAS,KAAK,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,CAE/E;AAED,wBAAgB,WAAW,CAAC,CAAC,SAAS,KAAK,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,CAE7E;AAED,wBAAgB,SAAS,CAAC,CAAC,SAAS,KAAK,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,CAEzE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,KAAK,CAAC,CAAC,SAAS,KAAK,EAAE,CAAC,EACtC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,EACb,QAAQ,EAAE;IACR,UAAU,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACpC,SAAS,EAAE,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAClC,OAAO,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;CAC/B,GACA,CAAC,CASH;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,OAAO,IACjE,GAAG,OAAO,CAAC,CAAC,CAAC,KAAG,OAAO,CAAC,CAAC,CAAC,CASnC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hourslabs/domovoi",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Typed-uncertainty classification for TypeScript. Bind a domovoi to your code; receive Verdicts with calibrated probability and structured failure modes.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./providers": {
|
|
14
|
+
"types": "./dist/providers/index.d.ts",
|
|
15
|
+
"import": "./dist/providers/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./calibration": {
|
|
18
|
+
"types": "./dist/calibration/index.d.ts",
|
|
19
|
+
"import": "./dist/calibration/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./testing": {
|
|
22
|
+
"types": "./dist/testing/index.d.ts",
|
|
23
|
+
"import": "./dist/testing/index.js"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist",
|
|
28
|
+
"LICENSE",
|
|
29
|
+
"NOTICE",
|
|
30
|
+
"README.md"
|
|
31
|
+
],
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsup && tsc --emitDeclarationOnly --declaration --declarationMap",
|
|
34
|
+
"check": "biome check .",
|
|
35
|
+
"check:fix": "biome check --write .",
|
|
36
|
+
"typecheck": "tsc --noEmit",
|
|
37
|
+
"typecheck:examples": "tsc --noEmit -p tsconfig.examples.json",
|
|
38
|
+
"test": "vitest run",
|
|
39
|
+
"test:watch": "vitest",
|
|
40
|
+
"test:types": "vitest run --typecheck",
|
|
41
|
+
"test:coverage": "vitest run --coverage",
|
|
42
|
+
"knip": "knip",
|
|
43
|
+
"publint": "publint",
|
|
44
|
+
"attw": "attw --pack --profile esm-only",
|
|
45
|
+
"validate:pack": "npm run build && npm run publint && npm run attw",
|
|
46
|
+
"changeset": "changeset",
|
|
47
|
+
"version": "changeset version",
|
|
48
|
+
"release": "npm run validate:pack && changeset publish",
|
|
49
|
+
"prepublishOnly": "npm run check && npm run typecheck && npm test && npm run validate:pack"
|
|
50
|
+
},
|
|
51
|
+
"engines": {
|
|
52
|
+
"node": ">=22.0.0"
|
|
53
|
+
},
|
|
54
|
+
"keywords": [
|
|
55
|
+
"classification",
|
|
56
|
+
"classifier",
|
|
57
|
+
"llm",
|
|
58
|
+
"typed",
|
|
59
|
+
"uncertainty",
|
|
60
|
+
"calibrated",
|
|
61
|
+
"openai",
|
|
62
|
+
"ollama",
|
|
63
|
+
"anthropic",
|
|
64
|
+
"vllm",
|
|
65
|
+
"embeddings",
|
|
66
|
+
"logprobs",
|
|
67
|
+
"discriminated-union"
|
|
68
|
+
],
|
|
69
|
+
"author": "Alex Roh",
|
|
70
|
+
"license": "Apache-2.0",
|
|
71
|
+
"repository": {
|
|
72
|
+
"type": "git",
|
|
73
|
+
"url": "git+https://github.com/alexbroh/domovoi.git"
|
|
74
|
+
},
|
|
75
|
+
"homepage": "https://github.com/alexbroh/domovoi#readme",
|
|
76
|
+
"bugs": {
|
|
77
|
+
"url": "https://github.com/alexbroh/domovoi/issues"
|
|
78
|
+
},
|
|
79
|
+
"dependencies": {
|
|
80
|
+
"openai": "^6.35.0",
|
|
81
|
+
"tiktoken": "^1.0.22"
|
|
82
|
+
},
|
|
83
|
+
"devDependencies": {
|
|
84
|
+
"@arethetypeswrong/cli": "^0.18.2",
|
|
85
|
+
"@biomejs/biome": "^2.4.13",
|
|
86
|
+
"@changesets/cli": "^2.31.0",
|
|
87
|
+
"@types/node": "^25.6.0",
|
|
88
|
+
"@vitest/coverage-v8": "^4.1.5",
|
|
89
|
+
"knip": "^6.9.0",
|
|
90
|
+
"publint": "^0.3.18",
|
|
91
|
+
"tsup": "^8.5.1",
|
|
92
|
+
"tsx": "^4.21.0",
|
|
93
|
+
"typescript": "^6.0.3",
|
|
94
|
+
"vitest": "^4.1.5"
|
|
95
|
+
},
|
|
96
|
+
"peerDependencies": {
|
|
97
|
+
"typescript": ">=5.0.0"
|
|
98
|
+
},
|
|
99
|
+
"peerDependenciesMeta": {
|
|
100
|
+
"typescript": {
|
|
101
|
+
"optional": true
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
"sideEffects": false,
|
|
105
|
+
"publishConfig": {
|
|
106
|
+
"access": "public"
|
|
107
|
+
}
|
|
108
|
+
}
|