pi-ui-extend 0.1.31 → 0.1.32

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.
@@ -8,6 +8,7 @@ export type ModelUsageDescriptor = BaseModelUsageDescriptor & ({
8
8
  readonly kind: "google-antigravity";
9
9
  readonly quotaModelKey: string;
10
10
  readonly account: AntigravityQuotaAccount;
11
+ readonly accounts?: readonly AntigravityQuotaAccount[];
11
12
  });
12
13
  export type ModelUsageLimitWindow = {
13
14
  readonly remainingPercent: number;
@@ -35,14 +35,16 @@ export function modelUsageDescriptor(model) {
35
35
  }
36
36
  if (ANTIGRAVITY_QUOTA_PROVIDERS.has(provider)) {
37
37
  const quotaModelKey = resolveAntigravityQuotaModelKey(model);
38
- const account = readActiveAntigravityQuotaAccount();
38
+ const accounts = readAllAntigravityQuotaAccounts();
39
+ const account = readActiveAntigravityQuotaAccount(accounts);
39
40
  if (!quotaModelKey || !account)
40
41
  return undefined;
41
42
  return {
42
43
  kind: "google-antigravity",
43
- modelKey: `${model.provider}/${model.id}@${account.cacheKey}`,
44
+ modelKey: `${model.provider}/${model.id}@all:${accounts.map((item) => item.cacheKey).join(",")}`,
44
45
  quotaModelKey,
45
46
  account,
47
+ accounts,
46
48
  };
47
49
  }
48
50
  return undefined;
@@ -384,15 +386,9 @@ export function resolveAntigravityQuotaModelKey(model) {
384
386
  return undefined;
385
387
  }
386
388
  export function googleAntigravityUsageStatusFromResponse(data, descriptor, now = Date.now()) {
387
- const quotaInfo = data.models[descriptor.quotaModelKey]?.quotaInfo;
388
- if (!quotaInfo)
389
+ const window = googleAntigravityWindowFromResponse(data, descriptor.quotaModelKey, now);
390
+ if (!window)
389
391
  return undefined;
390
- const resetAt = parseResetTime(quotaInfo.resetTime, now);
391
- const window = {
392
- remainingPercent: quotaRemainingPercent(quotaInfo),
393
- resetAt,
394
- windowSeconds: Math.max(0, Math.round((resetAt - now) / 1000)),
395
- };
396
392
  const weekly = window.windowSeconds >= DAY_SECONDS ? window : undefined;
397
393
  const hourly = weekly ? undefined : window;
398
394
  return {
@@ -404,10 +400,48 @@ export function googleAntigravityUsageStatusFromResponse(data, descriptor, now =
404
400
  ...(hourly ? { hourly } : {}),
405
401
  };
406
402
  }
403
+ function googleAntigravityWindowFromResponse(data, quotaModelKey, now) {
404
+ const quotaInfo = data.models[quotaModelKey]?.quotaInfo;
405
+ if (!quotaInfo)
406
+ return undefined;
407
+ const resetAt = parseResetTime(quotaInfo.resetTime, now);
408
+ return {
409
+ remainingPercent: quotaRemainingPercent(quotaInfo),
410
+ resetAt,
411
+ windowSeconds: Math.max(0, Math.round((resetAt - now) / 1000)),
412
+ };
413
+ }
407
414
  async function queryGoogleAntigravityModelUsage(descriptor) {
408
415
  const now = Date.now();
409
- const response = await fetchGoogleAntigravityQuotaForAccount(descriptor.account, now);
410
- return googleAntigravityUsageStatusFromResponse(response, descriptor, now);
416
+ const accounts = descriptor.accounts?.length ? descriptor.accounts : [descriptor.account];
417
+ const windows = (await Promise.all(accounts.map(async (account) => {
418
+ try {
419
+ const response = await fetchGoogleAntigravityQuotaForAccount(account, now);
420
+ return googleAntigravityWindowFromResponse(response, descriptor.quotaModelKey, now);
421
+ }
422
+ catch {
423
+ return undefined;
424
+ }
425
+ }))).filter((window) => window !== undefined);
426
+ if (windows.length === 0)
427
+ return undefined;
428
+ const resetAt = Math.min(...windows.map((window) => window.resetAt));
429
+ const windowSeconds = Math.max(0, Math.round((resetAt - now) / 1000));
430
+ const aggregateWindow = {
431
+ remainingPercent: clampPercent(Math.round(windows.reduce((sum, window) => sum + window.remainingPercent, 0) / windows.length)),
432
+ resetAt,
433
+ windowSeconds,
434
+ };
435
+ const weekly = aggregateWindow.windowSeconds >= DAY_SECONDS ? aggregateWindow : undefined;
436
+ const hourly = weekly ? undefined : aggregateWindow;
437
+ return {
438
+ modelKey: descriptor.modelKey,
439
+ provider: "google-antigravity",
440
+ updatedAt: now,
441
+ accountEmail: "Σ",
442
+ ...(weekly ? { weekly } : {}),
443
+ ...(hourly ? { hourly } : {}),
444
+ };
411
445
  }
412
446
  const GOOGLE_ACCOUNT_QUOTA_WINDOWS = [
413
447
  { label: "Claude Opus", quotaModelKey: "claude-opus-4-6-thinking" },
@@ -440,8 +474,7 @@ async function queryGoogleAntigravityAccountUsage(now) {
440
474
  }));
441
475
  return results;
442
476
  }
