mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 14:16:43 +00:00
fix(cliproxy): attach entitlement evidence to agy failures
This commit is contained in:
@@ -185,6 +185,7 @@ interface ProjectLookupResult {
|
||||
tier?: AccountTier;
|
||||
rawTierId?: string | null;
|
||||
rawTierLabel?: string | null;
|
||||
entitlement?: ProviderEntitlementEvidence;
|
||||
error?: string;
|
||||
errorCode?: string;
|
||||
errorDetail?: string;
|
||||
@@ -219,7 +220,14 @@ function buildAntigravityFailure(
|
||||
bodyText?: string
|
||||
): Pick<
|
||||
QuotaResult,
|
||||
'error' | 'errorCode' | 'errorDetail' | 'actionHint' | 'retryable' | 'httpStatus' | 'needsReauth'
|
||||
| 'error'
|
||||
| 'errorCode'
|
||||
| 'errorDetail'
|
||||
| 'actionHint'
|
||||
| 'retryable'
|
||||
| 'httpStatus'
|
||||
| 'needsReauth'
|
||||
| 'entitlement'
|
||||
> & { isForbidden?: boolean } {
|
||||
const detail = normalizeErrorDetail(bodyText || '');
|
||||
|
||||
@@ -232,6 +240,13 @@ function buildAntigravityFailure(
|
||||
'Re-authenticate this account. If CLIProxy is running, retry after the proxy finishes refreshing the token.',
|
||||
needsReauth: true,
|
||||
errorDetail: detail,
|
||||
entitlement: buildProviderEntitlementEvidence({
|
||||
normalizedTier: 'unknown',
|
||||
source: 'runtime_inference',
|
||||
confidence: 'medium',
|
||||
accessState: 'unknown',
|
||||
capacityState: 'unknown',
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -243,6 +258,13 @@ function buildAntigravityFailure(
|
||||
actionHint: 'This account does not have Gemini Code Assist quota access.',
|
||||
isForbidden: true,
|
||||
errorDetail: detail,
|
||||
entitlement: buildProviderEntitlementEvidence({
|
||||
normalizedTier: 'unknown',
|
||||
source: 'runtime_inference',
|
||||
confidence: 'medium',
|
||||
accessState: 'not_entitled',
|
||||
capacityState: 'unknown',
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -254,6 +276,13 @@ function buildAntigravityFailure(
|
||||
actionHint: 'Retry later. This looks temporary.',
|
||||
retryable: true,
|
||||
errorDetail: detail,
|
||||
entitlement: buildProviderEntitlementEvidence({
|
||||
normalizedTier: 'unknown',
|
||||
source: 'runtime_inference',
|
||||
confidence: 'low',
|
||||
accessState: 'unknown',
|
||||
capacityState: 'rate_limited',
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -265,6 +294,13 @@ function buildAntigravityFailure(
|
||||
actionHint: 'Retry later. This looks temporary.',
|
||||
retryable: true,
|
||||
errorDetail: detail,
|
||||
entitlement: buildProviderEntitlementEvidence({
|
||||
normalizedTier: 'unknown',
|
||||
source: 'runtime_inference',
|
||||
confidence: 'low',
|
||||
accessState: 'unknown',
|
||||
capacityState: 'temporarily_unavailable',
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -276,6 +312,13 @@ function buildAntigravityFailure(
|
||||
actionHint: 'Retry later. The provider appears unavailable.',
|
||||
retryable: true,
|
||||
errorDetail: detail,
|
||||
entitlement: buildProviderEntitlementEvidence({
|
||||
normalizedTier: 'unknown',
|
||||
source: 'runtime_inference',
|
||||
confidence: 'low',
|
||||
accessState: 'unknown',
|
||||
capacityState: 'temporarily_unavailable',
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -285,6 +328,13 @@ function buildAntigravityFailure(
|
||||
error: `API error: ${status}`,
|
||||
errorCode: 'quota_request_failed',
|
||||
errorDetail: detail,
|
||||
entitlement: buildProviderEntitlementEvidence({
|
||||
normalizedTier: 'unknown',
|
||||
source: 'runtime_inference',
|
||||
confidence: 'low',
|
||||
accessState: 'unknown',
|
||||
capacityState: 'unknown',
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -292,6 +342,13 @@ function buildAntigravityFailure(
|
||||
error: 'Quota request failed',
|
||||
errorCode: 'quota_request_failed',
|
||||
errorDetail: detail,
|
||||
entitlement: buildProviderEntitlementEvidence({
|
||||
normalizedTier: 'unknown',
|
||||
source: 'runtime_inference',
|
||||
confidence: 'low',
|
||||
accessState: 'unknown',
|
||||
capacityState: 'unknown',
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -581,6 +638,14 @@ async function getProjectId(accountId: string, accessToken: string): Promise<Pro
|
||||
errorCode: 'account_unprovisioned',
|
||||
actionHint: 'Complete sign-in in the Antigravity app, then retry quota refresh.',
|
||||
isUnprovisioned: true,
|
||||
entitlement: buildProviderEntitlementEvidence({
|
||||
normalizedTier: 'unknown',
|
||||
source: 'runtime_inference',
|
||||
confidence: 'medium',
|
||||
accessState: 'unknown',
|
||||
capacityState: 'unknown',
|
||||
notes: 'Project provisioning is incomplete for this account.',
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -881,6 +946,10 @@ export async function fetchAllProviderQuotas(
|
||||
return results;
|
||||
}
|
||||
|
||||
export const __testExports = {
|
||||
buildAntigravityFailure,
|
||||
};
|
||||
|
||||
/**
|
||||
* Find available account with remaining quota
|
||||
* Used by preflight check for auto-switching
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import { describe, expect, it } from 'bun:test';
|
||||
|
||||
async function loadAntigravityQuotaTestExports() {
|
||||
const moduleId = Date.now() + Math.random();
|
||||
const mod = await import(`../../../src/cliproxy/quota-fetcher?agy-quota-fetcher=${moduleId}`);
|
||||
return mod.__testExports;
|
||||
}
|
||||
|
||||
describe('Antigravity quota failure metadata', () => {
|
||||
it('marks 403 failures as not entitled', async () => {
|
||||
const { buildAntigravityFailure } = await loadAntigravityQuotaTestExports();
|
||||
|
||||
const result = buildAntigravityFailure(403, 'forbidden');
|
||||
|
||||
expect(result.entitlement).toMatchObject({
|
||||
accessState: 'not_entitled',
|
||||
capacityState: 'unknown',
|
||||
});
|
||||
});
|
||||
|
||||
it('marks 429 failures as rate limited', async () => {
|
||||
const { buildAntigravityFailure } = await loadAntigravityQuotaTestExports();
|
||||
|
||||
const result = buildAntigravityFailure(429, 'rate limited');
|
||||
|
||||
expect(result.entitlement).toMatchObject({
|
||||
accessState: 'unknown',
|
||||
capacityState: 'rate_limited',
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user