Skip to content

fix: update ACP SDK large frame handling - #1496

Merged
carlosflorencio merged 1 commit into
mainfrom
feature/migration-tanstack-a-d4z
Jun 25, 2026
Merged

fix: update ACP SDK large frame handling#1496
carlosflorencio merged 1 commit into
mainfrom
feature/migration-tanstack-a-d4z

Conversation

@carlosflorencio

@carlosflorencio carlosflorencio commented Jun 25, 2026

Copy link
Copy Markdown
Member

Long ACP session resumes can emit JSON-RPC lines larger than the SDK scanner limit and notification bursts larger than Kandev’s previous inbound queue default, causing the peer to disconnect before session/load completes. Updating to the fixed Kandev ACP SDK fork and raising the default ACP notification queue lets long sessions resume without requiring a special environment override.

Important Changes

  • Updates the ACP SDK fork to the commit with chunked large-line JSON-RPC reads.
  • Raises Kandev’s default inbound ACP notification queue from 16,384 to 131,072 while keeping KANDEV_ACP_NOTIF_QUEUE as a clamped override.

Validation

  • go test ./... in /root/.kandev/tasks/acp-go-sdk-fix
  • go test ./internal/agentctl/server/adapter/transport/acp
  • make -C apps/backend test

SDK PR: kdlbs/acp-go-sdk#1

Checklist

  • I have performed a self-review of my code.
  • I have manually tested my changes and they work as expected.
  • My changes have tests that cover the new functionality and edge cases.
  • If my change touches UI files (apps/web/), I have added or updated Playwright e2e tests in apps/web/e2e/ and verified them with make test-e2e.

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The ACP backend now points to a newer SDK pseudo-version, increases the default inbound notification queue capacity, and adds tests covering unset, invalid, and bounded KANDEV_ACP_NOTIF_QUEUE values.

Changes

ACP transport update

Layer / File(s) Summary
SDK target update
apps/backend/go.mod
go.mod points github.com/coder/acp-go-sdk at a newer pseudo-version.
Queue default and tests
apps/backend/internal/agentctl/server/adapter/transport/acp/adapter.go, apps/backend/internal/agentctl/server/adapter/transport/acp/adapter_queue_test.go
The ACP notification queue default changes to 131072, and TestACPNotifQueueCapacity checks empty, invalid, non-positive, in-range, and clamped KANDEV_ACP_NOTIF_QUEUE values.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐇 I hopped through the ACP burrow bright,
with a bigger queue and tests in sight.
New version set, old limits fade,
and clamped env values behave as laid.
thump thump — the carrots all align 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: updating the ACP SDK and queue handling for large frames.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The PR description follows the required template, includes summary, changes, validation, and preserves the checklist.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/migration-tanstack-a-d4z

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@claude

claude Bot commented Jun 25, 2026

Copy link
Copy Markdown

Claude finished @carlosflorencio's task in 47s —— View job


Review Todos

  • Identify changed files and scope (go.mod/go.sum only)
  • Review the diff for security/architecture/logic/testing issues
  • Post findings

Findings

No blockers or suggestions. This PR is a pure dependency pin bump:

  • apps/backend/go.mod:119replace directive moves the forked SDK pin from v0.13.6-0.20260609161428-91d5e43d6599 to v0.13.6-0.20260625174839-e37105a28386.
  • apps/backend/go.sum — corresponding hash updates, consistent with the new pseudo-version.

There's no new or changed logic in this repository to test — the actual fix (chunked large-line handling in the JSON-RPC scanner) lives in the upstream fork (kdlbs/acp-go-sdk#1), which is out of scope for this repo's test suite. The require/replace versions are consistent, and the PR description notes validation via go test ./... against the SDK fork and make -C apps/backend test here.

Summary

Severity Count
Blocker 0
Suggestion 0

Verdict: Ready to merge

@github-actions

Copy link
Copy Markdown
Contributor

OpenCode review complete

OpenCode model: opencode-go/minimax-m3

No suggestions found for commit 115a01c06d23.

@greptile-apps

greptile-apps Bot commented Jun 25, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes two related issues that caused ACP session resumes to disconnect prematurely: it bumps the ACP Go SDK fork to the commit that adds chunked large-line JSON-RPC reads (so lines larger than the scanner limit are handled), and it raises Kandev's default inbound notification queue from 16,384 to 131,072 to absorb burst replays during session/load.

  • SDK bump (go.mod/go.sum): replaces 91d5e43d6599 with e37105a28386, the commit containing chunked JSON-RPC line reading.
  • Queue default raised (adapter.go): acpNotifQueueDefault goes from 16,384 to 131,072, now matching acpNotifQueueMax; the KANDEV_ACP_NOTIF_QUEUE env override is preserved but can now only lower the queue, not raise it beyond the new default.
  • New tests (adapter_queue_test.go): cover all branches of acpNotifQueueCapacity(), including empty env, invalid value, non-positive, in-range, and out-of-range (clamped) cases.

Confidence Score: 5/5

Safe to merge — the changes are narrowly scoped to the ACP notification queue size and a dependency bump, with new tests covering all code paths.

