opencode-copilot-usage-detector 0.1.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.
- package/CHANGELOG.md +20 -0
- package/LICENSE +21 -0
- package/README.md +336 -0
- package/dist/aggregator.d.ts +40 -0
- package/dist/aggregator.d.ts.map +1 -0
- package/dist/aggregator.js +254 -0
- package/dist/aggregator.js.map +1 -0
- package/dist/classifier.d.ts +50 -0
- package/dist/classifier.d.ts.map +1 -0
- package/dist/classifier.js +304 -0
- package/dist/classifier.js.map +1 -0
- package/dist/copilot-budget.d.ts +57 -0
- package/dist/copilot-budget.d.ts.map +1 -0
- package/dist/copilot-budget.js +500 -0
- package/dist/copilot-budget.js.map +1 -0
- package/dist/debug.d.ts +7 -0
- package/dist/debug.d.ts.map +1 -0
- package/dist/debug.js +49 -0
- package/dist/debug.js.map +1 -0
- package/dist/estimator.d.ts +92 -0
- package/dist/estimator.d.ts.map +1 -0
- package/dist/estimator.js +523 -0
- package/dist/estimator.js.map +1 -0
- package/dist/github-api.d.ts +11 -0
- package/dist/github-api.d.ts.map +1 -0
- package/dist/github-api.js +273 -0
- package/dist/github-api.js.map +1 -0
- package/dist/persistence.d.ts +28 -0
- package/dist/persistence.d.ts.map +1 -0
- package/dist/persistence.js +246 -0
- package/dist/persistence.js.map +1 -0
- package/dist/tools.d.ts +20 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +300 -0
- package/dist/tools.js.map +1 -0
- package/dist/types.d.ts +184 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +15 -0
- package/dist/types.js.map +1 -0
- package/package.json +47 -0
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
import { recoverFromJSONL, processAssistantMessage, processErrorEvent, getDaily, getCurrentRPM, setTimezone, } from "./aggregator.js";
|
|
2
|
+
import { ensureDataDir, readConfig, appendObservation, readObservations, readEstimates, } from "./persistence.js";
|
|
3
|
+
import { budgetTool, formatStatus, formatHistory, formatErrors, formatInsights } from "./tools.js";
|
|
4
|
+
import { enableDebug, debugLogEvent, debugLogChatParams } from "./debug.js";
|
|
5
|
+
import { classifyErrorImmediate, extractRateLimitHeaders, scheduleReclassification, } from "./classifier.js";
|
|
6
|
+
import { getBudgetStatus, checkThresholds, computeEstimates } from "./estimator.js";
|
|
7
|
+
import { pollPremiumRequests, getCachedPremiumRequests, formatPremiumRequestStatus, } from "./github-api.js";
|
|
8
|
+
// ============================================================
|
|
9
|
+
// Helpers
|
|
10
|
+
// ============================================================
|
|
11
|
+
export function formatTokensShort(n) {
|
|
12
|
+
if (n >= 1_000_000)
|
|
13
|
+
return `${(n / 1_000_000).toFixed(1)}M`;
|
|
14
|
+
if (n >= 1_000)
|
|
15
|
+
return `${(n / 1_000).toFixed(0)}K`;
|
|
16
|
+
return String(n);
|
|
17
|
+
}
|
|
18
|
+
export function isAssistantMessage(msg) {
|
|
19
|
+
return (typeof msg === "object" &&
|
|
20
|
+
msg !== null &&
|
|
21
|
+
msg.role === "assistant" &&
|
|
22
|
+
typeof msg.id === "string");
|
|
23
|
+
}
|
|
24
|
+
export function isApiError(error) {
|
|
25
|
+
return (typeof error === "object" &&
|
|
26
|
+
error !== null &&
|
|
27
|
+
error.name === "APIError");
|
|
28
|
+
}
|
|
29
|
+
const MODEL_BLOCKED_MESSAGE_PATTERNS = [
|
|
30
|
+
"not available",
|
|
31
|
+
"not supported",
|
|
32
|
+
"forbidden",
|
|
33
|
+
"access denied",
|
|
34
|
+
"not authorized",
|
|
35
|
+
"not included",
|
|
36
|
+
"not enabled",
|
|
37
|
+
"model not found",
|
|
38
|
+
"not allowed",
|
|
39
|
+
"not permitted",
|
|
40
|
+
"does not have access",
|
|
41
|
+
"not part of your",
|
|
42
|
+
"unavailable for your",
|
|
43
|
+
];
|
|
44
|
+
export function isModelBlockedError(error, modelCumulativeTokens, modelCumulativeRequests) {
|
|
45
|
+
const code = error.data?.statusCode;
|
|
46
|
+
const msg = error.data?.message?.toLowerCase() ?? "";
|
|
47
|
+
// 403 Forbidden — always blocked
|
|
48
|
+
if (code === 403)
|
|
49
|
+
return true;
|
|
50
|
+
// Message patterns + model was never successfully used
|
|
51
|
+
if (modelCumulativeTokens === 0 && modelCumulativeRequests === 0) {
|
|
52
|
+
if (MODEL_BLOCKED_MESSAGE_PATTERNS.some((p) => msg.includes(p)))
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
// 401 with model-specific denial (not generic auth failure)
|
|
56
|
+
if (code === 401 && MODEL_BLOCKED_MESSAGE_PATTERNS.some((p) => msg.includes(p))) {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
export function isRateLimitError(error) {
|
|
62
|
+
const code = error.data?.statusCode;
|
|
63
|
+
const msg = error.data?.message?.toLowerCase() ?? "";
|
|
64
|
+
return (code === 429 ||
|
|
65
|
+
msg.includes("rate") ||
|
|
66
|
+
msg.includes("limit") ||
|
|
67
|
+
msg.includes("exceeded") ||
|
|
68
|
+
msg.includes("capacity") ||
|
|
69
|
+
msg.includes("throttl"));
|
|
70
|
+
}
|
|
71
|
+
function readRecentObservations(sinceTs) {
|
|
72
|
+
return readObservations({ since: sinceTs });
|
|
73
|
+
}
|
|
74
|
+
// ============================================================
|
|
75
|
+
// Plugin
|
|
76
|
+
// ============================================================
|
|
77
|
+
const plugin = (async (ctx) => {
|
|
78
|
+
const { client } = ctx;
|
|
79
|
+
// Initialize
|
|
80
|
+
ensureDataDir();
|
|
81
|
+
const config = readConfig();
|
|
82
|
+
if (config.debug) {
|
|
83
|
+
enableDebug();
|
|
84
|
+
}
|
|
85
|
+
if (config.timezone) {
|
|
86
|
+
setTimezone(config.timezone);
|
|
87
|
+
}
|
|
88
|
+
recoverFromJSONL();
|
|
89
|
+
// Track the last requested model per session (avoids cross-session contamination)
|
|
90
|
+
const sessionModels = new Map();
|
|
91
|
+
const SESSION_MODEL_MAX = 500;
|
|
92
|
+
const SESSION_MODEL_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
93
|
+
function getSessionModel(sessionId) {
|
|
94
|
+
const entry = sessionModels.get(sessionId);
|
|
95
|
+
return entry ? { model: entry.model, provider: entry.provider } : { model: null, provider: null };
|
|
96
|
+
}
|
|
97
|
+
function pruneSessionModels() {
|
|
98
|
+
if (sessionModels.size <= SESSION_MODEL_MAX)
|
|
99
|
+
return;
|
|
100
|
+
const now = Date.now();
|
|
101
|
+
for (const [key, val] of sessionModels) {
|
|
102
|
+
if (now - val.ts > SESSION_MODEL_TTL_MS)
|
|
103
|
+
sessionModels.delete(key);
|
|
104
|
+
}
|
|
105
|
+
// If still over limit, drop oldest half
|
|
106
|
+
if (sessionModels.size > SESSION_MODEL_MAX) {
|
|
107
|
+
const entries = [...sessionModels.entries()].sort((a, b) => a[1].ts - b[1].ts);
|
|
108
|
+
const toDelete = entries.slice(0, Math.floor(entries.length / 2));
|
|
109
|
+
for (const [key] of toDelete)
|
|
110
|
+
sessionModels.delete(key);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// Auto-recompute estimates periodically
|
|
114
|
+
let usageEventsSinceRecompute = 0;
|
|
115
|
+
const RECOMPUTE_EVERY_N_EVENTS = 50;
|
|
116
|
+
let lastRecomputeTime = 0;
|
|
117
|
+
const RECOMPUTE_INTERVAL_MS = 60 * 60 * 1000; // 1 hour
|
|
118
|
+
function maybeRecomputeEstimates(force = false) {
|
|
119
|
+
const now = Date.now();
|
|
120
|
+
if (force || usageEventsSinceRecompute >= RECOMPUTE_EVERY_N_EVENTS || now - lastRecomputeTime > RECOMPUTE_INTERVAL_MS) {
|
|
121
|
+
try {
|
|
122
|
+
computeEstimates(config.known_preview_models, config.known_stable_models, config.premium_request_multipliers);
|
|
123
|
+
usageEventsSinceRecompute = 0;
|
|
124
|
+
lastRecomputeTime = now;
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
// Recompute failure is not critical
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// Helper to send a message to the user without triggering a reply
|
|
132
|
+
async function sendMessage(sessionId, text) {
|
|
133
|
+
try {
|
|
134
|
+
await client.session.prompt({
|
|
135
|
+
path: { id: sessionId },
|
|
136
|
+
body: {
|
|
137
|
+
noReply: true,
|
|
138
|
+
parts: [{ type: "text", text, ignored: true }],
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// Notification failure is not critical
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
// ----------------------------------------------------------
|
|
148
|
+
// Config hook: register /budget command
|
|
149
|
+
// ----------------------------------------------------------
|
|
150
|
+
config: async (opencodeConfig) => {
|
|
151
|
+
opencodeConfig.command ??= {};
|
|
152
|
+
opencodeConfig.command["budget"] = {
|
|
153
|
+
template: "",
|
|
154
|
+
description: "Show Copilot budget status, usage history, and insights",
|
|
155
|
+
};
|
|
156
|
+
},
|
|
157
|
+
// ----------------------------------------------------------
|
|
158
|
+
// Command handler: /budget [subcommand]
|
|
159
|
+
// ----------------------------------------------------------
|
|
160
|
+
"command.execute.before": async (input, _output) => {
|
|
161
|
+
if (input.command !== "budget")
|
|
162
|
+
return;
|
|
163
|
+
const args = (input.arguments || "").trim().split(/\s+/).filter(Boolean);
|
|
164
|
+
const subcommand = args[0]?.toLowerCase() || "status";
|
|
165
|
+
let result;
|
|
166
|
+
switch (subcommand) {
|
|
167
|
+
case "status":
|
|
168
|
+
result = formatStatus();
|
|
169
|
+
break;
|
|
170
|
+
case "history":
|
|
171
|
+
result = formatHistory(14);
|
|
172
|
+
break;
|
|
173
|
+
case "insights":
|
|
174
|
+
result = formatInsights();
|
|
175
|
+
break;
|
|
176
|
+
case "errors":
|
|
177
|
+
result = formatErrors();
|
|
178
|
+
break;
|
|
179
|
+
case "recompute":
|
|
180
|
+
computeEstimates(config.known_preview_models, config.known_stable_models, config.premium_request_multipliers);
|
|
181
|
+
result = "Estimates recomputed. Run `/budget insights` to see results.";
|
|
182
|
+
break;
|
|
183
|
+
default:
|
|
184
|
+
result = [
|
|
185
|
+
"## /budget commands",
|
|
186
|
+
"",
|
|
187
|
+
"- `/budget` or `/budget status` — Current usage and estimates",
|
|
188
|
+
"- `/budget history` — Daily usage for the last 14 days",
|
|
189
|
+
"- `/budget insights` — Learned patterns and limit analysis",
|
|
190
|
+
"- `/budget errors` — Rate limit events and error catalog",
|
|
191
|
+
"- `/budget recompute` — Force recompute all estimates",
|
|
192
|
+
].join("\n");
|
|
193
|
+
}
|
|
194
|
+
await sendMessage(input.sessionID, result);
|
|
195
|
+
},
|
|
196
|
+
// ----------------------------------------------------------
|
|
197
|
+
// Event handler
|
|
198
|
+
// ----------------------------------------------------------
|
|
199
|
+
event: async ({ event }) => {
|
|
200
|
+
try {
|
|
201
|
+
debugLogEvent(event.type, event);
|
|
202
|
+
// ----- message.updated: extract tokens from assistant messages -----
|
|
203
|
+
if (event.type === "message.updated") {
|
|
204
|
+
const msgEvent = event;
|
|
205
|
+
const msg = msgEvent.properties.info;
|
|
206
|
+
if (!isAssistantMessage(msg))
|
|
207
|
+
return;
|
|
208
|
+
const finished = !!msg.finish;
|
|
209
|
+
const tokens = msg.tokens ?? {
|
|
210
|
+
input: 0,
|
|
211
|
+
output: 0,
|
|
212
|
+
reasoning: 0,
|
|
213
|
+
cache: { read: 0, write: 0 },
|
|
214
|
+
};
|
|
215
|
+
const sm = getSessionModel(msg.sessionID);
|
|
216
|
+
const incoming = {
|
|
217
|
+
messageId: msg.id,
|
|
218
|
+
sessionId: msg.sessionID,
|
|
219
|
+
modelId: msg.modelID ?? sm.model ?? "unknown",
|
|
220
|
+
providerId: msg.providerID ?? sm.provider ?? "unknown",
|
|
221
|
+
tokens: {
|
|
222
|
+
total: tokens.input + tokens.output + tokens.reasoning + tokens.cache.read + tokens.cache.write,
|
|
223
|
+
input: tokens.input,
|
|
224
|
+
output: tokens.output,
|
|
225
|
+
reasoning: tokens.reasoning,
|
|
226
|
+
cache: tokens.cache,
|
|
227
|
+
},
|
|
228
|
+
cost: msg.cost ?? 0,
|
|
229
|
+
finished,
|
|
230
|
+
};
|
|
231
|
+
processAssistantMessage(incoming);
|
|
232
|
+
usageEventsSinceRecompute++;
|
|
233
|
+
maybeRecomputeEstimates();
|
|
234
|
+
// Detect silent model fallback
|
|
235
|
+
if (finished && msg.modelID && sm.model && msg.modelID !== sm.model) {
|
|
236
|
+
appendObservation({
|
|
237
|
+
ts: new Date().toISOString(),
|
|
238
|
+
type: "model_fallback",
|
|
239
|
+
requested: sm.model,
|
|
240
|
+
received: msg.modelID,
|
|
241
|
+
day_cumulative_tokens: getDaily().totalTokens,
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
// Check threshold notifications
|
|
245
|
+
if (finished && !config.quiet_mode) {
|
|
246
|
+
const d = getDaily();
|
|
247
|
+
const status = getBudgetStatus(d.totalTokens, d.totalRequests, d.totalCost, d.byModel, d.limitHits.length, config.known_preview_models, config.known_stable_models, config.premium_request_multipliers);
|
|
248
|
+
const threshold = checkThresholds(status.percentage, config.notification_thresholds, d.notifiedThresholds);
|
|
249
|
+
if (threshold !== null) {
|
|
250
|
+
d.notifiedThresholds.add(threshold);
|
|
251
|
+
const pctStr = status.percentage !== null ? `${status.percentage}%` : "?";
|
|
252
|
+
const limitStr = status.estimatedTokenLimit
|
|
253
|
+
? formatTokensShort(status.estimatedTokenLimit) : "unknown";
|
|
254
|
+
const confStr = status.confidence > 0.8 ? ""
|
|
255
|
+
: status.confidence > 0.5 ? " (moderate confidence)" : " (low confidence)";
|
|
256
|
+
await sendMessage(msg.sessionID, `\u{26A1} **${pctStr} of daily Copilot budget used** (${formatTokensShort(d.totalTokens)} / ~${limitStr} est.)${confStr}`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
// ----- session.error: log all errors, detect rate limits -----
|
|
261
|
+
if (event.type === "session.error") {
|
|
262
|
+
const errEvent = event;
|
|
263
|
+
const error = errEvent.properties.error;
|
|
264
|
+
if (!error)
|
|
265
|
+
return;
|
|
266
|
+
const sessionId = errEvent.properties.sessionID;
|
|
267
|
+
const errSm = getSessionModel(sessionId ?? "");
|
|
268
|
+
if (isApiError(error)) {
|
|
269
|
+
const apiErr = error;
|
|
270
|
+
const errModel = errSm.model ?? "unknown";
|
|
271
|
+
const modelUsage = getDaily().byModel[errModel];
|
|
272
|
+
const modelTokens = modelUsage?.tokens ?? 0;
|
|
273
|
+
const modelRequests = modelUsage?.requests ?? 0;
|
|
274
|
+
// Check for blocked model BEFORE rate limit check
|
|
275
|
+
if (isModelBlockedError(apiErr, modelTokens, modelRequests)) {
|
|
276
|
+
const d = getDaily();
|
|
277
|
+
const blockedTs = new Date().toISOString();
|
|
278
|
+
d.blockedModels.push({
|
|
279
|
+
ts: blockedTs,
|
|
280
|
+
model: errModel,
|
|
281
|
+
errorMessage: apiErr.data?.message ?? "",
|
|
282
|
+
statusCode: apiErr.data?.statusCode,
|
|
283
|
+
});
|
|
284
|
+
appendObservation({
|
|
285
|
+
ts: blockedTs,
|
|
286
|
+
type: "model_blocked",
|
|
287
|
+
session: sessionId ?? "unknown",
|
|
288
|
+
model: errModel,
|
|
289
|
+
provider: errSm.provider ?? "unknown",
|
|
290
|
+
error_name: apiErr.name,
|
|
291
|
+
error_message: apiErr.data?.message ?? "",
|
|
292
|
+
error_raw: JSON.stringify(apiErr),
|
|
293
|
+
status_code: apiErr.data?.statusCode,
|
|
294
|
+
is_retryable: apiErr.data?.isRetryable ?? false,
|
|
295
|
+
day_cumulative_tokens: d.totalTokens,
|
|
296
|
+
day_cumulative_requests: d.totalRequests,
|
|
297
|
+
});
|
|
298
|
+
if (sessionId) {
|
|
299
|
+
await sendMessage(sessionId, `\u{1F6AB} **Model blocked:** ${errModel} is not available on your plan (status: ${apiErr.data?.statusCode ?? "unknown"}). This won't count toward rate limit estimates.`);
|
|
300
|
+
}
|
|
301
|
+
return; // Skip rate-limit path entirely
|
|
302
|
+
}
|
|
303
|
+
const rateLimitHeaders = extractRateLimitHeaders(apiErr.data?.responseHeaders);
|
|
304
|
+
const classification = classifyErrorImmediate(apiErr.data?.message ?? "", apiErr.data?.statusCode, apiErr.data?.responseHeaders);
|
|
305
|
+
if (isRateLimitError(apiErr)) {
|
|
306
|
+
const incomingError = {
|
|
307
|
+
sessionId,
|
|
308
|
+
errorName: apiErr.name,
|
|
309
|
+
errorMessage: apiErr.data?.message ?? "",
|
|
310
|
+
errorRaw: JSON.stringify(apiErr),
|
|
311
|
+
statusCode: apiErr.data?.statusCode,
|
|
312
|
+
isRetryable: apiErr.data?.isRetryable ?? false,
|
|
313
|
+
responseHeaders: apiErr.data?.responseHeaders,
|
|
314
|
+
responseBody: apiErr.data?.responseBody,
|
|
315
|
+
};
|
|
316
|
+
const errorTs = processErrorEvent(incomingError, errSm.model, errSm.provider);
|
|
317
|
+
maybeRecomputeEstimates(true);
|
|
318
|
+
const d = getDaily();
|
|
319
|
+
if (d.limitHits.length > 0) {
|
|
320
|
+
d.limitHits[d.limitHits.length - 1].class = classification.class;
|
|
321
|
+
}
|
|
322
|
+
// Schedule delayed reclassification (10 min after event)
|
|
323
|
+
scheduleReclassification(errorTs, () => {
|
|
324
|
+
const current = getDaily();
|
|
325
|
+
const recentObs = readRecentObservations(errorTs);
|
|
326
|
+
const errorModel = errSm.model ?? "unknown";
|
|
327
|
+
const otherModels = recentObs
|
|
328
|
+
.filter((o) => o.type === "usage" && o.model !== errorModel)
|
|
329
|
+
.map((o) => o.model);
|
|
330
|
+
const uniqueOtherModels = [...new Set(otherModels)];
|
|
331
|
+
const totalRecent = recentObs.length;
|
|
332
|
+
const errorRecent = recentObs.filter((o) => o.type === "limit_hit").length;
|
|
333
|
+
const recoveryEvent = recentObs.find((o) => o.type === "recovery");
|
|
334
|
+
const recoveryMinutes = recoveryEvent
|
|
335
|
+
? (new Date(recoveryEvent.ts).getTime() - new Date(errorTs).getTime()) / 60_000
|
|
336
|
+
: null;
|
|
337
|
+
return {
|
|
338
|
+
recentObservations: recentObs.map((o) => ({
|
|
339
|
+
type: o.type,
|
|
340
|
+
model: "model" in o ? String(o.model) : undefined,
|
|
341
|
+
ts: o.ts,
|
|
342
|
+
})),
|
|
343
|
+
dailyTokens: current.totalTokens,
|
|
344
|
+
dailyRequests: current.totalRequests,
|
|
345
|
+
globalEstimate: (() => {
|
|
346
|
+
try {
|
|
347
|
+
const est = readEstimates();
|
|
348
|
+
if (est && typeof est === "object") {
|
|
349
|
+
const gdb = est.globalDailyBudget;
|
|
350
|
+
if (gdb && typeof gdb === "object") {
|
|
351
|
+
const te = gdb.tokenEstimate;
|
|
352
|
+
if (te && typeof te === "object") {
|
|
353
|
+
const val = te.value;
|
|
354
|
+
return typeof val === "number" ? val : null;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return null;
|
|
359
|
+
}
|
|
360
|
+
catch {
|
|
361
|
+
return null;
|
|
362
|
+
}
|
|
363
|
+
})(),
|
|
364
|
+
otherModelsWorking: uniqueOtherModels.length > 0,
|
|
365
|
+
workingModels: uniqueOtherModels,
|
|
366
|
+
errorRate: totalRecent > 0 ? errorRecent / totalRecent : 0,
|
|
367
|
+
minutesSinceError: (Date.now() - new Date(errorTs).getTime()) / 60_000,
|
|
368
|
+
hasRecovered: !!recoveryEvent,
|
|
369
|
+
recoveryMinutes,
|
|
370
|
+
};
|
|
371
|
+
});
|
|
372
|
+
// Notify user
|
|
373
|
+
if (sessionId) {
|
|
374
|
+
const headerInfo = rateLimitHeaders
|
|
375
|
+
? ` | Headers: ${Object.entries(rateLimitHeaders.all).map(([k, v]) => `${k}=${v}`).join(", ")}`
|
|
376
|
+
: "";
|
|
377
|
+
await sendMessage(sessionId, `\u{1F534} **Rate limited!** Day total: ${formatTokensShort(d.totalTokens)} tokens, ${d.totalRequests} requests | Model: ${errSm.model ?? "unknown"} | Status: ${apiErr.data?.statusCode ?? "unknown"} | Class: ${classification.class}${headerInfo}\n\nRun \`/budget errors\` for details.`);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
else {
|
|
381
|
+
appendObservation({
|
|
382
|
+
ts: new Date().toISOString(),
|
|
383
|
+
type: "error_logged",
|
|
384
|
+
session: sessionId ?? "unknown",
|
|
385
|
+
model: errSm.model ?? "unknown",
|
|
386
|
+
provider: errSm.provider ?? "unknown",
|
|
387
|
+
error_name: apiErr.name,
|
|
388
|
+
error_message: apiErr.data?.message ?? "",
|
|
389
|
+
error_raw: JSON.stringify(apiErr),
|
|
390
|
+
status_code: apiErr.data?.statusCode,
|
|
391
|
+
is_retryable: apiErr.data?.isRetryable ?? false,
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
else {
|
|
396
|
+
appendObservation({
|
|
397
|
+
ts: new Date().toISOString(),
|
|
398
|
+
type: "error_logged",
|
|
399
|
+
session: sessionId ?? "unknown",
|
|
400
|
+
model: errSm.model ?? "unknown",
|
|
401
|
+
provider: errSm.provider ?? "unknown",
|
|
402
|
+
error_name: error.name ?? "Unknown",
|
|
403
|
+
error_message: error.data?.message ?? "",
|
|
404
|
+
error_raw: JSON.stringify(error),
|
|
405
|
+
status_code: undefined,
|
|
406
|
+
is_retryable: false,
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
catch (err) {
|
|
412
|
+
try {
|
|
413
|
+
await client.app.log({
|
|
414
|
+
body: {
|
|
415
|
+
service: "copilot-budget",
|
|
416
|
+
level: "error",
|
|
417
|
+
message: `Event handler error: ${err instanceof Error ? err.message : String(err)}`,
|
|
418
|
+
},
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
catch {
|
|
422
|
+
// Even logging failed, silently ignore
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
},
|
|
426
|
+
// ----------------------------------------------------------
|
|
427
|
+
// chat.params: capture model/provider before each LLM call
|
|
428
|
+
// ----------------------------------------------------------
|
|
429
|
+
"chat.params": async ({ sessionID, model, provider }) => {
|
|
430
|
+
try {
|
|
431
|
+
sessionModels.set(sessionID, { model: model.id, provider: provider.info.id, ts: Date.now() });
|
|
432
|
+
pruneSessionModels();
|
|
433
|
+
debugLogChatParams(model, provider);
|
|
434
|
+
}
|
|
435
|
+
catch {
|
|
436
|
+
// Non-critical
|
|
437
|
+
}
|
|
438
|
+
},
|
|
439
|
+
// ----------------------------------------------------------
|
|
440
|
+
// System prompt injection
|
|
441
|
+
// ----------------------------------------------------------
|
|
442
|
+
"experimental.chat.system.transform": async (_input, output) => {
|
|
443
|
+
try {
|
|
444
|
+
const d = getDaily();
|
|
445
|
+
const rpm = getCurrentRPM();
|
|
446
|
+
const status = getBudgetStatus(d.totalTokens, d.totalRequests, d.totalCost, d.byModel, d.limitHits.length, config.known_preview_models, config.known_stable_models, config.premium_request_multipliers);
|
|
447
|
+
const pr = await pollPremiumRequests(config).catch(() => getCachedPremiumRequests());
|
|
448
|
+
const premiumLine = pr ? formatPremiumRequestStatus(pr) : "";
|
|
449
|
+
const limitLine = status.estimatedTokenLimit
|
|
450
|
+
? `Estimated daily limit: ~${formatTokensShort(status.estimatedTokenLimit)} tokens (confidence: ${Math.round(status.confidence * 100)}%)`
|
|
451
|
+
: "Estimated daily limit: unknown (still learning)";
|
|
452
|
+
const pctLine = status.percentage !== null ? `Usage percentage: ~${status.percentage}%` : "";
|
|
453
|
+
const limitHitLine = d.limitHits.length > 0
|
|
454
|
+
? `Limit hits today: ${d.limitHits.length} (last at ${d.limitHits[d.limitHits.length - 1]?.ts.split("T")[1]?.split(".")[0] ?? "?"})`
|
|
455
|
+
: "";
|
|
456
|
+
const blockedLine = d.blockedModels.length > 0
|
|
457
|
+
? `Blocked models: ${[...new Set(d.blockedModels.map((b) => b.model))].join(", ")}`
|
|
458
|
+
: "";
|
|
459
|
+
const previewLine = status.previewWarnings ? `\nPreview model warnings:\n${status.previewWarnings}` : "";
|
|
460
|
+
const insightLine = status.insights ? `\nInsights:\n${status.insights}` : "";
|
|
461
|
+
output.system.push(`<copilot-budget>
|
|
462
|
+
${premiumLine ? premiumLine + "\n" : ""}Daily token usage: ${formatTokensShort(d.totalTokens)} tokens (${d.totalRequests} requests)
|
|
463
|
+
${limitLine}
|
|
464
|
+
${pctLine}
|
|
465
|
+
Cost today: $${d.totalCost.toFixed(4)}
|
|
466
|
+
Current rate: ${rpm} req/min (peak: ${d.peakRPM})
|
|
467
|
+
${status.modelBreakdown ? `\nModel breakdown:\n${status.modelBreakdown}` : ""}
|
|
468
|
+
${limitHitLine}
|
|
469
|
+
${blockedLine}${previewLine}${insightLine}
|
|
470
|
+
</copilot-budget>`);
|
|
471
|
+
}
|
|
472
|
+
catch {
|
|
473
|
+
// Non-critical
|
|
474
|
+
}
|
|
475
|
+
},
|
|
476
|
+
// ----------------------------------------------------------
|
|
477
|
+
// Session compaction
|
|
478
|
+
// ----------------------------------------------------------
|
|
479
|
+
"experimental.session.compacting": async (_input, output) => {
|
|
480
|
+
try {
|
|
481
|
+
const d = getDaily();
|
|
482
|
+
const blockedStr = d.blockedModels.length > 0
|
|
483
|
+
? ` ${[...new Set(d.blockedModels.map((b) => b.model))].length} model(s) are blocked.`
|
|
484
|
+
: "";
|
|
485
|
+
output.context.push(`The user has used ${formatTokensShort(d.totalTokens)} tokens today across ${d.totalRequests} requests. ${d.limitHits.length > 0 ? `Rate-limited ${d.limitHits.length} time(s) today.` : "No rate limits hit today."}${blockedStr}`);
|
|
486
|
+
}
|
|
487
|
+
catch {
|
|
488
|
+
// Non-critical
|
|
489
|
+
}
|
|
490
|
+
},
|
|
491
|
+
// ----------------------------------------------------------
|
|
492
|
+
// Custom tool (for LLM to call)
|
|
493
|
+
// ----------------------------------------------------------
|
|
494
|
+
tool: {
|
|
495
|
+
budget: budgetTool,
|
|
496
|
+
},
|
|
497
|
+
};
|
|
498
|
+
});
|
|
499
|
+
export default plugin;
|
|
500
|
+
//# sourceMappingURL=copilot-budget.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copilot-budget.js","sourceRoot":"","sources":["../src/copilot-budget.ts"],"names":[],"mappings":"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"}
|
package/dist/debug.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function enableDebug(): void;
|
|
2
|
+
export declare function isDebugEnabled(): boolean;
|
|
3
|
+
/** Reset debug state. For testing only. */
|
|
4
|
+
export declare function resetDebug(): void;
|
|
5
|
+
export declare function debugLogEvent(type: string, data: unknown): void;
|
|
6
|
+
export declare function debugLogChatParams(model: unknown, provider: unknown): void;
|
|
7
|
+
//# sourceMappingURL=debug.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debug.d.ts","sourceRoot":"","sources":["../src/debug.ts"],"names":[],"mappings":"AAUA,wBAAgB,WAAW,IAAI,IAAI,CAElC;AAED,wBAAgB,cAAc,IAAI,OAAO,CAExC;AAED,2CAA2C;AAC3C,wBAAgB,UAAU,IAAI,IAAI,CAEjC;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAY/D;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,OAAO,GAChB,IAAI,CAaN"}
|
package/dist/debug.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { appendFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
const DEBUG_FILE = join(homedir(), ".config", "copilot-budget", "debug-events.jsonl");
|
|
5
|
+
// Set to true to enable debug logging of ALL events
|
|
6
|
+
// Controlled via config.json: { "debug": true }
|
|
7
|
+
let enabled = false;
|
|
8
|
+
export function enableDebug() {
|
|
9
|
+
enabled = true;
|
|
10
|
+
}
|
|
11
|
+
export function isDebugEnabled() {
|
|
12
|
+
return enabled;
|
|
13
|
+
}
|
|
14
|
+
/** Reset debug state. For testing only. */
|
|
15
|
+
export function resetDebug() {
|
|
16
|
+
enabled = false;
|
|
17
|
+
}
|
|
18
|
+
export function debugLogEvent(type, data) {
|
|
19
|
+
if (!enabled)
|
|
20
|
+
return;
|
|
21
|
+
try {
|
|
22
|
+
const line = JSON.stringify({
|
|
23
|
+
ts: new Date().toISOString(),
|
|
24
|
+
type,
|
|
25
|
+
data,
|
|
26
|
+
});
|
|
27
|
+
appendFileSync(DEBUG_FILE, line + "\n");
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// Debug logging must never fail loudly
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export function debugLogChatParams(model, provider) {
|
|
34
|
+
if (!enabled)
|
|
35
|
+
return;
|
|
36
|
+
try {
|
|
37
|
+
const line = JSON.stringify({
|
|
38
|
+
ts: new Date().toISOString(),
|
|
39
|
+
type: "chat.params",
|
|
40
|
+
model,
|
|
41
|
+
provider,
|
|
42
|
+
});
|
|
43
|
+
appendFileSync(DEBUG_FILE, line + "\n");
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// Debug logging must never fail loudly
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=debug.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debug.js","sourceRoot":"","sources":["../src/debug.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAEhC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,gBAAgB,EAAE,oBAAoB,CAAC,CAAA;AAErF,oDAAoD;AACpD,gDAAgD;AAChD,IAAI,OAAO,GAAG,KAAK,CAAA;AAEnB,MAAM,UAAU,WAAW;IACzB,OAAO,GAAG,IAAI,CAAA;AAChB,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,2CAA2C;AAC3C,MAAM,UAAU,UAAU;IACxB,OAAO,GAAG,KAAK,CAAA;AACjB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,IAAa;IACvD,IAAI,CAAC,OAAO;QAAE,OAAM;IACpB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;YAC1B,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YAC5B,IAAI;YACJ,IAAI;SACL,CAAC,CAAA;QACF,cAAc,CAAC,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC,CAAA;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,uCAAuC;IACzC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB,CAChC,KAAc,EACd,QAAiB;IAEjB,IAAI,CAAC,OAAO;QAAE,OAAM;IACpB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;YAC1B,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YAC5B,IAAI,EAAE,aAAa;YACnB,KAAK;YACL,QAAQ;SACT,CAAC,CAAA;QACF,cAAc,CAAC,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC,CAAA;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,uCAAuC;IACzC,CAAC;AACH,CAAC"}
|