Skip to content

Commit 19891e5

Browse files
Fix Java codegen and build failures after @github/copilot update
The new @github/copilot schemas introduced cross-schema $ref references in api.schema.json pointing to session-events.schema.json definitions: - session-events.schema.json#/definitions/SessionEvent - session-events.schema.json#/definitions/PermissionPromptRequest The code generator only handled local #/definitions/ refs, causing invalid Java type names to be emitted (the raw $ref string), which produced compilation errors: PendingPermissionRequest.java: illegal character '#' SessionEventLogReadResult.java: '<identifier> expected', etc. Fix in java/scripts/codegen/java.ts: - Track generated session-events type names in generatedSessionEventsTypes - Store session-events definitions in sessionEventsDefinitions - In schemaTypeToJava, detect cross-schema refs and resolve them: - If the type is already generated in the session-events package (e.g. SessionEvent), emit it with the correct import - Otherwise resolve inline using the external definitions (anyOf unions like PermissionPromptRequest fall back to Object) Regenerated affected files: PendingPermissionRequest.java: request field now typed as Object SessionEventLogReadResult.java: events field now typed as List<SessionEvent> Automated fix applied by java-codegen-fix workflow. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent cb8a3fd commit 19891e5

3 files changed

Lines changed: 42 additions & 2 deletions

File tree

java/scripts/codegen/java.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,13 @@ interface JavaTypeResult {
102102
let currentDefinitions: Record<string, JSONSchema7> = {};
103103
const pendingStandaloneTypes = new Map<string, JSONSchema7>();
104104

105+
// Definitions and generated type names from the session-events schema, populated
106+
// during generateSessionEvents so that cross-schema $ref resolution in generateRpcTypes
107+
// can look up types like SessionEvent and PermissionPromptRequest.
108+
let sessionEventsDefinitions: Record<string, JSONSchema7> = {};
109+
const generatedSessionEventsTypes = new Set<string>();
110+
const SESSION_EVENTS_PACKAGE = "com.github.copilot.sdk.generated";
111+
105112
/**
106113
* Resolve a $ref in a JSON Schema against the current definitions.
107114
* Returns the resolved schema, or the original if no $ref is present.
@@ -131,6 +138,28 @@ function schemaTypeToJava(
131138

132139
// Resolve $ref first — register standalone types for generation
133140
if (schema.$ref) {
141+
// Handle cross-schema refs (e.g. "session-events.schema.json#/definitions/X")
142+
if (!schema.$ref.startsWith("#")) {
143+
const hashIdx = schema.$ref.indexOf("#");
144+
const schemaFile = hashIdx >= 0 ? schema.$ref.substring(0, hashIdx) : schema.$ref;
145+
const pointer = hashIdx >= 0 ? schema.$ref.substring(hashIdx + 1) : "";
146+
const typeName = pointer.replace(/^\/definitions\//, "");
147+
if (schemaFile === "session-events.schema.json" && typeName) {
148+
if (generatedSessionEventsTypes.has(typeName)) {
149+
// Already generated in the session-events package — use with import
150+
imports.add(`${SESSION_EVENTS_PACKAGE}.${typeName}`);
151+
return { javaType: typeName, imports };
152+
}
153+
// Not a pre-generated standalone type; resolve inline from session-events defs
154+
const extDef = sessionEventsDefinitions[typeName];
155+
if (extDef) {
156+
return schemaTypeToJava(extDef, required, context, propName, nestedTypes);
157+
}
158+
}
159+
console.warn(`[codegen] Unresolved cross-schema $ref: ${schema.$ref}`);
160+
return { javaType: "Object", imports };
161+
}
162+
134163
const name = schema.$ref.replace(/^#\/definitions\//, "");
135164
const resolved = currentDefinitions[name];
136165
if (resolved) {
@@ -314,20 +343,30 @@ async function generateSessionEvents(schemaPath: string): Promise<void> {
314343
currentDefinitions = (schema.definitions ?? {}) as Record<string, JSONSchema7>;
315344
pendingStandaloneTypes.clear();
316345

346+
// Store session-events definitions for cross-schema $ref resolution during RPC generation
347+
sessionEventsDefinitions = currentDefinitions;
348+
generatedSessionEventsTypes.clear();
349+
317350
const variants = extractEventVariants(schema);
318351
const packageName = "com.github.copilot.sdk.generated";
319352
const packageDir = `src/generated/java/com/github/copilot/sdk/generated`;
320353

321354
// Generate base SessionEvent class
322355
await generateSessionEventBaseClass(variants, packageName, packageDir);
356+
generatedSessionEventsTypes.add("SessionEvent");
357+
generatedSessionEventsTypes.add("UnknownSessionEvent");
323358

324359
// Generate one class file per event variant
325360
for (const variant of variants) {
326361
await generateEventVariantClass(variant, packageName, packageDir);
362+
generatedSessionEventsTypes.add(variant.className);
327363
}
328364

329365
// Generate standalone types discovered via $ref resolution
330366
await generatePendingStandaloneTypes(packageName, packageDir, GENERATED_FROM_SESSION_EVENTS);
367+
for (const typeName of pendingStandaloneTypes.keys()) {
368+
generatedSessionEventsTypes.add(typeName);
369+
}
331370

332371
console.log(`✅ Generated ${variants.length + 1} session event files`);
333372
}

java/src/generated/java/com/github/copilot/sdk/generated/rpc/PendingPermissionRequest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@ public record PendingPermissionRequest(
2424
/** Unique identifier for the pending permission request */
2525
@JsonProperty("requestId") String requestId,
2626
/** The user-facing permission prompt details (commands, write, read, mcp, url, memory, custom-tool, path, hook) */
27-
@JsonProperty("request") session-events.schema.json#/definitions/PermissionPromptRequest request
27+
@JsonProperty("request") Object request
2828
) {
2929
}

java/src/generated/java/com/github/copilot/sdk/generated/rpc/SessionEventLogReadResult.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
1111
import com.fasterxml.jackson.annotation.JsonInclude;
1212
import com.fasterxml.jackson.annotation.JsonProperty;
13+
import com.github.copilot.sdk.generated.SessionEvent;
1314
import java.util.List;
1415
import javax.annotation.processing.Generated;
1516

@@ -23,7 +24,7 @@
2324
@JsonIgnoreProperties(ignoreUnknown = true)
2425
public record SessionEventLogReadResult(
2526
/** Events are delivered in two batches per read: persisted events first (in append order), then ephemeral events (in seq order). When `waitMs > 0` and the catch-up batches were empty, post-wait events follow the same two-batch ordering. Persisted and ephemeral events do not interleave within a single read. */
26-
@JsonProperty("events") List<session-events.schema.json#/definitions/SessionEvent> events,
27+
@JsonProperty("events") List<SessionEvent> events,
2728
/** Opaque cursor for the next read. Pass back unchanged in the next read.cursor to continue from where this read left off. Always present, even when no events were returned. */
2829
@JsonProperty("cursor") String cursor,
2930
/** True when the read returned `max` events and more events are available immediately. When false, the next read with a non-zero `waitMs` will block until a new event arrives or the wait expires. */

0 commit comments

Comments
 (0)