Budget Intelligence & TUI — programmatic spend data, live dashboard, mission cost tracking #5

Merged
vigilio merged 3 commits from budget-intel into main 2026-04-08 09:12:08 +00:00
3 changed files with 37 additions and 0 deletions
Showing only changes of commit ab9c60b67c - Show all commits

15
package-lock.json generated Normal file
View file

@ -0,0 +1,15 @@
{
"name": "token-monitor",
"version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "token-monitor",
"version": "0.1.0",
"engines": {
"node": ">=18"
}
}
}
}

View file

@ -116,6 +116,25 @@ export async function probeTeamsProvider(providerName, baseUrl, apiKey) {
}), }),
}); });
// HTTP 400 with "extra_usage" policy: Anthropic changed billing April 4 2026.
// Third-party apps (incl. pi) no longer draw from Teams plan limits.
// Rate-limit headers ARE present but the provider is unusable for sessions.
// Detect this before parseTeamsHeaders so we surface a clear status.
if (response.status === 400) {
let bodyText = '';
try { bodyText = await response.text(); } catch (_) {}
if (bodyText.includes('extra usage') || bodyText.includes('invalid_request_error')) {
// Still parse headers for quota visibility, but override status
const base = parseTeamsHeaders(response.headers, response.status, providerName);
return {
...base,
status: 'policy_rejected',
policy_message: 'Third-party apps blocked (Anthropic April 2026 billing change)',
severity: 'critical',
};
}
}
return parseTeamsHeaders(response.headers, response.status, providerName); return parseTeamsHeaders(response.headers, response.status, providerName);
} catch (err) { } catch (err) {
return { return {

View file

@ -10,6 +10,7 @@
export function getSeverity(provider) { export function getSeverity(provider) {
if (provider.type === 'teams-direct') { if (provider.type === 'teams-direct') {
if (provider.status === 'rejected') return 'critical'; if (provider.status === 'rejected') return 'critical';
if (provider.status === 'policy_rejected') return 'critical';
if (provider.utilization_7d > 0.85) return 'warning'; if (provider.utilization_7d > 0.85) return 'warning';
if (provider.utilization_5h > 0.7) return 'warning'; if (provider.utilization_5h > 0.7) return 'warning';
return 'ok'; return 'ok';
@ -99,6 +100,8 @@ export function generateReport(result) {
if (p.type === 'teams-direct') { if (p.type === 'teams-direct') {
if (p.status === 'invalid_key') { if (p.status === 'invalid_key') {
detail = 'Invalid API key (401)'; detail = 'Invalid API key (401)';
} else if (p.status === 'policy_rejected') {
detail = `POLICY BLOCKED — 7d: ${pct(p.utilization_7d)} | extra-usage billing required`;
} else if (p.status === 'rejected') { } else if (p.status === 'rejected') {
const resetIn = formatDuration(p.reset_in_seconds); const resetIn = formatDuration(p.reset_in_seconds);
detail = `MAXED — 7d: ${pct(p.utilization_7d)} | resets in ${resetIn}`; detail = `MAXED — 7d: ${pct(p.utilization_7d)} | resets in ${resetIn}`;