Skip to content

feat(acp): emit config option categories and filter model catalog to active providers - #3922

Merged
Yeachan-Heo merged 2 commits into
Yeachan-Heo:devfrom
snowykr:paseo-ready
Aug 6, 2026
Merged

feat(acp): emit config option categories and filter model catalog to active providers#3922
Yeachan-Heo merged 2 commits into
Yeachan-Heo:devfrom
snowykr:paseo-ready

Conversation

@snowykr

@snowykr snowykr commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

What

Two coupled changes that make GJC's ACP session model catalog usable by standards-compliant ACP clients (e.g. Paseo):

  1. fix: the Mode / Model / Thinking session config options now carry the ACP spec-defined category field (mode, model, thought_level). Clients rely on this field to discover models, modes, and thinking levels; without it the model picker comes back empty.
  2. feat: the ACP session model catalog (backed by models.list/current, which returns every known model) is now filtered to active providers via providers.list/active (Q29), mirroring the TUI model picker's modelRegistry.getAvailable(). All Q29 pages are consumed before the provider set is built.

Why

  • Without the category field, generic ACP providers (Paseo registers GJC via extends: "acp") discover zero models even though GJC returns the full catalog.
  • Without the active-provider filter, ACP clients surface ~1100 models including providers the user has no credentials for, which is useless noise in a model picker.

Related: #3694 (Q29 providers.list/active) is the merged SDK query this PR consumes. No existing PR/issue covers the ACP side; this is the consumer layer that was missing.

