feat(offload): managed tier (CodeGraph AI) — metered reasoning via org token [WIP]
Adds the managed offload mode: point codegraph_explore at the CodeGraph AI metered gateway (https://ai.getcodegraph.com) with an org token instead of a BYO provider key. Same synthesis client, pointed at codegraph-ai-proxy (a metered OpenAI-compatible gateway). - credentials.ts — org token in ~/.codegraph/credentials.json (0600); unlike a BYO provider key it's a revocable org-scoped auth token (gh/npm-login style), kept out of config.json - config.ts — managed branch in resolveOffload: default gateway URL + public model id (openai/gpt-oss-120b) + login token as bearer; managed requires a token to be enabled - reasoner.ts — fetchUsage() reads the credit balance from /v1/usage - bin/codegraph.ts — `codegraph offload login --token <t>` / `logout`; status shows the managed tier + live balance Proven GREEN end-to-end against a local wrangler-dev of the proxy: org token validated, credits prechecked, real Cerebras synthesis returned, and credits metered + charged (250,000 → 248,473). Graceful degrade on upstream failure; balance via /v1/usage. Phase 3 (codegraph login device flow) replaces the manual --token. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
db4c9f3641
commit
da5c6c2f79
+46
-4
@@ -37,6 +37,8 @@ import { relaunchWithWasmRuntimeFlagsIfNeeded } from '../extraction/wasm-runtime
|
||||
import { EXTRACTION_VERSION } from '../extraction/extraction-version';
|
||||
import { getTelemetry, TELEMETRY_DOCS, recordIndexEvent } from '../telemetry';
|
||||
import { writeOffloadConfig, resolveOffload } from '../reasoning/config';
|
||||
import { writeOffloadToken } from '../reasoning/credentials';
|
||||
import { fetchUsage } from '../reasoning/reasoner';
|
||||
|
||||
// Lazy-load heavy modules (CodeGraph, runInstaller) to keep CLI startup fast.
|
||||
async function loadCodeGraph(): Promise<typeof import('../index')> {
|
||||
@@ -1382,12 +1384,52 @@ offloadCmd
|
||||
});
|
||||
|
||||
offloadCmd
|
||||
.command('status')
|
||||
.description('Show the current reasoning-offload configuration')
|
||||
.command('login')
|
||||
.description('Use the managed CodeGraph AI tier (metered) with your account token')
|
||||
.requiredOption('--token <token>', 'Your CodeGraph AI org token')
|
||||
.option('--url <url>', 'Override the managed gateway URL (advanced/testing)')
|
||||
.option('--model <model>', 'Override the model id')
|
||||
.action((opts: { token: string; url?: string; model?: string }) => {
|
||||
// Phase 2: the token is pasted in. A future `codegraph login` device flow will
|
||||
// mint and store it automatically.
|
||||
writeOffloadConfig({ managed: true, url: opts.url, model: opts.model });
|
||||
writeOffloadToken(opts.token);
|
||||
success('Reasoning offload: signed in to CodeGraph AI (managed).');
|
||||
info(' Credits burn from your account. Check the balance with `codegraph offload status`.');
|
||||
info(' Restart your editor/agent session for running MCP servers to pick it up.');
|
||||
});
|
||||
|
||||
offloadCmd
|
||||
.command('logout')
|
||||
.description('Sign out of CodeGraph AI and clear the stored token')
|
||||
.action(() => {
|
||||
writeOffloadToken(null);
|
||||
writeOffloadConfig(null);
|
||||
success('Signed out of CodeGraph AI; offload turned off.');
|
||||
});
|
||||
|
||||
offloadCmd
|
||||
.command('status')
|
||||
.description('Show the current reasoning-offload configuration (and managed balance)')
|
||||
.action(async () => {
|
||||
const c = resolveOffload();
|
||||
if (!c.enabled) {
|
||||
info('Reasoning offload: off. Enable with `codegraph offload set-endpoint <url>`.');
|
||||
if (c.managed) info('Reasoning offload: managed, but signed out. Run `codegraph offload login --token <token>`.');
|
||||
else info('Reasoning offload: off. Enable with `codegraph offload set-endpoint <url>` or `codegraph offload login`.');
|
||||
return;
|
||||
}
|
||||
if (c.managed) {
|
||||
success(`Reasoning offload: on — CodeGraph AI (managed)`);
|
||||
info(` endpoint: ${c.url}`);
|
||||
info(` model: ${c.model}`);
|
||||
info(` token: present (from ${c.keySource})`);
|
||||
const usage = await fetchUsage();
|
||||
if (usage && typeof usage.remaining === 'number') {
|
||||
const reset = usage.periodEnd ? ` · allowance resets ${new Date(usage.periodEnd).toISOString().slice(0, 10)}` : '';
|
||||
info(` credits: ${usage.remaining.toLocaleString()} remaining (plan ${usage.plan ?? '—'})${reset}`);
|
||||
} else {
|
||||
warn(' credits: could not reach CodeGraph AI to read your balance (the offload still degrades gracefully).');
|
||||
}
|
||||
return;
|
||||
}
|
||||
success(`Reasoning offload: on (${c.origin === 'env' ? 'from environment' : 'configured'})`);
|
||||
@@ -1400,7 +1442,7 @@ offloadCmd
|
||||
|
||||
offloadCmd
|
||||
.command('disable')
|
||||
.description('Turn off the reasoning offload')
|
||||
.description('Turn off the reasoning offload (keeps any saved login token)')
|
||||
.action(() => {
|
||||
writeOffloadConfig(null);
|
||||
success('Reasoning offload disabled.');
|
||||
|
||||
Reference in New Issue
Block a user