@roberttlange/agentlens 0.2.2 → 0.2.3
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/node_modules/@agentlens/contracts/dist/index.d.ts +11 -0
- package/node_modules/@agentlens/core/dist/__tests__/config.test.js +49 -2
- package/node_modules/@agentlens/core/dist/__tests__/config.test.js.map +1 -1
- package/node_modules/@agentlens/core/dist/__tests__/index.test.js +220 -0
- package/node_modules/@agentlens/core/dist/__tests__/index.test.js.map +1 -1
- package/node_modules/@agentlens/core/dist/config.js +62 -5
- package/node_modules/@agentlens/core/dist/config.js.map +1 -1
- package/node_modules/@agentlens/core/dist/generatedPricing.d.ts +3 -0
- package/node_modules/@agentlens/core/dist/generatedPricing.js +131 -0
- package/node_modules/@agentlens/core/dist/generatedPricing.js.map +1 -0
- package/node_modules/@agentlens/core/dist/metrics.js +131 -54
- package/node_modules/@agentlens/core/dist/metrics.js.map +1 -1
- package/node_modules/@agentlens/core/dist/pricing.d.ts +15 -0
- package/node_modules/@agentlens/core/dist/pricing.js +133 -0
- package/node_modules/@agentlens/core/dist/pricing.js.map +1 -0
- package/node_modules/@agentlens/core/dist/pricing.test.d.ts +1 -0
- package/node_modules/@agentlens/core/dist/pricing.test.js +109 -0
- package/node_modules/@agentlens/core/dist/pricing.test.js.map +1 -0
- package/node_modules/@agentlens/core/dist/sourceProfiles.js +3 -67
- package/node_modules/@agentlens/core/dist/sourceProfiles.js.map +1 -1
- package/node_modules/@agentlens/core/dist/traceIndex.d.ts +12 -0
- package/node_modules/@agentlens/core/dist/traceIndex.js +58 -0
- package/node_modules/@agentlens/core/dist/traceIndex.js.map +1 -1
- package/node_modules/@agentlens/server/dist/activity-cache.d.ts +29 -0
- package/node_modules/@agentlens/server/dist/activity-cache.js +57 -0
- package/node_modules/@agentlens/server/dist/activity-cache.js.map +1 -0
- package/node_modules/@agentlens/server/dist/activity-cache.test.d.ts +1 -0
- package/node_modules/@agentlens/server/dist/activity-cache.test.js +84 -0
- package/node_modules/@agentlens/server/dist/activity-cache.test.js.map +1 -0
- package/node_modules/@agentlens/server/dist/activity.d.ts +12 -1
- package/node_modules/@agentlens/server/dist/activity.js +56 -34
- package/node_modules/@agentlens/server/dist/activity.js.map +1 -1
- package/node_modules/@agentlens/server/dist/app.js +6 -0
- package/node_modules/@agentlens/server/dist/app.js.map +1 -1
- package/node_modules/@agentlens/server/dist/app.test.js +1 -1
- package/node_modules/@agentlens/server/dist/app.test.js.map +1 -1
- package/node_modules/@agentlens/server/dist/web/assets/index-DjwZvHl6.css +1 -0
- package/node_modules/@agentlens/server/dist/web/assets/index-Ei_qfgA9.js +52 -0
- package/node_modules/@agentlens/server/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/node_modules/@agentlens/server/dist/web/assets/index-Ci8okH8M.js +0 -52
- package/node_modules/@agentlens/server/dist/web/assets/index-Cj3kmsFf.css +0 -1
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
function normalizedLookupCandidates(model) {
|
|
2
|
+
const raw = String(model).trim();
|
|
3
|
+
if (!raw)
|
|
4
|
+
return [];
|
|
5
|
+
const normalized = normalizePricingModelId(raw);
|
|
6
|
+
return normalized === raw ? [raw] : [raw, normalized];
|
|
7
|
+
}
|
|
8
|
+
function findCostRate(model, costConfig) {
|
|
9
|
+
const candidates = normalizedLookupCandidates(model);
|
|
10
|
+
for (const candidate of candidates) {
|
|
11
|
+
const match = costConfig.modelRates.find((rate) => rate.model === candidate);
|
|
12
|
+
if (match)
|
|
13
|
+
return match;
|
|
14
|
+
}
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
function pickActiveRate(rate, promptTokens) {
|
|
18
|
+
const useLongContext = typeof rate.longContextThresholdTokens === "number" &&
|
|
19
|
+
Number.isFinite(rate.longContextThresholdTokens) &&
|
|
20
|
+
rate.longContextThresholdTokens > 0 &&
|
|
21
|
+
promptTokens > rate.longContextThresholdTokens;
|
|
22
|
+
if (!useLongContext) {
|
|
23
|
+
const activeRate = {
|
|
24
|
+
inputPer1MUsd: rate.inputPer1MUsd,
|
|
25
|
+
outputPer1MUsd: rate.outputPer1MUsd,
|
|
26
|
+
cachedReadPer1MUsd: rate.cachedReadPer1MUsd,
|
|
27
|
+
cachedCreatePer1MUsd: rate.cachedCreatePer1MUsd,
|
|
28
|
+
reasoningOutputPer1MUsd: rate.reasoningOutputPer1MUsd,
|
|
29
|
+
};
|
|
30
|
+
if (typeof rate.cachedCreate5mPer1MUsd === "number")
|
|
31
|
+
activeRate.cachedCreate5mPer1MUsd = rate.cachedCreate5mPer1MUsd;
|
|
32
|
+
if (typeof rate.cachedCreate1hPer1MUsd === "number")
|
|
33
|
+
activeRate.cachedCreate1hPer1MUsd = rate.cachedCreate1hPer1MUsd;
|
|
34
|
+
return activeRate;
|
|
35
|
+
}
|
|
36
|
+
const activeRate = {
|
|
37
|
+
inputPer1MUsd: rate.longContextInputPer1MUsd ?? rate.inputPer1MUsd,
|
|
38
|
+
outputPer1MUsd: rate.longContextOutputPer1MUsd ?? rate.outputPer1MUsd,
|
|
39
|
+
cachedReadPer1MUsd: rate.longContextCachedReadPer1MUsd ?? rate.cachedReadPer1MUsd,
|
|
40
|
+
cachedCreatePer1MUsd: rate.longContextCachedCreatePer1MUsd ?? rate.cachedCreatePer1MUsd,
|
|
41
|
+
reasoningOutputPer1MUsd: rate.longContextReasoningOutputPer1MUsd ?? rate.reasoningOutputPer1MUsd,
|
|
42
|
+
};
|
|
43
|
+
const cachedCreate5mPer1MUsd = rate.longContextCachedCreate5mPer1MUsd ?? rate.cachedCreate5mPer1MUsd;
|
|
44
|
+
if (typeof cachedCreate5mPer1MUsd === "number")
|
|
45
|
+
activeRate.cachedCreate5mPer1MUsd = cachedCreate5mPer1MUsd;
|
|
46
|
+
const cachedCreate1hPer1MUsd = rate.longContextCachedCreate1hPer1MUsd ?? rate.cachedCreate1hPer1MUsd;
|
|
47
|
+
if (typeof cachedCreate1hPer1MUsd === "number")
|
|
48
|
+
activeRate.cachedCreate1hPer1MUsd = cachedCreate1hPer1MUsd;
|
|
49
|
+
return activeRate;
|
|
50
|
+
}
|
|
51
|
+
function estimateCachedCreateCost(usage, rate) {
|
|
52
|
+
const cachedCreate5mTokens = usage.cachedCreate5mTokens ?? 0;
|
|
53
|
+
const cachedCreate1hTokens = usage.cachedCreate1hTokens ?? 0;
|
|
54
|
+
const splitKnownTokens = Math.max(0, cachedCreate5mTokens) + Math.max(0, cachedCreate1hTokens);
|
|
55
|
+
const aggregateTokens = Math.max(0, usage.cachedCreateTokens);
|
|
56
|
+
const remainingAggregateTokens = Math.max(0, aggregateTokens - splitKnownTokens);
|
|
57
|
+
let total = 0;
|
|
58
|
+
if (cachedCreate5mTokens > 0) {
|
|
59
|
+
total +=
|
|
60
|
+
(cachedCreate5mTokens / 1_000_000) * (rate.cachedCreate5mPer1MUsd ?? rate.cachedCreatePer1MUsd);
|
|
61
|
+
}
|
|
62
|
+
if (cachedCreate1hTokens > 0) {
|
|
63
|
+
total +=
|
|
64
|
+
(cachedCreate1hTokens / 1_000_000) * (rate.cachedCreate1hPer1MUsd ?? rate.cachedCreatePer1MUsd);
|
|
65
|
+
}
|
|
66
|
+
if (remainingAggregateTokens > 0) {
|
|
67
|
+
total += (remainingAggregateTokens / 1_000_000) * rate.cachedCreatePer1MUsd;
|
|
68
|
+
}
|
|
69
|
+
return total;
|
|
70
|
+
}
|
|
71
|
+
export function estimateUsageCost(usage, costConfig) {
|
|
72
|
+
if (!costConfig.enabled)
|
|
73
|
+
return null;
|
|
74
|
+
const rate = findCostRate(usage.model, costConfig);
|
|
75
|
+
if (!rate) {
|
|
76
|
+
return costConfig.unknownModelPolicy === "zero" ? 0 : null;
|
|
77
|
+
}
|
|
78
|
+
const activeRate = pickActiveRate(rate, usage.promptTokens);
|
|
79
|
+
const total = (Math.max(0, usage.inputTokens) / 1_000_000) * activeRate.inputPer1MUsd +
|
|
80
|
+
(Math.max(0, usage.cachedReadTokens) / 1_000_000) * activeRate.cachedReadPer1MUsd +
|
|
81
|
+
estimateCachedCreateCost(usage, activeRate) +
|
|
82
|
+
(Math.max(0, usage.outputTokens) / 1_000_000) * activeRate.outputPer1MUsd +
|
|
83
|
+
(Math.max(0, usage.reasoningOutputTokens) / 1_000_000) * activeRate.reasoningOutputPer1MUsd;
|
|
84
|
+
return Number(total.toFixed(6));
|
|
85
|
+
}
|
|
86
|
+
export function normalizePricingModelId(model) {
|
|
87
|
+
let normalized = String(model).trim().toLowerCase();
|
|
88
|
+
if (!normalized)
|
|
89
|
+
return "";
|
|
90
|
+
normalized = normalized.replace(/^global\.anthropic\./, "");
|
|
91
|
+
normalized = normalized.replace(/^anthropic\//, "");
|
|
92
|
+
normalized = normalized.replace(/^openai\//, "");
|
|
93
|
+
normalized = normalized.replace(/-v\d+(?::\d+)?$/, "");
|
|
94
|
+
if (normalized.includes("/")) {
|
|
95
|
+
const tail = normalized.split("/").at(-1)?.trim() ?? normalized;
|
|
96
|
+
if (tail.startsWith("claude-") || tail.startsWith("gpt-"))
|
|
97
|
+
normalized = tail;
|
|
98
|
+
}
|
|
99
|
+
const claudeMatch = normalized.match(/^claude-(haiku|sonnet|opus)-4-(5|6)(?:-\d{8})?$/);
|
|
100
|
+
if (claudeMatch)
|
|
101
|
+
return `claude-${claudeMatch[1]}-4.${claudeMatch[2]}`;
|
|
102
|
+
const gpt54Match = normalized.match(/^gpt-5\.4(?:-\d{4}-\d{2}-\d{2})?$/);
|
|
103
|
+
if (gpt54Match)
|
|
104
|
+
return "gpt-5.4";
|
|
105
|
+
const gpt53CodexMatch = normalized.match(/^gpt-5\.3-codex(?:-\d{4}-\d{2}-\d{2})?$/);
|
|
106
|
+
if (gpt53CodexMatch)
|
|
107
|
+
return "gpt-5.3-codex";
|
|
108
|
+
const gpt52CodexMatch = normalized.match(/^gpt-5\.2-codex(?:-\d{4}-\d{2}-\d{2})?$/);
|
|
109
|
+
if (gpt52CodexMatch)
|
|
110
|
+
return "gpt-5.2-codex";
|
|
111
|
+
const gpt52Match = normalized.match(/^gpt-5\.2(?:-\d{4}-\d{2}-\d{2})?$/);
|
|
112
|
+
if (gpt52Match)
|
|
113
|
+
return "gpt-5.2";
|
|
114
|
+
return normalized;
|
|
115
|
+
}
|
|
116
|
+
export function resolveContextWindowTokens(model, config) {
|
|
117
|
+
const rawModel = String(model).trim();
|
|
118
|
+
const normalizedModel = normalizePricingModelId(rawModel);
|
|
119
|
+
for (const candidate of [rawModel, normalizedModel]) {
|
|
120
|
+
if (!candidate)
|
|
121
|
+
continue;
|
|
122
|
+
const direct = config.models.contextWindows.find((entry) => entry.model === candidate);
|
|
123
|
+
if (direct && Number.isFinite(direct.contextWindowTokens) && direct.contextWindowTokens > 0) {
|
|
124
|
+
return direct.contextWindowTokens;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const rate = findCostRate(rawModel || normalizedModel, config.cost);
|
|
128
|
+
if (rate && Number.isFinite(rate.contextWindowTokens) && (rate.contextWindowTokens ?? 0) > 0) {
|
|
129
|
+
return rate.contextWindowTokens ?? 0;
|
|
130
|
+
}
|
|
131
|
+
return config.models.defaultContextWindowTokens > 0 ? config.models.defaultContextWindowTokens : 0;
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=pricing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pricing.js","sourceRoot":"","sources":["../src/pricing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { mergeConfig } from "./config.js";
|
|
3
|
+
import { estimateUsageCost, normalizePricingModelId } from "./pricing.js";
|
|
4
|
+
describe("pricing", () => {
|
|
5
|
+
it("normalizes observed Anthropic and OpenAI model ids to canonical pricing keys", () => {
|
|
6
|
+
expect(normalizePricingModelId("global.anthropic.claude-opus-4-6-v1")).toBe("claude-opus-4.6");
|
|
7
|
+
expect(normalizePricingModelId("global.anthropic.claude-haiku-4-5-20251001-v1:0")).toBe("claude-haiku-4.5");
|
|
8
|
+
expect(normalizePricingModelId("claude-sonnet-4-6-20260219")).toBe("claude-sonnet-4.6");
|
|
9
|
+
expect(normalizePricingModelId("openai/gpt-5.4-2026-02-28")).toBe("gpt-5.4");
|
|
10
|
+
expect(normalizePricingModelId("gpt-5.3-codex")).toBe("gpt-5.3-codex");
|
|
11
|
+
});
|
|
12
|
+
it("uses Anthropic split cache write pricing and long-context premiums", () => {
|
|
13
|
+
const config = mergeConfig({
|
|
14
|
+
cost: {
|
|
15
|
+
enabled: true,
|
|
16
|
+
currency: "USD",
|
|
17
|
+
unknownModelPolicy: "n_a",
|
|
18
|
+
modelRates: [
|
|
19
|
+
{
|
|
20
|
+
model: "claude-sonnet-4.6",
|
|
21
|
+
inputPer1MUsd: 3,
|
|
22
|
+
outputPer1MUsd: 15,
|
|
23
|
+
cachedReadPer1MUsd: 0.3,
|
|
24
|
+
cachedCreatePer1MUsd: 3.75,
|
|
25
|
+
cachedCreate5mPer1MUsd: 3.75,
|
|
26
|
+
cachedCreate1hPer1MUsd: 6,
|
|
27
|
+
reasoningOutputPer1MUsd: 0,
|
|
28
|
+
longContextThresholdTokens: 200_000,
|
|
29
|
+
longContextInputPer1MUsd: 6,
|
|
30
|
+
longContextOutputPer1MUsd: 22.5,
|
|
31
|
+
longContextCachedReadPer1MUsd: 0.6,
|
|
32
|
+
longContextCachedCreatePer1MUsd: 7.5,
|
|
33
|
+
longContextCachedCreate5mPer1MUsd: 7.5,
|
|
34
|
+
longContextCachedCreate1hPer1MUsd: 12,
|
|
35
|
+
contextWindowTokens: 1_000_000,
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
const baseCost = estimateUsageCost({
|
|
41
|
+
model: "claude-sonnet-4-6-20260219",
|
|
42
|
+
promptTokens: 150_000,
|
|
43
|
+
inputTokens: 100_000,
|
|
44
|
+
cachedReadTokens: 20_000,
|
|
45
|
+
cachedCreateTokens: 10_000,
|
|
46
|
+
cachedCreate5mTokens: 8_000,
|
|
47
|
+
cachedCreate1hTokens: 2_000,
|
|
48
|
+
outputTokens: 50_000,
|
|
49
|
+
reasoningOutputTokens: 0,
|
|
50
|
+
}, config.cost);
|
|
51
|
+
const longCost = estimateUsageCost({
|
|
52
|
+
model: "claude-sonnet-4-6-20260219",
|
|
53
|
+
promptTokens: 250_000,
|
|
54
|
+
inputTokens: 100_000,
|
|
55
|
+
cachedReadTokens: 20_000,
|
|
56
|
+
cachedCreateTokens: 10_000,
|
|
57
|
+
cachedCreate5mTokens: 8_000,
|
|
58
|
+
cachedCreate1hTokens: 2_000,
|
|
59
|
+
outputTokens: 50_000,
|
|
60
|
+
reasoningOutputTokens: 0,
|
|
61
|
+
}, config.cost);
|
|
62
|
+
expect(baseCost).toBe(1.098);
|
|
63
|
+
expect(longCost).toBe(1.821);
|
|
64
|
+
});
|
|
65
|
+
it("applies GPT-5.4 premium pricing only above the long-context threshold", () => {
|
|
66
|
+
const config = mergeConfig({
|
|
67
|
+
cost: {
|
|
68
|
+
enabled: true,
|
|
69
|
+
currency: "USD",
|
|
70
|
+
unknownModelPolicy: "n_a",
|
|
71
|
+
modelRates: [
|
|
72
|
+
{
|
|
73
|
+
model: "gpt-5.4",
|
|
74
|
+
inputPer1MUsd: 1.25,
|
|
75
|
+
outputPer1MUsd: 7.5,
|
|
76
|
+
cachedReadPer1MUsd: 0.125,
|
|
77
|
+
cachedCreatePer1MUsd: 0,
|
|
78
|
+
reasoningOutputPer1MUsd: 0,
|
|
79
|
+
longContextThresholdTokens: 272_000,
|
|
80
|
+
longContextInputPer1MUsd: 2.5,
|
|
81
|
+
longContextOutputPer1MUsd: 11.25,
|
|
82
|
+
contextWindowTokens: 1_050_000,
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
const shortCost = estimateUsageCost({
|
|
88
|
+
model: "gpt-5.4-2026-02-28",
|
|
89
|
+
promptTokens: 200_000,
|
|
90
|
+
inputTokens: 180_000,
|
|
91
|
+
cachedReadTokens: 20_000,
|
|
92
|
+
cachedCreateTokens: 0,
|
|
93
|
+
outputTokens: 40_000,
|
|
94
|
+
reasoningOutputTokens: 0,
|
|
95
|
+
}, config.cost);
|
|
96
|
+
const longCost = estimateUsageCost({
|
|
97
|
+
model: "gpt-5.4-2026-02-28",
|
|
98
|
+
promptTokens: 300_000,
|
|
99
|
+
inputTokens: 180_000,
|
|
100
|
+
cachedReadTokens: 20_000,
|
|
101
|
+
cachedCreateTokens: 0,
|
|
102
|
+
outputTokens: 40_000,
|
|
103
|
+
reasoningOutputTokens: 0,
|
|
104
|
+
}, config.cost);
|
|
105
|
+
expect(shortCost).toBe(0.5275);
|
|
106
|
+
expect(longCost).toBe(0.9025);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
//# sourceMappingURL=pricing.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pricing.test.js","sourceRoot":"","sources":["../src/pricing.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DEFAULT_CONTEXT_WINDOWS, DEFAULT_PRICING_MODEL_RATES } from "./generatedPricing.js";
|
|
1
2
|
export const DEFAULT_SESSION_LOG_DIRECTORIES = [
|
|
2
3
|
{ directory: "~/.codex", logType: "codex" },
|
|
3
4
|
{ directory: "~/.claude", logType: "claude" },
|
|
@@ -111,76 +112,11 @@ export const DEFAULT_CONFIG = {
|
|
|
111
112
|
enabled: true,
|
|
112
113
|
currency: "USD",
|
|
113
114
|
unknownModelPolicy: "n_a",
|
|
114
|
-
modelRates:
|
|
115
|
-
{
|
|
116
|
-
model: "gpt-5.2-codex",
|
|
117
|
-
inputPer1MUsd: 1.5,
|
|
118
|
-
outputPer1MUsd: 6,
|
|
119
|
-
cachedReadPer1MUsd: 0.375,
|
|
120
|
-
cachedCreatePer1MUsd: 0.375,
|
|
121
|
-
reasoningOutputPer1MUsd: 0,
|
|
122
|
-
},
|
|
123
|
-
{
|
|
124
|
-
model: "gpt-5.3-codex",
|
|
125
|
-
inputPer1MUsd: 1.5,
|
|
126
|
-
outputPer1MUsd: 6,
|
|
127
|
-
cachedReadPer1MUsd: 0.375,
|
|
128
|
-
cachedCreatePer1MUsd: 0.375,
|
|
129
|
-
reasoningOutputPer1MUsd: 0,
|
|
130
|
-
},
|
|
131
|
-
{
|
|
132
|
-
model: "gpt-5.2",
|
|
133
|
-
inputPer1MUsd: 1.75,
|
|
134
|
-
outputPer1MUsd: 14,
|
|
135
|
-
cachedReadPer1MUsd: 0.175,
|
|
136
|
-
cachedCreatePer1MUsd: 0.175,
|
|
137
|
-
reasoningOutputPer1MUsd: 0,
|
|
138
|
-
},
|
|
139
|
-
{
|
|
140
|
-
model: "claude-opus-4-5-20251101",
|
|
141
|
-
inputPer1MUsd: 5,
|
|
142
|
-
outputPer1MUsd: 25,
|
|
143
|
-
cachedReadPer1MUsd: 0.5,
|
|
144
|
-
cachedCreatePer1MUsd: 6.25,
|
|
145
|
-
reasoningOutputPer1MUsd: 0,
|
|
146
|
-
},
|
|
147
|
-
{
|
|
148
|
-
model: "claude-opus-4-6",
|
|
149
|
-
inputPer1MUsd: 5,
|
|
150
|
-
outputPer1MUsd: 25,
|
|
151
|
-
cachedReadPer1MUsd: 0.5,
|
|
152
|
-
cachedCreatePer1MUsd: 6.25,
|
|
153
|
-
reasoningOutputPer1MUsd: 0,
|
|
154
|
-
},
|
|
155
|
-
{
|
|
156
|
-
model: "claude-sonnet-4-5-20250929",
|
|
157
|
-
inputPer1MUsd: 3,
|
|
158
|
-
outputPer1MUsd: 15,
|
|
159
|
-
cachedReadPer1MUsd: 0.3,
|
|
160
|
-
cachedCreatePer1MUsd: 3.75,
|
|
161
|
-
reasoningOutputPer1MUsd: 0,
|
|
162
|
-
},
|
|
163
|
-
{
|
|
164
|
-
model: "claude-haiku-4-5-20251001",
|
|
165
|
-
inputPer1MUsd: 1,
|
|
166
|
-
outputPer1MUsd: 5,
|
|
167
|
-
cachedReadPer1MUsd: 0.1,
|
|
168
|
-
cachedCreatePer1MUsd: 1.25,
|
|
169
|
-
reasoningOutputPer1MUsd: 0,
|
|
170
|
-
},
|
|
171
|
-
],
|
|
115
|
+
modelRates: DEFAULT_PRICING_MODEL_RATES,
|
|
172
116
|
},
|
|
173
117
|
models: {
|
|
174
118
|
defaultContextWindowTokens: 200_000,
|
|
175
|
-
contextWindows:
|
|
176
|
-
{ model: "gpt-5.2-codex", contextWindowTokens: 400_000 },
|
|
177
|
-
{ model: "gpt-5.3-codex", contextWindowTokens: 400_000 },
|
|
178
|
-
{ model: "gpt-5.2", contextWindowTokens: 400_000 },
|
|
179
|
-
{ model: "claude-opus-4-5-20251101", contextWindowTokens: 200_000 },
|
|
180
|
-
{ model: "claude-opus-4-6", contextWindowTokens: 200_000 },
|
|
181
|
-
{ model: "claude-sonnet-4-5-20250929", contextWindowTokens: 200_000 },
|
|
182
|
-
{ model: "claude-haiku-4-5-20251001", contextWindowTokens: 200_000 },
|
|
183
|
-
],
|
|
119
|
+
contextWindows: DEFAULT_CONTEXT_WINDOWS,
|
|
184
120
|
},
|
|
185
121
|
};
|
|
186
122
|
//# sourceMappingURL=sourceProfiles.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sourceProfiles.js","sourceRoot":"","sources":["../src/sourceProfiles.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sourceProfiles.js","sourceRoot":"","sources":["../src/sourceProfiles.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AAE7F,MAAM,CAAC,MAAM,+BAA+B,GAAgC;IAC1E,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE;IAC3C,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE;IAC7C,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE;IAC7C,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE;IAC7C,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE;IACrC,EAAE,SAAS,EAAE,yBAAyB,EAAE,OAAO,EAAE,UAAU,EAAE;CAC9D,CAAC;AAEF,MAAM,CAAC,MAAM,uBAAuB,GAAwC;IAC1E,UAAU,EAAE;QACV,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,CAAC,mBAAmB,CAAC;QAC5B,YAAY,EAAE,CAAC,YAAY,CAAC;QAC5B,YAAY,EAAE,EAAE;QAChB,QAAQ,EAAE,CAAC;QACX,SAAS,EAAE,OAAO;KACnB;IACD,eAAe,EAAE;QACf,IAAI,EAAE,iBAAiB;QACvB,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,CAAC,oBAAoB,CAAC;QAC7B,YAAY,EAAE,CAAC,YAAY,CAAC;QAC5B,YAAY,EAAE,CAAC,qCAAqC,CAAC;QACrD,QAAQ,EAAE,CAAC;QACX,SAAS,EAAE,QAAQ;KACpB;IACD,cAAc,EAAE;QACd,IAAI,EAAE,gBAAgB;QACtB,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,CAAC,WAAW,CAAC;QACpB,YAAY,EAAE,CAAC,eAAe,CAAC;QAC/B,YAAY,EAAE,EAAE;QAChB,QAAQ,EAAE,CAAC;QACX,SAAS,EAAE,QAAQ;KACpB;IACD,wBAAwB,EAAE;QACxB,IAAI,EAAE,0BAA0B;QAChC,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,CAAC,oBAAoB,CAAC;QAC7B,YAAY,EAAE,CAAC,4BAA4B,EAAE,8BAA8B,CAAC;QAC5E,YAAY,EAAE,EAAE;QAChB,QAAQ,EAAE,CAAC;QACX,SAAS,EAAE,QAAQ;KACpB;IACD,wBAAwB,EAAE;QACxB,IAAI,EAAE,0BAA0B;QAChC,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,CAAC,yCAAyC,CAAC;QAClD,YAAY,EAAE,CAAC,WAAW,CAAC;QAC3B,YAAY,EAAE,EAAE;QAChB,QAAQ,EAAE,CAAC;QACX,SAAS,EAAE,UAAU;KACtB;IACD,UAAU,EAAE;QACV,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,CAAC,eAAe,CAAC;QACxB,YAAY,EAAE,CAAC,yBAAyB,EAAE,YAAY,CAAC;QACvD,YAAY,EAAE,EAAE;QAChB,QAAQ,EAAE,CAAC;QACX,SAAS,EAAE,QAAQ;KACpB;IACD,iBAAiB,EAAE;QACjB,IAAI,EAAE,mBAAmB;QACzB,OAAO,EAAE,IAAI;QACb,KAAK,EAAE,CAAC,sBAAsB,CAAC;QAC/B,YAAY,EAAE,CAAC,YAAY,CAAC;QAC5B,YAAY,EAAE,EAAE;QAChB,QAAQ,EAAE,CAAC;QACX,SAAS,EAAE,IAAI;KAChB;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAc;IACvC,IAAI,EAAE;QACJ,IAAI,EAAE,UAAU;QAChB,eAAe,EAAE,CAAC;QAClB,aAAa,EAAE,GAAG;QAClB,aAAa,EAAE,IAAI;QACnB,oBAAoB,EAAE,OAAO;QAC7B,eAAe,EAAE,GAAG;QACpB,iBAAiB,EAAE,GAAG;QACtB,kBAAkB,EAAE,IAAI;QACxB,kBAAkB,EAAE,MAAM;QAC1B,kBAAkB,EAAE,SAAS;KAC9B;IACD,SAAS,EAAE;QACT,QAAQ,EAAE,oBAAoB;QAC9B,aAAa,EAAE,EAAE;QACjB,cAAc,EAAE,GAAG;QACnB,4BAA4B,EAAE,IAAI;QAClC,6BAA6B,EAAE,GAAG;QAClC,cAAc,EAAE,gBAAgB;KACjC;IACD,qBAAqB,EAAE,+BAA+B;IACtD,OAAO,EAAE,uBAAuB;IAChC,cAAc,EAAE;QACd,kBAAkB,EAAE,KAAK;QACzB,aAAa,EAAE,CAAC;QAChB,eAAe,EAAE,IAAI;QACrB,qBAAqB,EAAE,KAAK;KAC7B;IACD,SAAS,EAAE;QACT,IAAI,EAAE,QAAQ;QACd,QAAQ,EAAE,IAAI;QACd,WAAW,EAAE,YAAY;QACzB,UAAU,EACR,kHAAkH;QACpH,YAAY,EACV,2IAA2I;KAC9I;IACD,IAAI,EAAE;QACJ,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,KAAK;QACf,kBAAkB,EAAE,KAAK;QACzB,UAAU,EAAE,2BAA2B;KACxC;IACD,MAAM,EAAE;QACN,0BAA0B,EAAE,OAAO;QACnC,cAAc,EAAE,uBAAuB;KACxC;CACF,CAAC"}
|
|
@@ -8,6 +8,15 @@ export interface TracePageOptions {
|
|
|
8
8
|
export interface TraceIndexEvent {
|
|
9
9
|
envelope: StreamEnvelope;
|
|
10
10
|
}
|
|
11
|
+
interface SessionActivitySpan {
|
|
12
|
+
startMs: number;
|
|
13
|
+
endMs: number;
|
|
14
|
+
}
|
|
15
|
+
interface SessionActivityArtifacts {
|
|
16
|
+
eventCount: number;
|
|
17
|
+
eventTimestamps: number[];
|
|
18
|
+
activeSegments: SessionActivitySpan[];
|
|
19
|
+
}
|
|
11
20
|
export declare class TraceIndex extends EventEmitter {
|
|
12
21
|
private readonly parserRegistry;
|
|
13
22
|
private config;
|
|
@@ -34,6 +43,7 @@ export declare class TraceIndex extends EventEmitter {
|
|
|
34
43
|
stop(): void;
|
|
35
44
|
refresh(): Promise<void>;
|
|
36
45
|
getPerformanceStats(): IndexPerformanceStats;
|
|
46
|
+
getStreamVersion(): number;
|
|
37
47
|
getTopTools(limit?: number): NamedCount[];
|
|
38
48
|
private buildRetentionStats;
|
|
39
49
|
private computeBaseIntervalMs;
|
|
@@ -61,6 +71,8 @@ export declare class TraceIndex extends EventEmitter {
|
|
|
61
71
|
getOverview(): OverviewStats;
|
|
62
72
|
private hydrateEventsForEntry;
|
|
63
73
|
getSessionDetail(id: string): SessionDetail;
|
|
74
|
+
getSessionActivityArtifacts(id: string): Readonly<SessionActivityArtifacts>;
|
|
64
75
|
getTracePage(id: string, options?: TracePageOptions): TracePage;
|
|
65
76
|
resolveId(candidate: string): string;
|
|
66
77
|
}
|
|
78
|
+
export {};
|
|
@@ -22,6 +22,7 @@ const EVENT_KIND_KEYS = [
|
|
|
22
22
|
const WAITING_INPUT_PATTERN = /\b(?:await(?:ing)?\s+(?:user|input)|waiting\s+for\s+(?:user|input|approval)|user\s+input\s+required|needs?\s+user\s+input|permission\s+required|approval\s+required|confirm(?:ation)?\s+(?:required|needed)|press\s+enter\s+to\s+continue)\b/i;
|
|
23
23
|
const WAITING_PROMPT_PATTERN = /\b(?:do\s+you\s+want(?:\s+me)?|would\s+you\s+like(?:\s+me)?|should\s+i\b|can\s+you\s+confirm|please\s+confirm|let\s+me\s+know\s+if\s+you(?:'d)?\s+like|which\s+(?:option|approach)|choose\s+(?:one|an?\s+option)|pick\s+(?:one|an?\s+option)|approve(?:\s+this)?|permission\s+to)\b/i;
|
|
24
24
|
const ACTIVITY_BIN_COUNT = 12;
|
|
25
|
+
const ACTIVE_IDLE_GAP_MS = 20 * 60_000;
|
|
25
26
|
const MATERIALIZED_TTL_MS = 5 * 60_000;
|
|
26
27
|
const DIRTY_BATCH_LIMIT = 64;
|
|
27
28
|
function emptyEventKindCounts() {
|
|
@@ -36,6 +37,43 @@ function emptyEventKindCounts() {
|
|
|
36
37
|
meta: 0,
|
|
37
38
|
};
|
|
38
39
|
}
|
|
40
|
+
function collectTimestampMs(events) {
|
|
41
|
+
const timestamps = [];
|
|
42
|
+
for (const event of events) {
|
|
43
|
+
const timestampMs = event.timestampMs;
|
|
44
|
+
if (timestampMs === null || !Number.isFinite(timestampMs) || timestampMs <= 0)
|
|
45
|
+
continue;
|
|
46
|
+
timestamps.push(timestampMs);
|
|
47
|
+
}
|
|
48
|
+
timestamps.sort((left, right) => left - right);
|
|
49
|
+
return timestamps;
|
|
50
|
+
}
|
|
51
|
+
function buildActiveSegmentsFromEventTimestamps(eventTimestamps) {
|
|
52
|
+
if (eventTimestamps.length === 0)
|
|
53
|
+
return [];
|
|
54
|
+
const segments = [];
|
|
55
|
+
let segmentStartMs = eventTimestamps[0] ?? 0;
|
|
56
|
+
let previousTsMs = segmentStartMs;
|
|
57
|
+
for (let index = 1; index < eventTimestamps.length; index += 1) {
|
|
58
|
+
const nextTsMs = eventTimestamps[index] ?? previousTsMs;
|
|
59
|
+
const gapMs = Math.max(0, nextTsMs - previousTsMs);
|
|
60
|
+
if (gapMs > ACTIVE_IDLE_GAP_MS) {
|
|
61
|
+
segments.push({ startMs: segmentStartMs, endMs: previousTsMs });
|
|
62
|
+
segmentStartMs = nextTsMs;
|
|
63
|
+
}
|
|
64
|
+
previousTsMs = nextTsMs;
|
|
65
|
+
}
|
|
66
|
+
segments.push({ startMs: segmentStartMs, endMs: previousTsMs });
|
|
67
|
+
return segments;
|
|
68
|
+
}
|
|
69
|
+
function buildSessionActivityArtifacts(events) {
|
|
70
|
+
const eventTimestamps = collectTimestampMs(events);
|
|
71
|
+
return {
|
|
72
|
+
eventCount: events.length,
|
|
73
|
+
eventTimestamps,
|
|
74
|
+
activeSegments: buildActiveSegmentsFromEventTimestamps(eventTimestamps),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
39
77
|
function normalizeActivityCounts(counts) {
|
|
40
78
|
let maxCount = 0;
|
|
41
79
|
for (const count of counts) {
|
|
@@ -523,6 +561,9 @@ export class TraceIndex extends EventEmitter {
|
|
|
523
561
|
...stats,
|
|
524
562
|
};
|
|
525
563
|
}
|
|
564
|
+
getStreamVersion() {
|
|
565
|
+
return this.streamVersion;
|
|
566
|
+
}
|
|
526
567
|
getTopTools(limit = 12) {
|
|
527
568
|
const counts = new Map();
|
|
528
569
|
for (const entry of this.entries.values()) {
|
|
@@ -1000,6 +1041,7 @@ export class TraceIndex extends EventEmitter {
|
|
|
1000
1041
|
residentEvents: redactedEvents,
|
|
1001
1042
|
cachedFullEvents: redactedEvents,
|
|
1002
1043
|
cachedRawEvents: parsed.events,
|
|
1044
|
+
activityArtifacts: null,
|
|
1003
1045
|
pinnedMaterializedAtMs: current?.pinnedMaterializedAtMs ?? 0,
|
|
1004
1046
|
});
|
|
1005
1047
|
this.cursorById.set(file.id, {
|
|
@@ -1028,6 +1070,7 @@ export class TraceIndex extends EventEmitter {
|
|
|
1028
1070
|
residentEvents: [],
|
|
1029
1071
|
cachedFullEvents: [],
|
|
1030
1072
|
cachedRawEvents: [],
|
|
1073
|
+
activityArtifacts: null,
|
|
1031
1074
|
pinnedMaterializedAtMs: 0,
|
|
1032
1075
|
});
|
|
1033
1076
|
this.cursorById.set(file.id, {
|
|
@@ -1111,6 +1154,7 @@ export class TraceIndex extends EventEmitter {
|
|
|
1111
1154
|
residentEvents: mergedEvents,
|
|
1112
1155
|
cachedFullEvents: mergedEvents,
|
|
1113
1156
|
cachedRawEvents: mergedRawEvents,
|
|
1157
|
+
activityArtifacts: null,
|
|
1114
1158
|
pinnedMaterializedAtMs: current.pinnedMaterializedAtMs,
|
|
1115
1159
|
});
|
|
1116
1160
|
this.cursorById.set(file.id, {
|
|
@@ -1255,6 +1299,7 @@ export class TraceIndex extends EventEmitter {
|
|
|
1255
1299
|
const refreshedSummary = summarize(entry.file, parsed.agent, parsed.parser, parsed.sessionId, parsed.events, parsed.parseError, this.config, nowMs());
|
|
1256
1300
|
entry.cachedFullEvents = redactedEvents;
|
|
1257
1301
|
entry.cachedRawEvents = parsed.events;
|
|
1302
|
+
entry.activityArtifacts = null;
|
|
1258
1303
|
entry.pinnedMaterializedAtMs = nowMs();
|
|
1259
1304
|
entry.summary = {
|
|
1260
1305
|
...refreshedSummary,
|
|
@@ -1274,6 +1319,19 @@ export class TraceIndex extends EventEmitter {
|
|
|
1274
1319
|
events,
|
|
1275
1320
|
};
|
|
1276
1321
|
}
|
|
1322
|
+
getSessionActivityArtifacts(id) {
|
|
1323
|
+
const found = this.entries.get(id);
|
|
1324
|
+
if (!found) {
|
|
1325
|
+
throw new Error(`unknown trace id: ${id}`);
|
|
1326
|
+
}
|
|
1327
|
+
if (found.activityArtifacts && found.activityArtifacts.eventCount === found.summary.eventCount) {
|
|
1328
|
+
return found.activityArtifacts;
|
|
1329
|
+
}
|
|
1330
|
+
const events = this.hydrateEventsForEntry(found);
|
|
1331
|
+
const artifacts = buildSessionActivityArtifacts(events);
|
|
1332
|
+
found.activityArtifacts = artifacts;
|
|
1333
|
+
return artifacts;
|
|
1334
|
+
}
|
|
1277
1335
|
getTracePage(id, options = {}) {
|
|
1278
1336
|
const detail = this.getSessionDetail(id);
|
|
1279
1337
|
const includeMeta = options.includeMeta ?? this.config.scan.includeMetaDefault;
|