@juspay/neurolink 12.18.0 → 12.19.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/CHANGELOG.md +2 -2
- package/README.md +277 -75
- package/dist/browser/neurolink.min.js +396 -396
- package/dist/cli/commands/setup.js +2 -1
- package/dist/cli/factories/commandFactory.d.ts +22 -2
- package/dist/cli/factories/commandFactory.js +14 -2
- package/dist/cli/loop/optionsSchema.js +4 -0
- package/dist/cli/utils/classifierRouterFlags.js +39 -1
- package/dist/constants/enums.d.ts +13 -0
- package/dist/constants/enums.js +14 -0
- package/dist/context/budgetChecker.d.ts +3 -1
- package/dist/context/budgetChecker.js +20 -4
- package/dist/context/contextCompactor.d.ts +43 -3
- package/dist/context/contextCompactor.js +157 -41
- package/dist/context/contextDecision.d.ts +56 -0
- package/dist/context/contextDecision.js +234 -0
- package/dist/core/baseProvider.d.ts +27 -1
- package/dist/core/baseProvider.js +39 -0
- package/dist/core/toolRouting.d.ts +8 -0
- package/dist/core/toolRouting.js +52 -1
- package/dist/core/toolRoutingDecision.d.ts +35 -0
- package/dist/core/toolRoutingDecision.js +194 -0
- package/dist/factories/providerDescriptors.d.ts +15 -0
- package/dist/factories/providerDescriptors.js +57 -1
- package/dist/factories/providerRegistry.js +9 -1
- package/dist/index.d.ts +57 -1
- package/dist/index.js +60 -1
- package/dist/models/manifestRegistry.js +2 -0
- package/dist/models/manifests/typesafe.d.ts +16 -0
- package/dist/models/manifests/typesafe.js +42 -0
- package/dist/neurolink.d.ts +57 -1
- package/dist/neurolink.js +254 -10
- package/dist/observability/exporters/laminarExporter.js +3 -0
- package/dist/observability/exporters/posthogExporter.js +3 -0
- package/dist/observability/utils/spanSerializer.js +4 -0
- package/dist/providers/catalog/schema.d.ts +1 -1
- package/dist/providers/typesafe.d.ts +112 -0
- package/dist/providers/typesafe.js +654 -0
- package/dist/proxy/proxyHistoryTruncation.js +15 -10
- package/dist/rag/pipeline/RAGPipeline.d.ts +3 -1
- package/dist/rag/pipeline/RAGPipeline.js +65 -4
- package/dist/rag/retrieval/searchDecision.d.ts +27 -0
- package/dist/rag/retrieval/searchDecision.js +124 -0
- package/dist/routing/classifierRouter.d.ts +74 -2
- package/dist/routing/classifierRouter.js +232 -32
- package/dist/routing/classifierStrategies.d.ts +33 -1
- package/dist/routing/classifierStrategies.js +237 -0
- package/dist/routing/index.d.ts +1 -1
- package/dist/routing/index.js +1 -1
- package/dist/routing/modelCatalog.d.ts +79 -0
- package/dist/routing/modelCatalog.js +382 -0
- package/dist/telemetry/tracers.d.ts +1 -0
- package/dist/telemetry/tracers.js +1 -0
- package/dist/types/classifierRouter.d.ts +160 -4
- package/dist/types/cli.d.ts +17 -1
- package/dist/types/config.d.ts +12 -0
- package/dist/types/context.d.ts +55 -1
- package/dist/types/decision.d.ts +200 -0
- package/dist/types/decision.js +21 -0
- package/dist/types/generate.d.ts +20 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/providers.d.ts +59 -1
- package/dist/types/providers.js +5 -0
- package/dist/types/rag.d.ts +48 -0
- package/dist/types/span.d.ts +11 -0
- package/dist/types/span.js +11 -0
- package/dist/types/stream.d.ts +13 -0
- package/dist/types/toolRouting.d.ts +56 -0
- package/dist/utils/decisionAnswers.d.ts +56 -0
- package/dist/utils/decisionAnswers.js +95 -0
- package/dist/utils/modelChoices.js +13 -1
- package/dist/utils/pricing.js +11 -0
- package/dist/utils/providerConfig.d.ts +4 -0
- package/dist/utils/providerConfig.js +17 -0
- package/docs-site/static/search-index.json +1 -1
- package/package.json +16 -3
|
@@ -14,10 +14,29 @@
|
|
|
14
14
|
* `src/lib/types/` (see CLAUDE.md rule 9).
|
|
15
15
|
*/
|
|
16
16
|
import type { ValidationSchema } from "./aliases.js";
|
|
17
|
+
import type { DecisionCallerFn } from "./decision.js";
|
|
17
18
|
/** Coarse difficulty buckets the classifier maps a request into. */
|
|
18
19
|
export type ClassifierDifficulty = "trivial" | "simple" | "moderate" | "hard" | "expert";
|
|
19
|
-
/**
|
|
20
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Which classification strategy to run.
|
|
22
|
+
*
|
|
23
|
+
* - `heuristic` — keyword/length scoring. Deterministic, zero latency.
|
|
24
|
+
* - `llm` — a cheap classifier model via the injected `generate`.
|
|
25
|
+
* - `jev` — TypeSafe's System One model; one ~400ms round trip that returns a
|
|
26
|
+
* *calibrated* confidence rather than a self-reported one.
|
|
27
|
+
* - `auto` — `jev` when `TYPESAFE_API_KEY` is set, otherwise `heuristic`.
|
|
28
|
+
*/
|
|
29
|
+
export type ClassifierStrategyKind = "heuristic" | "llm" | "jev" | "auto";
|
|
30
|
+
/**
|
|
31
|
+
* How much of the available context a request actually needs, ordered
|
|
32
|
+
* narrowest → widest. This is a *rubric*, not a token count: a decision model
|
|
33
|
+
* is reliable at placing a request on an ordered scale and unreliable at
|
|
34
|
+
* naming a number (it reads digits as text, not as quantities).
|
|
35
|
+
*
|
|
36
|
+
* The index is mapped onto a compaction threshold by the router, and only
|
|
37
|
+
* ever downward — see `ClassifierRouterDecision.compactionThreshold`.
|
|
38
|
+
*/
|
|
39
|
+
export type ClassifierContextScope = "current-message" | "recent-turns" | "full-conversation" | "everything";
|
|
21
40
|
/**
|
|
22
41
|
* The classifier's verdict for a single request. Strategy-agnostic: produced
|
|
23
42
|
* by both the heuristic and the LLM classifier.
|
|
@@ -36,6 +55,27 @@ export type ClassifierDecision = {
|
|
|
36
55
|
* (matches a `ClassifierCandidate.id`). Ignored by the heuristic classifier.
|
|
37
56
|
*/
|
|
38
57
|
selectedModelId?: string;
|
|
58
|
+
/**
|
|
59
|
+
* Confidence in `selectedModelId`, when the strategy reports one.
|
|
60
|
+
*
|
|
61
|
+
* Separate from `confidence`, which is about the DIFFICULTY verdict: a
|
|
62
|
+
* classifier can be certain a task is hard and unsure which model suits it.
|
|
63
|
+
* The router needs this one on its own, because whether a pick must clear
|
|
64
|
+
* the upgrade bar or the downgrade bar depends on the pick, not the tier.
|
|
65
|
+
*
|
|
66
|
+
* Absent means the strategy does not report one (the LLM classifier), in
|
|
67
|
+
* which case the pick is honoured as it always was.
|
|
68
|
+
*/
|
|
69
|
+
selectedModelConfidence?: number;
|
|
70
|
+
/**
|
|
71
|
+
* How much context the request needs. Only the decision strategy produces
|
|
72
|
+
* this — the heuristic has no way to judge it and the LLM classifier is not
|
|
73
|
+
* asked, since for it every extra field costs output tokens. For a decision
|
|
74
|
+
* model the question is very nearly free.
|
|
75
|
+
*/
|
|
76
|
+
contextScope?: ClassifierContextScope;
|
|
77
|
+
/** Confidence in `contextScope`, 0-1. Calibrated for the decide strategy. */
|
|
78
|
+
contextScopeConfidence?: number;
|
|
39
79
|
/** Human-readable explanation, emitted at debug level. */
|
|
40
80
|
reason?: string;
|
|
41
81
|
};
|
|
@@ -50,6 +90,46 @@ export type ClassifierCandidate = {
|
|
|
50
90
|
description?: string;
|
|
51
91
|
tiers?: ClassifierDifficulty[];
|
|
52
92
|
capabilities?: string[];
|
|
93
|
+
/**
|
|
94
|
+
* Maximum input window, in tokens. Read from the model registry when the
|
|
95
|
+
* pool is built from the catalogue. Nothing in routing consulted this
|
|
96
|
+
* before — a request was routed to a model without ever asking whether it
|
|
97
|
+
* could hold the request.
|
|
98
|
+
*/
|
|
99
|
+
contextWindow?: number;
|
|
100
|
+
/** USD per 1K input tokens, for the cheapest-that-works judgement. */
|
|
101
|
+
inputCostPer1K?: number;
|
|
102
|
+
/** USD per 1K output tokens. */
|
|
103
|
+
outputCostPer1K?: number;
|
|
104
|
+
/** Registry speed bucket ("fast" | "medium" | "slow"). */
|
|
105
|
+
speed?: string;
|
|
106
|
+
/** Registry quality bucket ("high" | "medium" | "low"). */
|
|
107
|
+
quality?: string;
|
|
108
|
+
/**
|
|
109
|
+
* The registry's per-dimension suitability scores (1–10): coding, analysis,
|
|
110
|
+
* reasoning, conversation, creative, translation, summarization. Present
|
|
111
|
+
* only for registry-backed models.
|
|
112
|
+
*/
|
|
113
|
+
useCases?: Readonly<Record<string, number>>;
|
|
114
|
+
/**
|
|
115
|
+
* Deterministic merit score for the difficulty this candidate was built
|
|
116
|
+
* for, higher is better. Computed by `enrichCandidate`; it is what the
|
|
117
|
+
* fallback ranker sorts on and is never sent to the model.
|
|
118
|
+
*/
|
|
119
|
+
score?: number;
|
|
120
|
+
/**
|
|
121
|
+
* The host's own `cost` / `quality` from the pool member, if it declared
|
|
122
|
+
* them. These are RELATIVE scales, comparable only against other members
|
|
123
|
+
* of the same pool — never a currency and never a registry bucket.
|
|
124
|
+
*
|
|
125
|
+
* They are carried separately because they take precedence over anything
|
|
126
|
+
* the registry says. A host that writes `quality: 2` next to "cheap and
|
|
127
|
+
* fast; rote edits only" has made a statement about how it wants that
|
|
128
|
+
* model used, and the registry — which may rate the same model highly on
|
|
129
|
+
* its own general benchmarks — does not get to overrule it.
|
|
130
|
+
*/
|
|
131
|
+
relativeCost?: number;
|
|
132
|
+
relativeQuality?: number;
|
|
53
133
|
};
|
|
54
134
|
/**
|
|
55
135
|
* One candidate (provider, model, region) in the available base pool, with
|
|
@@ -102,12 +182,26 @@ export type ClassifierRouterConfig = {
|
|
|
102
182
|
/** Master switch. When false/absent, the router is never built. */
|
|
103
183
|
enabled: boolean;
|
|
104
184
|
/**
|
|
105
|
-
* Classification strategy. Default: "
|
|
106
|
-
* "
|
|
185
|
+
* Classification strategy. Default: "auto" — which resolves to "jev" when
|
|
186
|
+
* `TYPESAFE_API_KEY` is set and "heuristic" otherwise, so configuring a key
|
|
187
|
+
* upgrades routing without any code change. Behaviour for callers with no
|
|
188
|
+
* key is unchanged.
|
|
107
189
|
*/
|
|
108
190
|
classifier?: ClassifierStrategyKind;
|
|
109
191
|
/** Model used by the "llm" strategy. Defaults to provider/model auto. */
|
|
110
192
|
classifierModel?: ClassifierModelRef;
|
|
193
|
+
/**
|
|
194
|
+
* How sure the classifier must be to route a request UP to a more capable
|
|
195
|
+
* (costlier) model. Being wrong here costs money, so the bar is low.
|
|
196
|
+
* Only meaningful for "jev", whose confidence is calibrated. Default: 0.3.
|
|
197
|
+
*/
|
|
198
|
+
minUpgradeConfidence?: number;
|
|
199
|
+
/**
|
|
200
|
+
* How sure it must be to route DOWN to a cheaper model. Being wrong here
|
|
201
|
+
* means a task handled by too small a model, so the bar is high.
|
|
202
|
+
* Default: 0.6.
|
|
203
|
+
*/
|
|
204
|
+
minDowngradeConfidence?: number;
|
|
111
205
|
/** The available base pool the router selects a model from. */
|
|
112
206
|
pool: ClassifierRouterPoolMember[];
|
|
113
207
|
/**
|
|
@@ -119,6 +213,46 @@ export type ClassifierRouterConfig = {
|
|
|
119
213
|
toolDirectives?: Partial<Record<ClassifierDifficulty, ClassifierToolDirective>>;
|
|
120
214
|
/** Hard timeout (ms) for the LLM classifier call. Default: 8000. */
|
|
121
215
|
timeoutMs?: number;
|
|
216
|
+
/**
|
|
217
|
+
* Widen the pool with every model the registry knows about that this host
|
|
218
|
+
* actually has credentials for.
|
|
219
|
+
*
|
|
220
|
+
* Off by default, and deliberately so: the declared `pool` is a statement
|
|
221
|
+
* about which models a host is *willing* to be billed for, and NeuroLink
|
|
222
|
+
* cannot invent that. Turning this on says "anything I have a key for is
|
|
223
|
+
* fair game", which is exactly right for a CLI and exactly wrong for a
|
|
224
|
+
* service with a negotiated model list.
|
|
225
|
+
*/
|
|
226
|
+
catalog?: ClassifierCatalogConfig;
|
|
227
|
+
/**
|
|
228
|
+
* Ask the classifier how much context the request needs and use the answer
|
|
229
|
+
* to lower the compaction threshold. Default: true when the strategy
|
|
230
|
+
* resolves to a decision model, since the question rides along in a batch
|
|
231
|
+
* that is already being sent. Ignored by the other strategies.
|
|
232
|
+
*/
|
|
233
|
+
contextBudget?: boolean;
|
|
234
|
+
};
|
|
235
|
+
/** How the model catalogue widens the declared pool. */
|
|
236
|
+
export type ClassifierCatalogConfig = {
|
|
237
|
+
enabled: boolean;
|
|
238
|
+
/**
|
|
239
|
+
* Cap on catalogue-derived members. The binding constraint is the decision
|
|
240
|
+
* model's input ceiling — state plus the longest single question must stay
|
|
241
|
+
* under ~33K tokens, and the model question's `criteria` map is that
|
|
242
|
+
* question. At roughly 40 tokens per rendered model that ceiling is
|
|
243
|
+
* hundreds of models away.
|
|
244
|
+
*
|
|
245
|
+
* Default: 120. The registry currently holds 64 models, so the default
|
|
246
|
+
* never truncates today — it is a guard against a future registry that
|
|
247
|
+
* grows past what one question can carry, not a limit anyone is hitting.
|
|
248
|
+
*/
|
|
249
|
+
maxModels?: number;
|
|
250
|
+
/** Restrict the catalogue to these provider names. Omit for all configured. */
|
|
251
|
+
providers?: string[];
|
|
252
|
+
/** Drop models whose context window is below this. Default: 0 (keep all). */
|
|
253
|
+
minContextWindow?: number;
|
|
254
|
+
/** Include models flagged deprecated in the registry. Default: false. */
|
|
255
|
+
includeDeprecated?: boolean;
|
|
122
256
|
};
|
|
123
257
|
/**
|
|
124
258
|
* The router's combined decision: a provider/model/region override plus an
|
|
@@ -135,6 +269,20 @@ export type ClassifierRouterDecision = {
|
|
|
135
269
|
excludeTools?: string[];
|
|
136
270
|
/** The difficulty this decision was made for (debug/telemetry). */
|
|
137
271
|
difficulty?: ClassifierDifficulty;
|
|
272
|
+
/**
|
|
273
|
+
* Fraction of the model's window at which compaction should trigger for
|
|
274
|
+
* THIS request, replacing the fixed 0.8 default.
|
|
275
|
+
*
|
|
276
|
+
* **Only ever lower than the default, never higher.** Raising it would let
|
|
277
|
+
* a request through that the model then rejects with a context-window
|
|
278
|
+
* error — and `ModelPool` treats that as a permanent cooldown (10 years),
|
|
279
|
+
* so a single optimistic guess retires the model for the life of the
|
|
280
|
+
* process. Shrinking a budget wastes a little context; growing one is
|
|
281
|
+
* unrecoverable.
|
|
282
|
+
*/
|
|
283
|
+
compactionThreshold?: number;
|
|
284
|
+
/** The scope reading `compactionThreshold` was derived from. */
|
|
285
|
+
contextScope?: ClassifierContextScope;
|
|
138
286
|
/** Remaining ranked candidates, best-first, for downstream failover. */
|
|
139
287
|
modelFallbacks?: ClassifierRouterPoolMember[];
|
|
140
288
|
/** Human-readable explanation, emitted at debug level. */
|
|
@@ -178,6 +326,12 @@ export type ClassifierGenerateResult = {
|
|
|
178
326
|
};
|
|
179
327
|
/** Injected LLM caller — typically a bound `NeuroLink.generate`. */
|
|
180
328
|
export type ClassifierGenerateFn = (options: ClassifierGenerateOptions) => Promise<ClassifierGenerateResult>;
|
|
329
|
+
/**
|
|
330
|
+
* Injected decision caller — typically a bound `NeuroLink.tryDecide`, which
|
|
331
|
+
* returns null on any failure. Keeps `ClassifierRouter` free of provider
|
|
332
|
+
* imports, exactly as `ClassifierGenerateFn` does.
|
|
333
|
+
*/
|
|
334
|
+
export type ClassifierDecideFn = DecisionCallerFn;
|
|
181
335
|
/** Minimal logger surface the router uses (debug/warn). */
|
|
182
336
|
export type ClassifierLogger = {
|
|
183
337
|
debug: (message: string, meta?: unknown) => void;
|
|
@@ -190,5 +344,7 @@ export type ClassifierLogger = {
|
|
|
190
344
|
export type ClassifierRouterDeps = {
|
|
191
345
|
/** LLM caller for the "llm" strategy. Omit to disable LLM classification. */
|
|
192
346
|
generate?: ClassifierGenerateFn;
|
|
347
|
+
/** Decision caller for the "jev" strategy. Omit to disable it. */
|
|
348
|
+
decide?: ClassifierDecideFn;
|
|
193
349
|
logger?: ClassifierLogger;
|
|
194
350
|
};
|
package/dist/types/cli.d.ts
CHANGED
|
@@ -1681,8 +1681,24 @@ export type CliToolRoutingFlags = {
|
|
|
1681
1681
|
export type CliClassifierRouterFlags = {
|
|
1682
1682
|
/** Master enable switch (--classifier-router). */
|
|
1683
1683
|
classifierRouter?: boolean;
|
|
1684
|
-
/**
|
|
1684
|
+
/**
|
|
1685
|
+
* Strategy: "auto" (default), "heuristic", "llm" or "jev"
|
|
1686
|
+
* (--classifier-strategy). "auto" resolves to "jev" when TYPESAFE_API_KEY
|
|
1687
|
+
* is set and "heuristic" otherwise.
|
|
1688
|
+
*/
|
|
1685
1689
|
classifierStrategy?: string;
|
|
1690
|
+
/**
|
|
1691
|
+
* Minimum confidence required to route UP to a costlier model
|
|
1692
|
+
* (--classifier-min-upgrade-confidence). Only meaningful for "jev", whose
|
|
1693
|
+
* confidence is calibrated. Default: 0.3.
|
|
1694
|
+
*/
|
|
1695
|
+
classifierMinUpgradeConfidence?: number;
|
|
1696
|
+
/**
|
|
1697
|
+
* Minimum confidence required to route DOWN to a cheaper model
|
|
1698
|
+
* (--classifier-min-downgrade-confidence). Higher than the upgrade bar
|
|
1699
|
+
* because the mistakes cost differently. Default: 0.6.
|
|
1700
|
+
*/
|
|
1701
|
+
classifierMinDowngradeConfidence?: number;
|
|
1686
1702
|
/** LLM-classifier provider override (--classifier-model-provider). */
|
|
1687
1703
|
classifierModelProvider?: string;
|
|
1688
1704
|
/** LLM-classifier model override (--classifier-model-name). */
|
package/dist/types/config.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ import type { NeurolinkCredentials } from "./providers.js";
|
|
|
13
13
|
import type { ModelPoolConfig } from "./modelPool.js";
|
|
14
14
|
import type { RequestRouter } from "./requestRouter.js";
|
|
15
15
|
import type { ClassifierRouterConfig } from "./classifierRouter.js";
|
|
16
|
+
import type { ContextRelevanceOptions } from "./context.js";
|
|
16
17
|
import type { SkillsConfig } from "./skills.js";
|
|
17
18
|
import type { KnowledgeGroundingConfig } from "./knowledge.js";
|
|
18
19
|
/**
|
|
@@ -143,6 +144,17 @@ export type NeurolinkConstructorConfig = {
|
|
|
143
144
|
* caller pinned both `provider` and `model`. See {@link ClassifierRouterConfig}.
|
|
144
145
|
*/
|
|
145
146
|
classifierRouter?: ClassifierRouterConfig;
|
|
147
|
+
/**
|
|
148
|
+
* Relevance-driven context compaction. When a decision provider is
|
|
149
|
+
* configured, compaction gains a stage-zero pass that drops the earlier
|
|
150
|
+
* messages the current request provably does not need, before the
|
|
151
|
+
* positional stages (which protect by recency alone) get to choose.
|
|
152
|
+
*
|
|
153
|
+
* This object only TUNES that stage; it does not enable it. The stage runs
|
|
154
|
+
* whenever a decision provider is configured, and does nothing otherwise,
|
|
155
|
+
* which is the same activation rule every other decision consumer uses.
|
|
156
|
+
*/
|
|
157
|
+
contextRelevance?: ContextRelevanceOptions;
|
|
146
158
|
/**
|
|
147
159
|
* Native skills: versioned, discoverable instruction packs (SOPs,
|
|
148
160
|
* playbooks) with progressive disclosure. When enabled, each
|
package/dist/types/context.d.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import type { ExecutionContext } from "../types/tools.js";
|
|
6
6
|
import type { JsonObject } from "./common.js";
|
|
7
7
|
import type { ChatMessage, ConversationMemoryConfig } from "./conversation.js";
|
|
8
|
+
import type { DecisionCallerFn } from "./decision.js";
|
|
8
9
|
/**
|
|
9
10
|
* Base context type for all AI operations
|
|
10
11
|
*/
|
|
@@ -173,7 +174,7 @@ export declare class ContextConverter {
|
|
|
173
174
|
private static extractCustomData;
|
|
174
175
|
}
|
|
175
176
|
/** Stages available in the compaction pipeline. */
|
|
176
|
-
export type CompactionStage = "prune" | "deduplicate" | "summarize" | "truncate";
|
|
177
|
+
export type CompactionStage = "relevance" | "prune" | "deduplicate" | "summarize" | "truncate";
|
|
177
178
|
/** Result of multi-stage context compaction. */
|
|
178
179
|
export type CompactionResult = {
|
|
179
180
|
compacted: boolean;
|
|
@@ -577,4 +578,57 @@ export type NativeGenerateGuardConfig = {
|
|
|
577
578
|
availableInputTokens: number;
|
|
578
579
|
getFixedOverheadTokens: () => number;
|
|
579
580
|
};
|
|
581
|
+
/** Tuning for the relevance stage of context compaction. */
|
|
582
|
+
export type ContextRelevanceOptions = {
|
|
583
|
+
/** Trailing messages never eligible for dropping. Default 6. */
|
|
584
|
+
protectRecent?: number;
|
|
585
|
+
/** Confidence required to drop a message. Default 0.6. */
|
|
586
|
+
minDropConfidence?: number;
|
|
587
|
+
/** Ceiling on the share of eligible messages one pass may drop. Default 0.5. */
|
|
588
|
+
maxDropRatio?: number;
|
|
589
|
+
/** Per-call timeout override for the decision request. */
|
|
590
|
+
timeoutMs?: number;
|
|
591
|
+
};
|
|
592
|
+
/** What the relevance stage concluded. */
|
|
593
|
+
export type ContextRelevanceResult = {
|
|
594
|
+
/** The surviving messages, in their original order. */
|
|
595
|
+
messages: ChatMessage[];
|
|
596
|
+
/** Indices into the ORIGINAL array that were dropped. */
|
|
597
|
+
droppedIndices: number[];
|
|
598
|
+
/** How many messages were asked about. */
|
|
599
|
+
askedCount: number;
|
|
600
|
+
/** How many came back with a usable, confident answer. */
|
|
601
|
+
answeredCount: number;
|
|
602
|
+
/** Resolved decision model id, for telemetry. */
|
|
603
|
+
model: string;
|
|
604
|
+
/** Round trip in milliseconds. */
|
|
605
|
+
latencyMs: number;
|
|
606
|
+
};
|
|
607
|
+
/**
|
|
608
|
+
* Injected dependencies for {@link ContextCompactor}.
|
|
609
|
+
*
|
|
610
|
+
* Deliberately separate from `CompactionConfig`: that type is spread into a
|
|
611
|
+
* `Required<CompactionConfig>` default, so a function member would need a
|
|
612
|
+
* default implementation, and the compactor must stay fully usable with no
|
|
613
|
+
* decision provider configured.
|
|
614
|
+
*/
|
|
615
|
+
export type ContextCompactorDeps = {
|
|
616
|
+
/** Fail-open decision caller. Omitted = the previous pipeline, exactly. */
|
|
617
|
+
decide?: DecisionCallerFn;
|
|
618
|
+
/** Tuning for the relevance stage. */
|
|
619
|
+
relevance?: ContextRelevanceOptions;
|
|
620
|
+
/** Tuning for the post-summarization quality gate. */
|
|
621
|
+
summaryGate?: {
|
|
622
|
+
timeoutMs?: number;
|
|
623
|
+
minConfidence?: number;
|
|
624
|
+
};
|
|
625
|
+
};
|
|
626
|
+
/** Per-call context handed to `ContextCompactor.compact`. */
|
|
627
|
+
export type ContextCompactRequest = {
|
|
628
|
+
/**
|
|
629
|
+
* The request being prepared. Without it the relevance stage cannot run —
|
|
630
|
+
* "is this message still needed?" is meaningless without knowing what for.
|
|
631
|
+
*/
|
|
632
|
+
currentRequest?: string;
|
|
633
|
+
};
|
|
580
634
|
export {};
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decision inference types — typed, calibrated judgements from a model that
|
|
3
|
+
* emits no text.
|
|
4
|
+
*
|
|
5
|
+
* `decide` is the third inference type, alongside `generate` and `stream`. A
|
|
6
|
+
* decision model takes one `state` plus a map of named typed questions and
|
|
7
|
+
* returns one typed answer per question, all evaluated in a single parallel
|
|
8
|
+
* pass. TypeSafe's Jev is the first such model; Vercel's AI SDK models the
|
|
9
|
+
* same class separately from `LanguageModelV4`, for the same reason.
|
|
10
|
+
*
|
|
11
|
+
* The vocabulary here is deliberately **provider-neutral**. TypeSafe calls a
|
|
12
|
+
* yes/no question a `noul` and answers it in a field of the same name; both
|
|
13
|
+
* the Vercel AI SDK and Pydantic AI independently renamed that to `boolean` /
|
|
14
|
+
* `probability` when exposing it. This file follows them, and the mapping to
|
|
15
|
+
* a vendor's wire format belongs in that vendor's provider.
|
|
16
|
+
*
|
|
17
|
+
* Names are domain-prefixed `Decision*` to stay globally unique across
|
|
18
|
+
* `src/lib/types/` (CLAUDE.md rule 9). Note `evaluate`/`Evaluation*` is a
|
|
19
|
+
* different, unrelated feature — scoring a generated response with RAGAS.
|
|
20
|
+
*/
|
|
21
|
+
import type { NeurolinkCredentials } from "./providers.js";
|
|
22
|
+
/**
|
|
23
|
+
* Anything a decision model accepts as free-form content. `state` may be a
|
|
24
|
+
* plain string or structured JSON (chat logs, records); `instructions` and
|
|
25
|
+
* `criteria` values likewise.
|
|
26
|
+
*/
|
|
27
|
+
export type DecisionInput = string | number | boolean | readonly DecisionInput[] | {
|
|
28
|
+
readonly [key: string]: DecisionInput;
|
|
29
|
+
};
|
|
30
|
+
/** The content being judged. One shared state per request. */
|
|
31
|
+
export type DecisionState = DecisionInput;
|
|
32
|
+
/**
|
|
33
|
+
* A yes/no question. Answered with a probability and **no confidence of its
|
|
34
|
+
* own** — gate it on distance from 0.5 via {@link decisionBooleanConfidence}.
|
|
35
|
+
*/
|
|
36
|
+
export type DecisionBooleanQuestion = {
|
|
37
|
+
type: "boolean";
|
|
38
|
+
instructions: DecisionInput;
|
|
39
|
+
/** Optional descriptions of what a yes and a no mean. */
|
|
40
|
+
criteria?: {
|
|
41
|
+
true?: DecisionInput | null;
|
|
42
|
+
false?: DecisionInput | null;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Pick one option. `criteria` maps option name → rubric description.
|
|
47
|
+
*
|
|
48
|
+
* The answer carries the full probability distribution, not just the winner,
|
|
49
|
+
* so a single choice question over N options also **ranks** all N.
|
|
50
|
+
*/
|
|
51
|
+
export type DecisionChoiceQuestion = {
|
|
52
|
+
type: "choice";
|
|
53
|
+
instructions: DecisionInput;
|
|
54
|
+
criteria: Readonly<Record<string, DecisionInput | null>>;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Rate against an ordered rubric. The answer is the **0-based index**, so a
|
|
58
|
+
* four-level rubric scores 0–3. At least two levels are required.
|
|
59
|
+
*/
|
|
60
|
+
export type DecisionScoreQuestion = {
|
|
61
|
+
type: "score";
|
|
62
|
+
instructions: DecisionInput;
|
|
63
|
+
criteria: readonly (DecisionInput | null)[];
|
|
64
|
+
};
|
|
65
|
+
export type DecisionQuestion = DecisionBooleanQuestion | DecisionChoiceQuestion | DecisionScoreQuestion;
|
|
66
|
+
/** Questions keyed by an id you choose; answers return under the same ids. */
|
|
67
|
+
export type DecisionQuestionMap = Readonly<Record<string, DecisionQuestion>>;
|
|
68
|
+
export type DecisionBooleanAnswer = {
|
|
69
|
+
type: "boolean";
|
|
70
|
+
/** Probability the statement is true, 0–1. */
|
|
71
|
+
probability: number;
|
|
72
|
+
};
|
|
73
|
+
export type DecisionChoiceAnswer = {
|
|
74
|
+
type: "choice";
|
|
75
|
+
/** The highest-probability option name. */
|
|
76
|
+
choice: string;
|
|
77
|
+
/** Every option mapped to its probability. Key order is not stable. */
|
|
78
|
+
probabilities: Readonly<Record<string, number>>;
|
|
79
|
+
/** Calibrated certainty, 0–1, derived from the distribution. */
|
|
80
|
+
confidence: number;
|
|
81
|
+
};
|
|
82
|
+
export type DecisionScoreAnswer = {
|
|
83
|
+
type: "score";
|
|
84
|
+
/** Probability-weighted level index; lands between levels. */
|
|
85
|
+
score: number;
|
|
86
|
+
/** Level index (as a string key) → the description supplied. */
|
|
87
|
+
legend: Readonly<Record<string, string>>;
|
|
88
|
+
/** Level index (as a string key) → probability. */
|
|
89
|
+
probabilities: Readonly<Record<string, number>>;
|
|
90
|
+
confidence: number;
|
|
91
|
+
};
|
|
92
|
+
export type DecisionAnswer = DecisionBooleanAnswer | DecisionChoiceAnswer | DecisionScoreAnswer;
|
|
93
|
+
export type DecisionAnswerMap = Readonly<Record<string, DecisionAnswer>>;
|
|
94
|
+
export type DecisionUsage = {
|
|
95
|
+
inputTokens: number;
|
|
96
|
+
outputTokens: number;
|
|
97
|
+
};
|
|
98
|
+
export type DecisionRequest = {
|
|
99
|
+
state: DecisionState;
|
|
100
|
+
questions: DecisionQuestionMap;
|
|
101
|
+
/** Overrides the provider's configured model for this call only. */
|
|
102
|
+
model?: string;
|
|
103
|
+
signal?: AbortSignal;
|
|
104
|
+
/** Overrides the configured timeout for this call only. */
|
|
105
|
+
timeoutMs?: number;
|
|
106
|
+
};
|
|
107
|
+
export type DecisionResult = {
|
|
108
|
+
/** The RESOLVED model id (e.g. "jev-1.13.0"), not the alias sent. */
|
|
109
|
+
model: string;
|
|
110
|
+
provider: string;
|
|
111
|
+
answers: DecisionAnswerMap;
|
|
112
|
+
usage: DecisionUsage;
|
|
113
|
+
/** Vendor request id, for support escalation. */
|
|
114
|
+
requestId?: string;
|
|
115
|
+
/** Wall-clock round trip measured client-side. */
|
|
116
|
+
latencyMs: number;
|
|
117
|
+
/** Server-side time behind the edge; isolates model time from network. */
|
|
118
|
+
upstreamMs?: number;
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* Why a decision call failed, normalised across vendors. TypeSafe alone
|
|
122
|
+
* returns two different error envelopes, so a provider must flatten them.
|
|
123
|
+
*/
|
|
124
|
+
export type DecisionErrorKind = "authentication" | "invalid_request" | "max_tokens_exceeded" | "rate_limit" | "overloaded" | "server" | "timeout" | "network";
|
|
125
|
+
export type DecisionError = {
|
|
126
|
+
kind: DecisionErrorKind;
|
|
127
|
+
message: string;
|
|
128
|
+
status?: number;
|
|
129
|
+
requestId?: string;
|
|
130
|
+
/** True when a retry could plausibly succeed. */
|
|
131
|
+
retryable: boolean;
|
|
132
|
+
};
|
|
133
|
+
/** One entry from a decision provider's model listing. */
|
|
134
|
+
export type DecisionModelCard = {
|
|
135
|
+
name: string;
|
|
136
|
+
description: string;
|
|
137
|
+
releaseDate: string;
|
|
138
|
+
};
|
|
139
|
+
/**
|
|
140
|
+
* Narrowed view of a choice answer, safe to consume without re-narrowing.
|
|
141
|
+
* Returned by the reader helpers so call sites need no type assertion.
|
|
142
|
+
*/
|
|
143
|
+
export type DecisionChoiceReading = {
|
|
144
|
+
choice: string;
|
|
145
|
+
confidence: number;
|
|
146
|
+
probabilities: Readonly<Record<string, number>>;
|
|
147
|
+
/**
|
|
148
|
+
* Every option ordered by probability, highest first. A choice question is
|
|
149
|
+
* therefore also a ranking — the basis for catalogue selection.
|
|
150
|
+
*/
|
|
151
|
+
ranked: readonly {
|
|
152
|
+
name: string;
|
|
153
|
+
probability: number;
|
|
154
|
+
}[];
|
|
155
|
+
};
|
|
156
|
+
export type DecisionScoreReading = {
|
|
157
|
+
score: number;
|
|
158
|
+
confidence: number;
|
|
159
|
+
legend: Readonly<Record<string, string>>;
|
|
160
|
+
probabilities: Readonly<Record<string, number>>;
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* What `NeuroLink.decide()` accepts: a decision request plus the usual
|
|
164
|
+
* provider/credential selection every inference type shares.
|
|
165
|
+
*/
|
|
166
|
+
export type DecisionOptions = DecisionRequest & {
|
|
167
|
+
/**
|
|
168
|
+
* Provider name or alias. Defaults to the first registered provider whose
|
|
169
|
+
* descriptor declares `"decide"` in `inferenceKinds`.
|
|
170
|
+
*/
|
|
171
|
+
provider?: string;
|
|
172
|
+
/** Per-call credential overrides, as `generate()` takes. */
|
|
173
|
+
credentials?: NeurolinkCredentials;
|
|
174
|
+
};
|
|
175
|
+
/**
|
|
176
|
+
* Injected fail-open decision caller — typically a bound `NeuroLink.tryDecide`,
|
|
177
|
+
* which returns `null` on any failure rather than throwing.
|
|
178
|
+
*
|
|
179
|
+
* Every internal consumer of the `decide` inference type takes one of these
|
|
180
|
+
* instead of importing a provider, exactly as the tool router takes a
|
|
181
|
+
* `generateFn`. It is what keeps the consumers provider-import-free, and what
|
|
182
|
+
* makes "no decision provider configured" indistinguishable from "the call
|
|
183
|
+
* failed" at every call site: both are `null`, and both mean *carry on as
|
|
184
|
+
* before*.
|
|
185
|
+
*/
|
|
186
|
+
export type DecisionCallerFn = (options: DecisionOptions) => Promise<DecisionResult | null>;
|
|
187
|
+
/**
|
|
188
|
+
* Shared gate for acting on a yes/no answer.
|
|
189
|
+
*
|
|
190
|
+
* A `boolean` answer carries no confidence of its own, so two separate bars
|
|
191
|
+
* apply: which side of the coin flip it fell on, and how far from the flip it
|
|
192
|
+
* landed. Both must be cleared, which is why "probability 0.55" never counts
|
|
193
|
+
* as a yes.
|
|
194
|
+
*/
|
|
195
|
+
export type DecisionBooleanGate = {
|
|
196
|
+
/** Minimum probability to read the answer as "yes". Default 0.5. */
|
|
197
|
+
minProbability?: number;
|
|
198
|
+
/** Minimum {@link decisionBooleanConfidence} to act at all. Default 0.4. */
|
|
199
|
+
minConfidence?: number;
|
|
200
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decision inference types — typed, calibrated judgements from a model that
|
|
3
|
+
* emits no text.
|
|
4
|
+
*
|
|
5
|
+
* `decide` is the third inference type, alongside `generate` and `stream`. A
|
|
6
|
+
* decision model takes one `state` plus a map of named typed questions and
|
|
7
|
+
* returns one typed answer per question, all evaluated in a single parallel
|
|
8
|
+
* pass. TypeSafe's Jev is the first such model; Vercel's AI SDK models the
|
|
9
|
+
* same class separately from `LanguageModelV4`, for the same reason.
|
|
10
|
+
*
|
|
11
|
+
* The vocabulary here is deliberately **provider-neutral**. TypeSafe calls a
|
|
12
|
+
* yes/no question a `noul` and answers it in a field of the same name; both
|
|
13
|
+
* the Vercel AI SDK and Pydantic AI independently renamed that to `boolean` /
|
|
14
|
+
* `probability` when exposing it. This file follows them, and the mapping to
|
|
15
|
+
* a vendor's wire format belongs in that vendor's provider.
|
|
16
|
+
*
|
|
17
|
+
* Names are domain-prefixed `Decision*` to stay globally unique across
|
|
18
|
+
* `src/lib/types/` (CLAUDE.md rule 9). Note `evaluate`/`Evaluation*` is a
|
|
19
|
+
* different, unrelated feature — scoring a generated response with RAGAS.
|
|
20
|
+
*/
|
|
21
|
+
export {};
|
package/dist/types/generate.d.ts
CHANGED
|
@@ -273,6 +273,13 @@ export type GenerateOptions = {
|
|
|
273
273
|
region?: string;
|
|
274
274
|
temperature?: number;
|
|
275
275
|
maxTokens?: number;
|
|
276
|
+
/**
|
|
277
|
+
* Fraction of the model's context window at which history is compacted for
|
|
278
|
+
* this request, replacing the 0.8 default. Filled in per request by the
|
|
279
|
+
* classifier router when a decision provider is configured; always at or
|
|
280
|
+
* below the default, never above. See `TextGenerationOptions`.
|
|
281
|
+
*/
|
|
282
|
+
compactionThreshold?: number;
|
|
276
283
|
/** Top-p (nucleus) sampling parameter. Controls diversity of generated tokens. */
|
|
277
284
|
topP?: number;
|
|
278
285
|
/** Top-k sampling parameter. Limits the number of tokens considered. (Google/Gemini models only) */
|
|
@@ -1113,6 +1120,19 @@ export type FactoryEnhancedProvider = EnhancedProvider & {
|
|
|
1113
1120
|
*/
|
|
1114
1121
|
export type TextGenerationOptions = {
|
|
1115
1122
|
prompt?: string;
|
|
1123
|
+
/**
|
|
1124
|
+
* Fraction of the model's context window at which compaction runs for this
|
|
1125
|
+
* request, replacing the 0.8 default.
|
|
1126
|
+
*
|
|
1127
|
+
* A request that needs only the current message does not need the whole
|
|
1128
|
+
* window kept warm for it, and compacting earlier is free; a request that
|
|
1129
|
+
* depends on the entire conversation should compact as late as possible.
|
|
1130
|
+
* When the classifier router runs with a decision model it fills this in
|
|
1131
|
+
* per request — always at or below the default, never above, because a
|
|
1132
|
+
* request that overflows the window fails hard and `ModelPool` records that
|
|
1133
|
+
* failure as a permanent cooldown.
|
|
1134
|
+
*/
|
|
1135
|
+
compactionThreshold?: number;
|
|
1116
1136
|
/**
|
|
1117
1137
|
* Alternative input format for multimodal SDK operations.
|
|
1118
1138
|
*
|
package/dist/types/index.d.ts
CHANGED
package/dist/types/index.js
CHANGED