@raysonmeng/agentbridge 0.1.13 → 0.1.15

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.
@@ -26,11 +26,11 @@ function defineNumber(value, fallback) {
26
26
  return typeof value === "number" && Number.isFinite(value) ? value : fallback;
27
27
  }
28
28
  var BUILD_INFO = Object.freeze({
29
- version: defineString("0.1.13", "0.0.0-source"),
30
- commit: defineString("7a71869", "source"),
29
+ version: defineString("0.1.15", "0.0.0-source"),
30
+ commit: defineString("89d4c9a", "source"),
31
31
  bundle: defineBundle("plugin"),
32
32
  contractVersion: defineNumber(1, CONTRACT_VERSION),
33
- codeHash: defineString("e1fd67d07c62", "source")
33
+ codeHash: defineString("71ce81854ec9", "source")
34
34
  });
35
35
  function daemonStatusBuildInfo() {
36
36
  return { ...BUILD_INFO };
@@ -3401,7 +3401,8 @@ var DEFAULT_BUDGET_CONFIG = {
3401
3401
  full: null,
3402
3402
  balanced: { effort: "medium" },
3403
3403
  eco: { effort: "low" }
3404
- }
3404
+ },
3405
+ strategy: "conserve"
3405
3406
  };
3406
3407
  var DEFAULT_CONFIG = {
3407
3408
  version: "1.0",
@@ -3479,6 +3480,9 @@ function normalizeBoundedInteger(value, fallback, min, max) {
3479
3480
  return fallback;
3480
3481
  return parsed;
3481
3482
  }
3483
+ function normalizeStrategy(value, fallback) {
3484
+ return value === "conserve" || value === "maximize" ? value : fallback;
3485
+ }
3482
3486
  function normalizeBoolean(value, fallback) {
3483
3487
  if (typeof value === "boolean")
3484
3488
  return value;
@@ -3527,7 +3531,8 @@ function normalizeBudgetConfig(raw, fallback = DEFAULT_BUDGET_CONFIG) {
3527
3531
  timeWindowSec: normalizeBoundedInteger(parallel.timeWindowSec, fallback.parallel.timeWindowSec, 60, 604800)
3528
3532
  },
3529
3533
  codexTierControl: normalizeBoolean(budget.codexTierControl, fallback.codexTierControl) && codexTiers.full !== null,
3530
- codexTiers
3534
+ codexTiers,
3535
+ strategy: normalizeStrategy(budget.strategy, fallback.strategy)
3531
3536
  };
3532
3537
  }
3533
3538
  function applyBudgetEnvOverrides(budget, env = process.env) {
@@ -3542,7 +3547,8 @@ function applyBudgetEnvOverrides(budget, env = process.env) {
3542
3547
  timeWindowSec: env.AGENTBRIDGE_BUDGET_PARALLEL_TIME_WINDOW_SEC ?? budget.parallel.timeWindowSec
3543
3548
  },
3544
3549
  codexTierControl: env.AGENTBRIDGE_BUDGET_CODEX_TIER_CONTROL ?? budget.codexTierControl,
3545
- codexTiers: budget.codexTiers
3550
+ codexTiers: budget.codexTiers,
3551
+ strategy: env.AGENTBRIDGE_BUDGET_STRATEGY ?? budget.strategy
3546
3552
  };
3547
3553
  return normalizeBudgetConfig(overlay, budget);
3548
3554
  }
@@ -4038,6 +4044,54 @@ function classifyPoll(prev, state, cfg) {
4038
4044
  return { next: prev, effect: { kind: "none" } };
4039
4045
  }
4040
4046
 
4047
+ // src/budget/burn-view.ts
4048
+ function windowBurnRate(window) {
4049
+ if (!window || window.burnRate === undefined)
4050
+ return null;
4051
+ return {
4052
+ pctPerHour: window.burnRate,
4053
+ confident: window.burnConfident === true
4054
+ };
4055
+ }
4056
+ function agentBurnRates(usage) {
4057
+ if (!usage)
4058
+ return { fiveHour: null, weekly: null };
4059
+ return {
4060
+ fiveHour: windowBurnRate(usage.fiveHour),
4061
+ weekly: windowBurnRate(usage.weekly)
4062
+ };
4063
+ }
4064
+ function agentRunway(usage, now) {
4065
+ if (!usage || usage.stale || !usage.ok)
4066
+ return null;
4067
+ if (!isDecisionGrade(usage, now))
4068
+ return null;
4069
+ let best = null;
4070
+ const candidates = [
4071
+ ["fiveHour", usage.fiveHour],
4072
+ ["weekly", usage.weekly]
4073
+ ];
4074
+ for (const [basis, window] of candidates) {
4075
+ if (!window || window.resetEpoch <= now)
4076
+ continue;
4077
+ if (window.burnConfident !== true)
4078
+ continue;
4079
+ if (window.runwaySeconds === undefined)
4080
+ continue;
4081
+ if (best === null || window.runwaySeconds < best.seconds) {
4082
+ best = {
4083
+ seconds: window.runwaySeconds,
4084
+ basis,
4085
+ depletedAtEpoch: window.depletedAtEpoch ?? null
4086
+ };
4087
+ }
4088
+ }
4089
+ return best;
4090
+ }
4091
+ function hasAnyBurnSignal(rates, runway) {
4092
+ return rates.claude.fiveHour !== null || rates.claude.weekly !== null || rates.codex.fiveHour !== null || rates.codex.weekly !== null || runway.claude !== null || runway.codex !== null;
4093
+ }
4094
+
4041
4095
  // src/budget/budget-coordinator.ts
