@kunal_dutt/token-lens 0.0.0-stage → 0.2.16

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 (40) hide show
  1. package/GATEWAY.md +491 -0
  2. package/LICENSE +21 -0
  3. package/PRIVACY.md +36 -0
  4. package/README.md +80 -2
  5. package/agent-cost-check.yml +49 -0
  6. package/check-agent.mjs +3298 -0
  7. package/cli.mjs +22 -0
  8. package/gateway.mjs +3365 -0
  9. package/package.json +45 -4
  10. package/sdk.mjs +207719 -0
  11. package/server.mjs +3392 -0
  12. package/token-lens.mcpb +0 -0
  13. package/types/src/core/advice.d.ts +27 -0
  14. package/types/src/core/budget.d.ts +28 -0
  15. package/types/src/core/compress.d.ts +29 -0
  16. package/types/src/core/cost.d.ts +32 -0
  17. package/types/src/core/guard.d.ts +20 -0
  18. package/types/src/core/hotspots.d.ts +124 -0
  19. package/types/src/core/index.d.ts +74 -0
  20. package/types/src/core/media.d.ts +29 -0
  21. package/types/src/core/models.d.ts +81 -0
  22. package/types/src/core/plans.d.ts +88 -0
  23. package/types/src/core/redos.d.ts +32 -0
  24. package/types/src/core/review.d.ts +46 -0
  25. package/types/src/core/rules.d.ts +47 -0
  26. package/types/src/core/tasks.d.ts +44 -0
  27. package/types/src/core/tokens.d.ts +19 -0
  28. package/types/src/core/verify.d.ts +19 -0
  29. package/types/src/gateway/config.d.ts +217 -0
  30. package/types/src/gateway/guard.d.ts +56 -0
  31. package/types/src/gateway/images.d.ts +40 -0
  32. package/types/src/gateway/metrics.d.ts +287 -0
  33. package/types/src/gateway/optimize.d.ts +102 -0
  34. package/types/src/gateway/protocol.d.ts +68 -0
  35. package/types/src/gateway/runs.d.ts +182 -0
  36. package/types/src/gateway/shared.d.ts +57 -0
  37. package/types/src/gateway/signals.d.ts +38 -0
  38. package/types/src/gateway/storage.d.ts +88 -0
  39. package/types/src/gateway/verify.d.ts +51 -0
  40. package/types/src/sdk/index.d.ts +228 -0
