feat(#3653): add review.models.cursor — wire modelArg/modelConfigKey for the cursor reviewer lane (#4160)
* feat(#3653): add review.models.cursor — wire modelArg/modelConfigKey for the cursor reviewer lane cursor-agent exposes --model (204 selectable models) but the cursor lane declared modelArg: null / modelConfigKey: null, so review.models.cursor was rejected as an unknown config key and the #1517 reviewer-instances escape hatch silently discarded a configured model at modelExpansion. Wire the lane the same way codex already is: inject {{model}} into args right after -p, set modelArg to --model, and declare modelConfigKey as review.models.cursor plus its config schema entry. An unconfigured lane still invokes byte-identically to today. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * docs(#3653): add changeset for review.models.cursor Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(#3653): update co-change surfaces that assumed cursor has no model key gsd-test surfaced three surfaces still hardcoding "cursor declares no modelConfigKey", broken by wiring review.models.cursor: - tests/reviewer-config-federation.test.cjs: the #3691-narrows-#2797 invariant test listed cursor among lanes that must own no model key. - tests/settings-integrations.test.cjs: the #3651 keyless-lane test listed cursor as keyless, including a live config-set assertion that now correctly succeeds instead of failing (swapped to qwen). - gsd-core/workflows/settings-integrations.md: the settable-keys enumeration and two prose call-outs still named cursor as keyless. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * chore(#3653): acknowledge deliberate growth of settings-integrations.md settings-integrations.md grew 4 bytes because it now enumerates review.models.cursor as a settable key alongside the other reviewer lanes, matching the modelConfigKey wired for cursor in this PR. Emitted-Drift-Ack-Growth: settings-integrations.md — adds review.models.cursor to the settable-keys enumeration and removes cursor from the two keyless-lane call-outs, matching #3653's modelConfigKey change Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * chore(#3653): fix malformed Emitted-Drift-Ack-Growth trailer The previous commit's trailer was separated from Co-Authored-By by a blank line, splitting it into an earlier, non-trailer paragraph — git's trailer parser only recognizes the last contiguous block. Restating it here immediately adjacent to Co-Authored-By so both parse as trailers. Emitted-Drift-Ack-Growth: settings-integrations.md — adds review.models.cursor to the settable-keys enumeration and removes cursor from the two keyless-lane call-outs, matching #3653's modelConfigKey change Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * docs(#3653): backfill changeset pr number pr:0 -> pr:4160 now that https://github.com/open-gsd/gsd-core/pull/4160 exists. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> --------- Co-authored-by: sim <sim@local> Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1480,6 +1480,7 @@ const capabilities = {
|
||||
"binary": "cursor-agent",
|
||||
"args": [
|
||||
"-p",
|
||||
"{{model}}",
|
||||
"--mode",
|
||||
"ask",
|
||||
"--trust",
|
||||
@@ -1489,7 +1490,7 @@ const capabilities = {
|
||||
],
|
||||
"promptChannel": "argv-file-ref",
|
||||
"outputChannel": "stdout",
|
||||
"modelArg": null,
|
||||
"modelArg": "--model",
|
||||
"effortChannel": "none"
|
||||
},
|
||||
"timeoutFloorMs": 900000,
|
||||
@@ -1499,10 +1500,15 @@ const capabilities = {
|
||||
"evidenceClass": "source-grounded",
|
||||
"requiresBinaries": [],
|
||||
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.cursor",
|
||||
"modelConfigKey": null,
|
||||
"modelConfigKey": "review.models.cursor",
|
||||
"handler": null
|
||||
},
|
||||
"config": {
|
||||
"review.models.cursor": {
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"description": "Model passed to the Cursor reviewer lane."
|
||||
},
|
||||
"review.max_prompt_tokens_per_reviewer.cursor": {
|
||||
"type": "number",
|
||||
"default": -1,
|
||||
@@ -4833,6 +4839,7 @@ const configKeys = {
|
||||
"review.models.codex": "codex",
|
||||
"review.max_prompt_tokens_per_reviewer.codex": "codex",
|
||||
"review.timeouts.codex": "codex",
|
||||
"review.models.cursor": "cursor",
|
||||
"review.max_prompt_tokens_per_reviewer.cursor": "cursor",
|
||||
"workflow.drift_threshold": "drift",
|
||||
"workflow.drift_action": "drift",
|
||||
@@ -5024,6 +5031,12 @@ const configSchema = {
|
||||
"default": -1,
|
||||
"description": "Outer wall-clock timeout override (seconds) for the Codex reviewer lane. Unset is -1, a sentinel: 0 or a negative number is also treated as unset (a timeout has no legitimate zero/negative value), so no second sentinel is needed. Falls back to the lane's built-in timeoutFloorMs when unset."
|
||||
},
|
||||
"review.models.cursor": {
|
||||
"owner": "cursor",
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"description": "Model passed to the Cursor reviewer lane."
|
||||
},
|
||||
"review.max_prompt_tokens_per_reviewer.cursor": {
|
||||
"owner": "cursor",
|
||||
"type": "number",
|
||||
@@ -6494,6 +6507,7 @@ const runtimes = {
|
||||
"binary": "cursor-agent",
|
||||
"args": [
|
||||
"-p",
|
||||
"{{model}}",
|
||||
"--mode",
|
||||
"ask",
|
||||
"--trust",
|
||||
@@ -6503,7 +6517,7 @@ const runtimes = {
|
||||
],
|
||||
"promptChannel": "argv-file-ref",
|
||||
"outputChannel": "stdout",
|
||||
"modelArg": null,
|
||||
"modelArg": "--model",
|
||||
"effortChannel": "none"
|
||||
},
|
||||
"timeoutFloorMs": 900000,
|
||||
@@ -6513,10 +6527,15 @@ const runtimes = {
|
||||
"evidenceClass": "source-grounded",
|
||||
"requiresBinaries": [],
|
||||
"promptBudgetKey": "review.max_prompt_tokens_per_reviewer.cursor",
|
||||
"modelConfigKey": null,
|
||||
"modelConfigKey": "review.models.cursor",
|
||||
"handler": null
|
||||
},
|
||||
"config": {
|
||||
"review.models.cursor": {
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"description": "Model passed to the Cursor reviewer lane."
|
||||
},
|
||||
"review.max_prompt_tokens_per_reviewer.cursor": {
|
||||
"type": "number",
|
||||
"default": -1,
|
||||
|
||||
@@ -163,12 +163,13 @@ namespace — any other slug fails with `Unknown config key`.
|
||||
Settable keys (the shipped registry's model-bearing lanes):
|
||||
|
||||
`review.models.agy` (Antigravity), `review.models.claude`, `review.models.codex`,
|
||||
`review.models.gemini`, `review.models.kimi-code`, `review.models.llama_cpp`,
|
||||
`review.models.lm_studio`, `review.models.ollama`, `review.models.opencode`.
|
||||
`review.models.cursor`, `review.models.gemini`, `review.models.kimi-code`,
|
||||
`review.models.llama_cpp`, `review.models.lm_studio`, `review.models.ollama`,
|
||||
`review.models.opencode`.
|
||||
|
||||
Reviewer lanes `cursor`, `qwen`, and `coderabbit` declare no `modelConfigKey` —
|
||||
there is nothing to configure for them here (whether they should have a
|
||||
per-lane model key is a separate question, out of scope for this workflow).
|
||||
Reviewer lanes `qwen` and `coderabbit` declare no `modelConfigKey` — there is
|
||||
nothing to configure for them here (whether they should have a per-lane model
|
||||
key is a separate question, out of scope for this workflow).
|
||||
If the user asks for one of those, say exactly that and skip.
|
||||
|
||||
```text
|
||||
@@ -208,8 +209,8 @@ If it is not one of the settable keys, print:
|
||||
|
||||
```text
|
||||
Rejected: review.models.<slug> is not settable — only the reviewer lanes whose
|
||||
keys are enumerated above can be configured here. (cursor, qwen, and
|
||||
coderabbit have no per-lane model key.)
|
||||
keys are enumerated above can be configured here. (qwen and coderabbit have no
|
||||
per-lane model key.)
|
||||
```
|
||||
|
||||
and re-prompt.
|
||||
|
||||
Reference in New Issue
Block a user