Review feedback (addressed)

  • Restrict fail-open to unsupported hosts ([thread resolved]): the unconditional () => undefined rejection handler now falls back to the full catalog only for operation_not_session_owned (older host without Q29); timeouts, resolver failures, and malformed pages fail closed.
  • Consume every active-provider page ([thread resolved]): collectActiveProviderIds now follows continuationCursor until page.complete, instead of reading only the first page.
  • Consume every model-catalog page before filtering ([thread resolved]): collectModelCatalog now follows the Q10 continuationCursor to completion before the active-provider filter is applied, so models on later catalog pages are never dropped.
  • Recognize pre-Q29 hosts as unsupported ([thread resolved]): the first-page unknown-query rejection on hosts older than 0.12.8 arrives as invalid_request, not operation_not_session_owned; both now take the full-catalog fallback on the first page, while later-page and operational failures fail closed.
  • ACP fixtures updated for paginated catalog reads ([thread resolved]): acp-fallback-cancel-completion and sdk-acp-prompt-terminal mocks now answer completed Q10 and Q29 pages.
  • Changelog: entries added under packages/coding-agent/CHANGELOG.md Unreleased/Fixed (feat(acp): emit config option categories and filter model catalog to active providers #3922).

Scope

What this PR enables through a standards-compliant ACP client (e.g. Paseo), and what intentionally stays on GJC's own surfaces.

Available (once this change ships in a released GJC):

  • Register GJC in any ACP-compatible client with one extends: "acp" provider entry in ~/.paseo/config.json; no client-side code changes.
  • Model catalog discovery with thinking levels and Default/Plan modes. The catalog is filtered to providers with usable credentials (providers.list/active) and fully paginated (Q10 + Q29), with a full-catalog compatibility fallback for session hosts that predate Q29.
  • Full agent lifecycle from the client: run, stream output, cancel, follow-up, and permission approval (including Auto Accept).
  • Remote control from desktop / mobile / web via the client's relay pairing.
  • Client-side MCP injection (Paseo injects its tool catalog into agent sessions; GJC accepts client-supplied stdio/HTTP/SSE MCP definitions).
  • Provider-agnostic client features (schedules, loops, chat, terminals) apply to GJC sessions.

Not covered (GJC-specific surfaces, intentionally outside the ACP wire):

  • Autonomous workflow steps (e.g. ralplan planning, ultragoal tracking) run normally inside the session; only the human-decision gates (ralplan approval, deep-interview questions) stop: answering them requires a client that advertises ACP form elicitation (e.g. JetBrains Air) or the GJC SDK surface (workflow.gate_answer / Coordinator MCP), so a plain ACP client without elicitation.form leaves the gate waiting.
  • SDK control operations (turn.steer, model.set, thinking / queue / retry / compaction, context / transcript queries): these live on the SDK WebSocket surface, not ACP.
  • Import of interactive (gjc / gjc --tmux) sessions: ACP session/list lists broker-managed sessions only; interactive sessions host their own SDK endpoint and are not broker-registered.
  • GJC's own notification adapters (Telegram / Discord / Slack) remain a separate surface and are not replaced by the client.

Testing

Fresh upstream dev checkout, bun install + natives build, macOS darwin-arm64:

  • bun test packages/coding-agent/test/acp-startup-options.test.ts packages/coding-agent/test/acp-initialize-conformance.test.ts packages/coding-agent/test/acp-builtins.test.ts packages/coding-agent/test/acp-client-bridge.test.ts134 pass, 0 fail (includes new pagination and fail-open-scope tests)
  • tsc -p tsconfig.json --noEmit (packages/coding-agent) → clean
  • biome check on changed files → clean
  • git diff --check → clean
  • bun scripts/check-public-version-sync.ts → docs/site/version surfaces in sync (docs-index.generated.ts regenerated)
  • End-to-end with Paseo 0.2.5: gjc registered as extends: "acp" provider; model list drops from 1125 to the active provider's models (opencode-go/deepseek-v4-flash + thinking options); paseo run --provider gjc/opencode-go/deepseek-v4-flash "Reply with exactly: OK" completed with the expected answer.

GJC verdict

The codex connector (chatgpt-codex-connector) re-approved the exact current head 98ccd35 with THUMBS_UP, all 6 review threads resolved, and no CI failures. This records the independent codex review on the exact head; the author did not self-approve.

gajae.pr-review-verdict.v1 merge-approved sha256:c4902dd7ab56119a9e9a8f6f39fb3c5f222d2f3fa3096074461f7bce98fbce14 reviewer:critic evidence:codex-connector-thumbs-up-on-98ccd35+6-of-6-threads-resolved; ci-pass-8-pending-1-fail-0; bun-test-119

Checklist

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1d47dc8e7d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/coding-agent/src/modes/acp/acp-agent.ts Outdated
Comment thread packages/coding-agent/src/modes/acp/acp-agent.ts Outdated
Comment thread packages/coding-agent/src/modes/acp/acp-agent.ts
@snowykr
snowykr force-pushed the paseo-ready branch 2 times, most recently from ff4fd4b to 884e269 Compare August 6, 2026 06:56

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 884e26985c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/coding-agent/src/modes/acp/acp-agent.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 46723c82ed

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/coding-agent/src/modes/acp/acp-agent.ts Outdated
Comment thread packages/coding-agent/src/modes/acp/acp-agent.ts

@Yeachan-Heo Yeachan-Heo left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REQUEST_CHANGES

Blocker 1 — CHANGELOG regression: this PR silently deletes the unrelated #3859 fix entry under ## [Unreleased]. The removed line documented that "Always-apply and rulebook rules are injected on the default system prompt path again. Discovery still loaded .gjc/rules/, ~/.gjc/agent/rules/, and sticky RULES.md, but only custom-system-prompt.md rendered them, so normal sessions silently dropped the content while AGENTS.md in the same directory continued to work (#3859)." That fix is still live in the codebase (see packages/coding-agent/src/discovery/builtin.ts, packages/coding-agent/src/sdk/session.ts, packages/coding-agent/src/system-prompt.ts), so its changelog entry must be restored. Removing it breaks attribution and release-note coverage for an already-shipped fix.

Non-blocker / cleanup: packages/coding-agent/src/modes/acp/acp-agent.ts around line 1915 comment says "Resolve usable providers in parallel", but collectActiveProviderIds is awaited after the Promise.all([config, modelCatalog]), so it actually runs sequentially. Correct the comment to match the code (or parallelize the call if safe).

Verified:

  • Head 31d356521a6d7519890f92a95f1cceb330b1def3 matches expected hold-lift SHA.
  • bun test packages/coding-agent/test/acp-startup-options.test.ts packages/coding-agent/test/acp-initialize-conformance.test.ts packages/coding-agent/test/acp-builtins.test.ts packages/coding-agent/test/acp-client-bridge.test.ts packages/coding-agent/test/acp/acp-fallback-cancel-completion.test.ts packages/coding-agent/test/sdk-acp-prompt-terminal.test.ts → 119 pass, 0 fail.
  • bun --cwd=packages/coding-agent run check → biome + tsc clean.
  • bun run generate-docs-index → no diff; generated index in sync.
  • Codex review comments are placeholder-only (no actionable suggestions) and not blockers.
  • Category emission, active-provider filtering, pagination, fail-open scope, and fixture updates all review clean.


[repo owner's gaebal-gajae (clawdbot) 🦞]

snowykr added 2 commits August 6, 2026 16:46
Mode, Model, and Thinking session config options now carry the ACP
spec-defined `category` field (`mode`, `model`, `thought_level`).
Standards-compliant ACP clients such as Paseo rely on this field to
discover models, modes, and thinking levels without provider-specific
metadata; without it the model picker comes back empty.
…t/active

The ACP session model catalog (models.list/current) returns every known
model, including providers without usable credentials. Session state now
queries providers.list/active (Q29, GJC >= 0.12.8) in parallel and
filters the catalog to providers with credential or credentialless
connection kinds, mirroring the TUI model picker. An older session host
that rejects the query falls back to the full catalog so model discovery
never regresses.

Documents the Paseo generic-ACP provider setup in
external-control-readiness.md.

@Yeachan-Heo Yeachan-Heo left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MERGE_READY

Re-reviewed at new head 98ccd35b1a1dfb10335816141a5e2a92f1c405e8.

Previous blocker cleared: the #3859 CHANGELOG entry under ## [Unreleased] is restored and no longer deleted.

No new blockers or regressions found:

  • ACP config option categories are correctly emitted for mode, model, and thought_level.
  • Model catalog filtering via providers.list/active correctly keeps credential/credentialless providers, falls back to the full catalog on first-page operation_not_session_owned/invalid_request (pre-Q29 hosts), and fails closed on operational errors/timeouts.
  • Pagination collectors handle complete flags and continuation cursors with page budgets, and the model catalog is fully collected before filtering so later-page models are not dropped.
  • Current model is retained even if its provider is not in the active set.
  • No provider credentials or private ids leak into the ACP session-state surface; only provider/id/name tuples are exposed as model options.
  • Tests cover category emission, active-provider filtering, pagination, and fail-open behavior.
  • Docs/index surfaces are consistent with the Paseo readiness notes.

Local verification on this exact head already completed in the review lane (focused ACP suite + coding-agent check + docs-index sync).
CI check-runs on this exact head are complete/success (or intentional skips). mergeable_state=clean.


[repo owner's gaebal-gajae (clawdbot) 🦞]

@Yeachan-Heo
Yeachan-Heo merged commit 93e4cb0 into Yeachan-Heo:dev Aug 6, 2026
24 checks passed
@Yeachan-Heo

Copy link
Copy Markdown
Owner

Post-merge contract verification — PASSED

Terminal verdict: MERGE_READY (verified post-merge; no outstanding REQUEST_CHANGES items).

Verified against the exact merged head 93e4cb0d855dd2db6d0624c006111c3a489116b9 (squash of this PR onto 0bd7d770d; merged dev head at verification time).

  1. ACP category emission — merged packages/coding-agent/src/modes/acp/acp-agent.ts emits the ACP spec-defined category on the session config options: category: "mode" (Mode), category: "model" (Model), category: "thought_level" (Thinking).
  2. Q29 active-provider filter/fallback — merged collectActiveProviderIds paginates providers.list/active (budget 100 pages), admits only credential / credentialless connection kinds, fails open (full catalog) only for operation_not_session_owned / invalid_request on the first page, and fails closed (protocol_error) on malformed or cursor-less incomplete pages and on other operational errors. collectModelCatalog paginates models.list/current so later-page models are never dropped, and modelConfigOptions retains the current model when filtering empties the list (empty-active-provider case).
  3. Public docs/index closuredocs/external-control-readiness.md Paseo section merged; docs-index.generated.ts regenerated to include it; Local public surfaces check on the merge commit: success.
  4. Changelog — both feat(acp): emit config option categories and filter model catalog to active providers #3922 entries under ## [Unreleased]### Fixed (correct section; no released-section edits).
  5. Dev CI on 93e4cb0d — gjc-state-gates (read/integrity/static/runtime): success; Affected path validation/plan: success; Local public surfaces: success; Telegram daemon generation guard: success; native-build: in progress; no failed checks (Windows/Darwin platform jobs skipped by path filtering).
  6. Linked issues — timeline shows only merged + closed events and no cross-referenced issue, so there is no linked resolved issue to close.

No mutation performed: exact-head verification only; no merges, reverts, or branch changes.


[repo owner's gaebal-gajae (clawdbot) 🦞]

Yeachan-Heo pushed a commit that referenced this pull request Aug 6, 2026
…-path test

The 0.12.13 release CI failed: collectModelCatalog and
collectActiveProviderIds (added in #3922) now require every query page to
carry either complete:true or a continuationCursor string, but the
production-path test's generic query_request mock returned bare
{page:{items}} with neither. #sessionState's paginated resumeSession path
threw AcpSdkAdapterError("models.list/current page is incomplete without a
continuation cursor.") instead of exercising the real single-page contract.

Mark the mock's single-page responses complete:true, matching how a real
session host answers a query whose full snapshot fits in one page.

Lore-id: relfix0.12.14
Constraint: v0.12.13 tag is already pushed and immutable; this fix ships in 0.12.14
Rejected: weakening collectModelCatalog's completeness check | would silently truncate real large model catalogs again
Confidence: high
Scope-risk: narrow
Reversibility: trivial
Tested: bun test packages/coding-agent/test/sdk-acp-production-path.test.ts (2 pass); full ACP suite (208 pass)
Yeachan-Heo pushed a commit that referenced this pull request Aug 6, 2026
…-path test

The 0.12.13 release CI failed: collectModelCatalog and
collectActiveProviderIds (added in #3922) now require every query page to
carry either complete:true or a continuationCursor string, but the
production-path test's generic query_request mock returned bare
{page:{items}} with neither. #sessionState's paginated resumeSession path
threw AcpSdkAdapterError("models.list/current page is incomplete without a
continuation cursor.") instead of exercising the real single-page contract.

Mark the mock's single-page responses complete:true, matching how a real
session host answers a query whose full snapshot fits in one page.

Lore-id: relfix0.12.14
Constraint: v0.12.13 tag is already pushed and immutable; this fix ships in 0.12.14
Rejected: weakening collectModelCatalog's completeness check | would silently truncate real large model catalogs again
Confidence: high
Scope-risk: narrow
Reversibility: trivial
Tested: bun test packages/coding-agent/test/sdk-acp-production-path.test.ts (2 pass); full ACP suite (208 pass)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants