Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ export function ReviewAgentPageClient({
)
);
const councilEntitled = councilEntitlement?.entitled ?? false;
// Same gate as the manual council UI: local dev, or an entitled org behind the rollout flag.
const councilUiEnabled =
localCodeReviewDevelopmentEnabled || (councilEntitled && !!councilFlagEnabled);

const handlePlatformChange = (platform: Platform) => {
const params = new URLSearchParams();
Expand Down Expand Up @@ -297,7 +300,11 @@ export function ReviewAgentPageClient({
</TabsList>

<TabsContent value="config" className="mt-6 space-y-4">
<ReviewConfigForm organizationId={organizationId} platform="github" />
<ReviewConfigForm
organizationId={organizationId}
platform="github"
councilUiEnabled={councilUiEnabled}
/>
</TabsContent>

<TabsContent value="jobs" className="mt-6 space-y-4">
Expand Down Expand Up @@ -397,6 +404,7 @@ export function ReviewAgentPageClient({
<ReviewConfigForm
organizationId={organizationId}
platform="gitlab"
councilUiEnabled={councilUiEnabled}
gitlabStatusData={
gitlabStatusData
? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ import {
getManualCodeReviewConfig,
shouldPublishCodeReviewToProvider,
} from '@/lib/code-reviews/manual-config';
import { getAgentConfigForOwner } from '@/lib/agent-config/db/agent-configs';
import type { CodeReviewAgentConfig } from '@kilocode/db/schema-types';

const CallbackTextTruncationSchema = z
.object({
Expand Down Expand Up @@ -535,6 +537,25 @@ function isSupersededReview(review: CloudAgentCodeReview): boolean {
return review.terminal_reason === 'superseded';
}

/**
* Resolves the org/user Code Reviewer config for a review, used as the council-config source for
* AUTOMATED (webhook) council reviews, which carry no `manual_config`. Manual reviews resolve
* their council from `manual_config` and never need this. Returns null on any gap (no owner, no
* config) so council finalization fails safe rather than throwing.
*/
async function resolveOrgCodeReviewAgentConfig(
review: CloudAgentCodeReview
): Promise<CodeReviewAgentConfig | null> {
const owner = review.owned_by_organization_id
? ({ type: 'org', id: review.owned_by_organization_id } as const)
: review.owned_by_user_id
? ({ type: 'user', id: review.owned_by_user_id } as const)
: null;
if (!owner) return null;
const agentConfig = await getAgentConfigForOwner(owner, 'code_review', review.platform);
return agentConfig ? (agentConfig.config as CodeReviewAgentConfig) : null;
}

async function resolveTerminalOwner(
review: CloudAgentCodeReview,
reviewId: string
Expand Down Expand Up @@ -1060,6 +1081,15 @@ export async function POST(
// Code-owned council outcome for a completed council run. Set on whichever completion path
// runs below, then used to drive the merge gate (the council LLM never sets `gateResult`).
let councilResult: CodeReviewCouncilResult | null = null;
// Council-config source for AUTOMATED (webhook) council reviews, which carry no `manual_config`.
// Fetched once (only for completed council reviews without a manual config) and reused on
// whichever completion path runs. Manual/standard reviews skip the lookup.
const councilOrgAgentConfig: CodeReviewAgentConfig | null =
status === 'completed' &&
review.review_type === 'council' &&
getManualCodeReviewConfig(review) === null
? await resolveOrgCodeReviewAgentConfig(review)
: null;

if (
status === 'completed' &&
Expand All @@ -1076,6 +1106,7 @@ export async function POST(
councilResult = computeCouncilResultForReview({
review,
lastAssistantMessageText: rawPayload.lastAssistantMessageText,
orgAgentConfig: councilOrgAgentConfig,
});
const completionResult = await finalizeCompletedCodeReviewWithAnalytics({
codeReviewId: reviewId,
Expand Down Expand Up @@ -1370,6 +1401,7 @@ export async function POST(
councilResult = await finalizeCouncilResultForReview({
review,
lastAssistantMessageText: rawPayload.lastAssistantMessageText,
orgAgentConfig: councilOrgAgentConfig,
});
}

Expand Down
Loading