The queue increase is intentional and well-justified, the new SDK commit adds chunked JSON-RPC reading to fix the root cause, and the new test file validates every branch of the queue-capacity logic. No behavioral regressions are introduced by the change.

No files require special attention, though the stale comment in adapter.go is worth cleaning up alongside this change.

Important Files Changed

Filename Overview
apps/backend/go.mod Bumps the ACP SDK fork replace directive to the commit containing chunked large-line JSON-RPC reads; straightforward dependency update.
apps/backend/go.sum Updated checksums for the new ACP SDK fork commit; no concerns.
apps/backend/internal/agentctl/server/adapter/transport/acp/adapter.go Raises acpNotifQueueDefault from 16,384 to 131,072 (matching acpNotifQueueMax); the struct-level comment for notifQueue still references the old "1024-slot" SDK default which is now stale.
apps/backend/internal/agentctl/server/adapter/transport/acp/adapter_queue_test.go New test file covering all branches of acpNotifQueueCapacity(); logic and assertions are correct.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Agent as ACP Agent
    participant SDK as ACP Go SDK (chunked reader)
    participant NQ as SDK Inbound Queue (131072 slots)
    participant IQ as notifQueue (4096 slots)
    participant W as Update Worker
    participant App as Kandev App

    Agent->>SDK: Large JSON-RPC line during session/load replay
    Note over SDK: Chunked read assembles full line safely
    SDK->>NQ: Enqueue notification (non-blocking)
    Note over NQ: Raised from 16384 to 131072 slots
    NQ->>IQ: Update handler enqueues (nanosecond)
    IQ->>W: Worker drains in FIFO order
    W->>App: sendUpdate(AgentEvent)
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Agent as ACP Agent
    participant SDK as ACP Go SDK (chunked reader)
    participant NQ as SDK Inbound Queue (131072 slots)
    participant IQ as notifQueue (4096 slots)
    participant W as Update Worker
    participant App as Kandev App

    Agent->>SDK: Large JSON-RPC line during session/load replay
    Note over SDK: Chunked read assembles full line safely
    SDK->>NQ: Enqueue notification (non-blocking)
    Note over NQ: Raised from 16384 to 131072 slots
    NQ->>IQ: Update handler enqueues (nanosecond)
    IQ->>W: Worker drains in FIFO order
    W->>App: sendUpdate(AgentEvent)
Loading

Reviews (3): Last reviewed commit: "fix: update ACP SDK large frame handling" | Re-trigger Greptile

@carlosflorencio
carlosflorencio force-pushed the feature/migration-tanstack-a-d4z branch from 115a01c to 7048dd5 Compare June 25, 2026 17:59
@claude

claude Bot commented Jun 25, 2026

Copy link
Copy Markdown

Claude finished @carlosflorencio's task in 1m 54s —— View job


Review Todos

  • Identify changed files and scope (go.mod/go.sum, adapter.go, adapter_queue_test.go)
  • Review diff for security/architecture/logic/testing issues
  • Post findings

Summary

Posted a findings comment per the code-review skill. No blockers — 1 minor (non-blocking) suggestion about acpNotifQueueDefault now matching acpNotifQueueMax. The SDK fork bump pulls in the upstream chunked large-line fix, and the queue capacity increase (16384 → 131072) is covered by the new adapter_queue_test.go.

Verdict: Ready to merge

@claude

claude Bot commented Jun 25, 2026

Copy link
Copy Markdown

Findings

Reviewed apps/backend/go.mod/go.sum (SDK fork bump) and apps/backend/internal/agentctl/server/adapter/transport/acp/adapter.go + new adapter_queue_test.go.

No blockers.

Suggestion (recommended, doesn't block)

  1. acpNotifQueueDefault now equals acpNotifQueueMaxapps/backend/internal/agentctl/server/adapter/transport/acp/adapter.go:66,73
    • Issue: Both constants are now 131072, so the "clamp too high" branch in acpNotifQueueCapacity() can never return a value different from the default once an operator sets KANDEV_ACP_NOTIF_QUEUE above the default.
    • Why: Functionally correct (the comment explicitly says default now uses "the configured ceiling"), but the two distinct names with the same value may read as a stale leftover to a future reader who doesn't see the comment.
    • Fix: Optional — a one-line comment at the acpNotifQueueMax declaration noting it intentionally matches the default would remove the ambiguity. Not required for merge.

Summary

Severity Count
Blocker 0
Suggestion 1

Verdict: Ready to merge

The dependency bump pulls in the upstream chunked large-line fix (kdlbs/acp-go-sdk#1), and the queue capacity increase (16384 → 131072) plus the new adapter_queue_test.go coverage (default, invalid env, clamp) are consistent and well-tested for the change being made.

@carlosflorencio
carlosflorencio force-pushed the feature/migration-tanstack-a-d4z branch from 7048dd5 to 2fc7d84 Compare June 25, 2026 18:07
@claude

claude Bot commented Jun 25, 2026

Copy link
Copy Markdown

Claude finished @carlosflorencio's task in 2m 0s —— View job


I'll analyze this and get back to you.

if got := acpNotifQueueCapacity(); got != acpNotifQueueDefault {
t.Fatalf("default queue capacity = %d, want %d", got, acpNotifQueueDefault)
}
if got := acpNotifQueueDefault; got != acpNotifQueueMax {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

OpenCode: Brittle constant-comparison assertion in 'default uses max capacity' subtest

Lines 12-14 assert acpNotifQueueDefault == acpNotifQueueMax, which is a compile-time constant comparison rather than a behavior check. If either constant is intentionally changed (e.g., a future maintainer raises acpNotifQueueMax to 262144 to give operators headroom, or lowers the default to 65536 once a hot path is profiled), this test will fail even though acpNotifQueueCapacity() still returns the correct default. The first assertion (lines 9-11) already covers the actual contract — the function returns acpNotifQueueDefault when the env is unset. Drop the second if got := acpNotifQueueDefault; got != acpNotifQueueMax block, or move the relationship to a code-level invariant (e.g., a var _ = ... line or a comment) so it doesn't trip the test suite.

}
})

