feat: default reviewer is always claude-code (#2241) - temporary change
This commit is contained in:
parent
78cbe22928
commit
010c7e4c1a
|
|
@ -39,7 +39,7 @@ type ProjectConfig struct {
|
||||||
|
|
||||||
// Reviewers names the agent(s) that review a worker's PR when a review is
|
// Reviewers names the agent(s) that review a worker's PR when a review is
|
||||||
// triggered. It is configured independently of the Worker override; an empty
|
// triggered. It is configured independently of the Worker override; an empty
|
||||||
// list falls back to the worker's own harness (see ResolveReviewerHarness).
|
// list falls back to claude-code (see ResolveReviewerHarness).
|
||||||
Reviewers []ReviewerConfig `json:"reviewers,omitempty"`
|
Reviewers []ReviewerConfig `json:"reviewers,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -55,15 +55,11 @@ type ReviewerConfig struct {
|
||||||
const FallbackReviewerHarness = ReviewerClaudeCode
|
const FallbackReviewerHarness = ReviewerClaudeCode
|
||||||
|
|
||||||
// ResolveReviewerHarness picks the reviewer harness for a worker. A configured
|
// ResolveReviewerHarness picks the reviewer harness for a worker. A configured
|
||||||
// reviewer wins; otherwise it reuses the worker's own harness when that harness
|
// reviewer wins; otherwise claude-code is used.
|
||||||
// is also a supported reviewer, falling back to claude-code.
|
func (c ProjectConfig) ResolveReviewerHarness(_ AgentHarness) ReviewerHarness {
|
||||||
func (c ProjectConfig) ResolveReviewerHarness(workerHarness AgentHarness) ReviewerHarness {
|
|
||||||
if len(c.Reviewers) > 0 {
|
if len(c.Reviewers) > 0 {
|
||||||
return c.Reviewers[0].Harness
|
return c.Reviewers[0].Harness
|
||||||
}
|
}
|
||||||
if h := ReviewerHarness(workerHarness); h.IsKnown() {
|
|
||||||
return h
|
|
||||||
}
|
|
||||||
return FallbackReviewerHarness
|
return FallbackReviewerHarness
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,13 +80,12 @@ func TestResolveReviewerHarness(t *testing.T) {
|
||||||
t.Fatalf("configured reviewer = %q, want claude-code", got)
|
t.Fatalf("configured reviewer = %q, want claude-code", got)
|
||||||
}
|
}
|
||||||
|
|
||||||
// No reviewer configured: reuse the worker harness when it is also a
|
// No reviewer configured: always use claude-code.
|
||||||
// supported reviewer (claude-code is).
|
|
||||||
if got := (ProjectConfig{}).ResolveReviewerHarness(HarnessClaudeCode); got != ReviewerClaudeCode {
|
if got := (ProjectConfig{}).ResolveReviewerHarness(HarnessClaudeCode); got != ReviewerClaudeCode {
|
||||||
t.Fatalf("default = %q, want reviewer claude-code", got)
|
t.Fatalf("default = %q, want reviewer claude-code", got)
|
||||||
}
|
}
|
||||||
|
|
||||||
// A worker harness that is not a supported reviewer falls back to claude-code.
|
// A worker harness that is not claude-code also falls back to claude-code.
|
||||||
if got := (ProjectConfig{}).ResolveReviewerHarness(HarnessAider); got != FallbackReviewerHarness {
|
if got := (ProjectConfig{}).ResolveReviewerHarness(HarnessAider); got != FallbackReviewerHarness {
|
||||||
t.Fatalf("fallback = %q, want %q", got, FallbackReviewerHarness)
|
t.Fatalf("fallback = %q, want %q", got, FallbackReviewerHarness)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -375,8 +375,7 @@ func (e *Engine) List(ctx stdctx.Context, workerID domain.SessionID) (SessionRev
|
||||||
}
|
}
|
||||||
|
|
||||||
// reviewerHarness resolves which harness reviews the worker's PR: a configured
|
// reviewerHarness resolves which harness reviews the worker's PR: a configured
|
||||||
// reviewer wins, otherwise the worker's own harness is reused (falling back to
|
// reviewer wins, otherwise claude-code is used, per domain.ResolveReviewerHarness.
|
||||||
// claude-code), per domain.ResolveReviewerHarness.
|
|
||||||
func (e *Engine) reviewerHarness(ctx stdctx.Context, worker domain.SessionRecord) (domain.ReviewerHarness, error) {
|
func (e *Engine) reviewerHarness(ctx stdctx.Context, worker domain.SessionRecord) (domain.ReviewerHarness, error) {
|
||||||
var cfg domain.ProjectConfig
|
var cfg domain.ProjectConfig
|
||||||
if e.projects != nil {
|
if e.projects != nil {
|
||||||
|
|
|
||||||
|
|
@ -270,7 +270,7 @@ function ReviewerSelect({ id, value, onChange }: { id: string; value: string; on
|
||||||
<SelectValue />
|
<SelectValue />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="__default__">Project default</SelectItem>
|
<SelectItem value="__default__">claude-code (default)</SelectItem>
|
||||||
{REVIEWER_OPTIONS.map((reviewer) => (
|
{REVIEWER_OPTIONS.map((reviewer) => (
|
||||||
<SelectItem key={reviewer} value={reviewer}>
|
<SelectItem key={reviewer} value={reviewer}>
|
||||||
{reviewer}
|
{reviewer}
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,11 @@ const session = (prs: PullRequestFacts[]): WorkspaceSession => ({
|
||||||
prs,
|
prs,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const sessionWithProvider = (prs: PullRequestFacts[], provider: WorkspaceSession["provider"]): WorkspaceSession => ({
|
||||||
|
...session(prs),
|
||||||
|
provider,
|
||||||
|
});
|
||||||
|
|
||||||
function renderWithQuery(children: ReactNode) {
|
function renderWithQuery(children: ReactNode) {
|
||||||
const client = new QueryClient({
|
const client = new QueryClient({
|
||||||
defaultOptions: { queries: { retry: false }, mutations: { retry: false } },
|
defaultOptions: { queries: { retry: false }, mutations: { retry: false } },
|
||||||
|
|
@ -199,6 +204,36 @@ describe("SessionInspector reviews tab", () => {
|
||||||
expect(onOpenReviewerTerminal).toHaveBeenCalledWith({ handleId: "reviewer-pane", harness: "codex" });
|
expect(onOpenReviewerTerminal).toHaveBeenCalledWith({ handleId: "reviewer-pane", harness: "codex" });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("shows claude-code as the default reviewer before a run exists", async () => {
|
||||||
|
getMock.mockImplementation(async (path: string) => {
|
||||||
|
if (path === "/api/v1/sessions/{sessionId}/reviews") {
|
||||||
|
return { data: { reviewerHandleId: "", reviews: [] } };
|
||||||
|
}
|
||||||
|
if (path === "/api/v1/projects/{id}") {
|
||||||
|
return {
|
||||||
|
data: {
|
||||||
|
status: "ok",
|
||||||
|
project: {
|
||||||
|
id: "ws-1",
|
||||||
|
kind: "git",
|
||||||
|
name: "my-app",
|
||||||
|
path: "/repo",
|
||||||
|
repo: "my-app",
|
||||||
|
defaultBranch: "main",
|
||||||
|
config: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return { data: undefined };
|
||||||
|
});
|
||||||
|
|
||||||
|
renderWithQuery(<SessionInspector session={sessionWithProvider([pr(3, "open")], "codex")} />);
|
||||||
|
await openReviewsTab();
|
||||||
|
|
||||||
|
expect(await screen.findByText("claude-code")).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
it("shows eligible and up-to-date PR review rows", async () => {
|
it("shows eligible and up-to-date PR review rows", async () => {
|
||||||
mockCommonGets([approvedReview], "reviewer-pane", [
|
mockCommonGets([approvedReview], "reviewer-pane", [
|
||||||
reviewState(3, "needs_review", "abc123"),
|
reviewState(3, "needs_review", "abc123"),
|
||||||
|
|
|
||||||
|
|
@ -483,7 +483,7 @@ function ReviewPanel({
|
||||||
}
|
}
|
||||||
|
|
||||||
const latest = reviewStates.find((review) => review.latestRun)?.latestRun;
|
const latest = reviewStates.find((review) => review.latestRun)?.latestRun;
|
||||||
const harness = latest?.harness || config?.reviewers?.[0]?.harness || session.provider || "reviewer";
|
const harness = latest?.harness || config?.reviewers?.[0]?.harness || "claude-code";
|
||||||
const terminalEnabled = Boolean(reviewerHandleId && onOpenTerminal);
|
const terminalEnabled = Boolean(reviewerHandleId && onOpenTerminal);
|
||||||
const aggregateVerdict = sessionReviewVerdict(reviewStates);
|
const aggregateVerdict = sessionReviewVerdict(reviewStates);
|
||||||
const runAction = reviewSessionRunAction(reviewStates, isTriggering);
|
const runAction = reviewSessionRunAction(reviewStates, isTriggering);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue