usertrust 1.4.0 → 1.5.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.
Files changed (46) hide show
  1. package/dist/anomaly/detector.d.ts.map +1 -1
  2. package/dist/anomaly/detector.js +36 -11
  3. package/dist/anomaly/detector.js.map +1 -1
  4. package/dist/anomaly/signals/spend-velocity.d.ts +39 -12
  5. package/dist/anomaly/signals/spend-velocity.d.ts.map +1 -1
  6. package/dist/anomaly/signals/spend-velocity.js +66 -43
  7. package/dist/anomaly/signals/spend-velocity.js.map +1 -1
  8. package/dist/anomaly/signals/token-rate.d.ts +33 -13
  9. package/dist/anomaly/signals/token-rate.d.ts.map +1 -1
  10. package/dist/anomaly/signals/token-rate.js +124 -38
  11. package/dist/anomaly/signals/token-rate.js.map +1 -1
  12. package/dist/anomaly/types.d.ts +28 -6
  13. package/dist/anomaly/types.d.ts.map +1 -1
  14. package/dist/cli/init.d.ts.map +1 -1
  15. package/dist/cli/init.js +98 -1
  16. package/dist/cli/init.js.map +1 -1
  17. package/dist/cli/main.js +0 -0
  18. package/dist/detect.d.ts +34 -1
  19. package/dist/detect.d.ts.map +1 -1
  20. package/dist/detect.js +124 -0
  21. package/dist/detect.js.map +1 -1
  22. package/dist/govern.d.ts +8 -1
  23. package/dist/govern.d.ts.map +1 -1
  24. package/dist/govern.js +191 -12
  25. package/dist/govern.js.map +1 -1
  26. package/dist/headless.d.ts +41 -2
  27. package/dist/headless.d.ts.map +1 -1
  28. package/dist/headless.js +54 -3
  29. package/dist/headless.js.map +1 -1
  30. package/dist/index.d.ts +4 -3
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +3 -1
  33. package/dist/index.js.map +1 -1
  34. package/dist/ledger/pricing.d.ts +54 -0
  35. package/dist/ledger/pricing.d.ts.map +1 -1
  36. package/dist/ledger/pricing.js +128 -8
  37. package/dist/ledger/pricing.js.map +1 -1
  38. package/dist/shared/types.d.ts +175 -0
  39. package/dist/shared/types.d.ts.map +1 -1
  40. package/dist/shared/types.js +55 -5
  41. package/dist/shared/types.js.map +1 -1
  42. package/dist/streaming.d.ts +8 -3
  43. package/dist/streaming.d.ts.map +1 -1
  44. package/dist/streaming.js +61 -30
  45. package/dist/streaming.js.map +1 -1
  46. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"detector.d.ts","sourceRoot":"","sources":["../../src/anomaly/detector.ts"],"names":[],"mappings":"AAoCA,OAAO,KAAK,EAEX,aAAa,EACb,sBAAsB,EACtB,oBAAoB,EACpB,YAAY,EAGZ,cAAc,EACd,qBAAqB,EACrB,MAAM,YAAY,CAAC;AAIpB,qDAAqD;AACrD,wBAAgB,oBAAoB,CAAC,GAAG,CAAC,EAAE,aAAa,GAAG,qBAAqB,CAQ/E;AAWD,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,oBAAoB,CAAC,CAAC;IAC/C,0CAA0C;IAC1C,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;IACnC,wFAAwF;IACxF,KAAK,IAAI,cAAc,CAAC;IACxB,oDAAoD;IACpD,KAAK,IAAI,IAAI,CAAC;IACd,2EAA2E;IAC3E,SAAS,IAAI,OAAO,CAAC;CACrB;AAED,wBAAgB,qBAAqB,CACpC,GAAG,CAAC,EAAE,aAAa,EACnB,OAAO,CAAC,EAAE,sBAAsB,GAC9B,eAAe,CAuKjB"}
