Add classical code generation workflow for typed event and RPC classes#81
Open
Add classical code generation workflow for typed event and RPC classes#81
Conversation
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 ef1de83. 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
Contributor
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR introduces a TypeScript-based code generation workflow that replaces hand-written session event DTOs and untyped JSON-RPC invocations with generated, strongly-typed Java event classes and RPC wrapper APIs.
Changes:
- Added a TypeScript code generator (
scripts/codegen/java.ts) plus NPM project scaffolding to generate Java event/RPC types from JSON Schemas. - Wired core SDK code to use generated
SessionEventtypes and typedServerRpc/SessionRpcwrappers instead of the deletedeventspackage and rawrpc.invoke(...)calls. - Added Maven + CI workflow support to compile generated sources and verify generated code is in sync.
Show a summary per file
| File | Description |
|---|---|
scripts/codegen/java.ts |
Implements codegen for event classes, RPC DTOs, and RPC wrapper APIs. |
pom.xml |
Adds generated source root + profiles to run/update codegen; excludes generated sources from Spotless. |
src/main/java/com/github/copilot/sdk/CopilotSession.java |
Switches event handling to SessionEvent and replaces raw RPC calls with typed session RPC wrappers. |
src/main/java/com/github/copilot/sdk/CopilotClient.java |
Adds typed server RPC access via ServerRpc and exposes getRpc(). |
src/main/java/com/github/copilot/sdk/RpcHandlerDispatcher.java |
Switches session event parsing to Jackson polymorphic deserialization into generated SessionEvent. |
.github/workflows/codegen-check.yml |
CI workflow to fail if committed generated code is stale. |
.github/workflows/update-copilot-dependency.yml |
Workflow to bump @github/copilot schema version, regenerate, verify, and open a PR. |
Copilot's findings
Files not reviewed (1)
- scripts/codegen/package-lock.json: Language not supported
- Files reviewed: 83/329 changed files
- Comments generated: 6
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>
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add classical code generation workflow for typed event and RPC classes
Fixes #69 .
Supersedes #79 .
Reviewer's Guide
The Big Idea
This PR replaces hand-written session event classes and raw
rpc.invoke()calls with code-generated, strongly-typed Java classes produced by a TypeScript code generator (scripts/codegen/java.ts). The generator reads two JSON schemas distributed in the@github/copilotnpm package (session-events.schema.jsonandapi.schema.json) and emits:Typed session events — a
sealed class SessionEventhierarchy with ~75 event subclasses (records) undersrc/generated/java/.../generated/, replacing the hand-writtenAbstractSessionEventclass and its ~55 inner classes plus theSessionEventParserinsrc/main/.../events/.Typed RPC wrappers —
ServerRpcandSessionRpcnamespace classes with sub-API classes (e.g.,SessionToolsApi,SessionUiApi,SessionPermissionsApi) undersrc/generated/java/.../generated/rpc/, giving compile-time safety to every JSON-RPC call.The hand-coded
events/package (60 files, ~2900 lines) is deleted. All production code and tests are migrated to import fromcom.github.copilot.sdk.generatedinstead ofcom.github.copilot.sdk.events.The Groups of Changed Files
1. Code Generation Infrastructure
These files define how the generated Java code is produced, validated, and updated.
scripts/codegen/java.ts(1322 lines, new) — The TypeScript code generator. Readssession-events.schema.jsonandapi.schema.json, emits Java sealed classes, records, enums, and RPC namespace API classes.scripts/codegen/package.json/package-lock.json— npm project pinning the@github/copilot@1.0.24schema package as the generator's input.scripts/codegen/.gitignore— Ignoresnode_modules/.pom.xml— Three additions:build-helper-maven-pluginaddssrc/generated/javaas a source rootspotless-maven-pluginexcludessrc/generated/java/**/*.javafrom formattingcodegen(runsnpm ci+npm run generate) andupdate-schemas-from-npm-artifact(runsnpm install @github/copilot@<version>).github/workflows/codegen-check.yml(new) — CI workflow that re-runs the generator and fails if any committed generated file is stale..github/workflows/update-copilot-dependency.yml(new) — Manual workflow: accepts a@github/copilotversion, re-runs the generator, runs an AI-assisted schema verification step, and opens a PR..gitattributes— Markssrc/generated/java/**aslinguist-generated=true(collapses diffs on GitHub) andeol=lf(cross-platform consistency).config/checkstyle/checkstyle.xml— Addsgeneratedandrpcto the Checkstyle exclusion pattern.config/spotbugs/spotbugs-exclude.xml— Excludes generated packages from SpotBugs.docs/WORKFLOWS.md— Documents the two new workflows.2. Agentic Sync Guardrails
These changes prevent the automated reference-implementation merge agent from hand-editing generated code.
.github/prompts/agentic-merge-reference-impl.prompt.md— Adds an ABSOLUTE PROHIBITION block at the top forbidding any modification ofsrc/generated/java/. The file mapping table now shows ❌ fordotnet/src/Generated/*.cs. A checklist item verifies no generated files were touched. A reminder is inserted before Step 5 (Apply Changes)..github/prompts/coding-agent-merge-reference-impl-instructions.md— Adds a corresponding prohibition block for the coding agent's instructions file.3. Generated Code (Output)
All files under
src/generated/java/com/github/copilot/sdk/generated/(new). These are the output ofjava.tsand must never be hand-edited.SessionEvent.java(sealed base with@JsonTypeInfo/@JsonSubTypespolymorphic deserialization), individual event classes likeAssistantMessageEvent,SessionIdleEvent,ToolExecutionCompleteEvent, etc., plusUnknownSessionEventas thedefaultImplfallback.ServerRpc.java,SessionRpc.java, sub-API classes (SessionToolsApi,SessionUiApi, etc.), and param/result records for every RPC method.RpcCaller.java(functional interface forinvoke),RpcMapper.java(JacksonObjectMapperholder).4. Wiring: Delete Hand-Written Events, Switch to Generated Types
Production code changes that remove the old events package and wire in the generated replacements.
src/main/.../events/(60 files deleted) — The entire hand-written events package:AbstractSessionEvent, all ~55 event inner classes,SessionEventParser, andpackage-info.java.src/main/.../CopilotSession.java— The largest behavioral change file:events.*togenerated.*Consumer<AbstractSessionEvent>→Consumer<SessionEvent>throughoutrpc.invoke("session.xxx", Map.of(...), Object.class)calls replaced with typedgetRpc().xxx.method(new XxxParams(...))callsgetRpc()method exposesSessionRpc(lazily created, double-checked locking)setActiveSessionId()nullssessionRpcso it re-creates with the new IDPermissionRequestedEvent.data.permissionRequest()is nowObject(from the generic schema) — requiresMAPPER.convertValue(...)to convert to the hand-writtenPermissionRequestDTObuildElicitationCancelParams()helper extracts repeated cancel-params constructionsrc/main/.../CopilotClient.java—Connectionrecord gains aServerRpc serverRpcfield, eagerly created. NewgetRpc()method exposes it.src/main/.../RpcHandlerDispatcher.java—SessionEventParser.parse(eventNode)replaced withMAPPER.treeToValue(eventNode, SessionEvent.class)(Jackson polymorphic deserialization via annotations).src/main/.../EventErrorHandler.java— Import change:AbstractSessionEvent→SessionEvent.src/main/.../json/SessionConfig.java/ResumeSessionConfig.java—Consumer<AbstractSessionEvent>→Consumer<SessionEvent>for theonEventfield.src/main/.../package-info.java— Javadoc reference update.5. Documentation Updates
README.md/jbang-example.java— Import paths changed fromevents.*togenerated.*.src/site/markdown/(8 files) — Cookbook pages, getting-started, advanced, and index all updated for the new import paths..github/copilot-instructions.md— Addsgeneratedto the package structure description.6. Test Changes
RpcWrappersTest.java(471 lines, new) — Comprehensive unit tests forServerRpcandSessionRpcusing an in-memoryRpcCallerstub. Verifies correct method names, sessionId injection, param serialization.SessionEventParserTest.java→SessionEventDeserializationTest.java(renamed + rewritten) — Tests Jackson polymorphic deserialization of all event types viaSessionEvent. Replaces the oldSessionEventParser-based tests.TestUtil.java(101 lines, new) — Shared test utility for Windows CLI path resolution (findCopilotInPath()), extracting the logic that was previously duplicated in E2E tests.SessionEventsE2ETest.java— UsesTestUtilfor CLI path finding; import changes.events.*togenerated.*, plusAbstractSessionEvent→SessionEvent.7. Review Fixes
Changes applied in response to review feedback on prior iterations:
sendExpandedToolResult()bypass removed — The previous version needed a manualObjectNodebypass because the generatedSessionToolsHandlePendingToolCallParams.resultwas typed asString. The schema'sanyOf[string, object]heuristic was fixed (multi-branchanyOfnow falls back toObject), soToolResultObjectcan be passed directly through the generated wrapper.fromValue()case sensitivity — Generated enumfromValue()uses case-sensitiveequals(), which is correct for wire protocol values. Consumer code (e.g., elicitation action matching) usesequalsIgnoreCase()on the enum'sgetValue()string where case-insensitive matching is needed.The Big Risks
1. Event deserialization fidelity after replacing
SessionEventParser(HIGH)The old
SessionEventParserwas a hand-written switch/map that parsed events from JSON. It is replaced by Jackson's@JsonTypeInfo+@JsonSubTypespolymorphic deserialization on the generatedSessionEventsealed class. This changes the deserialization path for every session event in the SDK.What to check: The
SessionEventDeserializationTestshould cover all event types. Verify that:UnknownSessionEvent(thedefaultImpl)visible = trueon@JsonTypeInfomeans thetypefield is populated onUnknownSessionEvent(preserving the wire type for forward compatibility)@JsonIgnoreProperties(ignoreUnknown = true)so new fields from the server don't break deserialization2.
PermissionRequestedEvent.data.permissionRequest()is nowObject(HIGH)The generated event's
permissionRequestfield is typed asObjectbecause the schema has no strong type for it. The code usesMAPPER.convertValue(data.permissionRequest(), PermissionRequest.class)to bridge to the hand-written DTO. If the wire shape changes, thisconvertValuewill fail at runtime with no compile-time signal.What to check: Look at the
handleBroadcastEventAsyncmethod inCopilotSession.javawhereconvertValueis called. Confirm the E2E test for permissions exercises this path.3. Lazy
SessionRpcinitialization andsetActiveSessionId()reset (MEDIUM)CopilotSession.getRpc()uses double-checked locking to lazily create aSessionRpcbound to the currentsessionId. WhensetActiveSessionId()is called (on session resume when the server returns a different ID), it setssessionRpc = nullso the next call re-creates with the new ID.What to check: The
sessionRpcfield isvolatileand the lazy init usessynchronized(this). This is correct for double-checked locking. SinceSessionRpcis stateless (just capturescaller+sessionId), concurrent creation of duplicate instances is benign, but the synchronization prevents it anyway.4.
fromValue()is case-sensitive — intentional but surprising (MEDIUM)Generated enum
fromValue()methods usev.value.equals(value)(case-sensitive). If the server ever sends"Accept"instead of"accept"for an elicitation action,fromValue()throwsIllegalArgumentException.What to check: The consumer-facing code in
CopilotSessioncorrectly usesequalsIgnoreCase()onresp.action().getValue()when mapping to the SDK'sElicitationResultActionenum, so the user-facing API is case-tolerant. But internal paths that callfromValue()directly on generated enums (e.g.,SessionUiHandlePendingElicitationParamsResultAction.fromValue(actionStr)) are case-sensitive. Verify this is intentional and matches the wire protocol.5. Generated code is not reviewed line-by-line (MEDIUM)
~195 generated files (~10,000 lines) are committed as output of
java.ts. Thecodegen-check.ymlCI workflow verifies they're reproducible, and theupdate-copilot-dependency.ymlworkflow includes an AI-assisted spot-check step, but no human reviews every generated file.What to check: Spot-check 2-3 generated API classes (e.g.,
SessionToolsApi.java,SessionUiApi.java) against the sourceapi.schema.jsonto confirm method names, param types, and return types are correct. TheRpcWrappersTestprovides mechanical coverage.6.
CopilotClient.getRpc()throws on non-connected state (LOW)The new
getRpc()onCopilotClientthrowsIllegalStateExceptionifconnectionFutureis null, not done, or completed exceptionally. This is stricter than the old pattern where callers would just get theConnectionfrom the future.What to check: Confirm test coverage for calling
getRpc()beforestart()(theCopilotClientTestshould cover this).Gotchas
The
events/package is entirely deleted, not deprecatedThere is no deprecation bridge. All 60 files under
src/main/.../events/are removed in this PR. Any downstream code importing fromcom.github.copilot.sdk.events.*will fail to compile. The replacement iscom.github.copilot.sdk.generated.*. This is acceptable because the SDK hasn't had a stable release with the old events package yet.src/generated/java/is FORBIDDEN for hand-editingThe files under
src/generated/java/must never be hand-edited — not by developers, and not by the agentic reference-implementation sync workflow. The correct way to update them is to trigger theupdate-copilot-dependency.ymlworkflow with a new@github/copilotnpm version. Theagentic-merge-reference-impl.prompt.mdenforces this with an ABSOLUTE PROHIBITION block and a required stop-and-fail procedure..gitattributesmarks generated code aslinguist-generatedGitHub's PR diff will collapse
src/generated/java/**by default. To inspect generated files, you need to expand them manually or usegit difflocally.build-helper-maven-pluginis required forsrc/generated/javato compileThe generated Java files live outside the standard
src/main/javasource root. Thebuild-helper-maven-pluginaddssrc/generated/javaas an additional source root duringgenerate-sources. Without this plugin, the compiler won't find the generated types.The
update-copilot-dependency.ymlworkflow includes an AI code review stepAfter running the generator, the workflow invokes
copilot --yolowith a verification prompt that asks the AI to spot-check 3 generated API classes against the JSON schema. This is a "trust but verify" guardrail. It requires aCOPILOT_GITHUB_TOKENsecret and the.github/actions/setup-copilotcomposite action. If the AI finds mismatches, the workflow fails before creating the PR.TestUtilextracts Windows CLI path resolutionOn Windows,
where.exe copilotcan return multiple candidates (including Linux ELF binaries from VS Code's embedded Copilot CLI).TestUtil.findCopilotInPath()iterates all candidates and tries launching each one — this replaces duplicated logic that was previously in individual E2E test classes.Elicitation mode field changed from
Stringto enumThe generated
ElicitationRequestedEventtypesmodeas an enum. The wiring code usesdata.mode() != null ? data.mode().getValue() : nullto convert back to a String for theElicitationContext. This is a behavioral change: previouslymodewas a raw String from the JSON.Two Maven profiles for codegen, used separately
mvn generate-sources -Pcodegen— regenerates from the currently-pinned schema versionmvn generate-sources -Pupdate-schemas-from-npm-artifact -Dcopilot.schema.version=1.0.25— updates the pinned schema version (mutatespackage.json)These are intentionally separate: the version bump is a distinct, explicit action.