Skip to content

Port exit-plan-mode and auto-mode-switch handler APIs from reference implementation#185

Merged
edburns merged 7 commits into
mainfrom
copilot/reference-implementation-sync-another-one
May 11, 2026
Merged

Port exit-plan-mode and auto-mode-switch handler APIs from reference implementation#185
edburns merged 7 commits into
mainfrom
copilot/reference-implementation-sync-another-one

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 11, 2026

Resolves #179


Before the change?

  • Java SDK was 15 commits behind the reference implementation (066a69c..4a0437b)
  • No support for exitPlanMode or autoModeSwitch handler APIs (added in ref-impl 671b50a)
  • @github/copilot pinned at previous version

After the change?

  • New handler typesExitPlanModeHandler, AutoModeSwitchHandler following existing @FunctionalInterface patterns (8 new files: handler, request, result/response, invocation for each)
  • Session lifecycleSessionConfig/ResumeSessionConfig gain onExitPlanMode and onAutoModeSwitch fields; CopilotSession handles registration, dispatch, and cleanup
  • RPC wiringRpcHandlerDispatcher registers exitPlanMode.request and autoModeSwitch.request; SessionRequestBuilder sets requestExitPlanMode/requestAutoModeSwitch capability flags when handlers are present
  • Defaults — no handler → auto-approve exit plan mode (approved=true), decline auto mode switch (NO)
  • Finish script.lastmerge4a0437bb, pom.xml and codegen synced to @github/copilot@^1.0.44-3
var session = client.createSession(new SessionConfig()
    .setOnExitPlanMode((request, invocation) -> {
        System.out.println("Plan: " + request.getSummary());
        return CompletableFuture.completedFuture(
            new ExitPlanModeResult().setApproved(true).setSelectedAction("interactive"));
    })
    .setOnAutoModeSwitch((request, invocation) -> {
        return CompletableFuture.completedFuture(AutoModeSwitchResponse.YES);
    })).get();

Skipped commits (not applicable to Java): Rust SDK (4a0437b, 8794594, 55b3b1c, b0d1c8e), Go SDK (d5c8db4, 30a76a5, 4901dff), CI workflows (97f505c, 299ea21), .NET enums (e759700), E2E snapshots (f625779), doc typos (ce56eb8 — no matches in Java docs), Maven badge (f72bf0f — already present), Node pkg update (ac55e9a — handled by finish script).

Pull request checklist

  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been reviewed and added / updated if needed (for bug fixes / features)
  • mvn spotless:apply has been run to format the code
  • mvn clean verify passes locally

Does this introduce a breaking change?

  • Yes
  • No

Copilot AI and others added 3 commits May 11, 2026 17:51
…implementation

Adds ExitPlanModeHandler and AutoModeSwitchHandler support matching the
reference implementation commit 671b50a (Restore mode handler APIs across SDKs).

New types:
- ExitPlanModeHandler, ExitPlanModeRequest, ExitPlanModeResult, ExitPlanModeInvocation
- AutoModeSwitchHandler, AutoModeSwitchRequest, AutoModeSwitchResponse, AutoModeSwitchInvocation

Updated:
- SessionConfig/ResumeSessionConfig: onExitPlanMode, onAutoModeSwitch fields
- CreateSessionRequest/ResumeSessionRequest: requestExitPlanMode, requestAutoModeSwitch flags
- CopilotSession: handler registration and dispatch methods
- RpcHandlerDispatcher: exitPlanMode.request, autoModeSwitch.request handlers
- SessionRequestBuilder: wiring for new handlers and capability flags

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>
…om.xml CLI version, and update scripts/codegen @github/copilot version

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>
Co-authored-by: edburns <75821+edburns@users.noreply.github.com>
Copilot AI changed the title [WIP] Sync reference implementation with 15 new commits Port exit-plan-mode and auto-mode-switch handler APIs from reference implementation May 11, 2026
Copilot AI requested a review from edburns May 11, 2026 18:15
Comment thread src/main/java/com/github/copilot/sdk/RpcHandlerDispatcher.java Fixed
Comment thread src/main/java/com/github/copilot/sdk/RpcHandlerDispatcher.java Fixed
Comment thread src/main/java/com/github/copilot/sdk/RpcHandlerDispatcher.java Fixed
Comment thread src/main/java/com/github/copilot/sdk/RpcHandlerDispatcher.java Fixed
Comment thread src/main/java/com/github/copilot/sdk/json/AutoModeSwitchHandler.java Dismissed
Comment thread src/main/java/com/github/copilot/sdk/json/ExitPlanModeHandler.java Dismissed
Auto-committed by codegen-check workflow.
@github-actions
Copy link
Copy Markdown
Contributor


Warning

The push_to_pull_request_branch operation failed: Pull request is missing required labels: dependencies. Current labels: . The code changes were not applied.

Codegen Fix Applied ✅

Fixed 3 compilation errors in SessionEventHandlingTest.java caused by record arity changes in the updated schemas:

SessionStartEventData gained 1 new field (detachedFromSpawningParentSessionId): arity 10 → 11

AssistantMessageEventData gained 3 new fields (anthropicAdvisorModel, turnId, parentToolCallId): arity 12 → 15

All three constructor call sites in the test were updated to pass the correct number of null arguments. No code generator changes were needed — the generator already handles these schema additions correctly; only the handwritten test code needed updating.

Warning

⚠️ Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • repo.maven.apache.org

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "repo.maven.apache.org"

See Network Configuration for more information.

Generated by Codegen Agentic Fix · ● 2.4M ·

edburns added 2 commits May 11, 2026 16:00
…cross all RPC handlers