1
+ {"version":3,"file":"detector.d.ts","sourceRoot":"","sources":["../../src/anomaly/detector.ts"],"names":[],"mappings":"AAuCA,OAAO,KAAK,EAEX,aAAa,EACb,sBAAsB,EACtB,oBAAoB,EACpB,YAAY,EAGZ,cAAc,EACd,qBAAqB,EACrB,MAAM,YAAY,CAAC;AAIpB,qDAAqD;AACrD,wBAAgB,oBAAoB,CAAC,GAAG,CAAC,EAAE,aAAa,GAAG,qBAAqB,CAQ/E;AA+CD,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,oBAAoB,CAAC,CAAC;IAC/C,0CAA0C;IAC1C,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAAC;IACnC,wFAAwF;IACxF,KAAK,IAAI,cAAc,CAAC;IACxB,oDAAoD;IACpD,KAAK,IAAI,IAAI,CAAC;IACd,2EAA2E;IAC3E,SAAS,IAAI,OAAO,CAAC;CACrB;AAED,wBAAgB,qBAAqB,CACpC,GAAG,CAAC,EAAE,aAAa,EACnB,OAAO,CAAC,EAAE,sBAAsB,GAC9B,eAAe,CAoKjB"}
@@ -14,9 +14,12 @@
14
14
  * - After cooldownMs the detector auto-resets; reset() can be called manually.
15
15
  *
16
16
  * Defaults are tuned conservatively (500 tok/s sustained, $1/min, 3 injections in 60s).
17
- * Detection is opt-in (anomaly.enabled=true) when off, observe/check are no-ops.
17
+ * Local-scope events (event.endpointClass === "local", stamped by govern.ts) use
18
+ * local-calibrated thresholds: 5000 tok/s (perModel glob overrides first) and
19
+ * 10_000 nominal usertokens/min. Detection is opt-in (anomaly.enabled=true) —
20
+ * when off, observe/check are no-ops.
18
21
  */
19
- import { estimateCost } from "../ledger/pricing.js";
22
+ import { costFromRates, estimateCost } from "../ledger/pricing.js";
20
23
  import { createInjectionCascadeSignal, resolveInjectionCascadeConfig, } from "./signals/injection-cascade.js";
21
24
  import { createSpendVelocitySignal, resolveSpendVelocityConfig, } from "./signals/spend-velocity.js";
22
25
  import { createTokenRateSignal, resolveTokenRateConfig, } from "./signals/token-rate.js";
@@ -33,11 +36,31 @@ export function resolveAnomalyConfig(cfg) {
33
36
  }
34
37
  /** USD value of one usertoken. 1 usertoken = $0.0001 (one basis point of a cent). */
35
38
  const USERTOKENS_PER_DOLLAR = 10_000;
36
- function defaultCostCalculator(model, inputTokens, outputTokens) {
37
- // estimateCost returns usertokens; convert to dollars.
39
+ function defaultCostCalculator(model, inputTokens, outputTokens, event) {
40
+ if (event?.endpointClass === "local") {
41
+ // Local scope without an injected calculator: price in nominal usertokens at
42
+ // the shipped default local rate {0,0}. costFromRates floors at 1, so the
43
+ // cumulative cost is a constant and spend-velocity stays flat — token_rate is
44
+ // the primary local signal. govern.ts injects a config-aware calculator that
45
+ // prices via resolveRates (operator-set local rates enable velocity showback).
46
+ return costFromRates({ inputPer1k: 0, outputPer1k: 0 }, inputTokens, outputTokens);
47
+ }
48
+ // estimateCost returns usertokens; convert to dollars (cloud usd-proxy scope).
38
49
  const usertokens = estimateCost(model, inputTokens, outputTokens);
39
50
  return usertokens / USERTOKENS_PER_DOLLAR;
40
51
  }
52
+ /** Verdict text for a token-rate result; names non-legacy thresholds (local/perModel). */
53
+ function tokenRateMessage(r) {
54
+ const base = `tokens/s ${r.metric.toFixed(1)} >= ${r.threshold}`;
55
+ return r.thresholdLabel === "thresholdTokPerSec" ? base : `${base} (${r.thresholdLabel})`;
56
+ }
57
+ /** Verdict text for a spend-velocity result; never fakes dollars for nominal spend. */
58
+ function spendVelocityMessage(r) {
59
+ if (r.unit === "usertokens") {
60
+ return `usertokens/min ${r.metric.toFixed(1)} >= ${r.threshold} (${r.thresholdLabel})`;
61
+ }
62
+ return `$/min ${r.metric.toFixed(4)} >= ${r.threshold}`;
63
+ }
41
64
  export function createAnomalyDetector(cfg, options) {
42
65
  const config = resolveAnomalyConfig(cfg);
43
66
  const now = options?.now ?? (() => Date.now());
@@ -60,9 +83,11 @@ export function createAnomalyDetector(cfg, options) {
60
83
  }
61
84
  function observeChunk(ev) {
62
85
  const t = ev.at ?? now();
63
- tokenRate.observe(ev.deltaTokens, t);
64
- const dollars = costCalculator(model, ev.cumulativeInputTokens, ev.cumulativeOutputTokens);
65
- spendVelocity.observe(dollars, t);
86
+ // Per-event scope: the event's model/endpointClass (stamped by govern.ts)
87
+ // override options.model / the default cloud scope when present (M2).
88
+ tokenRate.observe(ev.deltaTokens, t, ev);
89
+ const cost = costCalculator(ev.model ?? model, ev.cumulativeInputTokens, ev.cumulativeOutputTokens, ev);
90
+ spendVelocity.observe(cost, t, ev.endpointClass ?? "cloud");
66
91
  }
67
92
  function observeInjection(ev) {
68
93
  injectionCascade.observe(ev.at ?? now());
@@ -91,11 +116,11 @@ export function createAnomalyDetector(cfg, options) {
91
116
  // Check signals in priority order: token-rate first (cheapest), spend-velocity, then injection.
92
117
  const tr = tokenRate.check(t);
93
118
  if (tr.tripped) {
94
- return markTripped("token_rate", `tokens/s ${tr.metric.toFixed(1)} >= ${tr.threshold}`, tr.metric, tr.threshold);
119
+ return markTripped("token_rate", tokenRateMessage(tr), tr.metric, tr.threshold);
95
120
  }
96
121
  const sv = spendVelocity.check(t);
97
122
  if (sv.tripped) {
98
- return markTripped("spend_velocity", `$/min ${sv.metric.toFixed(4)} >= ${sv.threshold}`, sv.metric, sv.threshold);
123
+ return markTripped("spend_velocity", spendVelocityMessage(sv), sv.metric, sv.threshold);
99
124
  }
100
125
  const ic = injectionCascade.check(t);
101
126
  if (ic.tripped) {
@@ -112,7 +137,7 @@ export function createAnomalyDetector(cfg, options) {
112
137
  return {
113
138
  tripped: true,
114
139
  kind,
115
- message: `tokens/s ${r.metric.toFixed(1)} >= ${r.threshold}`,
140
+ message: tokenRateMessage(r),
116
141
  metric: r.metric,
117
142
  threshold: r.threshold,
118
143
  };
@@ -122,7 +147,7 @@ export function createAnomalyDetector(cfg, options) {
122
147
  return {
123
148
  tripped: true,
124
149
  kind,
125
- message: `$/min ${r.metric.toFixed(4)} >= ${r.threshold}`,
150
+ message: spendVelocityMessage(r),
126
151
  metric: r.metric,
127
152
  threshold: r.threshold,
128
153
  };
@@ -1 +1 @@
1
- {"version":3,"file":"detector.js","sourceRoot":"","sources":["../../src/anomaly/detector.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"detector.js","sourceRoot":"","sources":["../../src/anomaly/detector.ts"],"names":[],"mappings":"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"}
@@ -1,37 +1,64 @@
1
1
  /**
2
2
  * spend-velocity.ts — Spend-velocity anomaly signal.
3
3
  *
4
- * Tracks $/min over a rolling window. Each observation records the
5
- * cumulative cost (in dollars). The signal trips when the rolling
6
- * dollars-per-minute exceeds the configured ceiling.
4
+ * Dual denomination (M2): cloud-scope observations accumulate usd-proxy cost
5
+ * (dollars) against `thresholdDollarsPerMin`; local-scope observations
6
+ * accumulate NOMINAL USERTOKENS against `localThresholdUsertokensPerMin`
7
+ * (default 10_000). The two series are independent rolling windows; check()
8
+ * reports which denomination (and threshold) applied via `unit`/`thresholdLabel`
9
+ * so verdict text never fakes dollars for nominal spend.
7
10
  *
8
- * Default: $1.00/min over a 10s rolling window.
11
+ * Explicit documented behavior: with the default local rate {0,0}, per-chunk
12
+ * cumulative nominal cost is a constant floor of 1 usertoken, so spend_velocity
13
+ * CANNOT trip on default local config — token_rate is the primary local signal.
14
+ * Velocity becomes meaningful when the operator sets nonzero local rates
15
+ * (amortized-usd showback).
16
+ *
17
+ * Default: $1.00/min (cloud) / 10_000 ut/min (local) over a 10s rolling window.
9
18
  *
10
19
  * Cost is computed via a `costCalculator` callback so the signal stays
11
20
  * decoupled from the SDK's pricing module.
12
21
  */
22
+ import type { EndpointClass } from "../../shared/types.js";
13
23
  import type { SpendVelocityConfig } from "../types.js";
24
+ /** Denomination of a velocity measurement. */
25
+ export type SpendUnit = "dollars" | "usertokens";
14
26
  interface CostSample {
15
27
  tMs: number;
16
- cumulativeDollars: number;
28
+ /** Cumulative cost in the series' denomination (dollars or nominal usertokens). */
29
+ cumulative: number;
17
30
  }
18
31
  export interface SpendVelocitySignalState {
32
+ /** Cloud-scope samples (cumulative dollars). */
19
33
  samples: CostSample[];
34
+ /** Local-scope samples (cumulative nominal usertokens). */
35
+ localSamples: CostSample[];
20
36
  lastDollarsPerMin: number;
37
+ lastUsertokensPerMin: number;
38
+ }
39
+ export interface SpendVelocityCheckResult {
40
+ tripped: boolean;
41
+ metric: number;
42
+ threshold: number;
43
+ /** Denomination of metric/threshold. */
44
+ unit: SpendUnit;
45
+ /** Which config threshold applied: "thresholdDollarsPerMin" | "localThresholdUsertokensPerMin". */
46
+ thresholdLabel: string;
21
47
  }
22
48
  export interface SpendVelocitySignal {
23
49
  state: Readonly<SpendVelocitySignalState>;
24
- /** Record cumulative dollars at time `nowMs`. */
25
- observe(cumulativeDollars: number, nowMs: number): void;
26
- check(nowMs: number): {
27
- tripped: boolean;
28
- metric: number;
29
- threshold: number;
30
- };
50
+ /**
51
+ * Record cumulative cost at time `nowMs`. `scope` selects the series:
52
+ * "local" accumulates nominal usertokens, "cloud" (default) dollars.
53
+ */
54
+ observe(cumulativeCost: number, nowMs: number, scope?: EndpointClass): void;
55
+ check(nowMs: number): SpendVelocityCheckResult;
31
56
  reset(): void;
32
57
  }
33
58
  export interface ResolvedSpendVelocityConfig {
34
59
  thresholdDollarsPerMin: number;
60
+ /** Local-scope threshold; defaulted to 10_000 at consumption when absent. */
61
+ localThresholdUsertokensPerMin?: number | undefined;
35
62
  windowMs: number;
36
63
  }
37
64
  export declare const SPEND_VELOCITY_DEFAULTS: ResolvedSpendVelocityConfig;
@@ -1 +1 @@
1
- {"version":3,"file":"spend-velocity.d.ts","sourceRoot":"","sources":["../../../src/anomaly/signals/spend-velocity.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEvD,UAAU,UAAU;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,iBAAiB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,wBAAwB;IACxC,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,mBAAmB;IACnC,KAAK,EAAE,QAAQ,CAAC,wBAAwB,CAAC,CAAC;IAC1C,iDAAiD;IACjD,OAAO,CAAC,iBAAiB,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACxD,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG;QACrB,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,KAAK,IAAI,IAAI,CAAC;CACd;AAED,MAAM,WAAW,2BAA2B;IAC3C,sBAAsB,EAAE,MAAM,CAAC;IAC/B,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,uBAAuB,EAAE,2BAGrC,CAAC;AAEF,wBAAgB,0BAA0B,CAAC,GAAG,CAAC,EAAE,mBAAmB,GAAG,2BAA2B,CAMjG;AAED,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,2BAA2B,GAAG,mBAAmB,CAkF/F"}
1
+ {"version":3,"file":"spend-velocity.d.ts","sourceRoot":"","sources":["../../../src/anomaly/signals/spend-velocity.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAKvD,8CAA8C;AAC9C,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,YAAY,CAAC;AAEjD,UAAU,UAAU;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,mFAAmF;IACnF,UAAU,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,wBAAwB;IACxC,gDAAgD;IAChD,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,2DAA2D;IAC3D,YAAY,EAAE,UAAU,EAAE,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,wBAAwB;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,wCAAwC;IACxC,IAAI,EAAE,SAAS,CAAC;IAChB,mGAAmG;IACnG,cAAc,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IACnC,KAAK,EAAE,QAAQ,CAAC,wBAAwB,CAAC,CAAC;IAC1C;;;OAGG;IACH,OAAO,CAAC,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IAC5E,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,wBAAwB,CAAC;IAC/C,KAAK,IAAI,IAAI,CAAC;CACd;AAED,MAAM,WAAW,2BAA2B;IAC3C,sBAAsB,EAAE,MAAM,CAAC;IAC/B,6EAA6E;IAC7E,8BAA8B,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpD,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,uBAAuB,EAAE,2BAGrC,CAAC;AAEF,wBAAgB,0BAA0B,CAAC,GAAG,CAAC,EAAE,mBAAmB,GAAG,2BAA2B,CAQjG;AAED,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,2BAA2B,GAAG,mBAAmB,CAiG/F"}
@@ -1,5 +1,7 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  // Copyright 2026 Usertools, Inc.
3
+ /** Default local-scope threshold, applied where consumed (resolved config keeps it optional). */
4
+ const LOCAL_THRESHOLD_USERTOKENS_PER_MIN_DEFAULT = 10_000;
3
5
  export const SPEND_VELOCITY_DEFAULTS = {
4
6
  thresholdDollarsPerMin: 1.0,
5
7
  windowMs: 10_000,
@@ -7,20 +9,25 @@ export const SPEND_VELOCITY_DEFAULTS = {
7
9
  export function resolveSpendVelocityConfig(cfg) {
8
10
  return {
9
11
  thresholdDollarsPerMin: cfg?.thresholdDollarsPerMin ?? SPEND_VELOCITY_DEFAULTS.thresholdDollarsPerMin,
12
+ // M2 field stays optional in resolved config — defaulted where consumed.
13
+ localThresholdUsertokensPerMin: cfg?.localThresholdUsertokensPerMin,
10
14
  windowMs: cfg?.windowMs ?? SPEND_VELOCITY_DEFAULTS.windowMs,
11
15
  };
12
16
  }
13
17
  export function createSpendVelocitySignal(cfg) {
14
18
  const state = {
15
19
  samples: [],
20
+ localSamples: [],
16
21
  lastDollarsPerMin: 0,
22
+ lastUsertokensPerMin: 0,
17
23
  };
18
- function pruneOlderThan(cutoffMs) {
24
+ const localThreshold = cfg.localThresholdUsertokensPerMin ?? LOCAL_THRESHOLD_USERTOKENS_PER_MIN_DEFAULT;
25
+ function pruneOlderThan(series, cutoffMs) {
19
26
  // Keep at least one sample older than the cutoff so we can compute deltas.
20
27
  // Find the most recent sample at or before cutoffMs and drop everything before it.
21
28
  let lastBeforeCutoff = -1;
22
- for (let i = 0; i < state.samples.length; i++) {
23
- const sample = state.samples[i];
29
+ for (let i = 0; i < series.length; i++) {
30
+ const sample = series[i];
24
31
  if (sample !== undefined && sample.tMs <= cutoffMs) {
25
32
  lastBeforeCutoff = i;
26
33
  }
@@ -29,61 +36,77 @@ export function createSpendVelocitySignal(cfg) {
29
36
  }
30
37
  }
31
38
  if (lastBeforeCutoff > 0) {
32
- state.samples.splice(0, lastBeforeCutoff);
39
+ series.splice(0, lastBeforeCutoff);
33
40
  }
34
41
  }
35
- function observe(cumulativeDollars, nowMs) {
42
+ function observe(cumulativeCost, nowMs, scope = "cloud") {
36
43
  // Reject NaN/negative deltas — keep the cumulative monotonic non-decreasing.
37
- if (!Number.isFinite(cumulativeDollars) || cumulativeDollars < 0)
44
+ if (!Number.isFinite(cumulativeCost) || cumulativeCost < 0)
38
45
  return;
39
- const last = state.samples[state.samples.length - 1];
40
- if (last !== undefined && cumulativeDollars < last.cumulativeDollars) {
46
+ const series = scope === "local" ? state.localSamples : state.samples;
47
+ const last = series[series.length - 1];
48
+ if (last !== undefined && cumulativeCost < last.cumulative) {
41
49
  // Provider regressed (shouldn't happen) — clamp to last
42
- state.samples.push({ tMs: nowMs, cumulativeDollars: last.cumulativeDollars });
50
+ series.push({ tMs: nowMs, cumulative: last.cumulative });
43
51
  }
44
52
  else {
45
- state.samples.push({ tMs: nowMs, cumulativeDollars });
53
+ series.push({ tMs: nowMs, cumulative: cumulativeCost });
46
54
  }
47
- pruneOlderThan(nowMs - cfg.windowMs);
55
+ pruneOlderThan(series, nowMs - cfg.windowMs);
48
56
  }
49
- function check(nowMs) {
50
- pruneOlderThan(nowMs - cfg.windowMs);
51
- if (state.samples.length < 2) {
52
- return {
53
- tripped: false,
54
- metric: 0,
55
- threshold: cfg.thresholdDollarsPerMin,
56
- };
57
- }
58
- const first = state.samples[0];
59
- const last = state.samples[state.samples.length - 1];
60
- if (first === undefined || last === undefined) {
61
- return {
62
- tripped: false,
63
- metric: 0,
64
- threshold: cfg.thresholdDollarsPerMin,
65
- };
66
- }
67
- const dollarsDelta = last.cumulativeDollars - first.cumulativeDollars;
57
+ /** Rolling per-minute rate over a series, or null when not computable. */
58
+ function ratePerMin(series, nowMs) {
59
+ pruneOlderThan(series, nowMs - cfg.windowMs);
60
+ if (series.length < 2)
61
+ return null;
62
+ const first = series[0];
63
+ const last = series[series.length - 1];
64
+ if (first === undefined || last === undefined)
65
+ return null;
66
+ const costDelta = last.cumulative - first.cumulative;
68
67
  const minutesDelta = (last.tMs - first.tMs) / 60_000;
69
- if (minutesDelta <= 0) {
70
- return {
71
- tripped: false,
72
- metric: 0,
73
- threshold: cfg.thresholdDollarsPerMin,
74
- };
75
- }
76
- const dollarsPerMin = dollarsDelta / minutesDelta;
77
- state.lastDollarsPerMin = dollarsPerMin;
78
- return {
79
- tripped: dollarsPerMin >= cfg.thresholdDollarsPerMin,
80
- metric: dollarsPerMin,
68
+ if (minutesDelta <= 0)
69
+ return null;
70
+ return costDelta / minutesDelta;
71
+ }
72
+ function check(nowMs) {
73
+ const cloudRate = ratePerMin(state.samples, nowMs);
74
+ const localRate = ratePerMin(state.localSamples, nowMs);
75
+ if (cloudRate !== null)
76
+ state.lastDollarsPerMin = cloudRate;
77
+ if (localRate !== null)
78
+ state.lastUsertokensPerMin = localRate;
79
+ const cloudResult = (tripped) => ({
80
+ tripped,
81
+ metric: cloudRate ?? 0,
81
82
  threshold: cfg.thresholdDollarsPerMin,
82
- };
83
+ unit: "dollars",
84
+ thresholdLabel: "thresholdDollarsPerMin",
85
+ });
86
+ const localResult = (tripped, rate) => ({
87
+ tripped,
88
+ metric: rate,
89
+ threshold: localThreshold,
90
+ unit: "usertokens",
91
+ thresholdLabel: "localThresholdUsertokensPerMin",
92
+ });
93
+ if (cloudRate !== null && cloudRate >= cfg.thresholdDollarsPerMin)
94
+ return cloudResult(true);
95
+ if (localRate !== null && localRate >= localThreshold)
96
+ return localResult(true, localRate);
97
+ // Neither tripped: report the denomination closer to its threshold
98
+ // (cloud on tie / when nothing is computable — legacy behavior).
99
+ if (localRate !== null &&
100
+ (cloudRate === null || localRate / localThreshold > cloudRate / cfg.thresholdDollarsPerMin)) {
101
+ return localResult(false, localRate);
102
+ }
103
+ return cloudResult(false);
83
104
  }
84
105
  function reset() {
85
106
  state.samples.length = 0;
107
+ state.localSamples.length = 0;
86
108
  state.lastDollarsPerMin = 0;
109
+ state.lastUsertokensPerMin = 0;
87
110
  }
88
111
  return { state, observe, check, reset };
89
112
  }
@@ -1 +1 @@
1
- {"version":3,"file":"spend-velocity.js","sourceRoot":"","sources":["../../../src/anomaly/signals/spend-velocity.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"spend-velocity.js","sourceRoot":"","sources":["../../../src/anomaly/signals/spend-velocity.ts"],"names":[],"mappings":"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"}
@@ -1,15 +1,14 @@
1
- /**
2
- * token-rate.ts — Token-rate anomaly signal.
3
- *
4
- * Buckets observed chunks into fixed-width windows (default 2 s) and counts
5
- * tokens-per-second within each window. Trips when N consecutive windows
6
- * exceed the configured threshold (default 500 tok/s, 3 windows).
7
- *
8
- * Brief spikes (1-2 hot windows) are ignored — only sustained runaway
9
- * behavior trips the circuit.
10
- */
1
+ import type { EndpointClass } from "../../shared/types.js";
11
2
  import type { TokenRateConfig } from "../types.js";
12
- export interface TokenRateSignalState {
3
+ /** Threshold-source labels: "thresholdTokPerSec", "localThresholdTokPerSec", or `perModel["<pattern>"]`. */
4
+ export type TokenRateThresholdLabel = string;
5
+ /** Per-observation scope context (an AnomalyChunkEvent satisfies this shape). */
6
+ export interface TokenRateObserveContext {
7
+ model?: string | undefined;
8
+ endpointClass?: EndpointClass | undefined;
9
+ }
10
+ /** Rolling-window state for a single endpoint scope (cloud or local). */
11
+ export interface ScopeWindowState {
13
12
  /** Per-window tokens accumulated in the current bucket. */
14
13
  currentWindowTokens: number;
15
14
  /** Start time of the current window. */
@@ -18,11 +17,27 @@ export interface TokenRateSignalState {
18
17
  consecutiveHotWindows: number;
19
18
  /** Last computed peak rate (for the most recently closed window). */
20
19
  lastWindowRateTokPerSec: number;
20
+ /** Whether any observation has been routed to this scope yet. */
21
+ initialized: boolean;
22
+ /** Effective threshold for this scope's windows (resolved per observation). */
23
+ threshold: number;
24
+ /** Source label of the effective threshold. */
25
+ thresholdLabel: TokenRateThresholdLabel;
26
+ }
27
+ export interface TokenRateSignalState {
28
+ /** Cloud/unscoped window state (legacy `thresholdTokPerSec`). */
29
+ cloud: Readonly<ScopeWindowState>;
30
+ /** Local window state (`perModel` glob / `localThresholdTokPerSec`). */
31
+ local: Readonly<ScopeWindowState>;
21
32
  }
22
33
  export interface TokenRateSignal {
23
34
  state: Readonly<TokenRateSignalState>;
24
- /** Observe a chunk's delta tokens at time `nowMs`. */
25
- observe(deltaTokens: number, nowMs: number): void;
35
+ /**
36
+ * Observe a chunk's delta tokens at time `nowMs`. `context` (the chunk
37
+ * event) selects the effective threshold for subsequent window evaluation;
38
+ * omitted/unscoped context means the legacy cloud threshold.
39
+ */
40
+ observe(deltaTokens: number, nowMs: number, context?: TokenRateObserveContext): void;
26
41
  /**
27
42
  * Check if the threshold has been crossed.
28
43
  * Returns the metric (peak window rate) when tripped, else null.
@@ -32,11 +47,16 @@ export interface TokenRateSignal {
32
47
  metric: number;
33
48
  threshold: number;
34
49
  hotWindows: number;
50
+ thresholdLabel: TokenRateThresholdLabel;
35
51
  };
36
52
  reset(): void;
37
53
  }
38
54
  export interface ResolvedTokenRateConfig {
39
55
  thresholdTokPerSec: number;
56
+ /** Local-scope threshold; defaulted to 5000 at consumption when absent. */
57
+ localThresholdTokPerSec?: number | undefined;
58
+ /** Per-model overrides for local-scope events (trailing-* glob keys). */
59
+ perModel?: Record<string, number> | undefined;
40
60
  windowMs: number;
41
61
  consecutiveWindows: number;
42
62
  }
@@ -1 +1 @@
1
- {"version":3,"file":"token-rate.d.ts","sourceRoot":"","sources":["../../../src/anomaly/signals/token-rate.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEnD,MAAM,WAAW,oBAAoB;IACpC,2DAA2D;IAC3D,mBAAmB,EAAE,MAAM,CAAC;IAC5B,wCAAwC;IACxC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,uEAAuE;IACvE,qBAAqB,EAAE,MAAM,CAAC;IAC9B,qEAAqE;IACrE,uBAAuB,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,eAAe;IAC/B,KAAK,EAAE,QAAQ,CAAC,oBAAoB,CAAC,CAAC;IACtC,sDAAsD;IACtD,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAClD;;;OAGG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG;QACrB,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,KAAK,IAAI,IAAI,CAAC;CACd;AAED,MAAM,WAAW,uBAAuB;IACvC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,MAAM,CAAC;CAC3B;AAED,eAAO,MAAM,mBAAmB,EAAE,uBAIjC,CAAC;AAEF,wBAAgB,sBAAsB,CAAC,GAAG,CAAC,EAAE,eAAe,GAAG,uBAAuB,CAMrF;AAED,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,uBAAuB,GAAG,eAAe,CAmFnF"}
1
+ {"version":3,"file":"token-rate.d.ts","sourceRoot":"","sources":["../../../src/anomaly/signals/token-rate.ts"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAKnD,4GAA4G;AAC5G,MAAM,MAAM,uBAAuB,GAAG,MAAM,CAAC;AAE7C,iFAAiF;AACjF,MAAM,WAAW,uBAAuB;IACvC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,aAAa,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;CAC1C;AAED,yEAAyE;AACzE,MAAM,WAAW,gBAAgB;IAChC,2DAA2D;IAC3D,mBAAmB,EAAE,MAAM,CAAC;IAC5B,wCAAwC;IACxC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,uEAAuE;IACvE,qBAAqB,EAAE,MAAM,CAAC;IAC9B,qEAAqE;IACrE,uBAAuB,EAAE,MAAM,CAAC;IAChC,iEAAiE;IACjE,WAAW,EAAE,OAAO,CAAC;IACrB,+EAA+E;IAC/E,SAAS,EAAE,MAAM,CAAC;IAClB,+CAA+C;IAC/C,cAAc,EAAE,uBAAuB,CAAC;CACxC;AAED,MAAM,WAAW,oBAAoB;IACpC,iEAAiE;IACjE,KAAK,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IAClC,wEAAwE;IACxE,KAAK,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,eAAe;IAC/B,KAAK,EAAE,QAAQ,CAAC,oBAAoB,CAAC,CAAC;IACtC;;;;OAIG;IACH,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,uBAAuB,GAAG,IAAI,CAAC;IACrF;;;OAGG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG;QACrB,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,cAAc,EAAE,uBAAuB,CAAC;KACxC,CAAC;IACF,KAAK,IAAI,IAAI,CAAC;CACd;AAED,MAAM,WAAW,uBAAuB;IACvC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,2EAA2E;IAC3E,uBAAuB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7C,yEAAyE;IACzE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,MAAM,CAAC;CAC3B;AAED,eAAO,MAAM,mBAAmB,EAAE,uBAIjC,CAAC;AAEF,wBAAgB,sBAAsB,CAAC,GAAG,CAAC,EAAE,eAAe,GAAG,uBAAuB,CASrF;AAUD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,uBAAuB,GAAG,eAAe,CAsInF"}