@@ -0,0 +1,228 @@
1
+ /**
2
+ * Token Lens for developers who don't run the gateway: the gateway's fixes,
3
+ * applied inside your own process, with the same savings report.
4
+ *
5
+ * import OpenAI from "openai";
6
+ * import { withTokenLens } from "@kunal_dutt/token-lens/sdk";
7
+ * const client = withTokenLens(new OpenAI(), { agent: "support-bot" });
8
+ * ...
9
+ * console.log(client.tokenLens.summary());
10
+ *
11
+ * It hooks the SDK's `fetch`, so the same hook also works for anything that
12
+ * takes a fetch function: LangChain (`configuration: { fetch }` /
13
+ * `clientOptions: { fetch }`), the Vercel AI SDK (`createOpenAI({ fetch })`),
14
+ * LlamaIndex and others.
15
+ *
16
+ * Nothing leaves your process except the calls you were already making, to
17
+ * the provider you already call. The model is never changed.
18
+ *
19
+ * On by default, because the request means exactly the same thing:
20
+ * minify-json pretty-printed JSON in tool results -> compact JSON
21
+ * collapse-repeats runs of identical lines in tool results -> one line and a count
22
+ * dedupe-tool-outputs a tool result identical to an earlier one is sent once
23
+ * prompt-caching cache breakpoints (Anthropic) or a cache key (OpenAI) once a prefix repeats
24
+ * dedupe-retries an identical temperature-0 request is answered from the earlier response
25
+ *
26
+ * Opt-in, because it rewrites text the model reads:
27
+ * rewritePrompts the core prompt optimizer on user-written messages. It starts on
28
+ * probation, as opt-in fixes do in the gateway (guard.ts): for the
29
+ * first `probation` calls the original request goes too, and the
30
+ * app gets the rewritten call's answer only when the two match.
31
+ * Streamed calls aren't rewritten until probation is passed. After
32
+ * that it is checked on at least a quarter of calls. The first
33
+ * different answer switches it off for good.
34
+ *
35
+ * A failed output check also switches off the safe fixes that were in play,
36
+ * so a fix is never kept once a check has seen it change an answer.
37
+ */
38
+ import { type ModelPricing, type ModelProfile } from "../core";
39
+ import { type SafeOptimizations } from "../gateway/config";
40
+ import { type Action } from "../gateway/optimize";
41
+ import { type Protocol, type Usage } from "../gateway/protocol";
42
+ import { type Check } from "../gateway/verify";
43
+ export { registerModel, formatUsd, type CustomModel, type ModelPricing } from "../core";
44
+ type Fetch = typeof globalThis.fetch;
45
+ export type SafeFix = Exclude<keyof SafeOptimizations, "prompt">;
46
+ export interface TokenLensOptions {
47
+ /** Name for this agent or app in the report. */
48
+ agent?: string;
49
+ /** Run id; calls in one run share a prompt cache. Default: one per TokenLens instance. */
50
+ run?: string;
51
+ /** "observe" reports cost without changing any request. Default "optimize". */
52
+ mode?: "optimize" | "observe";
53
+ /** Turn individual safe fixes off, e.g. `{ dedupeRetries: false }`. */
54
+ fixes?: Partial<Record<SafeFix, boolean>>;
55
+ /** Opt-in: rewrite user-written messages with the core prompt optimizer (checked, see above). */
56
+ rewritePrompts?: boolean;
57
+ /**
58
+ * Share of optimized, non-streamed calls (0..1) to check by also sending the
59
+ * original request to the same model and comparing the answers. Off by
60
+ * default because each check is one extra call.
61
+ */
62
+ verify?: number;
63
+ /** Rewritten calls that must match the original's answer before the rewrite is trusted. Default 5. */
64
+ probation?: number;
65
+ /** Text similarity at or above which two answers count as the same; tool calls must match exactly. Default 0.8. */
66
+ minSimilarity?: number;
67
+ /** Your own price, USD per 1M tokens, for every model; default is each model's API list price. */
68
+ pricing?: ModelPricing;
69
+ /** Seconds an identical temperature-0 request is answered from the earlier response. Default 120. */
70
+ retryWindowSeconds?: number;
71
+ /** Called after each call with what Token Lens did and what it saved. */
72
+ onCall?: (call: CallRecord) => void;
73
+ }
74
+ export interface CallRecord {
75
+ protocol: Protocol;
76
+ model: string;
77
+ /** Token Lens profile the model was priced with. */
78
+ profile: string;
79
+ status: number;
80
+ stream: boolean;
81
+ /** Input tokens removed from the request. */
82
+ savedInputTokens: number;
83
+ fixes: Action[];
84
+ usage: Usage;
85
+ /** Answered from an earlier identical request, so the call was not made. */
86
+ replayed: boolean;
87
+ costUsd: number;
88
+ }
89
+ /**
90
+ * The model's prices for a request of `inputTokens` input tokens: past a
91
+ * long-context threshold, the whole request is billed at the higher rate.
92
+ */
93
+ export declare function pricedFor(profile: ModelProfile, inputTokens: number): ModelProfile;
94
+ export declare class TokenLens {
95
+ readonly options: TokenLensOptions;
96
+ private readonly counter;
97
+ private readonly prefixes;
98
+ private readonly rows;
99
+ private readonly byFix;
100
+ private readonly checks;
101
+ private checkCostUsd;
102
+ private readonly replays;
103
+ private readonly pending;
104
+ private readonly runId;
105
+ /** Set when an output check found a different answer with prompt rewriting on. */
106
+ private rewriteStopped?;
107
+ /** Rewritten calls whose answer matched the original's during probation. */
108
+ private rewriteMatched;
109
+ /** Safe fixes switched off because a check found a different answer while they were in play. */
110
+ private readonly disabled;
111
+ constructor(options?: TokenLensOptions);
112
+ /** A fetch that applies Token Lens to OpenAI and Anthropic API calls and passes everything else through. */
113
+ fetch(base?: Fetch): Fetch;
114
+ /** LangChain callback handler: reports tokens and cost for any LangChain chat model (no request changes). */
115
+ langchain(): {
116
+ name: string;
117
+ handleChatModelStart: (llm: any, _m: unknown, runId: string, _p?: string, extra?: any) => any;
118
+ handleLLMStart: (llm: any, _p: unknown, runId: string, _pr?: string, extra?: any) => any;
119
+ handleLLMEnd: (output: any, runId: string) => void;
120
+ };
121
+ /** Wait for background work (output checks, streams still being read). */
122
+ flush(): Promise<void>;
123
+ report(): {
124
+ agent: string;
125
+ run: string;
126
+ total: {
127
+ costUsd: number;
128
+ costBeforeUsd: number;
129
+ checkCostUsd: number;
130
+ savedTokens: number;
131
+ savedTokensPct: number;
132
+ savedUsd: number;
133
+ savedUsdPct: number;
134
+ netSavedUsd: number;
135
+ outputUnchangedPct: number;
136
+ unpricedRequests: number;
137
+ requests: number;
138
+ errors: number;
139
+ replayed: number;
140
+ inputTokens: number;
141
+ inputTokensBefore: number;
142
+ outputTokens: number;
143
+ outputTokensAvoided: number;
144
+ cachedInputTokens: number;
145
+ reasoningTokens: number;
146
+ savedInputTokens: number;
147
+ pricedRequests: number;
148
+ checks: number;
149
+ checksMatched: number;
150
+ };
151
+ byModel: {
152
+ costUsd: number;
153
+ costBeforeUsd: number;
154
+ checkCostUsd: number;
155
+ savedTokens: number;
156
+ savedTokensPct: number;
157
+ savedUsd: number;
158
+ savedUsdPct: number;
159
+ netSavedUsd: number;
160
+ outputUnchangedPct: number;
161
+ unpricedRequests: number;
162
+ requests: number;
163
+ errors: number;
164
+ replayed: number;
165
+ inputTokens: number;
166
+ inputTokensBefore: number;
167
+ outputTokens: number;
168
+ outputTokensAvoided: number;
169
+ cachedInputTokens: number;
170
+ reasoningTokens: number;
171
+ savedInputTokens: number;
172
+ pricedRequests: number;
173
+ checks: number;
174
+ checksMatched: number;
175
+ model: string;
176
+ }[];
177
+ byFix: {
178
+ fix: string;
179
+ calls: number;
180
+ tokens: number;
181
+ usd: number;
182
+ }[];
183
+ checks: {
184
+ recent: Check[];
185
+ checked: number;
186
+ matched: number;
187
+ sameToolCalls: number;
188
+ averageSimilarity: number;
189
+ savedOnChecked: number;
190
+ };
191
+ rewritePrompts: string;
192
+ switchedOff: SafeFix[];
193
+ };
194
+ /** The report in a few plain lines. */
195
+ summary(): string;
196
+ private profile;
197
+ private probation;
198
+ private onProbation;
199
+ private config;
200
+ private prepare;
201
+ private send;
202
+ /**
203
+ * Probation: send the rewritten and the original request together, and hand
204
+ * back the rewritten call's answer only when the two match. Otherwise the app
205
+ * gets the original's answer and rewriting is switched off.
206
+ */
207
+ private probationCall;
208
+ private addCheck;
209
+ /** Send the caller's original request too, in the background, and compare the two answers. */
210
+ private maybeCheck;
211
+ private base;
212
+ private record;
213
+ }
214
+ type WithOptions = {
215
+ withOptions(options: any): unknown;
216
+ };
217
+ /**
218
+ * Wrap an OpenAI or Anthropic client (any SDK with `withOptions({ fetch })`):
219
+ * every call through the returned client gets Token Lens, and
220
+ * `client.tokenLens` holds the report.
221
+ */
222
+ export declare function withTokenLens<T extends WithOptions>(client: T, options?: TokenLensOptions | TokenLens): T & {
223
+ tokenLens: TokenLens;
224
+ };
225
+ /** Shorthand for `new TokenLens(options).fetch()`, for LangChain, the Vercel AI SDK and other fetch-based clients. */
226
+ export declare function tokenLensFetch(options?: TokenLensOptions | TokenLens, base?: Fetch): Fetch & {
227
+ tokenLens: TokenLens;
228
+ };