Skip to content

Commit b9b4d2b

Browse files
tclemCopilot
andcommitted
codegen(rust): apply stripBooleanLiterals to schemas
Codegen was crashing on the post-1.0.41-0 schema with `TypeError: s.split is not a function` at toPascalCase. Root cause: the new `connect` JSON-RPC method's `ConnectResult.ok` field is declared as `{ "type": "boolean", "enum": [true] }` (a single-value boolean enum used as a "must-be-true" discriminant). The Rust generator's `emitRustStringEnum` assumes string values, fed a boolean, and panicked. Python and Go generators already pre-process the schema with `stripBooleanLiterals` (utils.ts:146) for exactly this reason — upstream PR #1176 added the helper precisely because quicktype's Python/Go renderers crashed on the same input. The TypeScript and C# generators handle it natively. Rust's generator wasn't pre- processing, so it inherited the same crash. Fix: apply `stripBooleanLiterals` to both `apiSchema` and `sessionEventsSchema` in `rust.ts` before postProcessSchema / emit. Mirrors the Python/Go invocation pattern. Boolean literal narrowing isn't expressible in Rust enums anyway — the field stays `pub ok: bool`. Regen produces two new types from the post-1.0.41-0 schema: - `ConnectRequest` (token: Option<String>) - `ConnectResult` (ok: bool, protocolVersion: u32) - rpc_methods::CONNECT constant These reflect the `connect` JSON-RPC method our hand-coded verify_protocol_version handshake already invokes via `client.call("connect", ...)`. We don't switch the call site to the typed RPC because the existing untyped call matches how `ping` is invoked next door, and the handshake needs the special MethodNotFound fallback that doesn't fit the typed RPC abstraction. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent b3471f3 commit b9b4d2b

3 files changed

Lines changed: 34 additions & 2 deletions

File tree

rust/src/generated/api_types.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ use crate::types::{RequestId, SessionId};
1212
pub mod rpc_methods {
1313
/// `ping`
1414
pub const PING: &str = "ping";
15+
/// `connect`
16+
pub const CONNECT: &str = "connect";
1517
/// `models.list`
1618
pub const MODELS_LIST: &str = "models.list";
1719
/// `tools.list`
@@ -275,6 +277,25 @@ pub struct CommandsHandlePendingCommandResult {
275277
pub success: bool,
276278
}
277279

280+
#[derive(Debug, Clone, Serialize, Deserialize)]
281+
#[serde(rename_all = "camelCase")]
282+
pub struct ConnectRequest {
283+
/// Connection token; required when the server was started with COPILOT_CONNECTION_TOKEN
284+
#[serde(skip_serializing_if = "Option::is_none")]
285+
pub token: Option<String>,
286+
}
287+
288+
#[derive(Debug, Clone, Serialize, Deserialize)]
289+
#[serde(rename_all = "camelCase")]
290+
pub struct ConnectResult {
291+
/// Always true on success
292+
pub ok: bool,
293+
/// Server protocol version number
294+
pub protocol_version: i64,
295+
/// Server package version
296+
pub version: String,
297+
}
298+
278299
#[derive(Debug, Clone, Serialize, Deserialize)]
279300
#[serde(rename_all = "camelCase")]
280301
pub struct CurrentModel {

rust/src/generated/rpc.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,16 @@ impl<'a> ClientRpc<'a> {
7777
.await?;
7878
Ok(serde_json::from_value(_value)?)
7979
}
80+
81+
/// Wire method: `connect`.
82+
pub async fn connect(&self, params: ConnectRequest) -> Result<ConnectResult, Error> {
83+
let wire_params = serde_json::to_value(params)?;
84+
let _value = self
85+
.client
86+
.call(rpc_methods::CONNECT, Some(wire_params))
87+
.await?;
88+
Ok(serde_json::from_value(_value)?)
89+
}
8090
}
8191

8292
/// `account.*` RPCs.

scripts/codegen/rust.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {
3232
resolveObjectSchema,
3333
resolveRef,
3434
resolveSchema,
35+
stripBooleanLiterals,
3536
} from "./utils.js";
3637

3738
const execFileAsync = promisify(execFile);
@@ -1359,10 +1360,10 @@ async function generate(): Promise<void> {
13591360
) as ApiSchema;
13601361

13611362
const sessionEventsSchema = postProcessSchema(
1362-
sessionEventsRaw as JSONSchema7,
1363+
stripBooleanLiterals(sessionEventsRaw) as JSONSchema7,
13631364
);
13641365
const apiSchema = postProcessSchema(
1365-
apiRaw as JSONSchema7,
1366+
stripBooleanLiterals(apiRaw) as JSONSchema7,
13661367
) as unknown as ApiSchema;
13671368

13681369
// Ensure output directory exists

0 commit comments

Comments
 (0)