llm-cli-gateway 2.11.1 → 2.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/async-job-orchestration/SKILL.md +288 -0
- package/.agents/skills/implement-review-fix/SKILL.md +154 -0
- package/.agents/skills/multi-llm-review/SKILL.md +174 -0
- package/.agents/skills/public-demo-session/SKILL.md +100 -0
- package/.agents/skills/secure-orchestration/SKILL.md +227 -0
- package/.agents/skills/session-workflow/SKILL.md +271 -0
- package/CHANGELOG.md +46 -0
- package/README.md +48 -19
- package/dist/acp/provider-registry.js +5 -5
- package/dist/api-provider.d.ts +7 -0
- package/dist/api-provider.js +7 -0
- package/dist/api-request.js +1 -0
- package/dist/async-job-manager.d.ts +11 -1
- package/dist/async-job-manager.js +44 -3
- package/dist/config.d.ts +2 -0
- package/dist/config.js +3 -0
- package/dist/index.d.ts +38 -2
- package/dist/index.js +609 -156
- package/dist/job-store.d.ts +48 -1
- package/dist/job-store.js +184 -0
- package/dist/provider-codegen.js +3 -0
- package/dist/provider-tool-capabilities.js +7 -7
- package/dist/upstream-contracts.d.ts +1 -0
- package/dist/upstream-contracts.js +128 -21
- package/dist/validation-orchestrator.d.ts +5 -2
- package/dist/validation-orchestrator.js +71 -5
- package/dist/validation-receipt.d.ts +68 -0
- package/dist/validation-receipt.js +245 -0
- package/dist/validation-report.d.ts +4 -2
- package/dist/validation-report.js +18 -1
- package/dist/validation-tools.js +58 -9
- package/npm-shrinkwrap.json +8 -8
- package/package.json +11 -4
- package/dist/xai-api-provider.d.ts +0 -43
- package/dist/xai-api-provider.js +0 -191
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: async-job-orchestration
|
|
3
|
+
description: Manage long-running async LLM jobs. Use for tasks >2min, parallel jobs, or non-blocking execution. Covers cache-aware `promptParts`, `cache-state://` MCP resources, and the Claude `cache_ttl_expiring_soon` warning.
|
|
4
|
+
metadata:
|
|
5
|
+
author: verivus-oss
|
|
6
|
+
version: "1.6"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Async Job Orchestration
|
|
10
|
+
|
|
11
|
+
Async execution for Claude, Codex, Gemini, Grok, and Mistral. Non-blocking jobs with polling lifecycle. Job state is **durable** — results survive gateway restarts and polling timeouts (see [Durability & Dedup](#durability--dedup)).
|
|
12
|
+
|
|
13
|
+
> **Mistral Vibe**: the gateway always emits `--agent <mode>` and defaults to `auto-approve` for programmatic callers. Current Vibe defaults session logging on; `doctor --json` flags an explicit `[session_logging] enabled = false` before session-continuity use.
|
|
14
|
+
|
|
15
|
+
## Dispatch Defaults
|
|
16
|
+
|
|
17
|
+
Apply these on every dispatch unless the caller has explicitly overridden a rule in the current turn:
|
|
18
|
+
|
|
19
|
+
1. **Omit `model`** — let the gateway use its configured default per CLI. Nominating a model risks deprecated IDs (`o3`, `o3-pro`, `gpt-4o`, …) and capability mismatches.
|
|
20
|
+
2. **`approvalStrategy:"mcp_managed"`** is the skill dispatch default (the gateway schema default is `"legacy"`). It gates the request before execution; Claude then runs with `bypassPermissions`, Gemini with `yolo`, and Codex still needs `fullAuto:true` for autonomous file/shell work. Prefer this over raw bypass flags.
|
|
21
|
+
3. **No wallclock timeout; poll every 60 s** — see [Polling Strategy](#polling-strategy) below. Do **not** cancel jobs for taking too long; cancel only on explicit instruction or hard failure. `idleTimeoutMs` (no-output safeguard) is separate.
|
|
22
|
+
4. **Iterate until unconditional APPROVED** (review dispatches only) — end every review prompt with "End with APPROVED or NOT APPROVED with findings." Loop: dispatch → poll → parse verdict → on `NOT APPROVED` or conditional approval, dispatch fixes + re-review → repeat. Escalate after 3 rounds. This rule does **not** apply to pure implementation or non-review analysis dispatches.
|
|
23
|
+
|
|
24
|
+
## Auto-Async Deferral
|
|
25
|
+
|
|
26
|
+
Sync tools auto-defer when execution exceeds sync deadline. No manual sync/async choice needed.
|
|
27
|
+
|
|
28
|
+
### Flow
|
|
29
|
+
|
|
30
|
+
1. Call sync tool (`claude_request`, `codex_request`, `gemini_request`, `grok_request`, `mistral_request`)
|
|
31
|
+
2. Gateway starts CLI as background job, polls internally
|
|
32
|
+
3. Job completes within deadline (default **45s**) → result returned directly
|
|
33
|
+
4. Deadline exceeded → **deferred response** with `jobId` for polling
|
|
34
|
+
|
|
35
|
+
### Deferred Response
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{"status":"deferred","jobId":"uuid","cli":"claude","correlationId":"...","message":"Execution exceeded sync deadline (45000ms). Poll with llm_job_status, fetch with llm_job_result.","sessionId":"...","pollWith":"llm_job_status","fetchWith":"llm_job_result","cancelWith":"llm_job_cancel"}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Handling
|
|
42
|
+
|
|
43
|
+
1. Parse response as JSON
|
|
44
|
+
2. If `status==="deferred"` → extract `jobId`
|
|
45
|
+
3. Poll `llm_job_status({jobId})` until `job.status` is terminal (`completed`, `failed`, `canceled`, or `orphaned`)
|
|
46
|
+
4. Fetch `llm_job_result({jobId})`
|
|
47
|
+
|
|
48
|
+
Non-deferred responses: process as normal. Results are durable (default 30 days) — you can fetch them long after the deferred response was returned, even across gateway restarts.
|
|
49
|
+
|
|
50
|
+
### Configuration
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
SYNC_DEADLINE_MS=45000 # Default: 45s (under 60s MCP client cap)
|
|
54
|
+
SYNC_DEADLINE_MS=0 # Disable auto-deferral (pure sync)
|
|
55
|
+
SYNC_DEADLINE_MS=20000 # Shorter deadline
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### When to Use Explicit Async
|
|
59
|
+
|
|
60
|
+
Use `*_request_async` when:
|
|
61
|
+
- Fire-and-forget (start job, work on other tasks, check later)
|
|
62
|
+
- Launching multiple parallel jobs (need all job IDs upfront)
|
|
63
|
+
- Avoiding any sync wait (even 45s deadline)
|
|
64
|
+
|
|
65
|
+
## Core Tools
|
|
66
|
+
|
|
67
|
+
| Tool | Purpose |
|
|
68
|
+
|------|---------|
|
|
69
|
+
| `claude_request_async` | Start async Claude job |
|
|
70
|
+
| `codex_request_async` | Start async Codex job |
|
|
71
|
+
| `gemini_request_async` | Start async Gemini job |
|
|
72
|
+
| `grok_request_async` | Start async Grok (xAI) job |
|
|
73
|
+
| `mistral_request_async` | Start async Mistral Vibe job |
|
|
74
|
+
| `llm_job_status` | Poll job status (in-memory + durable store fallback) |
|
|
75
|
+
| `llm_job_result` | Retrieve job output (in-memory + durable store fallback) |
|
|
76
|
+
| `llm_job_cancel` | Cancel running job |
|
|
77
|
+
| `llm_process_health` | Inspect in-memory job/process health |
|
|
78
|
+
|
|
79
|
+
## Single Job
|
|
80
|
+
|
|
81
|
+
### Start
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
claude_request_async({prompt:"Analyze src/ for type safety...",approvalStrategy:"mcp_managed",optimizePrompt:true})
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Response:
|
|
88
|
+
```json
|
|
89
|
+
{"success":true,"job":{"id":"job-abc123","cli":"claude","status":"running","startedAt":"..."},"sessionId":"...","approval":null,"mcpServers":{"requested":["example-server"]}}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
- Gemini async responses also include `resumable:true|false`; only user-provided Gemini `sessionId` values are resumable
|
|
93
|
+
- Gateway-generated Gemini `gw-*` IDs are bookkeeping IDs and are rejected if passed back as `sessionId`
|
|
94
|
+
|
|
95
|
+
### Poll
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
llm_job_status({jobId:"job-abc123"})
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Statuses: `running` | `completed` | `failed` | `canceled`
|
|
102
|
+
|
|
103
|
+
### Retrieve
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
llm_job_result({jobId:"job-abc123",maxChars:200000})
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
- `maxChars`: 1,000–2,000,000 (default 200,000). Returns tail (most recent) when truncated
|
|
110
|
+
- `stdoutTruncated`/`stderrTruncated` flags indicate truncation
|
|
111
|
+
|
|
112
|
+
### Cancel
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
llm_job_cancel({jobId:"job-abc123"})
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Sends SIGTERM, then SIGKILL after 5s.
|
|
119
|
+
|
|
120
|
+
## Idle Timeout
|
|
121
|
+
|
|
122
|
+
Kills process if no stdout/stderr for configurable duration. Detects stuck processes.
|
|
123
|
+
|
|
124
|
+
| CLI | Default | Notes |
|
|
125
|
+
|-----|---------|-------|
|
|
126
|
+
| Claude | 600,000ms | **stream-json mode only.** text/json produce no output until done (would false-positive) |
|
|
127
|
+
| Codex | 600,000ms | Streams stderr progress — works all modes |
|
|
128
|
+
| Gemini | 600,000ms | Streams stdout — works all modes |
|
|
129
|
+
| Grok | 600,000ms | Streams stdout — works all modes |
|
|
130
|
+
| Mistral Vibe | 600,000ms | Streams stdout/stderr — works all modes |
|
|
131
|
+
|
|
132
|
+
Override: `idleTimeoutMs:int (30,000–3,600,000)`
|
|
133
|
+
|
|
134
|
+
When idle timeout fires: exit code **125** (non-transient, no retry).
|
|
135
|
+
|
|
136
|
+
## Parallel Jobs
|
|
137
|
+
|
|
138
|
+
Start all, then collect:
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
claude_request_async({prompt:"Review architecture... End with APPROVED or NOT APPROVED with findings.",approvalStrategy:"mcp_managed",correlationId:"review-arch"})
|
|
142
|
+
codex_request_async({prompt:"Check for bugs... End with APPROVED or NOT APPROVED with findings.",fullAuto:true,approvalStrategy:"mcp_managed",correlationId:"review-impl"})
|
|
143
|
+
gemini_request_async({prompt:"Security audit... End with APPROVED or NOT APPROVED with findings.",approvalStrategy:"mcp_managed",correlationId:"review-sec"})
|
|
144
|
+
grok_request_async({prompt:"Independent diversity review... End with APPROVED or NOT APPROVED with findings.",approvalStrategy:"mcp_managed",correlationId:"review-grok"})
|
|
145
|
+
mistral_request_async({prompt:"Independent Vibe review... End with APPROVED or NOT APPROVED with findings.",approvalStrategy:"mcp_managed",correlationId:"review-mistral"})
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Poll each with `llm_job_status` every 60s. Retrieve with `llm_job_result` when terminal.
|
|
149
|
+
|
|
150
|
+
## Polling Strategy
|
|
151
|
+
|
|
152
|
+
- Poll `llm_job_status` **every 60 seconds** (not faster — wastes tokens/time)
|
|
153
|
+
- No wallclock timeout — good reviews take minutes to tens of minutes
|
|
154
|
+
- Do **not** cancel jobs for "taking too long"; cancel only on explicit user instruction or hard failure (process dead, non-transient error such as exit 125/126)
|
|
155
|
+
- `idleTimeoutMs` (no-output safeguard, default 10 min per CLI) remains active and will kill genuinely hung processes — this is separate from wallclock timeout and does not need tightening for normal reviews
|
|
156
|
+
- When using `ScheduleWakeup` or sleep loops, use 60 s cadence; the 5-minute prompt-cache window also favors intervals ≤ 270 s or ≥ 20 min — 60 s is safely inside cache
|
|
157
|
+
|
|
158
|
+
### Wait-between-polls mechanism (orchestrator-specific)
|
|
159
|
+
|
|
160
|
+
Between `llm_job_status` calls, use a **non-blocking** wait. Standalone `sleep` commands are blocked in some orchestrators (e.g. the Claude Code harness rejects `Bash({command: "sleep 60"})` as a standalone call).
|
|
161
|
+
|
|
162
|
+
- **Claude Code harness** — use `Bash` with `run_in_background: true` for a one-shot wait:
|
|
163
|
+
```
|
|
164
|
+
Bash({command: "sleep 60 && echo done", run_in_background: true})
|
|
165
|
+
// Returns a task ID. Harness emits a completion notification when the 60s elapses.
|
|
166
|
+
// On notification, call llm_job_status.
|
|
167
|
+
```
|
|
168
|
+
The `Monitor` tool is for **streaming** progress (one event per stdout line) — not for one-shot waits. Do not chain multiple short sleeps to work around the standalone-sleep block; the harness detects and blocks that too.
|
|
169
|
+
- **`ScheduleWakeup`** (if available in your orchestrator): schedule a wakeup with `delaySeconds: 60` and a prompt that resumes the polling loop. The runtime fires you back on schedule.
|
|
170
|
+
- **Codex CLI / other orchestrators**: use the orchestrator's native non-blocking wait primitive (e.g. async/await on a timer). Avoid synchronous blocking sleeps that freeze the agent loop.
|
|
171
|
+
|
|
172
|
+
Treat the wait as "yield control for ~60 s, then poll once" — not "block the shell for 60 s."
|
|
173
|
+
|
|
174
|
+
## Error Handling
|
|
175
|
+
|
|
176
|
+
| Status | Exit Code | Meaning | Action |
|
|
177
|
+
|--------|-----------|---------|--------|
|
|
178
|
+
| `completed` | 0 | Success | Retrieve result |
|
|
179
|
+
| `failed` | 124 | CLI timeout | Check stderr |
|
|
180
|
+
| `failed` | 125 | Idle timeout | Increase `idleTimeoutMs` or check CLI |
|
|
181
|
+
| `failed` | 126 | Output overflow (>50MB) | Reduce scope |
|
|
182
|
+
| `failed` | non-zero | CLI error | Check stderr |
|
|
183
|
+
| `failed` | null | Process error | Check `job.error` |
|
|
184
|
+
| `canceled` | any | Canceled | Result still retrievable |
|
|
185
|
+
|
|
186
|
+
Only `exitCode===0` → `completed`. All non-zero → `failed`. Results retrievable for ALL terminal states.
|
|
187
|
+
|
|
188
|
+
Exit codes 125/126 are non-transient — retry engine skips them. Adjust parameters instead.
|
|
189
|
+
|
|
190
|
+
## Job Lifecycle
|
|
191
|
+
|
|
192
|
+
- **Durable**. Every state transition (start, throttled output flush, completion) is persisted to a `jobs` table in `~/.llm-cli-gateway/logs.db`. `llm_job_status` / `llm_job_result` transparently fall back to the durable store when the job is no longer in memory.
|
|
193
|
+
- **Default retention 30 days** — override with `LLM_GATEWAY_JOB_RETENTION_DAYS`. Override the sqlite path with `LLM_GATEWAY_JOBS_DB` (defaults to `LLM_GATEWAY_LOGS_DB`, then `~/.llm-cli-gateway/logs.db`). Set `LLM_GATEWAY_JOBS_DB=none` to disable durability (in-memory only — legacy behavior, not recommended).
|
|
194
|
+
- **Jobs still running when the gateway stopped** are flipped to `orphaned` on next boot (the detached child cannot be reattached). Their captured partial output remains readable via `llm_job_result`.
|
|
195
|
+
- 50 MB max output (stdout+stderr) — exceeding kills process (exit 126).
|
|
196
|
+
- In-memory cache eviction has 1-hour TTL after completion; this no longer means the result is gone — durable store backs every read.
|
|
197
|
+
|
|
198
|
+
## Durability & Dedup
|
|
199
|
+
|
|
200
|
+
The gateway is a durable result collection layer. Two behaviors directly address the "agent polls, times out, re-issues, the whole CLI run starts over" failure mode:
|
|
201
|
+
|
|
202
|
+
### Auto-dedup
|
|
203
|
+
|
|
204
|
+
Identical `*_request` / `*_request_async` calls within the dedup window (default **1 hour**, `LLM_GATEWAY_DEDUP_WINDOW_MS` in ms) short-circuit onto the existing running or completed job. You get back the same `jobId` instead of spawning a duplicate run.
|
|
205
|
+
|
|
206
|
+
- Set `LLM_GATEWAY_DEDUP_WINDOW_MS=0` to disable dedup gateway-wide.
|
|
207
|
+
- Pass `forceRefresh: true` on a single call to bypass dedup for that request:
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
codex_request_async({prompt:"...",fullAuto:true,approvalStrategy:"mcp_managed",forceRefresh:true})
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Use `forceRefresh` when you genuinely need a fresh CLI run (e.g., file contents changed since the last dispatch, retry after manual fix). For normal "I crashed and restarted, let me re-issue" recovery, **omit `forceRefresh`** — dedup is exactly what you want.
|
|
214
|
+
|
|
215
|
+
### Durable retrieval
|
|
216
|
+
|
|
217
|
+
- Polling timeouts no longer destroy results. If your wrapper agent gives up at 5 minutes, `llm_job_status({jobId})` and `llm_job_result({jobId})` still return the completed result hours/days later.
|
|
218
|
+
- Gateway restarts no longer destroy results. Persisted rows survive process restarts.
|
|
219
|
+
- An `orphaned` job is one that was `running` when the gateway last stopped — partial output is still readable; treat it as a non-recoverable terminal state for the active CLI invocation (re-dispatch with `forceRefresh:true` if you need fresh work).
|
|
220
|
+
|
|
221
|
+
### Recovery pattern
|
|
222
|
+
|
|
223
|
+
```
|
|
224
|
+
// 1. Wrapper agent died after dispatching — you have no jobId in memory.
|
|
225
|
+
// 2. Re-issue the identical *_request_async call. The gateway dedups onto
|
|
226
|
+
// the existing in-flight or completed job and returns its jobId.
|
|
227
|
+
result = codex_request_async({prompt:"<same prompt as before>",fullAuto:true,approvalStrategy:"mcp_managed",correlationId:"<same correlationId>"})
|
|
228
|
+
// result.job.id is the original job
|
|
229
|
+
// 3. Poll/fetch as normal — works whether the job is running, completed, or completed days ago.
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## Cache-Aware Prompts (`promptParts`)
|
|
233
|
+
|
|
234
|
+
Every async request tool (`claude_request_async`, `codex_request_async`, `gemini_request_async`, `grok_request_async`, `mistral_request_async`) accepts a structured `promptParts` object instead of the flat `prompt` string. The two are **mutually exclusive** — supplying both returns `provide exactly one of \`prompt\` or \`promptParts\``; supplying neither returns `one of \`prompt\` or \`promptParts\` is required`.
|
|
235
|
+
|
|
236
|
+
```
|
|
237
|
+
codex_request_async({
|
|
238
|
+
promptParts: {
|
|
239
|
+
system: "<long stable system instruction>",
|
|
240
|
+
tools: "<long stable tool description>",
|
|
241
|
+
context: "<long stable spec or file dump>",
|
|
242
|
+
task: "Implement X per the above."
|
|
243
|
+
},
|
|
244
|
+
fullAuto: true,
|
|
245
|
+
approvalStrategy: "mcp_managed",
|
|
246
|
+
correlationId: "impl-r1"
|
|
247
|
+
})
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
The gateway concatenates in canonical order `system → tools → context → task` so parallel async dispatch to multiple CLIs sees byte-identical stable prefix bytes, and re-issues of the same async call (recovery, retry, dedup) keep the same stable-prefix hash. This raises implicit cache hit rate at each provider with no provider-API contortions.
|
|
251
|
+
|
|
252
|
+
For parallel async fan-out (Pattern: "fire N reviewers, collect when done"), the win is largest — every reviewer shares the prefix, and `cache-state://prefix/{hash}` lets you verify they actually hit cache.
|
|
253
|
+
|
|
254
|
+
### Cache observability resources
|
|
255
|
+
|
|
256
|
+
Three MCP resources expose cache effectiveness from the flight recorder (tokens / hashes / aggregates only — no prompt or response text):
|
|
257
|
+
|
|
258
|
+
- `cache-state://global` — last-24h aggregate hit rate, total hits, estimated savings, per-CLI breakdown
|
|
259
|
+
- `cache-state://session/{sessionId}` — per-session aggregates incl. `ttlRemainingMs` for Claude
|
|
260
|
+
- `cache-state://prefix/{hash}` — per-stable-prefix-hash aggregates with CLI × model breakdown
|
|
261
|
+
|
|
262
|
+
`session_get({sessionId})` also projects a compact `cacheState` block when the session has prior requests (omitted entirely for fresh sessions).
|
|
263
|
+
|
|
264
|
+
### TTL warning on Claude async jobs (opt-in)
|
|
265
|
+
|
|
266
|
+
With `[cache_awareness] warn_on_ttl_expiry = true` in `~/.llm-cli-gateway/config.toml`, both `claude_request` and `claude_request_async` responses include a structured warning when the resumed session's prior `lastRequestAt` is within 30 s of Anthropic's cache TTL (default 5 min; 1 h when `[cache_awareness] anthropic_ttl_seconds = 3600`):
|
|
267
|
+
|
|
268
|
+
```json
|
|
269
|
+
{ "warnings": [{ "code": "cache_ttl_expiring_soon", "ttlRemainingMs": 12000, "message": "Anthropic cache breakpoint for session <id> expires in 12000ms (< 30000ms). Subsequent requests may miss the cache." }] }
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
For long-running async loops on a Claude session, treat the warning as a hint to dispatch the next turn promptly (or accept the upcoming cache miss). The warning is gated on the config flag and appears only for Claude sessions with prior cache writes.
|
|
273
|
+
|
|
274
|
+
## Tips
|
|
275
|
+
|
|
276
|
+
- Use `correlationId` on every job for log tracing
|
|
277
|
+
- Async jobs do NOT support `optimizeResponse` — optimize after retrieval
|
|
278
|
+
- Sessions work with async — pass `sessionId` or `createNewSession`; Claude,
|
|
279
|
+
Codex, Gemini, Grok, and Mistral carry real provider continuity when their
|
|
280
|
+
provider-specific session rules are satisfied
|
|
281
|
+
- **Sync tools auto-defer at 45s** — check for `status:"deferred"` in sync responses, then poll every 60s
|
|
282
|
+
- `SYNC_DEADLINE_MS=0` disables auto-deferral
|
|
283
|
+
- For Gemini, check `resumable` — only `true` for user-provided `sessionId`
|
|
284
|
+
- Set higher `idleTimeoutMs` for tasks with long silent periods
|
|
285
|
+
- Review jobs: the verdict from the CLI is the gate — loop until unconditional APPROVED, do not settle early
|
|
286
|
+
- If jobs fail because a CLI is missing or stale, check `cli_versions` and run `cli_upgrade` as a dry run before any real upgrade. Grok self-updates via `grok update`; `cli_upgrade` routes that for you.
|
|
287
|
+
- **Don't burn re-runs after a polling timeout** — re-issue the same call; auto-dedup snaps you back onto the live job. Reserve `forceRefresh:true` for cases where the underlying inputs actually changed.
|
|
288
|
+
- **Durable results outlive in-memory caches** — `llm_job_result({jobId})` returns the same output 30 days later by default. Don't hold polling open just because you fear losing the result.
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: implement-review-fix
|
|
3
|
+
description: Run implement-review-fix cycle using multiple LLMs (Claude, Codex, Gemini, Grok, Mistral). Use for features, bugs, or refactoring with multi-LLM collaboration. Mistral defaults to `--agent auto-approve`; current Vibe defaults session logging on, and doctor flags explicit `[session_logging] enabled = false` before session-continuity use.
|
|
4
|
+
metadata:
|
|
5
|
+
author: verivus-oss
|
|
6
|
+
version: "1.6"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Implement-Review-Fix Cycle
|
|
10
|
+
|
|
11
|
+
Structured workflow: multiple LLMs implement, review, iterate until quality met.
|
|
12
|
+
|
|
13
|
+
## Cycle
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
1. Implement (Codex) → 2. Review (Claude+Gemini) → 3. Fix (Codex) → 4. Verify
|
|
17
|
+
└──────────────── loop until unconditional APPROVED ────────────────┘
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Single-level orchestration only — parent agent coordinates all steps. Child LLMs cannot call other LLMs through gateway.
|
|
21
|
+
|
|
22
|
+
## Dispatch Defaults
|
|
23
|
+
|
|
24
|
+
Apply these on every dispatch unless the caller has explicitly overridden a rule in the current turn:
|
|
25
|
+
|
|
26
|
+
1. **Omit `model`** — let the gateway use its configured default per CLI. Nominating a model risks deprecated IDs (`o3`, `o3-pro`, `gpt-4o`, …) and capability mismatches. Use `list_models` only if the caller has asked for a specific variant.
|
|
27
|
+
2. **`approvalStrategy:"mcp_managed"`** is the skill dispatch default (the gateway schema default is `"legacy"`). It gates the request before execution; Claude then runs with `--permission-mode bypassPermissions`, Gemini with `--approval-mode yolo`, and Codex still needs `fullAuto:true` for autonomous file/shell work. Prefer this over raw bypass flags.
|
|
28
|
+
3. **No wallclock timeout; poll every 60 s** — let sync auto-defer at 45 s or use `*_request_async`. Poll `llm_job_status` once every 60 seconds. Do **not** cancel jobs for taking too long; cancel only on explicit instruction or hard failure. `idleTimeoutMs` (no-output safeguard) is separate.
|
|
29
|
+
4. **Iterate until unconditional APPROVED** (review dispatches only) — every review/re-review dispatch is a loop. End every review prompt with "End with APPROVED or NOT APPROVED with findings." On `NOT APPROVED` or conditional approval, consolidate findings, dispatch fixes (Codex + `fullAuto:true`), re-dispatch the review to the **same reviewer**. Repeat until unconditional APPROVED. Escalate after 3 rounds. This rule does **not** apply to pure implementation or non-review analysis dispatches. (The implementation step in Step 1 is not itself a review; the loop is driven by the reviewer verdict in Step 2 / Step 4.)
|
|
30
|
+
|
|
31
|
+
## Session Continuity
|
|
32
|
+
|
|
33
|
+
| CLI | Effect | Mechanism |
|
|
34
|
+
|-----|--------|-----------|
|
|
35
|
+
| **Claude** | Real continuity | `--session-id` or `--continue` passed to CLI |
|
|
36
|
+
| **Codex** | Real continuity | `codex exec resume <UUID>` (`sessionId`) or `codex exec resume --last` (`resumeLatest:true`). `sessionId` must be a real Codex session UUID from `~/.codex/sessions/`; gateway-generated `gw-*` IDs are rejected |
|
|
37
|
+
| **Gemini** | Real continuity | `--resume` passed to CLI |
|
|
38
|
+
| **Grok** | Real continuity | `--resume` / `--continue` passed to CLI |
|
|
39
|
+
|
|
40
|
+
For Codex resumption: pass the UUID printed by `codex resume` / visible under `~/.codex/sessions/`, **or** pass `resumeLatest:true` to use the most recent session in cwd. Note: `--full-auto` is silently dropped on resume — Codex inherits the original session's approval policy.
|
|
41
|
+
|
|
42
|
+
## Cache-Aware Prompts (`promptParts`)
|
|
43
|
+
|
|
44
|
+
The implement → review → fix loop is the canonical use case for the structured `promptParts` field: across rounds the system instructions, tool block, and file/spec context are byte-identical; only the `task` mutates. Switch from `prompt` to `promptParts` in every step so the gateway can hash the stable prefix once and providers can serve the long prefix from cache:
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
codex_request({
|
|
48
|
+
promptParts: {
|
|
49
|
+
system: "<stable implementation brief>",
|
|
50
|
+
context: "<spec + relevant file paths or dump>",
|
|
51
|
+
task: "Implement [feature]. Requirements: …"
|
|
52
|
+
},
|
|
53
|
+
fullAuto: true,
|
|
54
|
+
approvalStrategy: "mcp_managed",
|
|
55
|
+
optimizePrompt: true
|
|
56
|
+
})
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`prompt` and `promptParts` are mutually exclusive — supplying both returns `provide exactly one of \`prompt\` or \`promptParts\``; supplying neither returns `one of \`prompt\` or \`promptParts\` is required`. The gateway assembles in canonical order `system → tools → context → task` so a re-review or fix call with the same `system` + `context` and a new `task` reuses the same hash.
|
|
60
|
+
|
|
61
|
+
After a round, `session_get({sessionId})` projects a compact `cacheState` block (hit rate, distinct prefix count, savings, `ttlRemainingMs` for Claude) — useful for confirming the loop is actually cache-warming as expected.
|
|
62
|
+
|
|
63
|
+
## Step 1: Implement
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
codex_request({prompt:"Implement [feature]. Requirements:\n- [req 1]\n- [req 2]\n\nWrite code in [path]. Include tests.",fullAuto:true,approvalStrategy:"mcp_managed",optimizePrompt:true})
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Step 2: Review
|
|
70
|
+
|
|
71
|
+
Send to reviewers in parallel. Reviewers **must have tool access** to read files and verify claims — never use `allowedTools:[]` or include tool-suppression language in review prompts. `mcp_managed` removes Claude/Gemini approval prompts; Codex also requires `fullAuto:true`.
|
|
72
|
+
|
|
73
|
+
Before adding provider-specific controls, check `provider_tool_capabilities` for
|
|
74
|
+
that provider. Do not copy Claude tool names into Grok, Gemini, Codex, or Vibe
|
|
75
|
+
requests; omit allowlists unless the capability record says the provider
|
|
76
|
+
supports the exact native tool names you intend to use.
|
|
77
|
+
|
|
78
|
+
**Claude — Quality:**
|
|
79
|
+
```
|
|
80
|
+
claude_request({prompt:"Review changes in [path]. Read the files directly. Check:\n- Code quality/maintainability\n- Project conventions\n- Error handling\n- Documentation gaps\nList issues with severity and fixes. End with APPROVED or NOT APPROVED with findings.",allowedTools:["Read","Grep","Glob"],approvalStrategy:"mcp_managed",optimizePrompt:true,optimizeResponse:true})
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Gemini — Bugs/Security:**
|
|
84
|
+
```
|
|
85
|
+
gemini_request({prompt:"Analyze [path] for bugs, edge cases, security issues. Read the files directly. Check test coverage. Rate: critical/high/medium/low. End with APPROVED or NOT APPROVED with findings.",approvalStrategy:"mcp_managed",optimizePrompt:true,optimizeResponse:true})
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**Grok — Optional 4th Reviewer (Diversity / Consensus):**
|
|
89
|
+
```
|
|
90
|
+
grok_request({prompt:"Independent review of [path]. Flag issues the other reviewers may have missed; contradict findings you disagree with. End with APPROVED or NOT APPROVED with findings.",approvalStrategy:"mcp_managed",optimizePrompt:true,optimizeResponse:true})
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Add Grok when consensus matters (high-stakes paths) or to break ties. Auth must already be set up (`grok login` or `GROK_CODE_XAI_API_KEY`).
|
|
94
|
+
|
|
95
|
+
Sync tools auto-defer at 45s — if response contains `status:"deferred"`, poll `jobId` via `llm_job_status` every 60s, fetch with `llm_job_result`. Results are durable (default 30 days) — if your polling wrapper times out, fetch by `jobId` later or re-issue the identical call (auto-dedup reattaches to the live job).
|
|
96
|
+
|
|
97
|
+
## Step 3: Fix
|
|
98
|
+
|
|
99
|
+
Consolidate findings, send to Codex. Use `resumeLatest:true` or a real Codex
|
|
100
|
+
session UUID when you want Codex CLI continuity; otherwise re-state problem
|
|
101
|
+
context inline:
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
codex_request({prompt:"Fix issues in [path]:\n\n1. [Critical] [desc]\n2. [High] [desc]\n3. [Medium] [desc]\n\nApply fixes and update tests.",fullAuto:true,approvalStrategy:"mcp_managed",optimizePrompt:true})
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Step 4: Verify (re-review)
|
|
108
|
+
|
|
109
|
+
Re-dispatch the **same reviewers** from Step 2 with fix context:
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
claude_request({prompt:"Re-review [path] after fixes. Previous findings:\n1. [issue 1] — Fixed by: [what changed]\n2. [issue 2] — Fixed by: [what changed]\n\nConfirm each fix or flag remaining issues. End with APPROVED or NOT APPROVED with findings.",approvalStrategy:"mcp_managed",optimizePrompt:true,optimizeResponse:true})
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Iteration (mandatory)
|
|
116
|
+
|
|
117
|
+
- Any `NOT APPROVED` or conditional approval → back to Step 3 → Step 4
|
|
118
|
+
- "APPROVED with residual notes" counts as approved only if notes are purely informational
|
|
119
|
+
- Max 3 iterations before escalating to the user (but continue iterating until then)
|
|
120
|
+
- All reviewers must return unconditional APPROVED before the cycle ends
|
|
121
|
+
|
|
122
|
+
## Long-Running Tasks
|
|
123
|
+
|
|
124
|
+
Sync tools auto-defer if execution exceeds 45s deadline. Response contains `status:"deferred"` with `jobId` — poll with `llm_job_status`, fetch with `llm_job_result`. No manual sync/async choice needed.
|
|
125
|
+
|
|
126
|
+
For explicit non-blocking (fire-and-forget, parallel jobs):
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
codex_request_async({prompt:"...",fullAuto:true,approvalStrategy:"mcp_managed"})
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Parallel Async Reviews (up to 4 CLIs)
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
codex_request_async({prompt:"Implement [feature]...",fullAuto:true,approvalStrategy:"mcp_managed",correlationId:"impl"})
|
|
136
|
+
// Poll every 60s until completed...
|
|
137
|
+
|
|
138
|
+
claude_request_async({prompt:"Review [path] for quality... End with APPROVED or NOT APPROVED with findings.",approvalStrategy:"mcp_managed",correlationId:"review-quality"})
|
|
139
|
+
codex_request_async({prompt:"Check [path] for logic bugs... End with APPROVED or NOT APPROVED with findings.",fullAuto:true,approvalStrategy:"mcp_managed",correlationId:"review-bugs"})
|
|
140
|
+
gemini_request_async({prompt:"Security audit [path]... End with APPROVED or NOT APPROVED with findings.",approvalStrategy:"mcp_managed",correlationId:"review-security"})
|
|
141
|
+
grok_request_async({prompt:"Independent review of [path]... End with APPROVED or NOT APPROVED with findings.",approvalStrategy:"mcp_managed",correlationId:"review-grok"})
|
|
142
|
+
// Poll every 60s, collect, synthesize, fix, re-review — until all APPROVED
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Tips
|
|
146
|
+
|
|
147
|
+
- Consolidate findings before sending fixes (avoid redundant work)
|
|
148
|
+
- Use `correlationId` to trace full cycle
|
|
149
|
+
- For security-sensitive code: raise to `approvalPolicy:"strict"` (on top of default `mcp_managed`)
|
|
150
|
+
- Keep implementation prompts specific — file paths, function names, acceptance criteria
|
|
151
|
+
- For Codex fixes: either pass `resumeLatest:true` (or the session UUID) to carry conversation context, **or** re-state problem context inline if running fresh
|
|
152
|
+
- Never pass Gemini `gw-*` session IDs — use your own Gemini IDs for resumable workflows
|
|
153
|
+
- Check for `status:"deferred"` in sync responses — poll `jobId` every 60s if present
|
|
154
|
+
- **Durable results**: deferred jobs persist for 30 days (`LLM_GATEWAY_JOB_RETENTION_DAYS`). If the cycle is interrupted, re-issue identical calls (auto-dedup snaps onto the live job) or fetch by `jobId` later. Use `forceRefresh:true` only when inputs have actually changed
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: multi-llm-review
|
|
3
|
+
description: Parallel code reviews across Claude, Codex, Gemini, Grok, and Mistral. Use for quality analysis, bug finding, or security audit.
|
|
4
|
+
metadata:
|
|
5
|
+
author: verivus-oss
|
|
6
|
+
version: "1.6"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Multi-LLM Code Review
|
|
10
|
+
|
|
11
|
+
Parallel reviews using gateway MCP tools. Each LLM has different strengths — combine for comprehensive coverage.
|
|
12
|
+
|
|
13
|
+
## LLM Strengths
|
|
14
|
+
|
|
15
|
+
| LLM | Best For | Sync | Async |
|
|
16
|
+
|-----|----------|------|-------|
|
|
17
|
+
| Claude | Architecture, design, quality, docs | `claude_request` | `claude_request_async` |
|
|
18
|
+
| Codex | Implementation correctness, logic bugs, tests | `codex_request` | `codex_request_async` |
|
|
19
|
+
| Gemini | Security, edge cases, multimodal context | `gemini_request` | `gemini_request_async` |
|
|
20
|
+
| Grok (xAI) | Independent fourth perspective for diversity / consensus tie-breaks | `grok_request` | `grok_request_async` |
|
|
21
|
+
| Mistral Vibe | Independent fifth perspective; uncorrelated with the OpenAI/Anthropic/Google/xAI family; defaults to `--agent auto-approve` | `mistral_request` | `mistral_request_async` |
|
|
22
|
+
|
|
23
|
+
## Dispatch Defaults
|
|
24
|
+
|
|
25
|
+
Apply these on every dispatch unless the caller has explicitly overridden a rule in the current turn:
|
|
26
|
+
|
|
27
|
+
1. **Omit `model`** — let the gateway use its configured default per CLI. Nominating a model risks deprecated IDs (`o3`, `o3-pro`, `gpt-4o`, …) and capability mismatches. Call `list_models` only when the caller has asked for a specific variant.
|
|
28
|
+
2. **`approvalStrategy:"mcp_managed"`** is the skill dispatch default (the gateway schema default is `"legacy"`). It gates the request before execution; Claude then runs with `--permission-mode bypassPermissions`, Gemini with `--approval-mode yolo`, and Codex still needs `fullAuto:true` for autonomous file/shell work. Prefer this over raw bypass flags.
|
|
29
|
+
3. **No wallclock timeout; poll every 60 s** — let sync auto-defer at 45 s or use `*_request_async`. Poll `llm_job_status` once every 60 seconds. Do **not** cancel jobs for taking too long; cancel only on explicit instruction or hard failure. `idleTimeoutMs` (no-output safeguard) is separate.
|
|
30
|
+
4. **Iterate until unconditional APPROVED** (review dispatches only) — every review prompt must end with "End with APPROVED or NOT APPROVED with findings." On `NOT APPROVED` or conditional approval, consolidate findings, dispatch fixes (Codex + `fullAuto:true`), re-dispatch the review to the same reviewer. Repeat until unconditional APPROVED. Escalate after 3 rounds without convergence. This rule does **not** apply to pure implementation or non-review analysis dispatches.
|
|
31
|
+
|
|
32
|
+
## Workflow
|
|
33
|
+
|
|
34
|
+
### 1. Discover Models (optional)
|
|
35
|
+
|
|
36
|
+
Only when the caller has asked for a specific variant:
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
list_models()
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Otherwise omit `model` and proceed.
|
|
43
|
+
|
|
44
|
+
### 1a. Discover Provider Capabilities
|
|
45
|
+
|
|
46
|
+
Before applying provider-specific controls such as tool allowlists, MCP server
|
|
47
|
+
fields, session resume, media skills, or output formats, ask the gateway for the
|
|
48
|
+
provider surface:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
provider_tool_capabilities({cli:"claude"})
|
|
52
|
+
provider_tool_capabilities({cli:"codex"})
|
|
53
|
+
provider_tool_capabilities({cli:"gemini"})
|
|
54
|
+
provider_tool_capabilities({cli:"grok"})
|
|
55
|
+
provider_tool_capabilities({cli:"mistral"})
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Use the reported `unsupportedInputs` and `controls` instead of assuming all
|
|
59
|
+
CLIs share Claude's tool names or MCP semantics. The same data is available as
|
|
60
|
+
`provider-tools://{provider}` resources.
|
|
61
|
+
|
|
62
|
+
### 2. Send Parallel Reviews
|
|
63
|
+
|
|
64
|
+
Sync tools auto-defer at 45s — if response contains `status:"deferred"`, poll `jobId` via `llm_job_status` every 60s, fetch with `llm_job_result`.
|
|
65
|
+
|
|
66
|
+
**Tip — share the stable prefix across reviewers:** when the same long brief / file dump is sent to every reviewer, switch from `prompt` to the structured `promptParts` field. The gateway concatenates in canonical order `system → tools → context → task`, so every reviewer sees byte-identical stable prefix bytes, raising implicit cache hit rate at each provider. `prompt` and `promptParts` are mutually exclusive — the runtime returns `provide exactly one of \`prompt\` or \`promptParts\`` if both are supplied. After the round, read `cache-state://prefix/{hash}` (tokens/hashes only, no prompt text) to confirm reviewers actually shared the prefix.
|
|
67
|
+
|
|
68
|
+
**Claude — Quality & Architecture:**
|
|
69
|
+
```
|
|
70
|
+
claude_request({prompt:"Review changes in {path} for architecture, design patterns, maintainability, documentation gaps. Read the files directly. Specific line numbers and fixes. End with APPROVED or NOT APPROVED with findings.",approvalStrategy:"mcp_managed",optimizePrompt:true,optimizeResponse:true})
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Codex — Logic & Correctness:**
|
|
74
|
+
```
|
|
75
|
+
codex_request({prompt:"Analyze {path} for logic bugs, off-by-one, missing error handling, race conditions, test gaps. Read the files directly. Severity: critical/high/medium/low. End with APPROVED or NOT APPROVED with findings.",fullAuto:true,approvalStrategy:"mcp_managed",optimizePrompt:true,optimizeResponse:true})
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Gemini — Security & Edge Cases:**
|
|
79
|
+
```
|
|
80
|
+
gemini_request({prompt:"Security audit {path}: injection, auth bypasses, data leaks, OWASP Top 10, crash-causing edge cases. Read the files directly. End with APPROVED or NOT APPROVED with findings.",approvalStrategy:"mcp_managed",optimizePrompt:true,optimizeResponse:true})
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Grok — Independent Diversity (optional 4th reviewer):**
|
|
84
|
+
```
|
|
85
|
+
grok_request({prompt:"Independent review of {path}. Read the files directly. Flag issues the other reviewers may have missed, contradict findings you disagree with, and call out blind spots. End with APPROVED or NOT APPROVED with findings.",approvalStrategy:"mcp_managed",optimizePrompt:true,optimizeResponse:true})
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Add Grok when consensus matters (high-stakes changes, security-critical paths) or to break ties between the other three. Auth must already be set up (`grok login` OAuth or `GROK_CODE_XAI_API_KEY`).
|
|
89
|
+
|
|
90
|
+
### 3. Synthesize
|
|
91
|
+
|
|
92
|
+
1. **Deduplicate** — Remove findings from multiple LLMs
|
|
93
|
+
2. **Prioritize** — critical > high > medium > low
|
|
94
|
+
3. **Cross-validate** — Unique findings from one LLM → verify
|
|
95
|
+
4. **Categorize** — Security, Correctness, Performance, Maintainability
|
|
96
|
+
|
|
97
|
+
### 4. Consolidated Report
|
|
98
|
+
|
|
99
|
+
```markdown
|
|
100
|
+
## Code Review Summary
|
|
101
|
+
### Critical (must fix)
|
|
102
|
+
- [Issue] — found by [LLM], severity: critical
|
|
103
|
+
### High Priority
|
|
104
|
+
- ...
|
|
105
|
+
### Medium Priority
|
|
106
|
+
- ...
|
|
107
|
+
### Suggestions
|
|
108
|
+
- ...
|
|
109
|
+
### Positive Observations
|
|
110
|
+
- ...
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Large Codebases
|
|
114
|
+
|
|
115
|
+
Use async for parallel execution:
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
claude_request_async({prompt:"Review all TS files in src/ for architecture/quality... End with APPROVED or NOT APPROVED with findings.",approvalStrategy:"mcp_managed",optimizePrompt:true,correlationId:"review-quality"})
|
|
119
|
+
codex_request_async({prompt:"Check all TS files in src/ for logic bugs/test gaps... End with APPROVED or NOT APPROVED with findings.",fullAuto:true,approvalStrategy:"mcp_managed",optimizePrompt:true,correlationId:"review-bugs"})
|
|
120
|
+
gemini_request_async({prompt:"Security audit all TS files in src/... End with APPROVED or NOT APPROVED with findings.",approvalStrategy:"mcp_managed",correlationId:"review-security"})
|
|
121
|
+
grok_request_async({prompt:"Independent diversity review of all TS files in src/... End with APPROVED or NOT APPROVED with findings.",approvalStrategy:"mcp_managed",correlationId:"review-grok"})
|
|
122
|
+
mistral_request_async({prompt:"Independent Vibe review of all TS files in src/... End with APPROVED or NOT APPROVED with findings.",approvalStrategy:"mcp_managed",correlationId:"review-mistral"})
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Poll with `llm_job_status` every 60s, retrieve with `llm_job_result` when terminal. Jobs are durable — if your polling wrapper times out, re-issue the same call (the gateway auto-dedups onto the live job) or fetch by `jobId` later (default 30-day retention).
|
|
126
|
+
|
|
127
|
+
For iterative Gemini reviews, pass `sessionId` for resumability:
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
gemini_request_async({prompt:"Deep security audit of src/... End with APPROVED or NOT APPROVED with findings.",sessionId:"gemini-security-review",approvalStrategy:"mcp_managed"})
|
|
131
|
+
// Response: resumable:true
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Anti-Patterns
|
|
135
|
+
|
|
136
|
+
These patterns undermine review quality and trigger review integrity warnings:
|
|
137
|
+
|
|
138
|
+
- **Don't inline code in `<code>` blocks** — provide file paths and let reviewers read files directly
|
|
139
|
+
- **Don't suppress tools** — never include "do not run tools" or "respond only based on code provided" in review prompts
|
|
140
|
+
- **Don't use `allowedTools:[]`** for reviews — reviewers need tool access to
|
|
141
|
+
verify claims
|
|
142
|
+
- **Don't copy tool names between providers** — Claude's `Read` / `Grep` /
|
|
143
|
+
`Glob` names are not Grok, Codex, Gemini, or Vibe allowlist names. Check
|
|
144
|
+
`provider_tool_capabilities` first, or omit provider tool allowlists.
|
|
145
|
+
- **Do provide file paths** — `"Review changes in src/auth.ts"` instead of dumping file contents
|
|
146
|
+
|
|
147
|
+
## Iteration Loop (mandatory)
|
|
148
|
+
|
|
149
|
+
Reviews are not one-shot. The caller runs this loop:
|
|
150
|
+
|
|
151
|
+
1. Dispatch reviewer(s) with the verdict clause in the prompt
|
|
152
|
+
2. Poll every 60s if deferred; fetch result
|
|
153
|
+
3. Parse verdict from each reviewer — APPROVED / NOT APPROVED / conditional
|
|
154
|
+
4. **Any NOT APPROVED or conditional** → consolidate findings → dispatch fixes (Codex + `fullAuto:true`) → re-dispatch same review → goto 2
|
|
155
|
+
5. **All APPROVED (unconditional)** → done
|
|
156
|
+
6. After 3 rounds without convergence, escalate to the user
|
|
157
|
+
|
|
158
|
+
"APPROVED with residual notes" counts as approved only if notes are purely informational.
|
|
159
|
+
|
|
160
|
+
## Tips
|
|
161
|
+
|
|
162
|
+
- Always use `optimizePrompt:true` and `optimizeResponse:true`
|
|
163
|
+
- Use sessions for iterative reviews (review → fix → re-review). Claude,
|
|
164
|
+
Codex, Gemini, Grok, and Mistral carry real provider continuity when their
|
|
165
|
+
provider-specific session rules are satisfied
|
|
166
|
+
- For security-sensitive: `approvalPolicy:"strict"` (in addition to default `mcp_managed`)
|
|
167
|
+
- Include file paths and line numbers for actionable feedback
|
|
168
|
+
- If CLI unavailable, skip gracefully and note gap
|
|
169
|
+
- Use all five async variants for true parallel reviews when you want Grok's
|
|
170
|
+
independent perspective and Mistral Vibe's fifth review
|
|
171
|
+
- Pass `sessionId` to `gemini_request_async` / `grok_request_async` for resumable follow-up
|
|
172
|
+
- Check for `status:"deferred"` in sync responses — poll `jobId` every 60s if present
|
|
173
|
+
- Gateway `mcpServers` default to the host's configured Claude MCP set; pass explicit server names only when the review needs those capabilities
|
|
174
|
+
- **Re-issuing after a polling timeout is safe** — auto-dedup (default 1 h window, `LLM_GATEWAY_DEDUP_WINDOW_MS`) reattaches the new call to the existing job. Use `forceRefresh:true` only when inputs genuinely changed
|