4042
4096
  var LOW_UTIL_PCT = 50;
4043
4097
  var NEAR_PAUSE_MARGIN_PCT = 10;
@@ -4348,8 +4402,22 @@ class BudgetCoordinator {
4348
4402
  resumeAfterEpoch: paused ? this.fpState.resumeEpoch ?? state.pause.resumeAfterEpoch : null,
4349
4403
  parallelRecommended: paused ? false : state.parallel.recommended,
4350
4404
  codexTier: state.effort.codexTier,
4351
- claudeAdvice: state.effort.claudeAdvice
4405
+ claudeAdvice: state.effort.claudeAdvice,
4406
+ ...this.burnRateSnapshotFields(state)
4407
+ };
4408
+ }
4409
+ burnRateSnapshotFields(state) {
4410
+ const rates = {
4411
+ claude: agentBurnRates(state.perAgent.claude),
4412
+ codex: agentBurnRates(state.perAgent.codex)
4413
+ };
4414
+ const runway = {
4415
+ claude: agentRunway(state.perAgent.claude, state.now),
4416
+ codex: agentRunway(state.perAgent.codex, state.now)
4352
4417
  };
4418
+ if (!hasAnyBurnSignal(rates, runway))
4419
+ return {};
4420
+ return { burnRate: rates, runway };
4353
4421
  }
4354
4422
  }
4355
4423
 
@@ -4358,6 +4426,57 @@ import { execFile } from "child_process";
4358
4426
  import { existsSync as existsSync5 } from "fs";
4359
4427
  import { homedir as homedir2 } from "os";
4360
4428
  import { basename, join as join5 } from "path";
4429
+ function parseBurnFields(record) {
4430
+ const group = {};
4431
+ let any = false;
4432
+ const takeNumber = (value, min) => {
4433
+ if (value === undefined)
4434
+ return "absent";
4435
+ if (typeof value !== "number" || !Number.isFinite(value))
4436
+ return "invalid";
4437
+ if (min === "zero" && value < 0)
4438
+ return "invalid";
4439
+ if (min === "positive" && value <= 0)
4440
+ return "invalid";
4441
+ return value;
4442
+ };
4443
+ const burnRate = takeNumber(record.burn_rate_pct_per_hour ?? record.burnRatePctPerHour, "zero");
4444
+ if (burnRate === "invalid")
4445
+ return null;
4446
+ if (burnRate !== "absent") {
4447
+ group.burnRate = burnRate;
4448
+ any = true;
4449
+ }
4450
+ const confidentRaw = record.burn_confident ?? record.burnConfident;
4451
+ if (confidentRaw !== undefined) {
4452
+ if (typeof confidentRaw !== "boolean")
4453
+ return null;
4454
+ group.burnConfident = confidentRaw;
4455
+ any = true;
4456
+ }
4457
+ const runwaySeconds = takeNumber(record.runway_seconds ?? record.runwaySeconds, "zero");
4458
+ if (runwaySeconds === "invalid")
4459
+ return null;
4460
+ if (runwaySeconds !== "absent") {
4461
+ group.runwaySeconds = runwaySeconds;
4462
+ any = true;
4463
+ }
4464
+ const depletedAtEpoch = takeNumber(record.depleted_at_epoch ?? record.depletedAtEpoch, "positive");
4465
+ if (depletedAtEpoch === "invalid")
4466
+ return null;
4467
+ if (depletedAtEpoch !== "absent") {
4468
+ group.depletedAtEpoch = depletedAtEpoch;
4469
+ any = true;
4470
+ }
4471
+ const fiveHourWindowsLeft = takeNumber(record.five_hour_windows_left ?? record.fiveHourWindowsLeft, "zero");
4472
+ if (fiveHourWindowsLeft === "invalid")
4473
+ return null;
4474
+ if (fiveHourWindowsLeft !== "absent") {
4475
+ group.fiveHourWindowsLeft = fiveHourWindowsLeft;
4476
+ any = true;
4477
+ }
4478
+ return any ? group : null;
4479
+ }
4361
4480
  var DEFAULT_TIMEOUT_MS = 1e4;
4362
4481
  var MAX_BUFFER = 1024 * 1024;
