Skip to content

Commit 9c1b40e

Browse files
committed
air: add --llm-mode support
Chris has announced new way of running the LLM reviews: https://lore.kernel.org/b187e0c1-1df8-4529-bfe4-0a1d65221adc@meta.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent 2b6c5c6 commit 9c1b40e

4 files changed

Lines changed: 325 additions & 141 deletions

File tree

air-submit.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ def submit_review(url: str, token: str, tree: str, branch: Optional[str],
8585
patches: Optional[List[str]] = None,
8686
patchwork_series_id: Optional[int] = None,
8787
chash: Optional[str] = None,
88-
model: Optional[str] = None) -> str:
88+
model: Optional[str] = None,
89+
llm_mode: Optional[str] = None) -> str:
8990
"""Submit patches for review
9091
9192
Args:
@@ -97,6 +98,7 @@ def submit_review(url: str, token: str, tree: str, branch: Optional[str],
9798
patchwork_series_id: Patchwork series ID (or None if using patches/hash)
9899
chash: Git hash or range (or None if using patches/patchwork)
99100
model: Optional model name (sonnet, opus, haiku)
101+
llm_mode: Optional LLM mode (classic, orc)
100102
101103
Returns:
102104
Review ID
@@ -124,6 +126,9 @@ def submit_review(url: str, token: str, tree: str, branch: Optional[str],
124126
if model:
125127
payload['model'] = model
126128

129+
if llm_mode:
130+
payload['llm_mode'] = llm_mode
131+
127132
try:
128133
response = requests.post(api_url, json=payload, timeout=30)
129134
response.raise_for_status()
@@ -301,6 +306,7 @@ def main():
301306
tree = netdev/net-next
302307
branch = main
303308
model = sonnet
309+
llm_mode = classic
304310
305311
Command-line arguments always override config file values.
306312
To unset a config value, pass an empty string:
@@ -320,6 +326,8 @@ def main():
320326
help='Git branch name (optional)')
321327
parser.add_argument('--model',
322328
help='Claude model to use (e.g., sonnet, opus, haiku) [optional]')
329+
parser.add_argument('--llm-mode', choices=['classic', 'orc'],
330+
help='LLM review mode: classic (default) or orc (agent-based)')
323331
parser.add_argument('--format', choices=['json', 'markup', 'inline'],
324332
default='inline',
325333
help='Review output format (default: inline)')
@@ -353,6 +361,8 @@ def main():
353361
args.branch = config.get('air', 'branch')
354362
if args.model is None and config.has_option('air', 'model'):
355363
args.model = config.get('air', 'model')
364+
if getattr(args, 'llm_mode', None) is None and config.has_option('air', 'llm_mode'):
365+
args.llm_mode = config.get('air', 'llm_mode')
356366

357367
# Convert empty strings to None (allows unsetting config values)
358368
if args.token == '':
@@ -361,6 +371,8 @@ def main():
361371
args.branch = None
362372
if args.model == '':
363373
args.model = None
374+
if getattr(args, 'llm_mode', None) == '':
375+
args.llm_mode = None
364376

365377
# Validate that we have URL
366378
if not args.url:
@@ -408,19 +420,22 @@ def main():
408420
review_id = submit_review(args.url, args.token, args.tree,
409421
args.branch,
410422
patchwork_series_id=args.pw_series,
411-
model=args.model)
423+
model=args.model,
424+
llm_mode=getattr(args, 'llm_mode', None))
412425
elif args.hash:
413426
print(f"Submitting git hash/range {args.hash} to {args.tree}...")
414427
review_id = submit_review(args.url, args.token, args.tree,
415428
args.branch, chash=args.hash,
416-
model=args.model)
429+
model=args.model,
430+
llm_mode=getattr(args, 'llm_mode', None))
417431
else:
418432
print(f"Reading {len(args.patches)} patch file(s)...")
419433
patches = read_patch_files(args.patches)
420434
print(f"Submitting to {args.tree}...")
421435
review_id = submit_review(args.url, args.token, args.tree,
422436
args.branch, patches=patches,
423-
model=args.model)
437+
model=args.model,
438+
llm_mode=getattr(args, 'llm_mode', None))
424439

425440
print(f"Review ID: {review_id}")
426441

ui/ai-local.html

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,17 +263,53 @@ <h2>Review Prompts</h2>
263263
Clone this repository to get the latest prompts, and ask your
264264
favorite LLM to use them to review your code.
265265
</p>
266+
267+
<h3>Review Modes</h3>
266268
<p>
267-
The exact prompt we use on netdev is:
269+
There are two modes for running reviews:
270+
</p>
271+
272+
<h4>Classic Mode</h4>
273+
<p>
274+
The original single-prompt mode. Works well for small to medium patches.
268275
</p>
269276
<div class="prompt-text">Current directory is the root of a Linux Kernel git repository.
270277
Read the prompt from kernel/review-core.md.
271278
Using the prompt, do a deep dive regression analysis of the HEAD commit.
272279
Use commit range &lt;base&gt;..&lt;head&gt; for the false-positive-guide.md section.</div>
273280

281+
<h4>Orc Mode (Recommended for Large Patches)</h4>
282+
<p>
283+
The newer agent-based mode that breaks the review into individual tasks.
284+
This mode is recommended for large diffs because it:
285+
</p>
286+
<ul>
287+
<li>Breaks large diffs into smaller chunks and reviews each chunk individually</li>
288+
<li>Uses fewer tokens by avoiding repeated context for the entire diff</li>
289+
<li>Catches more bugs through focused analysis of each section</li>
290+
<li>Pre-processes the code to extract modified functions, types, and call graphs</li>
291+
</ul>
292+
293+
<p>To use orc mode, first run the preprocessing script:</p>
294+
<pre><code>cd /path/to/linux
295+
kernel/scripts/create_changes.py HEAD</code></pre>
296+
297+
<p>Then invoke the LLM with the orc prompt:</p>
298+
<div class="prompt-text">Current directory is the root of a Linux Kernel git repository.
299+
Read the prompt from kernel/agent/orc.md and run it on the HEAD commit.</div>
300+
301+
<div class="note">
302+
<div class="note-title">When to use Orc Mode</div>
303+
<p>
304+
Use orc mode for patches with large diffs, multiple files, or complex changes.
305+
The preprocessing step extracts context that helps the LLM focus on relevant code
306+
without spending tokens discovering it on its own.
307+
</p>
308+
</div>
309+
274310
<p>
275311
Where <code>&lt;base&gt;..&lt;head&gt;</code> should be replaced by a real
276-
git commit hash range.
312+
git commit hash range (classic mode only).
277313
</p>
278314

279315
<h2>Output Format</h2>

ui/ai-review.html

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,10 @@ <h2>Review Information <span style="font-family: monospace; font-size: 0.75em; f
341341
<label>Model:</label>
342342
<span id="review-model"></span>
343343
</div>
344+
<div class="review-info-item" id="llm-mode-info" style="display: none;">
345+
<label>Mode:</label>
346+
<span id="review-llm-mode"></span>
347+
</div>
344348
<div class="review-info-item">
345349
<label>Submitted:</label>
346350
<span id="review-date"></span>
@@ -387,6 +391,7 @@ <h2>Review Information <span style="font-family: monospace; font-size: 0.75em; f
387391
<select id="format" onchange="changeFormat()">
388392
<option value="inline">Review</option>
389393
<option value="markup">Full output</option>
394+
<option value="metadata">Metadata</option>
390395
</select>
391396
</div>
392397

@@ -517,6 +522,12 @@ <h2>Review Information <span style="font-family: monospace; font-size: 0.75em; f
517522
document.getElementById('review-model').textContent = data.model;
518523
}
519524

525+
// LLM Mode
526+
if (data.llm_mode) {
527+
document.getElementById('llm-mode-info').style.display = 'block';
528+
document.getElementById('review-llm-mode').textContent = data.llm_mode;
529+
}
530+
520531
// Patchwork series ID
521532
if (data.patchwork_series_id) {
522533
document.getElementById('patchwork-info').style.display = 'block';

0 commit comments

Comments
 (0)