443
- function readActiveAntigravityQuotaAccount() {
444
- const accounts = readAllAntigravityQuotaAccounts();
477
+ function readActiveAntigravityQuotaAccount(accounts = readAllAntigravityQuotaAccounts()) {
445
478
  const credential = readPiAuthSync().antigravity;
446
479
  return accounts[clampAccountIndex(credential?.activeIndex, accounts.length)];
447
480
  }
@@ -564,9 +597,9 @@ function googleQuotaResponseFromCachedQuota(cachedQuota, cachedQuotaUpdatedAt, n
564
597
  return Object.keys(models).length > 0 ? { models } : undefined;
565
598
  }
566
599
  function addCachedQuotaModels(models, quota, quotaModelKeys, cachedQuotaUpdatedAt, now) {
567
- if (!quota || !Number.isFinite(quota.remainingFraction))
600
+ if (!quota)
568
601
  return;
569
- const remainingFraction = quota.remainingFraction;
602
+ const remainingFraction = Number.isFinite(quota.remainingFraction) ? quota.remainingFraction : 0;
570
603
  const resetTime = cachedQuotaResetTimeForDisplay(quota.resetTime, cachedQuotaUpdatedAt, now);
571
604
  for (const quotaModelKey of quotaModelKeys) {
572
605
  models[quotaModelKey] = {
@@ -24,8 +24,8 @@ export interface DcpConfig {
24
24
  modelMaxContextLimits?: Record<string, number | string>
25
25
  modelMinContextLimits?: Record<string, number | string>
26
26
  summaryBuffer: boolean
27
- nudgeFrequency: number // inject nudge every N context events (default: 5)
28
- iterationNudgeThreshold: number // nudge after N tool calls since last user msg (default: 15)
27
+ nudgeFrequency: number // inject nudge every N context events (default: 2)
28
+ iterationNudgeThreshold: number // nudge after N tool calls since last user msg (default: 8)
29
29
  nudgeForce: "strong" | "soft"
30
30
  protectedTools: string[] // these tool outputs always protected from pruning
31
31
  protectTags: boolean
@@ -81,27 +81,27 @@ const DEFAULT_CONFIG: DcpConfig = {
81
81
  automaticStrategies: true,
82
82
  },
83
83
  compress: {
84
- maxContextPercent: 0.8,
85
- minContextPercent: 0.4,
84
+ maxContextPercent: 0.65,
85
+ minContextPercent: 0.25,
86
86
  modelMaxContextPercent: {},
87
87
  modelMinContextPercent: {},
88
88
  summaryBuffer: true,
89
- nudgeFrequency: 5,
90
- iterationNudgeThreshold: 15,
89
+ nudgeFrequency: 2,
90
+ iterationNudgeThreshold: 8,
91
91
  nudgeForce: "soft",
92
92
  protectedTools: ["compress", "write", "edit"],
93
93
  protectTags: false,
94
94
  protectUserMessages: false,
95
95
  autoCandidates: {
96
96
  enabled: true,
97
- minContextPercent: 0.4,
97
+ minContextPercent: 0.25,
98
98
  keepRecentTurns: 2,
99
99
  minMessages: 6,
100
100
  minTokens: 1500,
101
101
  },
102
102
  messageMode: {
103
103
  enabled: true,
104
- minContextPercent: 0.4,
104
+ minContextPercent: 0.25,
105
105
  keepRecentTurns: 2,
106
106
  mediumTokens: 500,
107
107
  highTokens: 5000,
@@ -174,6 +174,7 @@ You are at or beyond the configured max context threshold. This is an emergency
174
174
  You MUST use the \`compress\` tool now. Do not continue normal exploration until compression is handled.
175
175
 
176
176
  If you are in the middle of a critical atomic operation, finish that atomic step first, then compress immediately.
177
+ If a completed implementation+verification slice exists, compress it before replying or starting another task.
177
178
 
178
179
  RANGE STRATEGY (MANDATORY)
179
180
  Prioritize one large, closed, high-yield compression range first.
@@ -201,6 +202,8 @@ ACTION REQUIRED: Context usage is high.
201
202
  Before doing more exploration, look for a closed, self-contained range that no longer needs to stay raw and compress it now.
202
203
 
203
204
  Do not treat this as optional housekeeping. If any completed research, implementation, verification, CI-log inspection, or dead-end debugging slice is present, call the \`compress\` tool before continuing normal work.
205
+ If a completed implementation+verification slice exists, compress it before replying or starting another task.
206
+ High-priority stale tool outputs must be compressed once no exact raw text is needed.
204
207
 
205
208
  RANGE SELECTION
206
209
  Prefer older, resolved history. Avoid the newest active working slice unless it is clearly done.
@@ -222,6 +225,7 @@ If any range is cleanly closed and unlikely to be needed again, use the \`compre
222
225
  If direction has shifted, compress earlier ranges that are now less relevant.
223
226
 
224
227
  Do not defer this across another batch of searches, reads, CI log fetches, or tests. The next safe action should be compression whenever a closed slice exists.
228
+ High-priority stale tool outputs must be compressed once no exact raw text is needed.
225
229
 
226
230
  Prefer small, closed-range compressions over one broad compression.
227
231
  Use message-mode compression for isolated large stale messages.
@@ -238,6 +242,7 @@ ACTION REQUIRED: You've been iterating for a while after the last user message.
238
242
  Pause before the next non-atomic tool call. If there is a closed portion that is unlikely to be referenced immediately (for example, finished research before implementation, completed CI-log triage, a verified fix, or a dead-end investigation), use the \`compress\` tool on it now.
239
243
 
240
244
  Do not keep accumulating tool outputs while a completed slice remains raw. If a range is closed, compression is the next safe action.
245
+ If a completed implementation+verification slice exists, compress it before replying or starting another task.
241
246
 
242
247
  Prefer multiple short, closed ranges over one large range when several independent slices are ready.
243
248
  Use message-mode compression for isolated large stale messages.
@@ -149,11 +149,11 @@ export function resolveContextThresholds(
149
149
  minContextPercent: min ??
150
150
  resolveThresholdValue(config.compress.minContextLimit) ??
151
151
  resolveThresholdValue(config.compress.minContextPercent) ??
152
- 0.4,
152
+ 0.25,
153
153
  maxContextPercent: max ??
154
154
  resolveThresholdValue(config.compress.maxContextLimit) ??
155
155
  resolveThresholdValue(config.compress.maxContextPercent) ??
156
- 0.8,
156
+ 0.65,
157
157
  };
158
158
  }
159
159
 
@@ -291,11 +291,11 @@ export function getNudgeType(
291
291
  config.compress;
292
292
  const minContextPercent = coercePercentThreshold(
293
293
  thresholds.minContextPercent ?? config.compress.minContextPercent,
294
- 0.4,
294
+ 0.25,
295
295
  );
296
296
  const maxContextPercent = coercePercentThreshold(
297
297
  thresholds.maxContextPercent ?? config.compress.maxContextPercent,
298
- 0.8,
298
+ 0.65,
299
299
  );
300
300
  const cadence = Math.max(1, Math.floor(nudgeFrequency));
301
301
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-ui-extend",
3
- "version": "0.1.31",
3
+ "version": "0.1.32",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "bin": {