4363
4482
  function defaultRunner(command, args, options) {
@@ -4419,7 +4538,8 @@ function normalizeBucket(value, fetchedAt) {
4419
4538
  id,
4420
4539
  util: clamp(util, 0, 100),
4421
4540
  resetEpoch: Math.max(0, resetEpoch),
4422
- resetAfterSeconds: resetAfter === null ? null : Math.max(0, resetAfter)
4541
+ resetAfterSeconds: resetAfter === null ? null : Math.max(0, resetAfter),
4542
+ burn: parseBurnFields(bucket)
4423
4543
  };
4424
4544
  }
4425
4545
  function normalizeTopLevelBucket(record, util, fetchedAt) {
@@ -4432,13 +4552,27 @@ function normalizeTopLevelBucket(record, util, fetchedAt) {
4432
4552
  id: "top_level",
4433
4553
  util: clamp(util, 0, 100),
4434
4554
  resetEpoch: Math.max(0, resetEpoch),
4435
- resetAfterSeconds: resetAfter === null ? null : Math.max(0, resetAfter)
4555
+ resetAfterSeconds: resetAfter === null ? null : Math.max(0, resetAfter),
4556
+ burn: parseBurnFields(record)
4436
4557
  };
4437
4558
  }
4438
4559
  function toWindow(bucket) {
4439
4560
  if (!bucket)
4440
4561
  return null;
4441
- return { util: bucket.util, resetEpoch: bucket.resetEpoch };
4562
+ const window = { util: bucket.util, resetEpoch: bucket.resetEpoch };
4563
+ if (bucket.burn) {
4564
+ if (bucket.burn.burnRate !== undefined)
4565
+ window.burnRate = bucket.burn.burnRate;
4566
+ if (bucket.burn.burnConfident !== undefined)
4567
+ window.burnConfident = bucket.burn.burnConfident;
4568
+ if (bucket.burn.runwaySeconds !== undefined)
4569
+ window.runwaySeconds = bucket.burn.runwaySeconds;
4570
+ if (bucket.burn.depletedAtEpoch !== undefined)
4571
+ window.depletedAtEpoch = bucket.burn.depletedAtEpoch;
4572
+ if (bucket.burn.fiveHourWindowsLeft !== undefined)
4573
+ window.fiveHourWindowsLeft = bucket.burn.fiveHourWindowsLeft;
4574
+ }
4575
+ return window;
4442
4576
  }
4443
4577
  function bucketSortKey(bucket) {
4444
4578
  if (bucket.resetAfterSeconds !== null)
@@ -4518,10 +4652,11 @@ function normalizeTolerantProbeRecord(record) {
4518
4652
  };
4519
4653
  }
4520
4654
  var PROBE_SCHEMA_PARSERS = {
4521
- "1": normalizeTolerantProbeRecord
4655
+ "1": normalizeTolerantProbeRecord,
4656
+ "2": normalizeTolerantProbeRecord
4522
4657
  };
4523
4658
  function schemaVersionKey(record) {
4524
- const value = record.schema_version ?? record.schemaVersion;
4659
+ const value = record.schema_version ?? record.schemaVersion ?? record.probe_schema ?? record.probeSchema;
4525
4660
  if (typeof value === "number" && Number.isFinite(value))
4526
4661
  return String(value);
4527
4662
  if (typeof value === "string" && value.trim() !== "")
@@ -5119,7 +5254,7 @@ function ensureBudgetCoordinatorStarted() {
5119
5254
  if (!BUDGET_CONFIG.enabled)
5120
5255
  return;
5121
5256
  if (!budgetCoordinator) {
5122
- log(`Budget coordinator config: pollSeconds=${BUDGET_CONFIG.pollSeconds} pauseAt=${BUDGET_CONFIG.pauseAt} ` + `resumeBelow=${BUDGET_CONFIG.resumeBelow} syncDriftPct=${BUDGET_CONFIG.syncDriftPct} ` + `parallel=${BUDGET_CONFIG.parallel.minRemainingPct}%/${BUDGET_CONFIG.parallel.timeWindowSec}s ` + `codexTierControl=${BUDGET_CONFIG.codexTierControl} ` + `codexTiersFull=${BUDGET_CONFIG.codexTiers.full ? "configured" : "missing"}`);
5257
+ log(`Budget coordinator config: pollSeconds=${BUDGET_CONFIG.pollSeconds} pauseAt=${BUDGET_CONFIG.pauseAt} ` + `resumeBelow=${BUDGET_CONFIG.resumeBelow} syncDriftPct=${BUDGET_CONFIG.syncDriftPct} ` + `parallel=${BUDGET_CONFIG.parallel.minRemainingPct}%/${BUDGET_CONFIG.parallel.timeWindowSec}s ` + `codexTierControl=${BUDGET_CONFIG.codexTierControl} ` + `codexTiersFull=${BUDGET_CONFIG.codexTiers.full ? "configured" : "missing"} ` + `strategy=${BUDGET_CONFIG.strategy}`);
5123
5258
  budgetCoordinator = new BudgetCoordinator({
5124
5259
  source: createQuotaSource({ log }),
5125
5260
  config: BUDGET_CONFIG,