context-lens 0.2.0 → 0.2.1
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 +62 -17
- package/dist/cli-utils.d.ts +1 -1
- package/dist/cli-utils.d.ts.map +1 -1
- package/dist/cli-utils.js +28 -13
- package/dist/cli-utils.js.map +1 -1
- package/dist/cli.js +77 -65
- package/dist/cli.js.map +1 -1
- package/dist/core/conversation.d.ts +54 -0
- package/dist/core/conversation.d.ts.map +1 -0
- package/dist/core/conversation.js +188 -0
- package/dist/core/conversation.js.map +1 -0
- package/dist/core/models.d.ts +30 -0
- package/dist/core/models.d.ts.map +1 -0
- package/dist/core/models.js +96 -0
- package/dist/core/models.js.map +1 -0
- package/dist/core/parse.d.ts +17 -0
- package/dist/core/parse.d.ts.map +1 -0
- package/dist/core/parse.js +349 -0
- package/dist/core/parse.js.map +1 -0
- package/dist/core/routing.d.ts +47 -0
- package/dist/core/routing.d.ts.map +1 -0
- package/dist/core/routing.js +132 -0
- package/dist/core/routing.js.map +1 -0
- package/dist/core/source.d.ts +22 -0
- package/dist/core/source.d.ts.map +1 -0
- package/dist/core/source.js +56 -0
- package/dist/core/source.js.map +1 -0
- package/dist/core/tokens.d.ts +11 -0
- package/dist/core/tokens.d.ts.map +1 -0
- package/dist/core/tokens.js +16 -0
- package/dist/core/tokens.js.map +1 -0
- package/dist/core.d.ts +12 -22
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js +12 -471
- package/dist/core.js.map +1 -1
- package/dist/http/headers.d.ts +25 -0
- package/dist/http/headers.d.ts.map +1 -0
- package/dist/http/headers.js +54 -0
- package/dist/http/headers.js.map +1 -0
- package/dist/lhar-types.generated.d.ts +1 -1
- package/dist/lhar.d.ts +4 -4
- package/dist/lhar.d.ts.map +1 -1
- package/dist/lhar.js +190 -106
- package/dist/lhar.js.map +1 -1
- package/dist/server/config.d.ts +12 -0
- package/dist/server/config.d.ts.map +1 -0
- package/dist/server/config.js +33 -0
- package/dist/server/config.js.map +1 -0
- package/dist/server/projection.d.ts +9 -0
- package/dist/server/projection.d.ts.map +1 -0
- package/dist/server/projection.js +39 -0
- package/dist/server/projection.js.map +1 -0
- package/dist/server/proxy.d.ts +13 -0
- package/dist/server/proxy.d.ts.map +1 -0
- package/dist/server/proxy.js +232 -0
- package/dist/server/proxy.js.map +1 -0
- package/dist/server/store.d.ts +33 -0
- package/dist/server/store.d.ts.map +1 -0
- package/dist/server/store.js +350 -0
- package/dist/server/store.js.map +1 -0
- package/dist/server/webui.d.ts +5 -0
- package/dist/server/webui.d.ts.map +1 -0
- package/dist/server/webui.js +170 -0
- package/dist/server/webui.js.map +1 -0
- package/dist/server-utils.d.ts +2 -2
- package/dist/server-utils.d.ts.map +1 -1
- package/dist/server-utils.js +12 -21
- package/dist/server-utils.js.map +1 -1
- package/dist/server.js +30 -697
- package/dist/server.js.map +1 -1
- package/dist/types.d.ts +50 -10
- package/dist/types.d.ts.map +1 -1
- package/dist/version.generated.d.ts +2 -0
- package/dist/version.generated.d.ts.map +1 -0
- package/dist/version.generated.js +2 -0
- package/dist/version.generated.js.map +1 -0
- package/package.json +18 -6
- package/public/index.html +39 -12
- package/schema/lhar.schema.json +1 -1
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
import { estimateTokens } from "./tokens.js";
|
|
2
|
+
/**
|
|
3
|
+
* Parse a single item from the OpenAI Responses API `input` array.
|
|
4
|
+
*
|
|
5
|
+
* Maps typed items (function_call, function_call_output, reasoning, output_text, etc.)
|
|
6
|
+
* to a normalized `ParsedMessage` with a stable `role` and optional `contentBlocks`.
|
|
7
|
+
*/
|
|
8
|
+
function parseResponsesItem(item) {
|
|
9
|
+
const type = item.type || "";
|
|
10
|
+
// Standard message with role/content (e.g. {"type":"message","role":"user","content":[...]})
|
|
11
|
+
if (item.role) {
|
|
12
|
+
const isSystem = item.role === "system" || item.role === "developer";
|
|
13
|
+
let content;
|
|
14
|
+
let contentBlocks = null;
|
|
15
|
+
if (typeof item.content === "string") {
|
|
16
|
+
content = item.content;
|
|
17
|
+
}
|
|
18
|
+
else if (Array.isArray(item.content)) {
|
|
19
|
+
contentBlocks = item.content;
|
|
20
|
+
content = item.content.map((b) => b.text || "").join("\n");
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
content = JSON.stringify(item.content || item);
|
|
24
|
+
}
|
|
25
|
+
const tokens = estimateTokens(item.content ?? content);
|
|
26
|
+
return {
|
|
27
|
+
message: { role: item.role, content, contentBlocks, tokens },
|
|
28
|
+
tokens,
|
|
29
|
+
isSystem,
|
|
30
|
+
content,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
// function_call → assistant tool_use
|
|
34
|
+
if (type === "function_call" || type === "custom_tool_call") {
|
|
35
|
+
const name = item.name || "unknown";
|
|
36
|
+
const args = item.arguments || "";
|
|
37
|
+
const content = name +
|
|
38
|
+
"(" +
|
|
39
|
+
(typeof args === "string"
|
|
40
|
+
? args.slice(0, 200)
|
|
41
|
+
: JSON.stringify(args).slice(0, 200)) +
|
|
42
|
+
")";
|
|
43
|
+
const tokens = estimateTokens(item);
|
|
44
|
+
const block = {
|
|
45
|
+
type: "tool_use",
|
|
46
|
+
id: item.call_id || "",
|
|
47
|
+
name,
|
|
48
|
+
input: typeof args === "string" ? {} : args || {},
|
|
49
|
+
};
|
|
50
|
+
return {
|
|
51
|
+
message: { role: "assistant", content, contentBlocks: [block], tokens },
|
|
52
|
+
tokens,
|
|
53
|
+
isSystem: false,
|
|
54
|
+
content,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
// function_call_output → user tool_result
|
|
58
|
+
if (type === "function_call_output" || type === "custom_tool_call_output") {
|
|
59
|
+
const output = typeof item.output === "string"
|
|
60
|
+
? item.output
|
|
61
|
+
: JSON.stringify(item.output || "");
|
|
62
|
+
const tokens = estimateTokens(output);
|
|
63
|
+
const block = {
|
|
64
|
+
type: "tool_result",
|
|
65
|
+
tool_use_id: item.call_id || "",
|
|
66
|
+
content: output,
|
|
67
|
+
};
|
|
68
|
+
return {
|
|
69
|
+
message: {
|
|
70
|
+
role: "user",
|
|
71
|
+
content: output,
|
|
72
|
+
contentBlocks: [block],
|
|
73
|
+
tokens,
|
|
74
|
+
},
|
|
75
|
+
tokens,
|
|
76
|
+
isSystem: false,
|
|
77
|
+
content: output,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
// reasoning → assistant thinking
|
|
81
|
+
if (type === "reasoning") {
|
|
82
|
+
const summary = Array.isArray(item.summary)
|
|
83
|
+
? item.summary.map((s) => s.text || "").join("\n")
|
|
84
|
+
: "";
|
|
85
|
+
const content = summary || "[reasoning]";
|
|
86
|
+
const tokens = estimateTokens(item);
|
|
87
|
+
return {
|
|
88
|
+
message: {
|
|
89
|
+
role: "assistant",
|
|
90
|
+
content,
|
|
91
|
+
contentBlocks: [{ type: "thinking", thinking: content }],
|
|
92
|
+
tokens,
|
|
93
|
+
},
|
|
94
|
+
tokens,
|
|
95
|
+
isSystem: false,
|
|
96
|
+
content,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
// output_text → assistant text
|
|
100
|
+
if (type === "output_text") {
|
|
101
|
+
const text = item.text || "";
|
|
102
|
+
const tokens = estimateTokens(text);
|
|
103
|
+
return {
|
|
104
|
+
message: {
|
|
105
|
+
role: "assistant",
|
|
106
|
+
content: text,
|
|
107
|
+
contentBlocks: [{ type: "text", text }],
|
|
108
|
+
tokens,
|
|
109
|
+
},
|
|
110
|
+
tokens,
|
|
111
|
+
isSystem: false,
|
|
112
|
+
content: text,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
// input_text → user text
|
|
116
|
+
if (type === "input_text") {
|
|
117
|
+
const text = item.text || "";
|
|
118
|
+
const tokens = estimateTokens(text);
|
|
119
|
+
return {
|
|
120
|
+
message: {
|
|
121
|
+
role: "user",
|
|
122
|
+
content: text,
|
|
123
|
+
contentBlocks: [{ type: "text", text }],
|
|
124
|
+
tokens,
|
|
125
|
+
},
|
|
126
|
+
tokens,
|
|
127
|
+
isSystem: false,
|
|
128
|
+
content: text,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
// Fallback: serialize the whole item
|
|
132
|
+
const content = JSON.stringify(item);
|
|
133
|
+
const tokens = estimateTokens(content);
|
|
134
|
+
return {
|
|
135
|
+
message: { role: item.role || "user", content, tokens },
|
|
136
|
+
tokens,
|
|
137
|
+
isSystem: false,
|
|
138
|
+
content,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Parse a request body and extract normalized context information.
|
|
143
|
+
*
|
|
144
|
+
* This is the core "shape-normalizer" for Context Lens. It supports:
|
|
145
|
+
* - Anthropic Messages API
|
|
146
|
+
* - OpenAI Responses API and Chat Completions
|
|
147
|
+
* - ChatGPT backend schema (Codex subscription traffic)
|
|
148
|
+
* - Gemini (including Code Assist wrappers)
|
|
149
|
+
*
|
|
150
|
+
* @param provider - Provider inferred from routing (anthropic/openai/gemini/chatgpt/unknown).
|
|
151
|
+
* @param body - Parsed JSON request body.
|
|
152
|
+
* @param apiFormat - API schema family inferred from routing.
|
|
153
|
+
* @returns A `ContextInfo` with token estimates and normalized messages/blocks.
|
|
154
|
+
*/
|
|
155
|
+
export function parseContextInfo(provider, body, apiFormat) {
|
|
156
|
+
const info = {
|
|
157
|
+
provider,
|
|
158
|
+
apiFormat,
|
|
159
|
+
model: body.model || "unknown",
|
|
160
|
+
systemTokens: 0,
|
|
161
|
+
toolsTokens: 0,
|
|
162
|
+
messagesTokens: 0,
|
|
163
|
+
totalTokens: 0,
|
|
164
|
+
systemPrompts: [],
|
|
165
|
+
tools: [],
|
|
166
|
+
messages: [],
|
|
167
|
+
};
|
|
168
|
+
if (provider === "anthropic") {
|
|
169
|
+
if (body.system) {
|
|
170
|
+
const systemText = typeof body.system === "string"
|
|
171
|
+
? body.system
|
|
172
|
+
: Array.isArray(body.system)
|
|
173
|
+
? body.system.map((b) => b.text || "").join("\n")
|
|
174
|
+
: JSON.stringify(body.system);
|
|
175
|
+
info.systemPrompts.push({ content: systemText });
|
|
176
|
+
info.systemTokens = estimateTokens(systemText);
|
|
177
|
+
}
|
|
178
|
+
if (body.tools && Array.isArray(body.tools)) {
|
|
179
|
+
info.tools = body.tools;
|
|
180
|
+
info.toolsTokens = estimateTokens(JSON.stringify(body.tools));
|
|
181
|
+
}
|
|
182
|
+
if (body.messages && Array.isArray(body.messages)) {
|
|
183
|
+
info.messages = body.messages.map((msg) => {
|
|
184
|
+
const contentBlocks = Array.isArray(msg.content) ? msg.content : null;
|
|
185
|
+
return {
|
|
186
|
+
role: msg.role,
|
|
187
|
+
content: typeof msg.content === "string"
|
|
188
|
+
? msg.content
|
|
189
|
+
: JSON.stringify(msg.content),
|
|
190
|
+
contentBlocks,
|
|
191
|
+
tokens: estimateTokens(msg.content),
|
|
192
|
+
};
|
|
193
|
+
});
|
|
194
|
+
info.messagesTokens = info.messages.reduce((sum, m) => sum + m.tokens, 0);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
else if (apiFormat === "responses" || provider === "chatgpt") {
|
|
198
|
+
if (body.instructions) {
|
|
199
|
+
info.systemPrompts.push({ content: body.instructions });
|
|
200
|
+
info.systemTokens = estimateTokens(body.instructions);
|
|
201
|
+
}
|
|
202
|
+
if (body.system) {
|
|
203
|
+
const systemText = typeof body.system === "string"
|
|
204
|
+
? body.system
|
|
205
|
+
: Array.isArray(body.system)
|
|
206
|
+
? body.system.map((b) => b.text || "").join("\n")
|
|
207
|
+
: JSON.stringify(body.system);
|
|
208
|
+
info.systemPrompts.push({ content: systemText });
|
|
209
|
+
info.systemTokens += estimateTokens(systemText);
|
|
210
|
+
}
|
|
211
|
+
const msgs = body.input || body.messages;
|
|
212
|
+
if (msgs) {
|
|
213
|
+
if (typeof msgs === "string") {
|
|
214
|
+
info.messages.push({
|
|
215
|
+
role: "user",
|
|
216
|
+
content: msgs,
|
|
217
|
+
tokens: estimateTokens(msgs),
|
|
218
|
+
});
|
|
219
|
+
info.messagesTokens = estimateTokens(msgs);
|
|
220
|
+
}
|
|
221
|
+
else if (Array.isArray(msgs)) {
|
|
222
|
+
msgs.forEach((item) => {
|
|
223
|
+
const parsed = parseResponsesItem(item);
|
|
224
|
+
if (parsed.isSystem) {
|
|
225
|
+
info.systemPrompts.push({ content: parsed.content });
|
|
226
|
+
info.systemTokens += parsed.tokens;
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
info.messages.push(parsed.message);
|
|
230
|
+
info.messagesTokens += parsed.tokens;
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (body.tools && Array.isArray(body.tools)) {
|
|
236
|
+
info.tools = body.tools;
|
|
237
|
+
info.toolsTokens = estimateTokens(JSON.stringify(body.tools));
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
else if (provider === "gemini" || apiFormat === "gemini") {
|
|
241
|
+
// Gemini API: contents[], systemInstruction, tools[{functionDeclarations}]
|
|
242
|
+
// Code Assist wraps everything inside body.request: {contents, systemInstruction, tools, ...}
|
|
243
|
+
const geminiBody = body.request || body;
|
|
244
|
+
if (geminiBody.systemInstruction) {
|
|
245
|
+
const parts = geminiBody.systemInstruction.parts || [];
|
|
246
|
+
const systemText = parts.map((p) => p.text || "").join("\n");
|
|
247
|
+
info.systemPrompts.push({ content: systemText });
|
|
248
|
+
info.systemTokens = estimateTokens(systemText);
|
|
249
|
+
}
|
|
250
|
+
if (geminiBody.tools && Array.isArray(geminiBody.tools)) {
|
|
251
|
+
const allDecls = geminiBody.tools.flatMap((t) => t.functionDeclarations || []);
|
|
252
|
+
info.tools = allDecls;
|
|
253
|
+
info.toolsTokens = estimateTokens(JSON.stringify(geminiBody.tools));
|
|
254
|
+
}
|
|
255
|
+
if (geminiBody.contents && Array.isArray(geminiBody.contents)) {
|
|
256
|
+
info.messages = geminiBody.contents.map((turn) => {
|
|
257
|
+
const role = turn.role || "user";
|
|
258
|
+
const parts = turn.parts || [];
|
|
259
|
+
const contentBlocks = [];
|
|
260
|
+
const textParts = [];
|
|
261
|
+
for (const part of parts) {
|
|
262
|
+
if (part.text) {
|
|
263
|
+
textParts.push(part.text);
|
|
264
|
+
contentBlocks.push({ type: "text", text: part.text });
|
|
265
|
+
}
|
|
266
|
+
else if (part.functionCall) {
|
|
267
|
+
contentBlocks.push({
|
|
268
|
+
type: "tool_use",
|
|
269
|
+
id: part.functionCall.id || "",
|
|
270
|
+
name: part.functionCall.name || "",
|
|
271
|
+
input: part.functionCall.args || {},
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
else if (part.functionResponse) {
|
|
275
|
+
const resp = part.functionResponse.response;
|
|
276
|
+
// Gemini CLI wraps tool output in {output: "..."} or {error: "..."}
|
|
277
|
+
const respText = typeof resp === "string"
|
|
278
|
+
? resp
|
|
279
|
+
: typeof resp?.output === "string"
|
|
280
|
+
? resp.output
|
|
281
|
+
: typeof resp?.error === "string"
|
|
282
|
+
? resp.error
|
|
283
|
+
: JSON.stringify(resp || "");
|
|
284
|
+
contentBlocks.push({
|
|
285
|
+
type: "tool_result",
|
|
286
|
+
tool_use_id: part.functionResponse.id || "",
|
|
287
|
+
content: respText,
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
else if (part.inlineData) {
|
|
291
|
+
contentBlocks.push({ type: "image" });
|
|
292
|
+
}
|
|
293
|
+
else if (part.executableCode) {
|
|
294
|
+
contentBlocks.push({
|
|
295
|
+
type: "text",
|
|
296
|
+
text: part.executableCode.code || "",
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
else if (part.codeExecutionResult) {
|
|
300
|
+
contentBlocks.push({
|
|
301
|
+
type: "text",
|
|
302
|
+
text: part.codeExecutionResult.output || "",
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
const content = textParts.join("\n") || JSON.stringify(parts);
|
|
307
|
+
const tokens = estimateTokens(turn);
|
|
308
|
+
return {
|
|
309
|
+
role: role === "model" ? "assistant" : role,
|
|
310
|
+
content,
|
|
311
|
+
contentBlocks,
|
|
312
|
+
tokens,
|
|
313
|
+
};
|
|
314
|
+
});
|
|
315
|
+
info.messagesTokens = info.messages.reduce((sum, m) => sum + m.tokens, 0);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
else if (provider === "openai") {
|
|
319
|
+
if (body.messages && Array.isArray(body.messages)) {
|
|
320
|
+
body.messages.forEach((msg) => {
|
|
321
|
+
if (msg.role === "system" || msg.role === "developer") {
|
|
322
|
+
info.systemPrompts.push({ content: msg.content });
|
|
323
|
+
info.systemTokens += estimateTokens(msg.content);
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
info.messages.push({
|
|
327
|
+
role: msg.role,
|
|
328
|
+
content: typeof msg.content === "string"
|
|
329
|
+
? msg.content
|
|
330
|
+
: JSON.stringify(msg.content),
|
|
331
|
+
tokens: estimateTokens(msg.content),
|
|
332
|
+
});
|
|
333
|
+
info.messagesTokens += estimateTokens(msg.content);
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
if (body.tools && Array.isArray(body.tools)) {
|
|
338
|
+
info.tools = body.tools;
|
|
339
|
+
info.toolsTokens = estimateTokens(JSON.stringify(body.tools));
|
|
340
|
+
}
|
|
341
|
+
else if (body.functions && Array.isArray(body.functions)) {
|
|
342
|
+
info.tools = body.functions;
|
|
343
|
+
info.toolsTokens = estimateTokens(JSON.stringify(body.functions));
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
info.totalTokens = info.systemTokens + info.toolsTokens + info.messagesTokens;
|
|
347
|
+
return info;
|
|
348
|
+
}
|
|
349
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/core/parse.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { ApiFormat, ExtractSourceResult, ParsedUrl, Provider, ResolveTargetResult, Upstreams } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* URL path segments that represent API resources rather than "source tool" prefixes.
|
|
4
|
+
*
|
|
5
|
+
* Example: `/v1/messages` should not treat `v1` as a source tag.
|
|
6
|
+
*/
|
|
7
|
+
export declare const API_PATH_SEGMENTS: Set<string>;
|
|
8
|
+
/**
|
|
9
|
+
* Infer provider based on request path + headers.
|
|
10
|
+
*
|
|
11
|
+
* This is used for routing (choosing which upstream base URL to use) and parsing.
|
|
12
|
+
*/
|
|
13
|
+
export declare function detectProvider(pathname: string, headers: Record<string, string | undefined>): Provider;
|
|
14
|
+
/**
|
|
15
|
+
* Infer the API "format" (schema family) from the request path.
|
|
16
|
+
*
|
|
17
|
+
* This is distinct from provider: e.g. OpenAI can be `responses` or `chat-completions`.
|
|
18
|
+
*/
|
|
19
|
+
export declare function detectApiFormat(pathname: string): ApiFormat;
|
|
20
|
+
/**
|
|
21
|
+
* Classify an incoming request into `{ provider, apiFormat }`.
|
|
22
|
+
*
|
|
23
|
+
* Keep all path/format heuristics in one place to avoid drift between
|
|
24
|
+
* routing decisions and parsing decisions.
|
|
25
|
+
*/
|
|
26
|
+
export declare function classifyRequest(pathname: string, headers: Record<string, string | undefined>): {
|
|
27
|
+
provider: Provider;
|
|
28
|
+
apiFormat: ApiFormat;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Extract a "source tool" tag from a request path.
|
|
32
|
+
*
|
|
33
|
+
* Example: `/claude/v1/messages` => `{ source: 'claude', cleanPath: '/v1/messages' }`.
|
|
34
|
+
*
|
|
35
|
+
* This tag is used for attribution in the UI/LHAR and for per-tool grouping.
|
|
36
|
+
*/
|
|
37
|
+
export declare function extractSource(pathname: string): ExtractSourceResult;
|
|
38
|
+
/**
|
|
39
|
+
* Determine the final upstream target URL for a request.
|
|
40
|
+
*
|
|
41
|
+
* @param parsedUrl - Path + query extracted from the incoming request.
|
|
42
|
+
* @param headers - Headers used for detection and optional override.
|
|
43
|
+
* @param upstreams - Base URLs for each provider.
|
|
44
|
+
* @returns `{ targetUrl, provider }`.
|
|
45
|
+
*/
|
|
46
|
+
export declare function resolveTargetUrl(parsedUrl: ParsedUrl, headers: Record<string, string | undefined>, upstreams: Upstreams): ResolveTargetResult;
|
|
47
|
+
//# sourceMappingURL=routing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../../src/core/routing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,mBAAmB,EACnB,SAAS,EACT,QAAQ,EACR,mBAAmB,EACnB,SAAS,EACV,MAAM,aAAa,CAAC;AAErB;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,aAW5B,CAAC;AAEH;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAC1C,QAAQ,CAEV;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAE3D;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAC1C;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,SAAS,CAAA;CAAE,CAiC9C;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,mBAAmB,CAqBnE;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,EAC3C,SAAS,EAAE,SAAS,GACnB,mBAAmB,CAsBrB"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URL path segments that represent API resources rather than "source tool" prefixes.
|
|
3
|
+
*
|
|
4
|
+
* Example: `/v1/messages` should not treat `v1` as a source tag.
|
|
5
|
+
*/
|
|
6
|
+
export const API_PATH_SEGMENTS = new Set([
|
|
7
|
+
"v1",
|
|
8
|
+
"v1beta",
|
|
9
|
+
"v1alpha",
|
|
10
|
+
"v1internal",
|
|
11
|
+
"responses",
|
|
12
|
+
"chat",
|
|
13
|
+
"models",
|
|
14
|
+
"embeddings",
|
|
15
|
+
"backend-api",
|
|
16
|
+
"api",
|
|
17
|
+
]);
|
|
18
|
+
/**
|
|
19
|
+
* Infer provider based on request path + headers.
|
|
20
|
+
*
|
|
21
|
+
* This is used for routing (choosing which upstream base URL to use) and parsing.
|
|
22
|
+
*/
|
|
23
|
+
export function detectProvider(pathname, headers) {
|
|
24
|
+
return classifyRequest(pathname, headers).provider;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Infer the API "format" (schema family) from the request path.
|
|
28
|
+
*
|
|
29
|
+
* This is distinct from provider: e.g. OpenAI can be `responses` or `chat-completions`.
|
|
30
|
+
*/
|
|
31
|
+
export function detectApiFormat(pathname) {
|
|
32
|
+
return classifyRequest(pathname, {}).apiFormat;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Classify an incoming request into `{ provider, apiFormat }`.
|
|
36
|
+
*
|
|
37
|
+
* Keep all path/format heuristics in one place to avoid drift between
|
|
38
|
+
* routing decisions and parsing decisions.
|
|
39
|
+
*/
|
|
40
|
+
export function classifyRequest(pathname, headers) {
|
|
41
|
+
// ChatGPT backend traffic (Codex subscription)
|
|
42
|
+
if (pathname.match(/^\/(api|backend-api)\//))
|
|
43
|
+
return { provider: "chatgpt", apiFormat: "chatgpt-backend" };
|
|
44
|
+
// Anthropic Messages API
|
|
45
|
+
if (pathname.includes("/v1/messages"))
|
|
46
|
+
return { provider: "anthropic", apiFormat: "anthropic-messages" };
|
|
47
|
+
if (pathname.includes("/v1/complete"))
|
|
48
|
+
return { provider: "anthropic", apiFormat: "unknown" };
|
|
49
|
+
if (headers["anthropic-version"])
|
|
50
|
+
return { provider: "anthropic", apiFormat: "unknown" };
|
|
51
|
+
// Gemini: must come BEFORE openai catch-all (which matches /models/)
|
|
52
|
+
const isGeminiPath = pathname.includes(":generateContent") ||
|
|
53
|
+
pathname.includes(":streamGenerateContent") ||
|
|
54
|
+
pathname.match(/\/v1(beta|alpha)\/models\//) ||
|
|
55
|
+
pathname.includes("/v1internal:");
|
|
56
|
+
if (isGeminiPath || headers["x-goog-api-key"])
|
|
57
|
+
return { provider: "gemini", apiFormat: "gemini" };
|
|
58
|
+
// OpenAI
|
|
59
|
+
if (pathname.includes("/responses"))
|
|
60
|
+
return { provider: "openai", apiFormat: "responses" };
|
|
61
|
+
if (pathname.includes("/chat/completions"))
|
|
62
|
+
return { provider: "openai", apiFormat: "chat-completions" };
|
|
63
|
+
if (pathname.match(/\/(models|embeddings)/))
|
|
64
|
+
return { provider: "openai", apiFormat: "unknown" };
|
|
65
|
+
if (headers.authorization?.startsWith("Bearer sk-"))
|
|
66
|
+
return { provider: "openai", apiFormat: "unknown" };
|
|
67
|
+
return { provider: "unknown", apiFormat: "unknown" };
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Extract a "source tool" tag from a request path.
|
|
71
|
+
*
|
|
72
|
+
* Example: `/claude/v1/messages` => `{ source: 'claude', cleanPath: '/v1/messages' }`.
|
|
73
|
+
*
|
|
74
|
+
* This tag is used for attribution in the UI/LHAR and for per-tool grouping.
|
|
75
|
+
*/
|
|
76
|
+
export function extractSource(pathname) {
|
|
77
|
+
const match = pathname.match(/^\/([^/]+)(\/.*)?$/);
|
|
78
|
+
if (match?.[2] && !API_PATH_SEGMENTS.has(match[1])) {
|
|
79
|
+
// `decodeURIComponent` may introduce `/` via `%2f` (path traversal) or throw on bad encodings.
|
|
80
|
+
// Treat suspicious/invalid tags as "no source tag" and route the request normally.
|
|
81
|
+
let decoded = match[1];
|
|
82
|
+
try {
|
|
83
|
+
decoded = decodeURIComponent(match[1]);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
decoded = match[1];
|
|
87
|
+
}
|
|
88
|
+
if (decoded.includes("/") ||
|
|
89
|
+
decoded.includes("\\") ||
|
|
90
|
+
decoded.includes("..")) {
|
|
91
|
+
return { source: null, cleanPath: pathname };
|
|
92
|
+
}
|
|
93
|
+
return { source: decoded, cleanPath: match[2] || "/" };
|
|
94
|
+
}
|
|
95
|
+
return { source: null, cleanPath: pathname };
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Determine the final upstream target URL for a request.
|
|
99
|
+
*
|
|
100
|
+
* @param parsedUrl - Path + query extracted from the incoming request.
|
|
101
|
+
* @param headers - Headers used for detection and optional override.
|
|
102
|
+
* @param upstreams - Base URLs for each provider.
|
|
103
|
+
* @returns `{ targetUrl, provider }`.
|
|
104
|
+
*/
|
|
105
|
+
export function resolveTargetUrl(parsedUrl, headers, upstreams) {
|
|
106
|
+
const provider = classifyRequest(parsedUrl.pathname, headers).provider;
|
|
107
|
+
const search = parsedUrl.search || "";
|
|
108
|
+
let targetUrl = headers["x-target-url"];
|
|
109
|
+
if (!targetUrl) {
|
|
110
|
+
if (provider === "chatgpt") {
|
|
111
|
+
targetUrl = upstreams.chatgpt + parsedUrl.pathname + search;
|
|
112
|
+
}
|
|
113
|
+
else if (provider === "anthropic") {
|
|
114
|
+
targetUrl = upstreams.anthropic + parsedUrl.pathname + search;
|
|
115
|
+
}
|
|
116
|
+
else if (provider === "gemini") {
|
|
117
|
+
const isCodeAssist = parsedUrl.pathname.includes("/v1internal");
|
|
118
|
+
targetUrl =
|
|
119
|
+
(isCodeAssist ? upstreams.geminiCodeAssist : upstreams.gemini) +
|
|
120
|
+
parsedUrl.pathname +
|
|
121
|
+
search;
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
targetUrl = upstreams.openai + parsedUrl.pathname + search;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
else if (!targetUrl.startsWith("http")) {
|
|
128
|
+
targetUrl = targetUrl + parsedUrl.pathname + search;
|
|
129
|
+
}
|
|
130
|
+
return { targetUrl, provider };
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=routing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routing.js","sourceRoot":"","sources":["../../src/core/routing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ContextInfo, HeaderSignature, SourceSignature } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Header signatures used to infer which CLI/tool produced a request.
|
|
4
|
+
*
|
|
5
|
+
* This is best-effort: many tools do not have stable identifiers.
|
|
6
|
+
*/
|
|
7
|
+
export declare const HEADER_SIGNATURES: HeaderSignature[];
|
|
8
|
+
/**
|
|
9
|
+
* System-prompt signatures used as a fallback when headers are missing/ambiguous.
|
|
10
|
+
*/
|
|
11
|
+
export declare const SOURCE_SIGNATURES: SourceSignature[];
|
|
12
|
+
/**
|
|
13
|
+
* Infer a human-friendly "source tool" label (claude/codex/gemini/aider/...) for attribution.
|
|
14
|
+
*
|
|
15
|
+
* Priority:
|
|
16
|
+
* 1. explicit source tag if provided and not `"unknown"`
|
|
17
|
+
* 2. request header signatures
|
|
18
|
+
* 3. system prompt signatures
|
|
19
|
+
* 4. fallback to `"unknown"`
|
|
20
|
+
*/
|
|
21
|
+
export declare function detectSource(contextInfo: ContextInfo, source: string | null, headers?: Record<string, string>): string;
|
|
22
|
+
//# sourceMappingURL=source.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../src/core/source.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,eAAe,EACf,eAAe,EAChB,MAAM,aAAa,CAAC;AAErB;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,eAAe,EAK9C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,EAAE,eAAe,EAK9C,CAAC;AAEF;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,WAAW,EAAE,WAAW,EACxB,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,MAAM,CA0BR"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Header signatures used to infer which CLI/tool produced a request.
|
|
3
|
+
*
|
|
4
|
+
* This is best-effort: many tools do not have stable identifiers.
|
|
5
|
+
*/
|
|
6
|
+
export const HEADER_SIGNATURES = [
|
|
7
|
+
{ header: "user-agent", pattern: /^claude-cli\//, source: "claude" },
|
|
8
|
+
{ header: "user-agent", pattern: /aider/i, source: "aider" },
|
|
9
|
+
{ header: "user-agent", pattern: /kimi/i, source: "kimi" },
|
|
10
|
+
{ header: "user-agent", pattern: /^GeminiCLI\//, source: "gemini" },
|
|
11
|
+
];
|
|
12
|
+
/**
|
|
13
|
+
* System-prompt signatures used as a fallback when headers are missing/ambiguous.
|
|
14
|
+
*/
|
|
15
|
+
export const SOURCE_SIGNATURES = [
|
|
16
|
+
{ pattern: "Act as an expert software developer", source: "aider" },
|
|
17
|
+
{ pattern: "You are Claude Code", source: "claude" },
|
|
18
|
+
{ pattern: "You are Kimi Code CLI", source: "kimi" },
|
|
19
|
+
{ pattern: "operating inside pi, a coding agent harness", source: "pi" },
|
|
20
|
+
];
|
|
21
|
+
/**
|
|
22
|
+
* Infer a human-friendly "source tool" label (claude/codex/gemini/aider/...) for attribution.
|
|
23
|
+
*
|
|
24
|
+
* Priority:
|
|
25
|
+
* 1. explicit source tag if provided and not `"unknown"`
|
|
26
|
+
* 2. request header signatures
|
|
27
|
+
* 3. system prompt signatures
|
|
28
|
+
* 4. fallback to `"unknown"`
|
|
29
|
+
*/
|
|
30
|
+
export function detectSource(contextInfo, source, headers) {
|
|
31
|
+
if (source && source !== "unknown")
|
|
32
|
+
return source;
|
|
33
|
+
// Primary: check request headers
|
|
34
|
+
if (headers) {
|
|
35
|
+
for (const sig of HEADER_SIGNATURES) {
|
|
36
|
+
const val = headers[sig.header];
|
|
37
|
+
if (!val)
|
|
38
|
+
continue;
|
|
39
|
+
if (sig.pattern instanceof RegExp
|
|
40
|
+
? sig.pattern.test(val)
|
|
41
|
+
: val.includes(sig.pattern)) {
|
|
42
|
+
return sig.source;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// Fallback: check system prompt content
|
|
47
|
+
const systemText = (contextInfo.systemPrompts || [])
|
|
48
|
+
.map((sp) => sp.content)
|
|
49
|
+
.join("\n");
|
|
50
|
+
for (const sig of SOURCE_SIGNATURES) {
|
|
51
|
+
if (systemText.includes(sig.pattern))
|
|
52
|
+
return sig.source;
|
|
53
|
+
}
|
|
54
|
+
return source || "unknown";
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source.js","sourceRoot":"","sources":["../../src/core/source.ts"],"names":[],"mappings":"AAMA;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAsB;IAClD,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,QAAQ,EAAE;IACpE,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE;IAC5D,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE;IAC1D,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,QAAQ,EAAE;CACpE,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAsB;IAClD,EAAE,OAAO,EAAE,qCAAqC,EAAE,MAAM,EAAE,OAAO,EAAE;IACnE,EAAE,OAAO,EAAE,qBAAqB,EAAE,MAAM,EAAE,QAAQ,EAAE;IACpD,EAAE,OAAO,EAAE,uBAAuB,EAAE,MAAM,EAAE,MAAM,EAAE;IACpD,EAAE,OAAO,EAAE,6CAA6C,EAAE,MAAM,EAAE,IAAI,EAAE;CACzE,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAC1B,WAAwB,EACxB,MAAqB,EACrB,OAAgC;IAEhC,IAAI,MAAM,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IAElD,iCAAiC;IACjC,IAAI,OAAO,EAAE,CAAC;QACZ,KAAK,MAAM,GAAG,IAAI,iBAAiB,EAAE,CAAC;YACpC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAChC,IAAI,CAAC,GAAG;gBAAE,SAAS;YACnB,IACE,GAAG,CAAC,OAAO,YAAY,MAAM;gBAC3B,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC;gBACvB,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAC7B,CAAC;gBACD,OAAO,GAAG,CAAC,MAAM,CAAC;YACpB,CAAC;QACH,CAAC;IACH,CAAC;IAED,wCAAwC;IACxC,MAAM,UAAU,GAAG,CAAC,WAAW,CAAC,aAAa,IAAI,EAAE,CAAC;SACjD,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC;SACvB,IAAI,CAAC,IAAI,CAAC,CAAC;IACd,KAAK,MAAM,GAAG,IAAI,iBAAiB,EAAE,CAAC;QACpC,IAAI,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC;YAAE,OAAO,GAAG,CAAC,MAAM,CAAC;IAC1D,CAAC;IACD,OAAO,MAAM,IAAI,SAAS,CAAC;AAC7B,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight token estimator used throughout Context Lens.
|
|
3
|
+
*
|
|
4
|
+
* This is intentionally simple and model-agnostic: we approximate tokens as `ceil(chars / 4)`.
|
|
5
|
+
* It is good enough for rough context utilization and relative comparisons.
|
|
6
|
+
*
|
|
7
|
+
* @param text - Value to estimate tokens for. Objects are stringified as JSON.
|
|
8
|
+
* @returns Estimated token count (>= 0).
|
|
9
|
+
*/
|
|
10
|
+
export declare function estimateTokens(text: unknown): number;
|
|
11
|
+
//# sourceMappingURL=tokens.d.ts.map
|