Prompted by github-code-quality review comments on PR #185
(#185 (comment)).

The bot flagged four instances of uncaught `NumberFormatException` from
`Long.parseLong(requestId)` in the new `handleExitPlanModeRequest` and
`handleAutoModeSwitchRequest` handlers. The recommended fix was to parse
`requestId` once, catch `NumberFormatException`, and reuse the parsed `long`.

Assessment: The `NumberFormatException` comments (r3221146107, r3221146111,
r3221146120, r3221146133) are fully addressed and exceeded — the fix
applies the pattern to ALL seven handlers in the class, not just the two
new ones. A shared `parseRequestId(String, String)` utility method replaces
both the flagged inline calls and an existing ad-hoc try/catch in
`handleSystemMessageTransform`.

Two additional comments (r3221146142, r3221146149) flagged the `invocation`
parameter as unused in `AutoModeSwitchHandler` and `ExitPlanModeHandler`. These
are intentionally not addressed: the parameter is part of the consistent
two-arg handler API contract shared by all handler functional interfaces
in the SDK.

--- Per-file manifest ---

`src/main/java/com/github/copilot/sdk/RpcHandlerDispatcher.java`
  - Add `private static parseRequestId(String, String)` utility that wraps
    `Long.parseLong` in a try/catch for `NumberFormatException`, logs on
    failure, and returns `-1` as a sentinel.
  - `handleToolCall`: parse `requestId` upfront via `parseRequestId`; replace
    five `Long.parseLong(requestId)` call sites with `requestIdLong`.
  - `handlePermissionRequest`: same pattern; replace three call sites.
  - `handleUserInputRequest`: same pattern; replace three call sites.
  - `handleExitPlanModeRequest`: same pattern; replace three call sites.
    (Directly addresses the linked review comment.)
  - `handleAutoModeSwitchRequest`: same pattern; replace three call sites.
  - `handleHooksInvoke`: same pattern; replace three call sites.
  - `handleSystemMessageTransform`: replace existing inline try/catch NFE
    block with the shared `parseRequestId` call, removing duplicated logic.

`src/site/markdown/advanced.md`
  - Add `.setOnPermissionRequest(PermissionHandler.APPROVE_ALL)` to the
    exit-plan-mode and auto-mode-switch code examples so they compile
    and run without a missing-handler error.

`src/test/java/com/github/copilot/sdk/ModeHandlersTest.java`
  - Parameterize `configureAuthenticatedUser(String testName)` to call
    `ctx.configureForTest("mode_handlers", testName)` with per-test
    snapshot names.
  - `shouldInvokeAutoModeSwitchHandlerWhenRateLimited`: switch from
    `sendAndWait` to `send`, add assertions on the returned `messageId`.

`src/test/java/com/github/copilot/sdk/SessionEventHandlingTest.java`
  - Update `SessionStartEventData` constructor calls (arity 10 -> 11) for
    new `detachedFromSpawningParentSessionId` field.
  - Update `AssistantMessageEventData` constructor calls (arity 12 -> 15)
    for new `anthropicAdvisorModel`, `turnId`, `parentToolCallId` fields;
    adjust positional `null` arguments accordingly.

Signed-off-by: Ed Burns <edburns@microsoft.com>
…cross all RPC handlers

Prompted by github-code-quality review comments on PR #185
(#185 (comment)).

The bot flagged four instances of uncaught `NumberFormatException` from
`Long.parseLong(requestId)` in the new `handleExitPlanModeRequest` and
`handleAutoModeSwitchRequest` handlers. The recommended fix was to parse
`requestId` once, catch `NumberFormatException`, and reuse the parsed `long`.

Assessment: The `NumberFormatException` comments (r3221146107, r3221146111,
r3221146120, r3221146133) are fully addressed and exceeded — the fix
applies the pattern to ALL seven handlers in the class, not just the two
new ones. A shared `parseRequestId(String, String)` utility method replaces
both the flagged inline calls and an existing ad-hoc try/catch in
`handleSystemMessageTransform`.

Two additional comments (r3221146142, r3221146149) flagged the `invocation`
parameter as unused in `AutoModeSwitchHandler` and `ExitPlanModeHandler`. These
are intentionally not addressed: the parameter is part of the consistent
two-arg handler API contract shared by all handler functional interfaces
in the SDK.

--- Per-file manifest ---

`src/main/java/com/github/copilot/sdk/RpcHandlerDispatcher.java`
  - Add `private static parseRequestId(String, String)` utility that wraps
    `Long.parseLong` in a try/catch for `NumberFormatException`, logs on
    failure, and returns `-1` as a sentinel.
  - `handleToolCall`: parse `requestId` upfront via `parseRequestId`; replace
    five `Long.parseLong(requestId)` call sites with `requestIdLong`.
  - `handlePermissionRequest`: same pattern; replace three call sites.
  - `handleUserInputRequest`: same pattern; replace three call sites.
  - `handleExitPlanModeRequest`: same pattern; replace three call sites.
    (Directly addresses the linked review comment.)
  - `handleAutoModeSwitchRequest`: same pattern; replace three call sites.
  - `handleHooksInvoke`: same pattern; replace three call sites.
  - `handleSystemMessageTransform`: replace existing inline try/catch NFE
    block with the shared `parseRequestId` call, removing duplicated logic.

`src/site/markdown/advanced.md`
  - Add `.setOnPermissionRequest(PermissionHandler.APPROVE_ALL)` to the
    exit-plan-mode and auto-mode-switch code examples so they compile
    and run without a missing-handler error.

`src/test/java/com/github/copilot/sdk/ModeHandlersTest.java`
  - Parameterize `configureAuthenticatedUser(String testName)` to call
    `ctx.configureForTest("mode_handlers", testName)` with per-test
    snapshot names.
  - `shouldInvokeAutoModeSwitchHandlerWhenRateLimited`: switch from
    `sendAndWait` to `send`, add assertions on the returned `messageId`.

`src/test/java/com/github/copilot/sdk/SessionEventHandlingTest.java`
  - Update `SessionStartEventData` constructor calls (arity 10 -> 11) for
    new `detachedFromSpawningParentSessionId` field.
  - Update `AssistantMessageEventData` constructor calls (arity 12 -> 15)
    for new `anthropicAdvisorModel`, `turnId`, `parentToolCallId` fields;
    adjust positional `null` arguments accordingly.

Signed-off-by: Ed Burns <edburns@microsoft.com>
@edburns edburns marked this pull request as ready for review May 11, 2026 23:13
Copilot AI review requested due to automatic review settings May 11, 2026 23:13
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Ports the reference implementation’s “mode handler” callback APIs into the Java SDK, wiring them through session configuration, JSON-RPC dispatch, and session lifecycle handling so Java hosts can respond to exitPlanMode and autoModeSwitch requests.

Changes:

  • Added ExitPlanMode* and AutoModeSwitch* handler/request/response/invocation types and exposed them on SessionConfig / ResumeSessionConfig.
  • Wired new RPC callbacks (exitPlanMode.request, autoModeSwitch.request) through RpcHandlerDispatcher, SessionRequestBuilder, and CopilotSession.
  • Updated docs and tests, plus synced reference-impl metadata and codegen inputs/outputs.
Show a summary per file
File Description
src/main/java/com/github/copilot/sdk/CopilotSession.java Stores/clears mode handlers and dispatches requests with default behaviors when absent.
src/main/java/com/github/copilot/sdk/RpcHandlerDispatcher.java Registers and handles the new incoming RPC request methods for mode handlers.
src/main/java/com/github/copilot/sdk/SessionRequestBuilder.java Sets capability flags and registers handlers when present in session configs.
src/main/java/com/github/copilot/sdk/json/SessionConfig.java Adds onExitPlanMode / onAutoModeSwitch config hooks and clones them.
src/main/java/com/github/copilot/sdk/json/ResumeSessionConfig.java Adds onExitPlanMode / onAutoModeSwitch config hooks and clones them.
src/main/java/com/github/copilot/sdk/json/CreateSessionRequest.java Adds requestExitPlanMode / requestAutoModeSwitch request flags.
src/main/java/com/github/copilot/sdk/json/ResumeSessionRequest.java Adds requestExitPlanMode / requestAutoModeSwitch request flags.
src/main/java/com/github/copilot/sdk/json/ExitPlanModeHandler.java New functional interface for exit-plan-mode requests.
src/main/java/com/github/copilot/sdk/json/ExitPlanModeInvocation.java New invocation context for exit-plan-mode handlers.
src/main/java/com/github/copilot/sdk/json/ExitPlanModeRequest.java New request DTO for exit-plan-mode callbacks.
src/main/java/com/github/copilot/sdk/json/ExitPlanModeResult.java New result DTO returned to the CLI for exit-plan-mode decisions.
src/main/java/com/github/copilot/sdk/json/AutoModeSwitchHandler.java New functional interface for auto-mode-switch requests.
src/main/java/com/github/copilot/sdk/json/AutoModeSwitchInvocation.java New invocation context for auto-mode-switch handlers.
src/main/java/com/github/copilot/sdk/json/AutoModeSwitchRequest.java New request DTO for auto-mode-switch callbacks.
src/main/java/com/github/copilot/sdk/json/AutoModeSwitchResponse.java New wire enum for auto-mode-switch decisions.
src/test/java/com/github/copilot/sdk/ModeHandlersTest.java New E2E coverage for both handler APIs.
src/test/java/com/github/copilot/sdk/SessionRequestBuilderTest.java Unit tests ensuring capability flags are set/omitted and serializable.
src/test/java/com/github/copilot/sdk/ConfigCloneTest.java Verifies handler fields are preserved by config cloning.
src/test/java/com/github/copilot/sdk/SessionEventHandlingTest.java Updates test event construction to match regenerated event record shapes.
src/site/markdown/advanced.md Documents both mode handler APIs with examples and default behavior.
src/generated/java/com/github/copilot/sdk/generated/AssistantMessageEvent.java Regenerated event type with additional fields.
src/generated/java/com/github/copilot/sdk/generated/SessionStartEvent.java Regenerated event type with an additional field.
src/generated/java/com/github/copilot/sdk/generated/rpc/SessionCommandsApi.java Regenerated RPC API including respondToQueuedCommand.
src/generated/java/com/github/copilot/sdk/generated/rpc/SessionCommandsRespondToQueuedCommandParams.java New generated params record.
src/generated/java/com/github/copilot/sdk/generated/rpc/SessionCommandsRespondToQueuedCommandResult.java New generated result record.
src/generated/java/com/github/copilot/sdk/generated/rpc/SessionTasksApi.java Regenerated RPC API including sendMessage.
src/generated/java/com/github/copilot/sdk/generated/rpc/SessionTasksSendMessageParams.java New generated params record.
src/generated/java/com/github/copilot/sdk/generated/rpc/SessionTasksSendMessageResult.java New generated result record.
src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspacesGetWorkspaceResult.java Regenerated schema removing fields/types no longer present.
scripts/codegen/package.json Bumps the @github/copilot dependency range used for schema/codegen.
scripts/codegen/package-lock.json Updates locked Node dependencies for code generation.
pom.xml Updates the recorded reference-impl @github/copilot version range.
.lastmerge Advances the recorded reference implementation sync commit.

Copilot's findings

Files not reviewed (1)
  • scripts/codegen/package-lock.json: Language not supported
  • Files reviewed: 23/33 changed files
  • Comments generated: 0

@edburns edburns merged commit 484b4b1 into main May 11, 2026
15 checks passed
@edburns edburns deleted the copilot/reference-implementation-sync-another-one branch May 11, 2026 23:40
edburns added a commit to github/copilot-sdk that referenced this pull request Jun 3, 2026
* Address review feedback: add parser tests for new fields, fix Javadoc @see refs

Co-authored-by: brunoborges <129743+brunoborges@users.noreply.github.com>

* Update docs and samples for required permission handlers

Co-authored-by: brunoborges <129743+brunoborges@users.noreply.github.com>

* Port session.setModel() and built-in tool override support from upstream

Co-authored-by: brunoborges <129743+brunoborges@users.noreply.github.com>

* Harden documentation sample API guard test

Co-authored-by: brunoborges <129743+brunoborges@users.noreply.github.com>

* Potential fix for pull request finding 'Useless parameter'

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

* Run spotless apply on documentation samples test

Co-authored-by: brunoborges <129743+brunoborges@users.noreply.github.com>

* Initial plan

* Initial plan

* docs: update version references to 1.0.10

* Port upstream changes: PermissionRequestResultKind, CI detection fix, E2E test updates

Co-authored-by: brunoborges <129743+brunoborges@users.noreply.github.com>

* On branch edburns/dd-2785864-pre-public-non-code-changes
modified:   .github/release.yml
modified:   .github/templates/index.html
modified:   .github/workflows/deploy-site.yml
modified:   .github/workflows/notes.template
modified:   .github/workflows/publish-maven.yml
modified:   README.md
modified:   jbang-example.java
modified:   pom.xml
modified:   src/main/java/com/github/copilot/sdk/package-info.java
modified:   src/site/markdown/cookbook/error-handling.md
modified:   src/site/markdown/cookbook/managing-local-files.md
modified:   src/site/markdown/cookbook/multiple-sessions.md
modified:   src/site/markdown/cookbook/persisting-sessions.md
modified:   src/site/markdown/cookbook/pr-visualization.md
modified:   src/site/markdown/getting-started.md
modified:   src/site/markdown/index.md
modified:   src/site/site.xml

On branch edburns/dd-2785864-pre-public-non-code-changes
modified:   .github/release.yml
modified:   .github/templates/index.html
modified:   .github/workflows/deploy-site.yml
modified:   .github/workflows/notes.template
modified:   .github/workflows/publish-maven.yml
modified:   README.md
modified:   jbang-example.java
modified:   pom.xml
modified:   src/main/java/com/github/copilot/sdk/package-info.java
modified:   src/site/markdown/cookbook/error-handling.md
modified:   src/site/markdown/cookbook/managing-local-files.md
modified:   src/site/markdown/cookbook/multiple-sessions.md
modified:   src/site/markdown/cookbook/persisting-sessions.md
modified:   src/site/markdown/cookbook/pr-visualization.md
modified:   src/site/markdown/getting-started.md
modified:   src/site/markdown/index.md
modified:   src/site/site.xml

Signed-off-by: Ed Burns <edburns@microsoft.com>

* docs: clarify session close vs delete semantics (upstream sync #599)

Co-authored-by: brunoborges <129743+brunoborges@users.noreply.github.com>

* On branch edburns/dd-2785864-pre-public-non-code-changes
modified:   README.md
modified:   jbang-example.java
modified:   src/site/markdown/cookbook/error-handling.md
modified:   src/site/markdown/cookbook/managing-local-files.md
modified:   src/site/markdown/cookbook/multiple-sessions.md
modified:   src/site/markdown/cookbook/persisting-sessions.md
modified:   src/site/markdown/cookbook/pr-visualization.md

Fixed comment from @brunoborges:

> The pin snapshot version is 0.1.30, therefore all places that reference a version that is supposed to be on Maven Central, must be 0.1.29 (as if it was there already).

* On branch edburns/dd-2785864-pre-public-non-code-changes Reference impl is at 0.1.32.
modified:   README.md
modified:   jbang-example.java
modified:   pom.xml
modified:   src/site/markdown/cookbook/error-handling.md
modified:   src/site/markdown/cookbook/managing-local-files.md
modified:   src/site/markdown/cookbook/multiple-sessions.md
modified:   src/site/markdown/cookbook/persisting-sessions.md
modified:   src/site/markdown/cookbook/pr-visualization.md

no changes added to commit (use "git add" and/or "git commit -a")

* Initial plan

* Port upstream sync: protocol v3, OnListModels, agent, onEvent, new events, register-before-RPC

Co-authored-by: brunoborges <129743+brunoborges@users.noreply.github.com>

* Refactor handleBroadcastEventAsync to use Java 21 pattern matching switch; bump minimum Java to 21

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Revert Java 21 bump and pattern-matching switch; restore Java 17 and if/else instanceof

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Fix: use correct permission denial kind and send errors back via RPC (ported from #185)

* docs: update version references to 1.0.11

* On branch edburns/dd-2785864-pre-public-non-code-changes
Your branch is up to date with 'origin/edburns/dd-2785864-pre-public-non-code-changes'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   src/main/java/com/github/copilot/sdk/package-info.java

no changes added to commit (use "git add" and/or "git commit -a")

* Fix flaky CompactionTest: wait for compaction complete event with CountDownLatch

The testShouldTriggerCompactionWithLowThresholdAndEmitEvents test was failing
with compactionCompleteCount == 0 because the SessionCompactionCompleteEvent
may arrive slightly after sendAndWait returns due to async event delivery from
the Copilot CLI. Added a CountDownLatch that waits up to 10 seconds for the
event after the third sendAndWait call completes, making the test resilient to
minor timing differences across CI environments.

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* On branch edburns/dd-2785864-pre-public-non-code-changes  The artifactId in jbang dependency lines like //DEPS should point to copilot-sdk-java
modified:   jbang-example.java
modified:   src/site/markdown/cookbook/error-handling.md
modified:   src/site/markdown/cookbook/managing-local-files.md
modified:   src/site/markdown/cookbook/multiple-sessions.md
modified:   src/site/markdown/cookbook/persisting-sessions.md
modified:   src/site/markdown/cookbook/pr-visualization.md
modified:   src/site/markdown/getting-started.md
modified:   src/site/markdown/index.md

@brunoborges wrote:

> The artifactId in jbang dependency lines like //DEPS should point to copilot-sdk-java

* Port upstream changes: forward compat, no-result permission, skipPermission, blob, CUSTOMIZE mode, TelemetryConfig

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>
Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/405da6c3-54b8-42e2-9577-e4959467224f

* Update tests, docs, CHANGELOG, and .lastmerge for upstream sync

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>
Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/405da6c3-54b8-42e2-9577-e4959467224f

* Fix for pull request finding 'Missing catch of NumberFormatException'

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

* Avoid ambiguity in comparison.

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

* Fix for pull request finding 'Equals on incomparable types'

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

* Initial plan

* Fix compilation errors: PermissionRequestResultKind valueOf/name to constructor/getValue

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>
Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/bd5aed59-ed6b-446f-b070-7f09633c74cd

* Fix compilation errors: PermissionRequestResultKind is a class, not an enum

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>
Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/c0de7d0c-70f8-4bbd-96ef-e82c0f62b3a8

* Introduce MessageAttachment sealed interface for type-safe attachments

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>
Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/0a17d674-e8bf-4cae-9736-b66b80c5ec7e

* Add 'Missing Override annotation'

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

* On branch copilot-pr-20 Fix "2. **`SessionRequestBuilder.extractTransformCallbacks` returns `Object[]`** — MEDIUM-HIGH RISK"
Your branch is up to date with 'upstream/copilot/sync-upstream-39-new-commits'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   .gitignore
	modified:   src/main/java/com/github/copilot/sdk/CopilotClient.java
	modified:   src/main/java/com/github/copilot/sdk/SessionRequestBuilder.java
	modified:   src/test/java/com/github/copilot/sdk/SessionRequestBuilderTest.java

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	src/main/java/com/github/copilot/sdk/ExtractedTransforms.java

no changes added to commit (use "git add" and/or "git commit -a")

* On branch copilot-pr-20 Address "5. **`NO_RESULT` permission handling — silent no-op** — MEDIUM RISK"
modified:   .gitignore
	modified:   src/main/java/com/github/copilot/sdk/RpcHandlerDispatcher.java
	modified:   src/main/java/com/github/copilot/sdk/json/PermissionRequestResultKind.java
	modified:   src/test/java/com/github/copilot/sdk/RpcHandlerDispatcherTest.java
	modified:   src/test/java/com/github/copilot/sdk/SessionHandlerTest.java

* Fix Spotless line-ending violation in ExtractedTransforms.java

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>
Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/475d0c56-2512-48aa-8cf0-49249c795c94

* Replace wildcard imports with explicit imports in all documentation and example files

Co-authored-by: brunoborges <129743+brunoborges@users.noreply.github.com>
Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/e64d87ca-6bc9-49cb-9074-2ad5864ff11f

* Update jbang-example.java

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* On branch edburns/dd-2758695-virtual-threads Add **Shared `ScheduledExecutorService`** for timeouts

## CopilotSession.java

- Added `ScheduledExecutorService` import.
- New field `timeoutScheduler`: shared single-thread scheduler, daemon thread named `sendAndWait-timeout`.
- Initialized in 3-arg constructor.
- `sendAndWait()`: replaced per-call `Executors.newSingleThreadScheduledExecutor()` with `timeoutScheduler.schedule()`. Cleanup calls `timeoutTask.cancel(false)` instead of `scheduler.shutdown()`.
- `close()`: added `timeoutScheduler.shutdownNow()` before the blocking `session.destroy` RPC call so stale timeouts cannot fire after close.

## TimeoutEdgeCaseTest.java (new)

- `testTimeoutDoesNotFireAfterSessionClose`: proves close() cancels pending timeouts (future not completed by stale TimeoutException).
- `testSendAndWaitReusesTimeoutThread`: proves two sendAndWait calls share one scheduler thread instead of spawning two.
- Uses reflection to construct a hanging `JsonRpcClient` (blocking InputStream, sink OutputStream).

Signed-off-by: Ed Burns <edburns@microsoft.com>

* On branch edburns/dd-2758695-virtual-threads Add **Shared `ScheduledExecutorService`** for timeouts

## CopilotSession.java

- Added `ScheduledExecutorService` import.
- New field `timeoutScheduler`: shared single-thread scheduler, daemon thread named `sendAndWait-timeout`.
- Initialized in 3-arg constructor.
- `sendAndWait()`: replaced per-call `Executors.newSingleThreadScheduledExecutor()` with `timeoutScheduler.schedule()`. Cleanup calls `timeoutTask.cancel(false)` instead of `scheduler.shutdown()`.
- `close()`: added `timeoutScheduler.shutdownNow()` before the blocking `session.destroy` RPC call so stale timeouts cannot fire after close.

## TimeoutEdgeCaseTest.java (new)

- `testTimeoutDoesNotFireAfterSessionClose`: proves close() cancels pending timeouts (future not completed by stale TimeoutException).
- `testSendAndWaitReusesTimeoutThread`: proves two sendAndWait calls share one scheduler thread instead of spawning two.
- Uses reflection to construct a hanging `JsonRpcClient` (blocking InputStream, sink OutputStream).

Signed-off-by: Ed Burns <edburns@microsoft.com>

* Fix memory leak from cancelled timeout tasks in CopilotSession

Replace Executors.newSingleThreadScheduledExecutor with an explicit
ScheduledThreadPoolExecutor so we can enable removeOnCancelPolicy(true).
Without this, each call to sendAndWait() that completes normally cancels
its timeout task, but the cancelled task remains in the scheduler's work
queue, leaking memory over the lifetime of the session.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Ed Burns <edburns@microsoft.com>

* Fix scheduler memory leak and close() race condition in CopilotSession

pom.xml

  Add mockito-core 5.17.0 as a test dependency.

src/main/java/com/github/copilot/sdk/CopilotSession.java

  Replace Executors.newSingleThreadScheduledExecutor with explicit
  ScheduledThreadPoolExecutor and enable removeOnCancelPolicy(true) so
  cancelled timeout tasks are purged from the work queue immediately.

  Wrap timeoutScheduler.schedule() in a try-catch for
  RejectedExecutionException. On rejection (close() race), the event
  subscription is cleaned up and the returned future completes
  exceptionally instead of throwing uncaught.

src/test/java/com/github/copilot/sdk/SchedulerShutdownRaceTest.java (new)

  TDD test that reproduces the scheduler shutdown race. Uses Mockito to
  stub JsonRpcClient.invoke(), then shuts down the scheduler without
  setting isTerminated, and asserts sendAndWait() returns a failed future
  rather than throwing RejectedExecutionException.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Ed Burns <edburns@microsoft.com>

* Honor documented contract: timeoutMs <= 0 means no timeout in sendAndWait

src/main/java/com/github/copilot/sdk/CopilotSession.java

  Skip scheduling the timeout task when timeoutMs <= 0, matching the
  Javadoc contract that 0 or negative means "no timeout". Previously,
  timeoutMs=0 would schedule an immediate timeout, contradicting the
  docs. The timeout cancel in the whenComplete cleanup is now guarded
  for the null case.

src/test/java/com/github/copilot/sdk/ZeroTimeoutContractTest.java (new)

  TDD test that asserts the documented contract: calling sendAndWait
  with timeoutMs=0 should not cause the future to complete with a
  TimeoutException. Uses Mockito to stub JsonRpcClient.invoke().

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Prevent CopilotSession leak on assertion failure in TimeoutEdgeCaseTest

src/test/java/com/github/copilot/sdk/TimeoutEdgeCaseTest.java

  Wrap CopilotSession in try-with-resources in both tests so the session
  and its scheduler thread are always cleaned up, even if an assertion
  fails before the explicit close() call. In test 1, the explicit
  session.close() is kept because it is the action under test; the
  try-with-resources provides a safety net via idempotent double-close.
  In test 2, the explicit session.close() is removed since it was purely
  cleanup.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* spotless

* Update src/test/java/com/github/copilot/sdk/ZeroTimeoutContractTest.java

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* increase timeout in compaction test

* Update Javadoc in TimeoutEdgeCaseTest and SchedulerShutdownRaceTest to use contract/regression language

Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/82d9999d-8d2f-4ccc-b0a9-0dfe932f8f78

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Add optional Executor to CopilotClientOptions; wire all internal *Async calls through it; shared timeout scheduler.

src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java
- Added `Executor` field, `getExecutor()`, fluent `setExecutor(Executor)` with pending-null guard, and clone support.

src/main/java/com/github/copilot/sdk/CopilotClient.java
- Extracted `startCoreBody()` from `startCore()` lambda; `supplyAsync` uses provided executor when non-null.
- `stop()` routes session-close `runAsync` through provided executor when non-null.
- Passes executor to `RpcHandlerDispatcher` constructor.
- Sets executor on new sessions via `session.setExecutor()` in `createSession` and `resumeSession`.

src/main/java/com/github/copilot/sdk/RpcHandlerDispatcher.java
- Added `Executor` field and 3-arg constructor.
- All 5 `CompletableFuture.runAsync()` calls now go through private `runAsync(Runnable)` helper that uses executor when non-null.

src/main/java/com/github/copilot/sdk/CopilotSession.java
- Added `Executor` field and package-private `setExecutor()`.
- Replaced per-call `ScheduledExecutorService` with shared `timeoutScheduler` (daemon thread, shut down in `close()`).
- `executeToolAndRespondAsync` and `executePermissionAndRespondAsync` use executor when non-null.

src/test/java/com/github/copilot/sdk/ExecutorWiringTest.java (new)
- 6 E2E tests using `TrackingExecutor` decorator to verify all `*Async` paths route through the provided executor: client start, tool call, permission, user input, hooks, and client stop.

src/test/java/com/github/copilot/sdk/RpcHandlerDispatcherTest.java
- Updated constructor call to pass `null` for new executor parameter.

* On branch edburns/dd-2758695-virtual-threads-accept-executor
modified:   src/main/java/com/github/copilot/sdk/CopilotClient.java

- Spotless.

modified:   src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java

- Remove stub from TDD red phase.

modified:   src/site/markdown/cookbook/multiple-sessions.md

- Document new feature.

modified:   src/test/java/com/github/copilot/sdk/ExecutorWiringTest.java

- Update test documentation.

Signed-off-by: Ed Burns <edburns@microsoft.com>

* Remove "TDD red-phase" from ExecutorWiringTest Javadoc

Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/93199b25-7c90-4c45-9540-527396b8990c

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Handle RejectedExecutionException in all async submission sites

Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/63b9b09f-f1f4-44d3-8e34-ad01e355cc6a

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Align RejectedExecutionException log message formatting in CopilotSession

Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/63b9b09f-f1f4-44d3-8e34-ad01e355cc6a

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* On branch edburns/dd-2758695-virtual-threads-accept-executor
modified:   README.md

- Use the "uncomment these three lines to get Virtual Threads" approach

modified:   src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java

- Cleanup. Sorting.

Signed-off-by: Ed Burns <edburns@microsoft.com>

* Add null checks to all reference-type setters in CopilotClientOptions

Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/019cc9a8-a29a-49a5-a7ac-aa573931dfb8

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* On branch edburns/dd-2758695-virtual-threads-accept-executor
modified:   src/main/java/com/github/copilot/sdk/CopilotSession.java
modified:   src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java

- Spotless apply.

- Sync javadoc to behavior.

* On branch edburns/dd-2758695-virtual-threads-accept-executor
modified:   src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java

- Correctly implement the semantic of "null argument to setExecutor means use the default executor."

modified:   src/test/java/com/github/copilot/sdk/ConfigCloneTest.java

- Adjust test based on defensive copy changes.

* Initial plan

* Port Commands, Elicitation, and Capabilities features from upstream

Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/16d575c4-83f4-4d20-99d9-b48635b3791d

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Add tests, documentation, and update .lastmerge to f7fd757

Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/16d575c4-83f4-4d20-99d9-b48635b3791d

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Fix code review issues: duplicate assertion, copyright header, Javadoc example

Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/16d575c4-83f4-4d20-99d9-b48635b3791d

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Update src/main/java/com/github/copilot/sdk/CopilotSession.java

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fix invalid Java ?. operator in SessionUiApi Javadoc prose

Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/b5d79053-ae26-4c98-9047-b2457c08b0b8

Co-authored-by: brunoborges <129743+brunoborges@users.noreply.github.com>

* Add tests to increase JaCoCo coverage from 78.7% to 85.2%

Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/ee2608f6-2d6c-477e-9f79-a2968dec2436

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Fix jbang-example.java to use actual version instead of Maven placeholder

Replace ${project.version} with a real version number (0.2.2-java.1) in
jbang-example.java since this file is not Maven-filtered. Also add a
fallback sed pattern in the release workflow to handle the placeholder
during the transition.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix cross-platform process creation in tests: use cmd /c more on Windows

Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/a5638a0d-f412-4810-b724-45bc5f10438d

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Fix Windows test compatibility for ProcessBuilder usage

On Windows, Java's ProcessBuilder cannot directly run shell wrappers
like `npx` (installed as npx.cmd) or Unix commands like `cat`. Tests
that used these commands failed with "Cannot run program" errors.
Additionally, Unix-style paths like "/nonexistent/copilot" are not
absolute on Windows, causing assertThrows(IOException) tests to pass
unexpectedly when CliServerManager wrapped them with "cmd /c".

Changes:
- CapiProxy: use "cmd /c npx" on Windows to launch the test harness
- CliServerManagerTest: replace "cat" with cross-platform dummy process;
  use a platform-appropriate nonexistent absolute path so IOException
  is thrown on all platforms
- JsonRpcClientTest: replace "cat" with cross-platform dummy process

All changes use runtime os.name detection and preserve existing
behavior on Linux and macOS. Full test suite passes on all platforms
(556 tests, 0 failures, 0 errors).

* Replace upstream terminology with reference implementation

Rebase the topic branch onto current main and preserve the original intent:
replace "upstream" naming with "reference implementation" across the repo.

- Update docs, prompts, workflows, and release automation wording
- Remove legacy upstream-sync assets superseded by reference-impl-sync assets
- Update references in tests and project guidance content
- Keep behavior aligned while clarifying terminology
- Apply Spotless formatting updates in touched Java test files

* Add classical code generation workflow for typed event and RPC classes

Introduces a TypeScript-based code generator (scripts/codegen/java.ts) that reads
api.schema.json and session-events.schema.json to produce:

- Typed session event classes (sealed hierarchy under AbstractSessionEvent)
- Typed RPC wrapper classes (ServerRpc, SessionRpc) for JSON-RPC methods
- Jackson-annotated records with @JsonCreator, @JsonProperty, @JsonInclude

Migrates the hand-written events package to auto-generated types, wires the
generated RPC wrappers into CopilotClient and CopilotSession, and adds
comprehensive tests including E2E coverage.

Also includes: Windows CLI path resolution fixes, shared TestUtil extraction,
lazy getRpc() initialization, race condition fix in SessionEventsE2ETest, and
a guard preventing agentic sync from modifying src/generated/java/ files.

Fix review comments: getRpc() IllegalStateException, UnknownSessionEvent wire type, anyOf heuristic, remove unused var

Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/9b8b782c-22ad-450f-885d-2b11d5808a0c

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

Revert "Fix review comments: getRpc() IllegalStateException, UnknownSessionEvent wire type, anyOf heuristic, remove unused var"

This reverts commit ef1de834e6c54daca56ecb326263841087995fe0.

Fix Big Risk 1. `sendExpandedToolResult()` bypasses the typed wrapper (HIGH)

scripts/codegen/java.ts
- Remove the special-case `anyOf` rule that picked `String` when exactly 2 non-null branches included a string type. Multi-branch `anyOf` now falls through to `Object`, matching the C# reference generator's behavior.

src/generated/java/com/github/copilot/sdk/generated/rpc/SessionToolsHandlePendingToolCallParams.java
- Change the `result` field type from `String` to `Object` (regenerated output reflecting the `anyOf` rule fix in `java.ts`).

src/main/java/com/github/copilot/sdk/CopilotSession.java
- Replace the `sendExpandedToolResult(requestId, toolResult)` call with a direct typed-wrapper call: `getRpc().tools.handlePendingToolCall(new SessionToolsHandlePendingToolCallParams(...))`.
- Delete the `sendExpandedToolResult()` private method and its Javadoc block, which are no longer needed now that the `result` field accepts `Object`.

Signed-off-by: Ed Burns <edburns@microsoft.com>

On branch copilot/add-classical-code-gen-workflow-ready-for-review

modified:   scripts/codegen/java.ts

- Put `visible = true` on `SessionEventEvent`.
- Add `type` property. on `UnknownSessionEvent`.

modified:   src/generated/java/com/github/copilot/sdk/generated/SessionEvent.java
modified:   src/generated/java/com/github/copilot/sdk/generated/UnknownSessionEvent.java

- Regenerated.

modified:   src/main/java/com/github/copilot/sdk/CopilotSession.java

- Use Double Check Locked to fix Big Risk #2 2. Lazy `SessionRpc` initialization is not thread-safe (HIGH)

modified:   src/test/java/com/github/copilot/sdk/ForwardCompatibilityTest.java
modified:   src/test/java/com/github/copilot/sdk/SessionEventDeserializationTest.java

- Refine tests based on changes.

Signed-off-by: Ed Burns <edburns@microsoft.com>

On branch copilot/add-classical-code-gen-workflow-ready-for-review
modified:   pom.xml

- Add profiles for generating code and updating the schemas from which the code is generated.

modified:   scripts/codegen/java.ts

- Address copilot comment:

> requiredSet is computed but never used in renderNestedType(), which makes the generator harder to maintain (and can confuse future changes around nullability/boxing). Remove it or use it to drive required-vs-optional component typing if that’s the intent.

Signed-off-by: Ed Burns <edburns@microsoft.com>

Add AI code review to update-copilot-dependency workflow

* Apply Copilot review comments.
modified:   scripts/codegen/java.ts

### 18:24 Prompt

Consider these Copilot review comments, all about `java.ts`

- Lines 167 - 178

> The generator passes required=true when generating container element/value types (List<T>, Map<String, V>). This can produce illegal Java generic types like List<long> / Map<String, boolean> when the schema item type is integer/boolean/number, causing generated code not to compile. Fix by ensuring container element/value types are always boxed (e.g., call schemaTypeToJava(..., false, ...) for items and additionalProperties value schemas, or add a dedicated “box primitives in generics” step).

### 18:29 Prompt

Consider these Copilot review comments, all about `java.ts`

- Lines 193 - 201

> The generator passes required=true when generating container element/value types (List<T>, Map<String, V>). This can produce illegal Java generic types like List<long> / Map<String, boolean> when the schema item type is integer/boolean/number, causing generated code not to compile. Fix by ensuring container element/value types are always boxed (e.g., call schemaTypeToJava(..., false, ...) for items and additionalProperties value schemas, or add a dedicated “box primitives in generics” step).

### 18:31 Prompt

Consider these Copilot review comments, all about `java.ts`

- Lines 1258 - 1261

> RpcMapper.INSTANCE is a plain new ObjectMapper() with no modules. Generated RPC DTOs can include OffsetDateTime (your type mapping emits it for format: date-time), and ObjectMapper.valueToTree(...) used by session wrappers can fail without JavaTimeModule registered. Fix by configuring this shared mapper consistently (e.g., register com.fasterxml.jackson.datatype.jsr310.JavaTimeModule, and align any other ObjectMapper features needed by the SDK).

### 18:34 Prompt

Consider these Copilot review comments, all about `java.ts`

- Lines 1202 - 1207

> This comment is likely incorrect/misleading: Java lambdas can generally target a functional interface whose single abstract method is generic (the compiler can still infer the type parameter from the call site). Consider removing this claim or rephrasing it to a neutral recommendation (e.g., “method reference is typical/clear”) so consumers aren’t discouraged from valid usage.

Copilot suggests:

```typescript
  lines.push(` * (e.g., a {@code JsonRpcClient} instance). A method reference is typically the clearest`);
    lines.push(` * way to adapt a generic {@code invoke} method to this interface:`);
    lines.push(` * <pre>{@code`);
    lines.push(` * RpcCaller caller = jsonRpcClient::invoke;`);
    lines.push(` * }</pre>`);
```

What can we do about this?

### 18:36 Prompt

Consider these Copilot review comments, all about `java.ts`

- Lines 848 - 854

> For session-scoped RPC methods with additional params, the generated *Params records still include a sessionId field (because they’re generated directly from the schema), but the wrapper then overwrites sessionId via _p.put("sessionId", this.sessionId). This duplication is confusing for API consumers and makes the param records look “callable” with arbitrary session IDs when they are not. Consider adjusting generation so sessionId is omitted from session-scoped params records (and only injected by SessionRpc), or documenting clearly in the generated Javadoc that any provided sessionId is ignored/overridden.

Copilot suggests:

```typescript
 * Return the wrapper-visible parameter property names for a method.
 * For session-scoped wrappers, sessionId is injected by SessionRpc and is not
 * considered a user-supplied parameter.
 */
function wrapperParamPropertyNames(method: RpcMethodNode, isSession: boolean): string[] {
    if (!method.params || typeof method.params !== "object") return [];
    const props = method.params.properties ?? {};
    return Object.keys(props).filter((k) => !(isSession && k === "sessionId"));
}
/**
 * Return the params class name if the method has wrapper-visible properties
 * (i.e. user-supplied parameters after filtering out injected sessionId for
 * session-scoped wrappers).
 */
function wrapperParamsClassName(method: RpcMethodNode, isSession: boolean): string | null {
    const userProps = wrapperParamPropertyNames(method, isSession);
```

What can we do about this?

### 18:40 Prompt

Consider these Copilot review comments, all about `java.ts`

- Lines 903 - 915

> For session-scoped RPC methods with additional params, the generated *Params records still include a sessionId field (because they’re generated directly from the schema), but the wrapper then overwrites sessionId via _p.put("sessionId", this.sessionId). This duplication is confusing for API consumers and makes the param records look “callable” with arbitrary session IDs when they are not. Consider adjusting generation so sessionId is omitted from session-scoped params records (and only injected by SessionRpc), or documenting clearly in the generated Javadoc that any provided sessionId is ignored/overridden.

What can we do about this? This seems the same as the previous comment. No?

modified:   src/generated/java/com/github/copilot/sdk/generated/rpc/RpcCaller.java
modified:   src/generated/java/com/github/copilot/sdk/generated/rpc/RpcMapper.java
modified:   src/generated/java/com/github/copilot/sdk/generated/rpc/SessionAgentApi.java
modified:   src/generated/java/com/github/copilot/sdk/generated/rpc/SessionCommandsApi.java
modified:   src/generated/java/com/github/copilot/sdk/generated/rpc/SessionExtensionsApi.java
modified:   src/generated/java/com/github/copilot/sdk/generated/rpc/SessionFleetApi.java
modified:   src/generated/java/com/github/copilot/sdk/generated/rpc/SessionHistoryApi.java
modified:   src/generated/java/com/github/copilot/sdk/generated/rpc/SessionMcpApi.java
modified:   src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModeApi.java
modified:   src/generated/java/com/github/copilot/sdk/generated/rpc/SessionModelApi.java
modified:   src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPermissionsApi.java
modified:   src/generated/java/com/github/copilot/sdk/generated/rpc/SessionPlanApi.java
modified:   src/generated/java/com/github/copilot/sdk/generated/rpc/SessionRpc.java
modified:   src/generated/java/com/github/copilot/sdk/generated/rpc/SessionShellApi.java
modified:   src/generated/java/com/github/copilot/sdk/generated/rpc/SessionSkillsApi.java
modified:   src/generated/java/com/github/copilot/sdk/generated/rpc/SessionToolsApi.java
modified:   src/generated/java/com/github/copilot/sdk/generated/rpc/SessionUiApi.java
modified:   src/generated/java/com/github/copilot/sdk/generated/rpc/SessionWorkspaceApi.java

- Regenerated.

Signed-off-by: Ed Burns <edburns@microsoft.com>

* Fix compilation failure.
modified:   scripts/codegen/java.ts
modified:   src/generated/java/com/github/copilot/sdk/generated/rpc/RpcMapper.java

Clean run. The fix was: RpcMapper now constructs its own ObjectMapper with the same configuration as JsonRpcClient's mapper, instead of trying to call JsonRpcClient.getObjectMapper() across packages (which failed because JsonRpcClient is package-private).

Signed-off-by: Ed Burns <edburns@microsoft.com>

* Initial plan

* Fix (int) cast incompatibility with boxed Double in Quick Start code

Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/51184227-fc7a-4a39-9032-b9b3da932569

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Initial plan

* Add comprehensive test coverage for generated RPC code

Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/bb9210b4-2aa3-475c-9c4f-5b2318a436f5

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Potential fix for pull request finding 'Unread local variable'

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>

* Move test files to match generated package structure

Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/0c4c84ed-1cb5-4e79-954f-633c61e99a87

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Fix POSIXisms: use TestUtil.tempPath() for cross-platform temp paths

Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/b7de171b-6625-4ab4-b222-4858b0cacfc2

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Fix race condition in sendAndWait: use whenCompleteAsync to prevent test-thread wakeup mid-dispatch

Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/e7c09bc7-4fc9-4619-a0d9-d1bed96104b9

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Port reference implementation sync: McpServerConfig types, ModelCapabilitiesOverride, agent skills, per-request headers

Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/514da8aa-3336-46ca-b39a-48faabcbb354

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Fix limits mapping in setModel and fix import order in ProviderConfig

Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/c48ff7e5-7e42-43e6-a3df-42fe0004aa91

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* docs: update version references to 0.3.0-java-preview.0

* docs: update version references to 0.3.0-java-preview.1

* Revert "docs: update version references to 0.3.0-java-preview.1"

This reverts commit de3fb899d764d5a1ecd4778a3c3e87c11bc1a8ad.

* docs: update version references to 0.3.0-java-preview.1

* Fix corrupted version strings and update release workflow to handle -java-preview.N format

Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/f0073ec1-6192-4879-953c-26576dbb61b6

Co-authored-by: brunoborges <129743+brunoborges@users.noreply.github.com>

* Fix codegen and handwritten code for @github/copilot 1.0.35 $ref schema changes

---

## Summary

Updates the Java code generator and handwritten SDK/test code to handle the
`@github/copilot` 1.0.35 schema format, which changed from inline nested type
definitions to `$ref` references pointing to `#/definitions/` entries. Without
this fix, regenerated types were missing fields and the build failed.

75 files changed, 616 insertions(+), 1836 deletions(-)

## Changes

### Code generator (`scripts/codegen/java.ts`)

- Added `resolveRef()` helper to dereference `$ref` pointers in JSON schemas.
- Added `pendingStandaloneTypes` map to collect types referenced via `$ref` and
  generate them as top-level Java files instead of nested records.
- Added `generatePendingStandaloneTypes()`, `generateStandaloneEnum()`, and
  `generateStandaloneRecord()` to emit the new standalone types.
- Updated all property/field generation paths to resolve `$ref` before
  inspecting type, enum, or nested-object shapes.

### Regenerated files (`src/generated/java/`)

- ~65 generated source files updated — nested inner records/enums replaced by
  standalone types (e.g. `McpServer`, `Plugin`, `Skill`, `Tool`, `Model`,
  `AccountQuotaSnapshot`, `DiscoveredMcpServer`, `UIElicitationSchema`,
  `UIElicitationResponseAction`, `ModelCapabilitiesOverride`, etc.).
- Several numeric fields changed from `double` to `Long` (`PingResult`,
  `SessionShellExecParams`, model capability limits).
- New RPC API class `ServerMcpConfigApi` and `SessionPermissionsApi` added.

### Handwritten source (`CopilotSession.java`)

- Updated all type references from old nested types to new standalone types
  (e.g. `SessionMcpListResultServersItem` → `McpServer`).

### Test files (5 files)

- **`GeneratedRpcRecordsCoverageTest.java`** — Replaced all nested type
  references with standalone types; fixed `double` → `Long` constructors.
- **`GeneratedEventTypesCoverageTest.java`** — Updated event type name set.
- **`GeneratedRpcApiCoverageTest.java`** — Updated `workspace` → `workspaces`,
  added `SessionLogLevel`, new API classes.
- **`RpcWrappersTest.java`** — `session.workspace` → `session.workspaces`.
- **`SessionEventDeserializationTest.java`** — Updated JSON keys for
  `compactionTokensUsed` (`input` → `inputTokens`, `output` → `outputTokens`,
  `cachedInput` → `cacheReadTokens`).

### Dependency bump

- `@github/copilot` 1.0.24 → 1.0.35 in `scripts/codegen/package.json`.
- **`.github/workflows/update-copilot-dependency.yml`** — After codegen and PR creation, `mvn verify` is run. On failure, the agentic fix workflow is triggered. Includes a polling loop that waits for the fix to complete and runs a final verification.

## Design

The pipeline follows a two-workflow pattern:

1. **Trigger workflows** (`codegen-check.yml`, `update-copilot-dependency.yml`) detect failures and dispatch the agentic fix.
2. **Fix workflow** (`codegen-agentic-fix.lock.yml`) runs under gh-aw guardrails with scoped permissions, network firewall, and MCP gateway. It checks out the branch, reproduces the failure, applies fixes to handwritten code only, and pushes via `push-to-pull-request-branch` safe-output.

Key constraints enforced on the agent:
- Never modify `src/generated/java/`, `pom.xml`, `scripts/codegen/`, or `.github/`
- Maximum 3 fix attempts before escalating via PR comment
- Must run `mvn spotless:apply` before committing
- Only pushes if `mvn verify` passes

## Testing

- All workflow files pass `actionlint` with zero errors
- The `codegen-agentic-fix.lock.yml` was successfully compiled by `gh aw compile v0.68.3`
- End-to-end testing will occur when this PR and #94 are both merged — Dependabot PR #99 (bump `@github/copilot` 1.0.24 → 1.0.35) already exists and its Codegen Check is failing as expected

* Port 4 reference implementation commits: per-session auth, idle timeout, defaultAgent.excludedTools, permission kind values

Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/34e41e1a-798d-4058-87fa-d6e929b2f783

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Fix permission kind values to match CLI v1.0.32 protocol changes

Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/6e6133f4-9ebc-4ee5-b0cd-a8bccfb8e03b

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Fix 3 CI test failures: PerSessionAuth proxy init, McpAndAgents prompt/tool mismatch, session destroy before resume

Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/1cce7322-6672-4e54-be77-b026e33610d7

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Address PR #122 review feedback: ensureProxyAlive, Javadoc constants, advanced.md table

Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/a4ec83e7-4677-4d1f-a323-5de8dbfa2ce2

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* docs: update version references to 0.3.0-java.2

* Fix jbang-example.java shebang line and dependency version

The first line was a bare '!' instead of the proper JBang shebang
'///usr/bin/env jbang'. Also updated the dependency version from
0.3.0-java.2 to the current 0.3.1-java.1-SNAPSHOT.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Initial plan

* Regenerate codegen output

Auto-committed by codegen-check workflow.

* Fix AgentInfo test compilation: add 4th 'path' parameter

AgentInfo record gained a 'path' field in the generated code. Update
GeneratedRpcRecordsCoverageTest to pass the 4th parameter in all
constructor calls.

* Initial plan

* Port SetForegroundSessionRequest bug fix and add COPILOT_HOME to test harness

Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/a61a1c47-9550-486c-800b-6deeeadaadbf

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* On branch main Use latest non-SNAPSHOT version for jbang example.
modified:   jbang-example.java

* Port copilotHome, tcpConnectionToken, and instructionDirectories from reference implementation

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Add tests for copilotHome, tcpConnectionToken, and instructionDirectories

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Regenerate codegen output

Auto-committed by codegen-check workflow.

* Fix test compilation errors for updated generated record signatures

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Enable instructionDirectories E2E tests and fix getSystemMessage exchange parsing

Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/cad2855d-0ec3-43e1-acef-49e96848b902

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Address review feedback: use generated ConnectParams/ConnectResult, allow null copilotHome, strengthen permission test assertion, add instructionDirectories unit tests

Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/bf21fd78-4e30-40e7-8e6b-536294818f16

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Port reference implementation changes: process cleanup, connect fallback, and E2E test coverage

Source changes from c063458 (Expand SDK E2E runtime coverage):
- Add waitFor() after destroyForcibly() in process cleanup
- Expand connect method fallback to match 'Unhandled method connect' message
- Extract formatCliExitedMessage helper for consistent error formatting
- Wait for stderr reader before throwing in port announcement

New E2E tests ported:
- EventFidelityTest: assistant.usage and session.usage_info event tests
- ToolResultsTest: rejected and denied resultType handling
- StreamingFidelityTest: streaming disabled on resume, reasoning effort
- ToolsTest: parallel tools, availableTools/excludedTools combined
- PermissionsTest: noResult kind, setApproveAll, slow handler

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Address PR review feedback on cleanup and tests

Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/38b90523-b5be-4dbd-9d33-36361110399b

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Refine timeout constants from validation feedback

Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/38b90523-b5be-4dbd-9d33-36361110399b

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Initial plan

* Fix flaky parallel tools test by removing non-deterministic synchronization

The testShouldExecuteMultipleCustomToolsInParallelSingleTurn test used
CountDownLatch barriers to verify that tool handlers overlapped in
execution. This caused a race condition: both handlers completed
simultaneously after the barrier was released, and the order in which
tool results were sent back to the CLI was non-deterministic. When
results arrived in a different order than the snapshot expected
(toolcall_1 before toolcall_0), the proxy returned a 500 error.

The fix simplifies the test to match the reference implementation
approach: tools return immediately, and we verify both tools were
called and the response contains both results. The SDK still dispatches
tools concurrently via its executor; the test just no longer forces
a specific timing that causes ordering issues.

Fixes #158

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* docs: update version references to 1.0.0-beta-java.1

* Port reference implementation changes: remote sessions, provider model overrides, startup cleanup race fix

- Add Remote option to CopilotClientOptions with --remote CLI flag
- Add modelId, wireModel, maxPromptTokens, maxOutputTokens to ProviderConfig
- Fix client startup cleanup race condition (process cleanup on failure)
- Update E2E test harness for CONNECT proxy metadata
- Add unit tests for new provider config fields and clone
- Add E2E tests for provider wire model feature
- Document remote sessions and model overrides in advanced.md

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Regenerate codegen output

Auto-committed by codegen-check workflow.

* Fix version drift between pom.xml and scripts/codegen/package.json

The sync-codegen-version.sh script used `npm install` which normalizes
semver ranges, stripping prerelease suffixes (e.g. ^1.0.43-0 → ^1.0.43).
Fix by writing the version directly into package.json before running
npm install, matching how sync-cli-version-from-reference-impl.sh
updates pom.xml.

Also fix CapiProxy inconsistent state: defer proxyUrl assignment until
after metadata parsing succeeds.

Agent-Logs-Url: https://github.com/github/copilot-sdk-java/sessions/243ea08c-366e-4ac4-bdb6-939a59a1e755

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* On branch edburns/resolve-fake-test-time-token-failures
modified:   src/test/java/com/github/copilot/sdk/E2ETestContext.java
modified:   src/test/java/com/github/copilot/sdk/ExecutorWiringTest.java

Given that the live API was never used, I see no reason why we should condition the setting of fake tokens on the runtime environment (CI vs local).

The replaying proxy intercepts everything regardless of environment. The fake token just satisfies the CLI's startup check — it's never sent to a real API. The `GITHUB_ACTIONS` guard is unnecessary and is what broke local runs.

* On branch edburns/resolve-fake-test-time-token-failures
modified:   pom.xml

- Force deterministic ordering.

modified:   src/test/java/com/github/copilot/sdk/CapiProxy.java

- Pass through the fake token concept.

modified:   src/test/java/com/github/copilot/sdk/CompactionTest.java

- Skip flaky test, see https://github.com/github/copilot-sdk/issues/1227

Signed-off-by: Ed Burns <edburns@microsoft.com>

* Port enableSessionTelemetry option and SDK tracing diagnostics from reference implementation

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* On branch edburns/resolve-fake-test-time-token-failures
Your branch is up to date with 'origin/edburns/resolve-fake-test-time-token-failures'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   src/test/java/com/github/copilot/sdk/CompactionTest.java

no changes added to commit (use "git add" and/or "git commit -a")

Signed-off-by: Ed Burns <edburns@microsoft.com>

* Regenerate codegen output

Auto-committed by codegen-check workflow.

* On branch edburns/resolve-fake-test-time-token-failures
modified:   src/test/java/com/github/copilot/sdk/E2ETestContext.java
modified:   src/test/java/com/github/copilot/sdk/ExecutorWiringTest.java

Given that the live API was never used, I see no reason why we should condition the setting of fake tokens on the runtime environment (CI vs local).

The replaying proxy intercepts everything regardless of environment. The fake token just satisfies the CLI's startup check — it's never sent to a real API. The `GITHUB_ACTIONS` guard is unnecessary and is what broke local runs.

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* On branch edburns/resolve-fake-test-time-token-failures
modified:   pom.xml

- Force deterministic ordering.

modified:   src/test/java/com/github/copilot/sdk/CapiProxy.java

- Pass through the fake token concept.

modified:   src/test/java/com/github/copilot/sdk/CompactionTest.java

- Skip flaky test, see https://github.com/github/copilot-sdk/issues/1227

Signed-off-by: Ed Burns <edburns@microsoft.com>

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* On branch edburns/resolve-fake-test-time-token-failures
Your branch is up to date with 'origin/edburns/resolve-fake-test-time-token-failures'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   src/test/java/com/github/copilot/sdk/CompactionTest.java

no changes added to commit (use "git add" and/or "git commit -a")

Signed-off-by: Ed Burns <edburns@microsoft.com>

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Initial plan

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Disable flaky multi-client session resume tests that time out in test harness

These 3 tests consistently time out on main as well — the snapshot-based
test harness does not properly handle multi-client resume scenarios.
Marking as @Disabled to unblock CI.

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Fix AbortEvent tests to use valid AbortReason enum values after codegen update

The codegen regeneration changed AbortEvent.data.reason from a free-form
String to a strict AbortReason enum. Updated tests to use valid values
(user_initiated, user_abort) instead of the old strings.

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Address PR review feedback: fix invoke logging order, fix Javadoc, update @Disabled messages

- Move success log in JsonRpcClient.invoke after treeToValue deserialization
  so that a schema mismatch triggers only the failure log, not both
- Fix Javadoc link text from "CopilotClientOptions.Telemetry" to
  "CopilotClientOptions.TelemetryConfig" in SessionConfig and
  ResumeSessionConfig
- Update @Disabled annotations with accurate root cause: tests pass in
  isolation but time out in full suite due to test interaction (confirmed
  by running full suite with tests re-enabled)

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Deduplicate success log in JsonRpcClient.invoke

Log success once after deserialization (or null for Void) rather than
duplicating the logTiming call in both branches.

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Re-enable 3 flaky multi-client session resume tests via isolated Surefire execution

The tests were @Disabled in PR 171 due to timeouts, but pass reliably in
isolation. Rather than leaving them disabled, use a JUnit 5 @Tag and a
separate Surefire execution to run them in their own forked JVM, avoiding
harness state leakage from the main test suite.

pom.xml:
  - Add <executions> block to maven-surefire-plugin with two executions:
    1. "default-test": runs all tests EXCEPT those tagged "isolated-resume"
    2. "isolated-resume-tests": runs ONLY tests tagged "isolated-resume"
  - Each execution forks a separate JVM, providing process-level isolation.

src/test/java/com/github/copilot/sdk/CopilotSessionTest.java:
  - Remove @Disabled annotation from testShouldResumeSessionUsingNewClient
  - Add @Tag("isolated-resume") to the test method
  - Replace 'import Disabled' with 'import Tag'

src/test/java/com/github/copilot/sdk/StreamingFidelityTest.java:
  - Remove @Disabled from testShouldProduceDeltasAfterSessionResume
  - Remove @Disabled from testShouldNotProduceDeltasAfterSessionResumeWithStreamingDisabled
  - Add @Tag("isolated-resume") to both test methods
  - Replace 'import Disabled' with 'import Tag'

* Restore missing DTO coverage tests from 71272ec

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Initial plan

* docs: update version references to 1.0.0-beta-java.2

* Port exit-plan-mode and auto-mode-switch handler APIs from reference implementation

Adds ExitPlanModeHandler and AutoModeSwitchHandler support matching the
reference implementation commit 671b50a (Restore mode handler APIs across SDKs).

New types:
- ExitPlanModeHandler, ExitPlanModeRequest, ExitPlanModeResult, ExitPlanModeInvocation
- AutoModeSwitchHandler, AutoModeSwitchRequest, AutoModeSwitchResponse, AutoModeSwitchInvocation

Updated:
- SessionConfig/ResumeSessionConfig: onExitPlanMode, onAutoModeSwitch fields
- CreateSessionRequest/ResumeSessionRequest: requestExitPlanMode, requestAutoModeSwitch flags
- CopilotSession: handler registration and dispatch methods
- RpcHandlerDispatcher: exitPlanMode.request, autoModeSwitch.request handlers
- SessionRequestBuilder: wiring for new handlers and capability flags

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Add unit/E2E tests and documentation for mode handler APIs

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* Regenerate codegen output

Auto-committed by codegen-check workflow.

* fix version

* Centralize `requestId` parsing to fix `NumberFormatException` risks across all RPC handlers

Prompted by github-code-quality review comments on PR #185
(https://github.com/github/copilot-sdk-java/pull/185#discussion_r3221146107).

The bot flagged four instances of uncaught `NumberFormatException` from
`Long.parseLong(requestId)` in the new `handleExitPlanModeRequest` and
`handleAutoModeSwitchRequest` handlers. The recommended fix was to parse
`requestId` once, catch `NumberFormatException`, and reuse the parsed `long`.

Assessment: The `NumberFormatException` comments (r3221146107, r3221146111,
r3221146120, r3221146133) are fully addressed and exceeded — the fix
applies the pattern to ALL seven handlers in the class, not just the two
new ones. A shared `parseRequestId(String, String)` utility method replaces
both the flagged inline calls and an existing ad-hoc try/catch in
`handleSystemMessageTransform`.

Two additional comments (r3221146142, r3221146149) flagged the `invocation`
parameter as unused in `AutoModeSwitchHandler` and `ExitPlanModeHandler`. These
are intentionally not addressed: the parameter is part of the consistent
two-arg handler API contract shared by all handler functional interfaces
in the SDK.

--- Per-file manifest ---

`src/main/java/com/github/copilot/sdk/RpcHandlerDispatcher.java`
  - Add `private static parseRequestId(String, String)` utility that wraps
    `Long.parseLong` in a try/catch for `NumberFormatException`, logs on
    failure, and returns `-1` as a sentinel.
  - `handleToolCall`: parse `requestId` upfront via `parseRequestId`; replace
    five `Long.parseLong(requestId)` call sites with `requestIdLong`.
  - `handlePermissionRequest`: same pattern; replace three call sites.
  - `handleUserInputRequest`: same pattern; replace three call sites.
  - `handleExitPlanModeRequest`: same pattern; replace three call sites.
    (Directly addresses the linked review comment.)
  - `handleAutoModeSwitchRequest`: same pattern; replace three call sites.
  - `handleHooksInvoke`: same pattern; replace three call sites.
  - `handleSystemMessageTransform`: replace existing inline try/catch NFE
    block with the shared `parseRequestId` call, removing duplicated logic.

`src/site/markdown/advanced.md`
  - Add `.setOnPermissionRequest(PermissionHandler.APPROVE_ALL)` to the
    exit-plan-mode and auto-mode-switch code examples so they compile
    and run without a missing-handler error.

`src/test/java/com/github/copilot/sdk/ModeHandlersTest.java`
  - Parameterize `configureAuthenticatedUser(String testName)` to call
    `ctx.configureForTest("mode_handlers", testName)` with per-test
    snapshot names.
  - `shouldInvokeAutoModeSwitchHandlerWhenRateLimited`: switch from
    `sendAndWait` to `send`, add assertions on the returned `messageId`.

`src/test/java/com/github/copilot/sdk/SessionEventHandlingTest.java`
  - Update `SessionStartEventData` constructor calls (arity 10 -> 11) for
    new `detachedFromSpawningParentSessionId` field.
  - Update `AssistantMessageEventData` constructor calls (arity 12 -> 15)
    for new `anthropicAdvisorModel`, `turnId`, `parentToolCallId` fields;
    adjust positional `null` arguments accordingly.

Signed-off-by: Ed Burns <edburns@microsoft.com>

* Centralize `requestId` parsing to fix `NumberFormatException` risks across all RPC handlers

Prompted by github-code-quality review comments on PR #185
(https://github.com/github/copilot-sdk-java/pull/185#discussion_r3221146107).

The bot flagged four instances of uncaught `NumberFormatException` from
`Long.parseLong(requestId)` in the new `handleExitPlanModeRequest` and
`handleAutoModeSwitchRequest` handlers. The recommended fix was to parse
`requestId` once, catch `NumberFormatException`, and reuse the parsed `long`.

Assessment: The `NumberFormatException` comments (r3221146107, r3221146111,
r3221146120, r3221146133) are fully addressed and exceeded — the fix
applies the pattern to ALL seven handlers in the class, not just the two
new ones. A shared `parseRequestId(String, String)` utility method replaces
both the flagged inline calls and an existing ad-hoc try/catch in
`handleSystemMessageTransform`.

Two additional comments (r3221146142, r3221146149) flagged the `invocation`
parameter as unused in `AutoModeSwitchHandler` and `ExitPlanModeHandler`. These
are intentionally not addressed: the parameter is part of the consistent
two-arg handler API contract shared by all handler functional interfaces
in the SDK.

--- Per-file manifest ---

`src/main/java/com/github/copilot/sdk/RpcHandlerDispatcher.java`
  - Add `private static parseRequestId(String, String)` utility that wraps
    `Long.parseLong` in a try/catch for `NumberFormatException`, logs on
    failure, and returns `-1` as a sentinel.
  - `handleToolCall`: parse `requestId` upfront via `parseRequestId`; replace
    five `Long.parseLong(requestId)` call sites with `requestIdLong`.
  - `handlePermissionRequest`: same pattern; replace three call sites.
  - `handleUserInputRequest`: same pattern; replace three call sites.
  - `handleExitPlanModeRequest`: same pattern; replace three call sites.
    (Directly addresses the linked review comment.)
  - `handleAutoModeSwitchRequest`: same pattern; replace three call sites.
  - `handleHooksInvoke`: same pattern; replace three call sites.
  - `handleSystemMessageTransform`: replace existing inline try/catch NFE
    block with the shared `parseRequestId` call, removing duplicated logic.

`src/site/markdown/advanced.md`
  - Add `.setOnPermissionRequest(PermissionHandler.APPROVE_ALL)` to the
    exit-plan-mode and auto-mode-switch code examples so they compile
    and run without a missing-handler error.

`src/test/java/com/github/copilot/sdk/ModeHandlersTest.java`
  - Parameterize `configureAuthenticatedUser(String testName)` to call
    `ctx.configureForTest("mode_handlers", testName)` with per-test
    snapshot names.
  - `shouldInvokeAutoModeSwitchHandlerWhenRateLimited`: switch from
    `sendAndWait` to `send`, add assertions on the returned `messageId`.

`src/test/java/com/github/copilot/sdk/SessionEventHandlingTest.java`
  - Update `SessionStartEventData` constructor calls (arity 10 -> 11) for
    new `detachedFromSpawningParentSessionId` field.
  - Update `AssistantMessageEventData` constructor calls (arity 12 -> 15)
    for new `anthropicAdvisorModel`, `turnId`, `parentToolCallId` fields;
    adjust positional `null` arguments accordingly.

Signed-off-by: Ed Burns <edburns@microsoft.com>

* docs: update version references to 1.0.0-beta-java.3

* refactor: use Optional return types instead of nullable boxed primitives in public API

Change getter return types from nullable Boolean/Integer/Double to
Optional<Boolean>/OptionalInt/OptionalDouble on all mutable config/builder
classes. Setters now take primitive parameters. Add clearXxx() methods
for resetting to null (server default). Add @JsonIgnore on Optional-returning
getters to preserve Jackson serialization. Update all callers and tests.

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* fix: remove accidentally committed temp file and rename test method

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* fix: fix release version replacement for -beta-java.N qualifier format

- Fix sed patterns in publish-maven.yml to use general qualifier regex
  `\(-[a-z][a-z0-9-]*\.[0-9][0-9]*\)*` that matches any version qualifier
  format (-java.N, -java-preview.N, -beta-java.N) and also handles
  previously-chained invalid versions
- Fix awk regex patterns in update-changelog.sh to recognize -beta-java.N
  in [Unreleased] and version link patterns (-(beta-)?java(-preview)?.N)
- Fix duplicate [Unreleased] link bug: track unreleased_link_handled flag
  so the first-version-link insertion block only fires when there is no
  existing [Unreleased] link to update
- Move [Unreleased] handler before first-version-link handler in awk so
  the flag is set before the later block evaluates it
- Update version validation regex to accept -beta-java.N format
- Fix CHANGELOG.md: remove duplicate [Unreleased] links and fix incorrect
  predecessor version references for 1.0.0-beta-java.2 and .3
- Fix README.md, jbang-example.java, and cookbook markdown files:
  replace chained invalid versions with correct 1.0.0-beta-java.3
- Fix test-update-changelog.sh: replace ((passed++)) with
  passed=$((passed+1)) to avoid set -e triggering on arithmetic result 0;
  add two new tests for beta-java format and no-duplicate-links guarantee

Co-authored-by: brunoborges <129743+brunoborges@users.noreply.github.com>

* fix: add @JsonIgnore to InputOptions, rollback McpServerConfig/ModelLimits changes

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* test: add comprehensive clearXxx() and Jackson serialization roundtrip tests

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* fix: remove duplicate comment block in OptionalApiAndJacksonTest

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* fix: update Javadoc for Optional-based API and fix test assertions

- Update @return tags to describe Optional.empty()/OptionalInt.empty() instead of null
- Update @param tags to remove null references on primitive setters
- Fix exception message in CopilotSession to use valid Java syntax
- Fix ElicitationTest to use assertEquals(Boolean.TRUE, ...) to avoid NPE

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* test: add Optional value retrieval and JSON deserialization tests

Adds tests for getAsInt/get/orElse value retrieval on all Optional-returning
getters, and JSON deserialization round-trip tests for ModelCapabilitiesOverride
inner classes and InfiniteSessionConfig to keep coverage above 83%.

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>

* refactor: revert Optional usage, use plain nullable fields with @JsonInclude(NON_NULL)

Remove all Optional<T>/OptionalInt/OptionalDouble usage from DTOs.
R…
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.

[reference-impl-sync] Reference Implementation sync: 15 new commits (2026-05-11) [MAINT]: Resolve nodejs 20 issues

3 participants