t.Run("in-range env is honored", func(t *testing.T) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

OpenCode: 'in-range env is honored' subtest only exercises a single mid-range value

The subtest at lines 37-43 only tests KANDEV_ACP_NOTIF_QUEUE=4096, which coincidentally equals the unrelated notifQueueCapacity constant (the internal buffered channel) defined in adapter.go:59. A reader skimming the test could misread 4096 as a special value tied to the internal channel. Add one or two additional in-range cases (e.g., 8192, 32768, and a value just below acpNotifQueueMax like 131071) to (a) make the test resilient to the chosen number and (b) verify the function honors any value in [acpNotifQueueMin, acpNotifQueueMax], not just the one picked. The 'env is clamped' subtest already covers both ends, so the gap is specifically the middle of the range.

// thousands of notifications before the response, so default to the configured
// ceiling instead of requiring operators to know about KANDEV_ACP_NOTIF_QUEUE.
// The SDK still bounds memory to (capacity * avg notification size).
const acpNotifQueueDefault = 131072

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

OpenCode: 8x default queue size increase has no operator-facing observability or log on first use

acpNotifQueueDefault jumped from 16384 to 131072 (8x). The Initialize call at line 347-352 already emits a debug log with the resolved capacity, which is good, but the new default equals acpNotifQueueMax — meaning operators who hit memory pressure now have no env-var headroom to reduce the buffer (clamping prevents going below acpNotifQueueMin=1024, and the default already sits at the top of the range). Consider either (a) raising acpNotifQueueMax to a higher ceiling (e.g., 262144) so operators can opt into a larger queue when truly needed, or (b) lowering the default back toward the middle of the range (e.g., 32768 or 65536) and keeping the max as a knob for the rare long-replay case. The comment at lines 61-65 acknowledges the memory bound but does not surface the new default's parity with the max, which is a meaningful behavioral change worth flagging in the constant's doc comment.

@claude

claude Bot commented Jun 25, 2026

Copy link
Copy Markdown

Findings

Reviewed the full diff for this PR (apps/backend/go.mod, apps/backend/go.sum, apps/backend/internal/agentctl/server/adapter/transport/acp/adapter.go, apps/backend/internal/agentctl/server/adapter/transport/acp/adapter_queue_test.go), per .agents/skills/code-review/SKILL.md.

Scope: SDK fork bump (go.mod/go.sum) pulling in the upstream chunked large-line JSON-RPC fix, plus raising acpNotifQueueDefault from 16384 to 131072 (now equal to acpNotifQueueMax) in adapter.go:61-66.

Tests: adapter_queue_test.go (added in the latest commit, 2fc7d84) now covers all branches of acpNotifQueueCapacity() (adapter.go:78-94):

  • empty env → default
  • invalid (non-numeric) env → default
  • non-positive env ("0", "-5") → default
  • in-range env (4096) → honored as-is
  • out-of-range env clamped to min/max

This closes the gap flagged earlier by the automated OpenCode review (missing in-range and non-positive coverage).

No blockers found:

  • No security, correctness, or architecture issues — this is a constrained, well-tested config/dependency change.
  • The doc comment on acpNotifQueueDefault (adapter.go:61-66) was updated and accurately reflects the new value/rationale.
  • No scope creep — all changes map directly to the stated fix (long ACP session resumes disconnecting on large frames / notification bursts).

Note: the unrelated notifQueue field comment a few lines below (adapter.go:132-149, mentioning a "1024-slot" SDK channel) is stale relative to the current SDK default, but that comment predates this diff and the lines weren't touched here — not a blocker for this PR.

Summary

Severity Count
Blocker 0
Suggestion 0

Verdict: Ready to merge

@carlosflorencio
carlosflorencio merged commit b3e8af5 into main Jun 25, 2026
60 checks passed
@carlosflorencio
carlosflorencio deleted the feature/migration-tanstack-a-d4z branch June 25, 2026 18:17
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.

1 participant