reviewRemote.ts
commands/review/reviewRemote.ts
317
Lines
11926
Bytes
4
Exports
12
Imports
10
Keywords
What this is
This page documents one file from the repository and includes its full source so you can read it without leaving the docs site.
Beginner explanation
This file lives in the command layer. It likely turns a user action into concrete program behavior.
How it is used
Start from the exports list and related files. Those are the easiest clues for where this file fits into the system.
Expert explanation
Architecturally, this file intersects with commands, planner-verifier-agents, remote-bridge. It contains 317 lines, 12 detected imports, and 4 detected exports.
Important relationships
Detected exports
confirmOverageOverageGatecheckOverageGatelaunchRemoteReview
Keywords
ultrareviewsessionrepokindlogeventquotatextbillingnoteproceedlaunch
Detected imports
@anthropic-ai/sdk/resources/messages.js../../services/analytics/growthbook.js../../services/analytics/index.js../../services/api/ultrareviewQuota.js../../services/api/usage.js../../Tool.js../../tasks/RemoteAgentTask/RemoteAgentTask.js../../utils/auth.js../../utils/detectRepository.js../../utils/execFileNoThrow.js../../utils/git.js../../utils/teleport.js
Source notes
This page embeds the full file contents. Small or leaf files are still indexed honestly instead of being over-explained.
Full source
/**
* Teleported /ultrareview execution. Creates a CCR session with the current repo,
* sends the review prompt as the initial message, and registers a
* RemoteAgentTask so the polling loop pipes results back into the local
* session via task-notification. Mirrors the /ultraplan → CCR flow.
*
* TODO(#22051): pass useBundleMode once landed so local-only / uncommitted
* repo state is captured. The GitHub-clone path (current) only works for
* pushed branches on repos with the Claude GitHub app installed.
*/
import type { ContentBlockParam } from '@anthropic-ai/sdk/resources/messages.js'
import { getFeatureValue_CACHED_MAY_BE_STALE } from '../../services/analytics/growthbook.js'
import {
type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
logEvent,
} from '../../services/analytics/index.js'
import { fetchUltrareviewQuota } from '../../services/api/ultrareviewQuota.js'
import { fetchUtilization } from '../../services/api/usage.js'
import type { ToolUseContext } from '../../Tool.js'
import {
checkRemoteAgentEligibility,
formatPreconditionError,
getRemoteTaskSessionUrl,
registerRemoteAgentTask,
} from '../../tasks/RemoteAgentTask/RemoteAgentTask.js'
import { isEnterpriseSubscriber, isTeamSubscriber } from '../../utils/auth.js'
import { detectCurrentRepositoryWithHost } from '../../utils/detectRepository.js'
import { execFileNoThrow } from '../../utils/execFileNoThrow.js'
import { getDefaultBranch, gitExe } from '../../utils/git.js'
import { teleportToRemote } from '../../utils/teleport.js'
// One-time session flag: once the user confirms overage billing via the
// dialog, all subsequent /ultrareview invocations in this session proceed
// without re-prompting.
let sessionOverageConfirmed = false
export function confirmOverage(): void {
sessionOverageConfirmed = true
}
export type OverageGate =
| { kind: 'proceed'; billingNote: string }
| { kind: 'not-enabled' }
| { kind: 'low-balance'; available: number }
| { kind: 'needs-confirm' }
/**
* Determine whether the user can launch an ultrareview and under what
* billing terms. Fetches quota and utilization in parallel.
*/
export async function checkOverageGate(): Promise<OverageGate> {
// Team and Enterprise plans include ultrareview — no free-review quota
// or Extra Usage dialog. The quota endpoint is scoped to consumer plans
// (pro/max); hitting it on team/ent would surface a confusing dialog.
if (isTeamSubscriber() || isEnterpriseSubscriber()) {
return { kind: 'proceed', billingNote: '' }
}
const [quota, utilization] = await Promise.all([
fetchUltrareviewQuota(),
fetchUtilization().catch(() => null),
])
// No quota info (non-subscriber or endpoint down) — let it through,
// server-side billing will handle it.
if (!quota) {
return { kind: 'proceed', billingNote: '' }
}
if (quota.reviews_remaining > 0) {
return {
kind: 'proceed',
billingNote: ` This is free ultrareview ${quota.reviews_used + 1} of ${quota.reviews_limit}.`,
}
}
// Utilization fetch failed (transient network error, timeout, etc.) —
// let it through, same rationale as the quota fallback above.
if (!utilization) {
return { kind: 'proceed', billingNote: '' }
}
// Free reviews exhausted — check Extra Usage setup.
const extraUsage = utilization.extra_usage
if (!extraUsage?.is_enabled) {
logEvent('tengu_review_overage_not_enabled', {})
return { kind: 'not-enabled' }
}
// Check available balance (null monthly_limit = unlimited).
const monthlyLimit = extraUsage.monthly_limit
const usedCredits = extraUsage.used_credits ?? 0
const available =
monthlyLimit === null || monthlyLimit === undefined
? Infinity
: monthlyLimit - usedCredits
if (available < 10) {
logEvent('tengu_review_overage_low_balance', { available })
return { kind: 'low-balance', available }
}
if (!sessionOverageConfirmed) {
logEvent('tengu_review_overage_dialog_shown', {})
return { kind: 'needs-confirm' }
}
return {
kind: 'proceed',
billingNote: ' This review bills as Extra Usage.',
}
}
/**
* Launch a teleported review session. Returns ContentBlockParam[] describing
* the launch outcome for injection into the local conversation (model is then
* queried with this content, so it can narrate the launch to the user).
*
* Returns ContentBlockParam[] with user-facing error messages on recoverable
* failures (missing merge-base, empty diff, bundle too large), or null on
* other failures so the caller falls through to the local-review prompt.
* Reason is captured in analytics.
*
* Caller must run checkOverageGate() BEFORE calling this function
* (ultrareviewCommand.tsx handles the dialog).
*/
export async function launchRemoteReview(
args: string,
context: ToolUseContext,
billingNote?: string,
): Promise<ContentBlockParam[] | null> {
const eligibility = await checkRemoteAgentEligibility()
// Synthetic DEFAULT_CODE_REVIEW_ENVIRONMENT_ID works without per-org CCR
// setup, so no_remote_environment isn't a blocker. Server-side quota
// consume at session creation routes billing: first N zero-rate, then
// anthropic:cccr org-service-key (overage-only).
if (!eligibility.eligible) {
const blockers = eligibility.errors.filter(
e => e.type !== 'no_remote_environment',
)
if (blockers.length > 0) {
logEvent('tengu_review_remote_precondition_failed', {
precondition_errors: blockers
.map(e => e.type)
.join(
',',
) as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
})
const reasons = blockers.map(formatPreconditionError).join('\n')
return [
{
type: 'text',
text: `Ultrareview cannot launch:\n${reasons}`,
},
]
}
}
const resolvedBillingNote = billingNote ?? ''
const prNumber = args.trim()
const isPrNumber = /^\d+$/.test(prNumber)
// Synthetic code_review env. Go taggedid.FromUUID(TagEnvironment,
// UUID{...,0x02}) encodes with version prefix '01' — NOT Python's
// legacy tagged_id() format. Verified in prod.
const CODE_REVIEW_ENV_ID = 'env_011111111111111111111113'
// Lite-review bypasses bughunter.go entirely, so it doesn't see the
// webhook's bug_hunter_config (different GB project). These env vars are
// the only tuning surface — without them, run_hunt.sh's bash defaults
// apply (60min, 120s agent timeout), and 120s kills verifiers mid-run
// which causes infinite respawn.
//
// total_wallclock must stay below RemoteAgentTask's 30min poll timeout
// with headroom for finalization (~3min synthesis). Per-field guards
// match autoDream.ts — GB cache can return stale wrong-type values.
const raw = getFeatureValue_CACHED_MAY_BE_STALE<Record<
string,
unknown
> | null>('tengu_review_bughunter_config', null)
const posInt = (v: unknown, fallback: number, max?: number): number => {
if (typeof v !== 'number' || !Number.isFinite(v)) return fallback
const n = Math.floor(v)
if (n <= 0) return fallback
return max !== undefined && n > max ? fallback : n
}
// Upper bounds: 27min on wallclock leaves ~3min for finalization under
// RemoteAgentTask's 30min poll timeout. If GB is set above that, the
// hang we're fixing comes back — fall to the safe default instead.
const commonEnvVars = {
BUGHUNTER_DRY_RUN: '1',
BUGHUNTER_FLEET_SIZE: String(posInt(raw?.fleet_size, 5, 20)),
BUGHUNTER_MAX_DURATION: String(posInt(raw?.max_duration_minutes, 10, 25)),
BUGHUNTER_AGENT_TIMEOUT: String(
posInt(raw?.agent_timeout_seconds, 600, 1800),
),
BUGHUNTER_TOTAL_WALLCLOCK: String(
posInt(raw?.total_wallclock_minutes, 22, 27),
),
...(process.env.BUGHUNTER_DEV_BUNDLE_B64 && {
BUGHUNTER_DEV_BUNDLE_B64: process.env.BUGHUNTER_DEV_BUNDLE_B64,
}),
}
let session
let command
let target
if (isPrNumber) {
// PR mode: refs/pull/N/head via github.com. Orchestrator --pr N.
const repo = await detectCurrentRepositoryWithHost()
if (!repo || repo.host !== 'github.com') {
logEvent('tengu_review_remote_precondition_failed', {})
return null
}
session = await teleportToRemote({
initialMessage: null,
description: `ultrareview: ${repo.owner}/${repo.name}#${prNumber}`,
signal: context.abortController.signal,
branchName: `refs/pull/${prNumber}/head`,
environmentId: CODE_REVIEW_ENV_ID,
environmentVariables: {
BUGHUNTER_PR_NUMBER: prNumber,
BUGHUNTER_REPOSITORY: `${repo.owner}/${repo.name}`,
...commonEnvVars,
},
})
command = `/ultrareview ${prNumber}`
target = `${repo.owner}/${repo.name}#${prNumber}`
} else {
// Branch mode: bundle the working tree, orchestrator diffs against
// the fork point. No PR, no existing comments, no dedup.
const baseBranch = (await getDefaultBranch()) || 'main'
// Env-manager's `git remote remove origin` after bundle-clone
// deletes refs/remotes/origin/* — the base branch name won't resolve
// in the container. Pass the merge-base SHA instead: it's reachable
// from HEAD's history so `git diff <sha>` works without a named ref.
const { stdout: mbOut, code: mbCode } = await execFileNoThrow(
gitExe(),
['merge-base', baseBranch, 'HEAD'],
{ preserveOutputOnError: false },
)
const mergeBaseSha = mbOut.trim()
if (mbCode !== 0 || !mergeBaseSha) {
logEvent('tengu_review_remote_precondition_failed', {})
return [
{
type: 'text',
text: `Could not find merge-base with ${baseBranch}. Make sure you're in a git repo with a ${baseBranch} branch.`,
},
]
}
// Bail early on empty diffs instead of launching a container that
// will just echo "no changes".
const { stdout: diffStat, code: diffCode } = await execFileNoThrow(
gitExe(),
['diff', '--shortstat', mergeBaseSha],
{ preserveOutputOnError: false },
)
if (diffCode === 0 && !diffStat.trim()) {
logEvent('tengu_review_remote_precondition_failed', {})
return [
{
type: 'text',
text: `No changes against the ${baseBranch} fork point. Make some commits or stage files first.`,
},
]
}
session = await teleportToRemote({
initialMessage: null,
description: `ultrareview: ${baseBranch}`,
signal: context.abortController.signal,
useBundle: true,
environmentId: CODE_REVIEW_ENV_ID,
environmentVariables: {
BUGHUNTER_BASE_BRANCH: mergeBaseSha,
...commonEnvVars,
},
})
if (!session) {
logEvent('tengu_review_remote_teleport_failed', {})
return [
{
type: 'text',
text: 'Repo is too large. Push a PR and use `/ultrareview <PR#>` instead.',
},
]
}
command = '/ultrareview'
target = baseBranch
}
if (!session) {
logEvent('tengu_review_remote_teleport_failed', {})
return null
}
registerRemoteAgentTask({
remoteTaskType: 'ultrareview',
session,
command,
context,
isRemoteReview: true,
})
logEvent('tengu_review_remote_launched', {})
const sessionUrl = getRemoteTaskSessionUrl(session.id)
// Concise — the tool-output block is visible to the user, so the model
// shouldn't echo the same info. Just enough for Claude to acknowledge the
// launch without restating the target/URL (both already printed above).
return [
{
type: 'text',
text: `Ultrareview launched for ${target} (~10–20 min, runs in the cloud). Track: ${sessionUrl}${resolvedBillingNote} Findings arrive via task-notification. Briefly acknowledge the launch to the user without repeating the target or URL — both are already visible in the tool output above.`,
},
]
}