@bivelio/savings-layer 0.4.19 → 0.4.21
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/README.md +20 -9
- package/dist/gateway/bin.js +240 -204
- package/dist/index.d.ts +127 -4
- package/dist/index.js +550 -538
- package/docs/terminales/README.md +4 -1
- package/package.json +7 -7
package/dist/index.d.ts
CHANGED
|
@@ -205,7 +205,7 @@ declare function precioDeLista(model: string): CostModel | undefined;
|
|
|
205
205
|
* on the customer's machine. `test/version-declarada.test.ts` ties this
|
|
206
206
|
* constant to package.json so the two can never drift.
|
|
207
207
|
*/
|
|
208
|
-
declare const BV_SALA_VERSION = "0.4.
|
|
208
|
+
declare const BV_SALA_VERSION = "0.4.21";
|
|
209
209
|
|
|
210
210
|
/**
|
|
211
211
|
* Environment-agnostic UUID generation.
|
|
@@ -990,6 +990,15 @@ interface LicenseGate {
|
|
|
990
990
|
* que tener una rama por defecto de todas formas.
|
|
991
991
|
*/
|
|
992
992
|
status?(): string;
|
|
993
|
+
/**
|
|
994
|
+
* Why the key does not open, when it does not; `undefined` when it does. It
|
|
995
|
+
* only refines the MESSAGE, never the verdict: an `"invalid"` whose reason is
|
|
996
|
+
* `"malformed"` (not even the shape of a token: the `bvk_` pasted where the
|
|
997
|
+
* license goes) gets different advice from an `"invalid"` that has the shape
|
|
998
|
+
* but no valid signature. Optional because a gate is implemented by the
|
|
999
|
+
* caller; without it, the generic message for that status.
|
|
1000
|
+
*/
|
|
1001
|
+
reason?(): string | undefined;
|
|
993
1002
|
}
|
|
994
1003
|
interface TraceEvent {
|
|
995
1004
|
stage: string;
|
|
@@ -1686,10 +1695,46 @@ interface ToolSelectorOptions {
|
|
|
1686
1695
|
maxTools?: number;
|
|
1687
1696
|
/** Tokenizer-aware scorer for tie-breaking (optional). */
|
|
1688
1697
|
scoreIntentMatch?: (text: string, tool: ToolDescriptor) => number;
|
|
1698
|
+
/**
|
|
1699
|
+
* How many requests are selected by relevance before the set is FROZEN for a
|
|
1700
|
+
* given key. Below this count the selector learns; past it, it always emits
|
|
1701
|
+
* the same set and `setIsStable` is true again.
|
|
1702
|
+
*
|
|
1703
|
+
* The default of 16 is measured, not round: across 214 sessions of real
|
|
1704
|
+
* traffic, a set frozen from the first 16 invoked tools came up short in
|
|
1705
|
+
* 0.0% of sessions (8 fell short in 2.3%, 12 in 0.5%).
|
|
1706
|
+
*/
|
|
1707
|
+
learningTurns?: number;
|
|
1708
|
+
/** Where frozen sets are remembered. Defaults to an in-process map. */
|
|
1709
|
+
freezer?: ToolSetFreezer;
|
|
1710
|
+
}
|
|
1711
|
+
/**
|
|
1712
|
+
* Memory for the frozen tool set. The caller owns the key: the pipeline passes
|
|
1713
|
+
* the caller's toolset hash, which in practice is one key per session.
|
|
1714
|
+
*/
|
|
1715
|
+
interface ToolSetFreezer {
|
|
1716
|
+
read(key: string): {
|
|
1717
|
+
ids: string[];
|
|
1718
|
+
turns: number;
|
|
1719
|
+
} | undefined;
|
|
1720
|
+
record(key: string, ids: string[], turns: number): void;
|
|
1721
|
+
}
|
|
1722
|
+
/** In-process freezer with a key cap (clears wholesale when full). */
|
|
1723
|
+
declare class InMemoryToolSetFreezer implements ToolSetFreezer {
|
|
1724
|
+
private readonly cap;
|
|
1725
|
+
private map;
|
|
1726
|
+
constructor(cap?: number);
|
|
1727
|
+
read(key: string): {
|
|
1728
|
+
ids: string[];
|
|
1729
|
+
turns: number;
|
|
1730
|
+
} | undefined;
|
|
1731
|
+
record(key: string, ids: string[], turns: number): void;
|
|
1689
1732
|
}
|
|
1690
1733
|
declare class ToolSelector {
|
|
1691
1734
|
private readonly maxTools;
|
|
1692
1735
|
private readonly scoreIntentMatch;
|
|
1736
|
+
private readonly learningTurns;
|
|
1737
|
+
private readonly freezer;
|
|
1693
1738
|
constructor(opts?: ToolSelectorOptions);
|
|
1694
1739
|
/**
|
|
1695
1740
|
* Todas las herramientas que pasó el llamante, acotadas SOLO por el
|
|
@@ -1704,7 +1749,13 @@ declare class ToolSelector {
|
|
|
1704
1749
|
* pasaría a fallar en duro.
|
|
1705
1750
|
*/
|
|
1706
1751
|
passthrough(tools: ToolDescriptor[] | undefined): ToolSelection;
|
|
1707
|
-
select(text: string, tools: ToolDescriptor[] | undefined, execution: ExecutionClass
|
|
1752
|
+
select(text: string, tools: ToolDescriptor[] | undefined, execution: ExecutionClass,
|
|
1753
|
+
/**
|
|
1754
|
+
* Freeze key. The pipeline passes the caller's toolset hash, which in
|
|
1755
|
+
* practice is one key per session. Without a key nothing is frozen and the
|
|
1756
|
+
* selector behaves exactly as before.
|
|
1757
|
+
*/
|
|
1758
|
+
freezeKey?: string): ToolSelection;
|
|
1708
1759
|
}
|
|
1709
1760
|
|
|
1710
1761
|
/**
|
|
@@ -2533,8 +2584,14 @@ declare class LicenseError extends Error {
|
|
|
2533
2584
|
*
|
|
2534
2585
|
* El comportamiento no cambia —sigue siendo fail-closed, `granted()` no lo
|
|
2535
2586
|
* concede— pero ahora el mensaje puede decir la verdad.
|
|
2587
|
+
*
|
|
2588
|
+
* `none` means "there is no key": what is left after `normalizeLicenseKey` is
|
|
2589
|
+
* EMPTY. It is the same value `LicenseError.status` already carries when nothing
|
|
2590
|
+
* was configured, because it is the same problem with the same fix: a
|
|
2591
|
+
* `licenseKey: " "` (an empty environment variable, a blank secret file) used
|
|
2592
|
+
* to tell the customer their key "does not verify" — there was no key.
|
|
2536
2593
|
*/
|
|
2537
|
-
type LicenseStatus = "active" | "grace" | "expired" | "invalid" | "revoked" | "stale";
|
|
2594
|
+
type LicenseStatus = "active" | "grace" | "expired" | "invalid" | "revoked" | "stale" | "none";
|
|
2538
2595
|
/** Decoded license token body (mirror of `@bivelio/protocol`'s LicensePayload,
|
|
2539
2596
|
* declared locally so the SDK stays free of a control-plane dependency). */
|
|
2540
2597
|
interface LicenseTokenPayload {
|
|
@@ -2579,6 +2636,48 @@ interface LicenseKeyset {
|
|
|
2579
2636
|
}
|
|
2580
2637
|
/** Narrow a verification key to a {@link LicenseKeyset} (vs a bare SPKI PEM string). */
|
|
2581
2638
|
declare function isKeyset(k: string | LicenseKeyset): k is LicenseKeyset;
|
|
2639
|
+
/**
|
|
2640
|
+
* Normalize a license key the way it arrives from the real world — ONCE, at the
|
|
2641
|
+
* entry point, never inside the verifier.
|
|
2642
|
+
*
|
|
2643
|
+
* The README says `export BIVELIO_LICENSE_KEY=…` and dotenv trims, so that path
|
|
2644
|
+
* never showed it. But anyone reading the key from a file (`readFileSync`), from
|
|
2645
|
+
* a Docker/Kubernetes secret (mounted as a file, trailing newline included) or
|
|
2646
|
+
* copying it out of an `Authorization` header handed over a CORRECT key with a
|
|
2647
|
+
* `\n` after it, a space before it, quotes around it or a `Bearer ` in front —
|
|
2648
|
+
* and the SDK answered "does not verify, check you pasted the WHOLE key". A
|
|
2649
|
+
* wrong diagnosis on a good key is the worst possible hint: it sends the
|
|
2650
|
+
* customer to look where the problem is not.
|
|
2651
|
+
*
|
|
2652
|
+
* Worse, it was INCONSISTENT: `tok + "\r\n"` passed and `tok + "\n"` did not,
|
|
2653
|
+
* because `atob` ignores ASCII whitespace while the padding was computed from a
|
|
2654
|
+
* length that included it, and two extra characters give the same remainder
|
|
2655
|
+
* modulo 4 as zero. Behavior that depends on which editor saved the file is not
|
|
2656
|
+
* behavior.
|
|
2657
|
+
*
|
|
2658
|
+
* Only OUTER wrapping is removed — whitespace, one pair of single or double
|
|
2659
|
+
* quotes, a `Bearer` prefix in any capitalization — in that order, in one pass.
|
|
2660
|
+
* Anything INSIDE the key is left alone: an interior space is not wrapping, it
|
|
2661
|
+
* is a broken key, and {@link licenseKeyShape} reports it as `malformed`.
|
|
2662
|
+
*/
|
|
2663
|
+
declare function normalizeLicenseKey(raw: string): string;
|
|
2664
|
+
/**
|
|
2665
|
+
* The SHAPE of an already-normalized key, so the error message can tell apart
|
|
2666
|
+
* three problems that used to get the same text:
|
|
2667
|
+
*
|
|
2668
|
+
* · `empty` — there is no key (only whitespace, or nothing at all).
|
|
2669
|
+
* · `malformed` — not even the shape of a token: not three dot-separated
|
|
2670
|
+
* base64url segments. This is where the `bvk_` service key
|
|
2671
|
+
* pasted where the license goes lands, as does arbitrary text
|
|
2672
|
+
* or a token with a line break in the middle.
|
|
2673
|
+
* · `token` — has the shape; whether it verifies is up to the signature.
|
|
2674
|
+
*
|
|
2675
|
+
* It is the SAME shape rule {@link verifyCompactSignature} enforces, so that "has
|
|
2676
|
+
* the shape" and "verification was attempted" mean the same thing.
|
|
2677
|
+
*/
|
|
2678
|
+
type LicenseKeyShape = "empty" | "malformed" | "token";
|
|
2679
|
+
/** Classify a normalized key. See {@link LicenseKeyShape}. */
|
|
2680
|
+
declare function licenseKeyShape(normalizedKey: string): LicenseKeyShape;
|
|
2582
2681
|
/**
|
|
2583
2682
|
* Verify the Ed25519 signature of any BV-SALA compact token
|
|
2584
2683
|
* (`base64url(header).base64url(body).base64url(sig)`, sig over `${head}.${body}`)
|
|
@@ -2587,6 +2686,13 @@ declare function isKeyset(k: string | LicenseKeyset): k is LicenseKeyset;
|
|
|
2587
2686
|
* so the browser (`@noble/curves`) and node (`node:crypto`) sides agree byte-for-byte
|
|
2588
2687
|
* and there is no bespoke per-message verification path to keep in sync. It does NOT
|
|
2589
2688
|
* interpret the payload or the header `typ` — callers do that.
|
|
2689
|
+
*
|
|
2690
|
+
* Shape is checked SEGMENT by segment, not just by counting dots. Three parts
|
|
2691
|
+
* used to be enough and the rest was left to `atob`, which ignores whitespace:
|
|
2692
|
+
* that is how a token with `\r\n` after it verified while the same token with
|
|
2693
|
+
* `\n` did not (see {@link normalizeLicenseKey}). The shared primitive must give
|
|
2694
|
+
* the same answer to the same input, always; a caller that wants to tolerate
|
|
2695
|
+
* wrapping normalizes BEFORE calling.
|
|
2590
2696
|
*/
|
|
2591
2697
|
declare function verifyCompactSignature(token: string, publicKey: string | LicenseKeyset): CompactVerification;
|
|
2592
2698
|
/** Verify a token's signature and decode its payload. Does not check expiry. */
|
|
@@ -2614,6 +2720,9 @@ declare function deriveStatus(payload: {
|
|
|
2614
2720
|
* Verify + apply the grace policy → a resolved status. Mirrors what the issuing
|
|
2615
2721
|
* control plane resolves for the same token. Bad signature / malformed
|
|
2616
2722
|
* → invalid; otherwise the status comes from {@link deriveStatus}.
|
|
2723
|
+
*
|
|
2724
|
+
* A public entry point, so it normalizes like the others (gate and refresher):
|
|
2725
|
+
* the same key must resolve the same whichever way it comes in.
|
|
2617
2726
|
*/
|
|
2618
2727
|
declare function resolveLicense(token: string, publicKey: string | LicenseKeyset, opts?: {
|
|
2619
2728
|
nowSeconds?: number;
|
|
@@ -2690,6 +2799,15 @@ declare class RevocationSnapshot {
|
|
|
2690
2799
|
interface ResolvedGate extends LicenseGate {
|
|
2691
2800
|
isActive(): boolean;
|
|
2692
2801
|
status(): LicenseStatus;
|
|
2802
|
+
/**
|
|
2803
|
+
* Why the key does not open, when it does not; `undefined` when it verified.
|
|
2804
|
+
* Under `status() === "invalid"` it tells a key that does NOT EVEN HAVE THE
|
|
2805
|
+
* SHAPE of a token (`"malformed"`: the `bvk_` pasted where the license goes,
|
|
2806
|
+
* arbitrary text) from a well-formed one whose signature fails (the verifier's
|
|
2807
|
+
* reason, e.g. `"bad signature"`). Both are `invalid` — the stable handle for
|
|
2808
|
+
* branching does not change — but the advice given to the customer differs.
|
|
2809
|
+
*/
|
|
2810
|
+
reason(): string | undefined;
|
|
2693
2811
|
/** Unix seconds after which the online status should be re-checked (poller anchor). */
|
|
2694
2812
|
refreshAfter?(): number | undefined;
|
|
2695
2813
|
}
|
|
@@ -3021,6 +3139,11 @@ interface SavingsLayerConfig {
|
|
|
3021
3139
|
* against the embedded public key and builds a {@link licenseGate} from it.
|
|
3022
3140
|
* Without a valid, active license (and without {@link devUnlicensed}), the
|
|
3023
3141
|
* pipeline refuses to run — get a key at https://savings.bivelio.com.
|
|
3142
|
+
*
|
|
3143
|
+
* Surrounding whitespace (the trailing newline of a file or mounted secret),
|
|
3144
|
+
* wrapping quotes and a `Bearer ` prefix are stripped before verification, so
|
|
3145
|
+
* a key read with `readFileSync` works as-is. Anything INSIDE the key is not
|
|
3146
|
+
* touched: a key with a space in the middle is a broken key.
|
|
3024
3147
|
*/
|
|
3025
3148
|
licenseKey?: string;
|
|
3026
3149
|
/**
|
|
@@ -3324,4 +3447,4 @@ interface SavingsLayer {
|
|
|
3324
3447
|
*/
|
|
3325
3448
|
declare function createSavingsLayer(config: Omit<SavingsLayerConfig, "tokenizer"> & Partial<Pick<SavingsLayerConfig, "tokenizer">>): SavingsLayer;
|
|
3326
3449
|
|
|
3327
|
-
export { type AnthropicOptions, AnthropicProvider, BV_SALA_VERSION, type BivelioHandoff, CATALOGO, COMPACT_ROWS_INSTRUCTION, type CacheOutcome, type CacheTier, type CachedAnswer, type CanonicalRequest, type ChatMessage, type CompactRowsDecodeOptions, type CompactRowsOptions, type CompactVerification, type CompressionEconomics, type CompressionPolicyInput, type CompressionRequest, type CompressionResult, type Compressor, type ConstraintBackend, type ConstraintBackendId, type ConstraintPlan, type ConversationState, type CostBasis, type CostModel, DEFAULT_COST_MODEL, DEFAULT_MAX_STALENESS_SECONDS, type DeferredExecutionReport, type DeterministicResolver, EMBEDDED_PUBLIC_KEY, type EmbeddingFn, type EvidenceDoc, type ExactCache, ExactTokenizer, type ExecutionClass, ExecutionRouter, type FormatChoice, FormatSelector, type FormatSelectorOptions, type HandoffFact, HeuristicEstimator, InMemoryExactCache, InMemorySemanticCache, type JsonSchema, LicenseError, type LicenseGate, type LicenseKeyset, type LicenseStatus, type LicenseTokenPayload, type LocalClassifier, MODELOS_POR_CODIFICACION, MODELS_BY_ENCODING, type MemoryDelta, type MessageRole, MockProvider, type MockProviderOptions, type ModelCascadeMode, type ModelCascadeReport, type ModelCascadeSettings, type OpenAICompatibleOptions, OpenAICompatibleProvider, type OutputContract, PRECIOS_AL_DIA, type Policy, type ProtectedSpan, type Provider, type ProviderRequest, type ProviderResponse, type ProviderUsage, QUALITY_STATUSES, type QualityStatus, type RequestContext, type Reranker, type ResolvedDeps, type ResolvedGate, type ResolvedLicense, ResolverRegistry, type ResolverResult, type RetrievalOptions, type RetrievalOutcome, type RetrievalPlan, type Retriever, type RevocationListBody, type RevocationListVerification, type RevocationPollEvent, RevocationPoller, type RevocationPollerOptions, RevocationSnapshot, type RouteDecision, type SavingsLayer, type SavingsLayerConfig, SavingsLedger, type SavingsReport, type SavingsRequest, type SavingsResult, type SavingsToggles, SchemaRegistry, type SemanticCacheOptions, type SemanticHit, type SemanticRecord, type SemanticVerifier, type SerializationFormat, type Serializer, Singleflight, type TokenEstimator, TokenizerRegistry, type ToolCallRequest, type ToolDescriptor, type ToolRisk, type ToolSelection, ToolSelector, type ToolSelectorOptions, TraceCollector, type TraceEvent, UMBRAL_LOCAL, UsageEmitter, type UsageEmitterOptions, type ValidationError, type ValidationResult, adaptiveK, arithmeticResolver, buildExactKey, buildInflightKey, canonicalize, compactRowsSerializer, compresionFiel, computeNextDelay, cosine, createCompactRowsSerializer, createDefaultResolvers, createHandoff, createMockProvider, createSavingsLayer, csvSerializer, decodeCompactRows, dedupe, defaultTokenizerRegistry, deriveSeatId, deriveStatus, detectCi, embebedorLocal, emptyState, encodeCompactRows, evalArithmetic, evaluatePolicy, executeRetrievalPlan, gateFromKey, heuristicEstimator, isKeyset, isStrictCompatible, jsonCompactSerializer, keyTokensMatch, liveGateFromKey, mergeDelta, modelFamilyOf, multisetEqual, negationCount, noopCompressor, normalizeText, numericTokens, precioDeLista, projectContext, providerNativeBackend, randomId, registerExactTokenizer, registrarTokenizadorExacto, renderState, resolveConstraintBackend, resolveDependencies, resolveLicense, sha256, shouldCompress, stableStringify, uniformColumns, validateAgainstSchema, vectorLocal, verifyCompactSignature, verifyLicenseToken, verifyRevocationList, withProtectedSpans, words };
|
|
3450
|
+
export { type AnthropicOptions, AnthropicProvider, BV_SALA_VERSION, type BivelioHandoff, CATALOGO, COMPACT_ROWS_INSTRUCTION, type CacheOutcome, type CacheTier, type CachedAnswer, type CanonicalRequest, type ChatMessage, type CompactRowsDecodeOptions, type CompactRowsOptions, type CompactVerification, type CompressionEconomics, type CompressionPolicyInput, type CompressionRequest, type CompressionResult, type Compressor, type ConstraintBackend, type ConstraintBackendId, type ConstraintPlan, type ConversationState, type CostBasis, type CostModel, DEFAULT_COST_MODEL, DEFAULT_MAX_STALENESS_SECONDS, type DeferredExecutionReport, type DeterministicResolver, EMBEDDED_PUBLIC_KEY, type EmbeddingFn, type EvidenceDoc, type ExactCache, ExactTokenizer, type ExecutionClass, ExecutionRouter, type FormatChoice, FormatSelector, type FormatSelectorOptions, type HandoffFact, HeuristicEstimator, InMemoryExactCache, InMemorySemanticCache, InMemoryToolSetFreezer, type JsonSchema, LicenseError, type LicenseGate, type LicenseKeyShape, type LicenseKeyset, type LicenseStatus, type LicenseTokenPayload, type LocalClassifier, MODELOS_POR_CODIFICACION, MODELS_BY_ENCODING, type MemoryDelta, type MessageRole, MockProvider, type MockProviderOptions, type ModelCascadeMode, type ModelCascadeReport, type ModelCascadeSettings, type OpenAICompatibleOptions, OpenAICompatibleProvider, type OutputContract, PRECIOS_AL_DIA, type Policy, type ProtectedSpan, type Provider, type ProviderRequest, type ProviderResponse, type ProviderUsage, QUALITY_STATUSES, type QualityStatus, type RequestContext, type Reranker, type ResolvedDeps, type ResolvedGate, type ResolvedLicense, ResolverRegistry, type ResolverResult, type RetrievalOptions, type RetrievalOutcome, type RetrievalPlan, type Retriever, type RevocationListBody, type RevocationListVerification, type RevocationPollEvent, RevocationPoller, type RevocationPollerOptions, RevocationSnapshot, type RouteDecision, type SavingsLayer, type SavingsLayerConfig, SavingsLedger, type SavingsReport, type SavingsRequest, type SavingsResult, type SavingsToggles, SchemaRegistry, type SemanticCacheOptions, type SemanticHit, type SemanticRecord, type SemanticVerifier, type SerializationFormat, type Serializer, Singleflight, type TokenEstimator, TokenizerRegistry, type ToolCallRequest, type ToolDescriptor, type ToolRisk, type ToolSelection, ToolSelector, type ToolSelectorOptions, type ToolSetFreezer, TraceCollector, type TraceEvent, UMBRAL_LOCAL, UsageEmitter, type UsageEmitterOptions, type ValidationError, type ValidationResult, adaptiveK, arithmeticResolver, buildExactKey, buildInflightKey, canonicalize, compactRowsSerializer, compresionFiel, computeNextDelay, cosine, createCompactRowsSerializer, createDefaultResolvers, createHandoff, createMockProvider, createSavingsLayer, csvSerializer, decodeCompactRows, dedupe, defaultTokenizerRegistry, deriveSeatId, deriveStatus, detectCi, embebedorLocal, emptyState, encodeCompactRows, evalArithmetic, evaluatePolicy, executeRetrievalPlan, gateFromKey, heuristicEstimator, isKeyset, isStrictCompatible, jsonCompactSerializer, keyTokensMatch, licenseKeyShape, liveGateFromKey, mergeDelta, modelFamilyOf, multisetEqual, negationCount, noopCompressor, normalizeLicenseKey, normalizeText, numericTokens, precioDeLista, projectContext, providerNativeBackend, randomId, registerExactTokenizer, registrarTokenizadorExacto, renderState, resolveConstraintBackend, resolveDependencies, resolveLicense, sha256, shouldCompress, stableStringify, uniformColumns, validateAgainstSchema, vectorLocal, verifyCompactSignature, verifyLicenseToken, verifyRevocationList, withProtectedSpans, words };
|