Skip to content

Commit fd9f2c1

Browse files
committed
Fix optional RPC request codegen
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent bb73d20 commit fd9f2c1

10 files changed

Lines changed: 291 additions & 104 deletions

File tree

dotnet/src/Generated/Rpc.cs

Lines changed: 33 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

go/rpc/zrpc.go

Lines changed: 28 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

nodejs/src/generated/rpc.ts

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

python/copilot/generated/rpc.py

Lines changed: 5 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/src/generated/rpc.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,19 @@ impl<'a> ClientRpcAccount<'a> {
105105
.await?;
106106
Ok(serde_json::from_value(_value)?)
107107
}
108+
109+
/// Wire method: `account.getQuota`.
110+
pub async fn get_quota_with_params(
111+
&self,
112+
params: AccountGetQuotaRequest,
113+
) -> Result<AccountGetQuotaResult, Error> {
114+
let wire_params = serde_json::to_value(params)?;
115+
let _value = self
116+
.client
117+
.call(rpc_methods::ACCOUNT_GETQUOTA, Some(wire_params))
118+
.await?;
119+
Ok(serde_json::from_value(_value)?)
120+
}
108121
}
109122

110123
/// `mcp.*` RPCs.
@@ -216,6 +229,16 @@ impl<'a> ClientRpcModels<'a> {
216229
.await?;
217230
Ok(serde_json::from_value(_value)?)
218231
}
232+
233+
/// Wire method: `models.list`.
234+
pub async fn list_with_params(&self, params: ModelsListRequest) -> Result<ModelList, Error> {
235+
let wire_params = serde_json::to_value(params)?;
236+
let _value = self
237+
.client
238+
.call(rpc_methods::MODELS_LIST, Some(wire_params))
239+
.await?;
240+
Ok(serde_json::from_value(_value)?)
241+
}
219242
}
220243

221244
/// `sessionFs.*` RPCs.
@@ -658,6 +681,21 @@ impl<'a> SessionRpcCommands<'a> {
658681
Ok(serde_json::from_value(_value)?)
659682
}
660683

684+
/// Wire method: `session.commands.list`.
685+
pub async fn list_with_params(
686+
&self,
687+
params: CommandsListRequest,
688+
) -> Result<CommandList, Error> {
689+
let mut wire_params = serde_json::to_value(params)?;
690+
wire_params["sessionId"] = serde_json::Value::String(self.session.id().to_string());
691+
let _value = self
692+
.session
693+
.client()
694+
.call(rpc_methods::SESSION_COMMANDS_LIST, Some(wire_params))
695+
.await?;
696+
Ok(serde_json::from_value(_value)?)
697+
}
698+
661699
/// Wire method: `session.commands.invoke`.
662700
pub async fn invoke(
663701
&self,

scripts/codegen/csharp.ts

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,6 +1506,10 @@ function emitSessionMethod(key: string, method: RpcMethod, lines: string[], clas
15061506
const effectiveParams = resolveMethodParamsSchema(method);
15071507
const paramEntries = (effectiveParams?.properties ? Object.entries(effectiveParams.properties) : []).filter(([k]) => k !== "sessionId");
15081508
const requiredSet = new Set(effectiveParams?.required || []);
1509+
const useRequestParameter =
1510+
paramEntries.length > 0 &&
1511+
!!getNullableInner(method.params) &&
1512+
paramEntries.every(([name]) => !requiredSet.has(name));
15091513

15101514
// Sort so required params come before optional (C# requires defaults at end)
15111515
paramEntries.sort((a, b) => {
@@ -1515,12 +1519,28 @@ function emitSessionMethod(key: string, method: RpcMethod, lines: string[], clas
15151519
});
15161520

15171521
const requestClassName = paramsTypeName(method);
1522+
const wireRequestClassName = useRequestParameter ? `${requestClassName}WithSession` : requestClassName;
15181523
if (method.stability === "experimental") {
15191524
experimentalRpcTypes.add(requestClassName);
1525+
if (useRequestParameter) {
1526+
experimentalRpcTypes.add(wireRequestClassName);
1527+
}
15201528
}
15211529
if (effectiveParams?.properties && Object.keys(effectiveParams.properties).length > 0) {
1522-
const reqClass = emitRpcClass(requestClassName, effectiveParams, "internal", classes);
1523-
if (reqClass) classes.push(reqClass);
1530+
if (useRequestParameter) {
1531+
const publicParams: JSONSchema7 = {
1532+
...effectiveParams,
1533+
properties: Object.fromEntries(paramEntries),
1534+
required: effectiveParams.required?.filter((name) => name !== "sessionId"),
1535+
};
1536+
const publicReqClass = emitRpcClass(requestClassName, publicParams, methodVisibility, classes);
1537+
if (publicReqClass) classes.push(publicReqClass);
1538+
const wireReqClass = emitRpcClass(wireRequestClassName, effectiveParams, "internal", classes);
1539+
if (wireReqClass) classes.push(wireReqClass);
1540+
} else {
1541+
const reqClass = emitRpcClass(requestClassName, effectiveParams, "internal", classes);
1542+
if (reqClass) classes.push(reqClass);
1543+
}
15241544
}
15251545

15261546
lines.push("", `${indent}/// <summary>Calls "${method.rpcMethod}".</summary>`);
@@ -1533,22 +1553,30 @@ function emitSessionMethod(key: string, method: RpcMethod, lines: string[], clas
15331553
const sigParams: string[] = [];
15341554
const bodyAssignments = [`SessionId = _sessionId`];
15351555

1536-
for (const [pName, pSchema] of paramEntries) {
1537-
if (typeof pSchema !== "object") continue;
1538-
const isReq = requiredSet.has(pName);
1539-
const csType = resolveRpcType(pSchema as JSONSchema7, isReq, requestClassName, toPascalCase(pName), classes);
1540-
sigParams.push(`${csType} ${pName}${isReq ? "" : " = null"}`);
1541-
bodyAssignments.push(`${toPascalCase(pName)} = ${pName}`);
1556+
if (useRequestParameter) {
1557+
sigParams.push(`${requestClassName}? request = null`);
1558+
for (const [pName] of paramEntries) {
1559+
bodyAssignments.push(`${toPascalCase(pName)} = request?.${toPascalCase(pName)}`);
1560+
}
1561+
} else {
1562+
for (const [pName, pSchema] of paramEntries) {
1563+
if (typeof pSchema !== "object") continue;
1564+
const isReq = requiredSet.has(pName);
1565+
const csType = resolveRpcType(pSchema as JSONSchema7, isReq, requestClassName, toPascalCase(pName), classes);
1566+
sigParams.push(`${csType} ${pName}${isReq ? "" : " = null"}`);
1567+
bodyAssignments.push(`${toPascalCase(pName)} = ${pName}`);
1568+
}
15421569
}
15431570
sigParams.push("CancellationToken cancellationToken = default");
15441571

15451572
const taskType = !isVoidSchema(resultSchema) ? `Task<${resultClassName}>` : "Task";
1573+
const localRequestName = useRequestParameter ? "rpcRequest" : "request";
15461574
lines.push(`${indent}${methodVisibility} async ${taskType} ${methodName}Async(${sigParams.join(", ")})`);
1547-
lines.push(`${indent}{`, `${indent} var request = new ${requestClassName} { ${bodyAssignments.join(", ")} };`);
1575+
lines.push(`${indent}{`, `${indent} var ${localRequestName} = new ${wireRequestClassName} { ${bodyAssignments.join(", ")} };`);
15481576
if (!isVoidSchema(resultSchema)) {
1549-
lines.push(`${indent} return await CopilotClient.InvokeRpcAsync<${resultClassName}>(_rpc, "${method.rpcMethod}", [request], cancellationToken);`, `${indent}}`);
1577+
lines.push(`${indent} return await CopilotClient.InvokeRpcAsync<${resultClassName}>(_rpc, "${method.rpcMethod}", [${localRequestName}], cancellationToken);`, `${indent}}`);
15501578
} else {
1551-
lines.push(`${indent} await CopilotClient.InvokeRpcAsync(_rpc, "${method.rpcMethod}", [request], cancellationToken);`, `${indent}}`);
1579+
lines.push(`${indent} await CopilotClient.InvokeRpcAsync(_rpc, "${method.rpcMethod}", [${localRequestName}], cancellationToken);`, `${indent}}`);
15521580
}
15531581
}
15541582

scripts/codegen/go.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3338,6 +3338,8 @@ function emitMethod(lines: string[], receiver: string, name: string, method: Rpc
33383338
.sort((left, right) => compareGoFieldNames(toGoFieldName(left), toGoFieldName(right)));
33393339
const hasParams = isSession ? nonSessionParams.length > 0 : hasSchemaPayload(effectiveParams);
33403340
const paramsType = hasParams ? resolveType(goParamsTypeName(method)) : "";
3341+
const hasRequiredNonSessionParams = nonSessionParams.some((name) => requiredParams.has(name));
3342+
const paramsAreOptional = hasParams && !!method.params && !!getNullableInner(method.params) && !hasRequiredNonSessionParams;
33413343

33423344
// For wrapper-level methods, access fields through a.common; for service type aliases, use a directly
33433345
const clientRef = isWrapper ? "a.common.client" : "a.client";
@@ -3353,15 +3355,22 @@ function emitMethod(lines: string[], receiver: string, name: string, method: Rpc
33533355
pushGoComment(lines, `Internal: ${methodName} is part of the SDK's internal handshake/plumbing; external callers should not use it.`);
33543356
}
33553357
const sig = hasParams
3356-
? `func (a *${receiver}) ${methodName}(ctx context.Context, params *${paramsType}) (${returnType}, error)`
3358+
? `func (a *${receiver}) ${methodName}(ctx context.Context, params ${paramsAreOptional ? "..." : ""}*${paramsType}) (${returnType}, error)`
33573359
: `func (a *${receiver}) ${methodName}(ctx context.Context) (${returnType}, error)`;
33583360

33593361
lines.push(sig + ` {`);
3362+
const paramsRef = paramsAreOptional ? "requestParams" : "params";
3363+
if (paramsAreOptional) {
3364+
lines.push(`\tvar requestParams *${paramsType}`);
3365+
lines.push(`\tif len(params) > 0 {`);
3366+
lines.push(`\t\trequestParams = params[0]`);
3367+
lines.push(`\t}`);
3368+
}
33603369

33613370
if (isSession) {
33623371
lines.push(`\treq := map[string]any{"sessionId": ${sessionIDRef}}`);
33633372
if (hasParams) {
3364-
lines.push(`\tif params != nil {`);
3373+
lines.push(`\tif ${paramsRef} != nil {`);
33653374
for (const pName of nonSessionParams) {
33663375
const field = fields.get(paramsType)?.get(pName);
33673376
const goField = field?.name ?? toGoFieldName(pName);
@@ -3370,19 +3379,19 @@ function emitMethod(lines: string[], receiver: string, name: string, method: Rpc
33703379
if (isOptional) {
33713380
// Optional fields are usually pointers; generated union interfaces, slices,
33723381
// and maps are nilable values and should be passed through directly.
3373-
lines.push(`\t\tif params.${goField} != nil {`);
3374-
const valueExpr = goOptionalFieldNeedsDereference(goType) ? `*params.${goField}` : `params.${goField}`;
3382+
lines.push(`\t\tif ${paramsRef}.${goField} != nil {`);
3383+
const valueExpr = goOptionalFieldNeedsDereference(goType) ? `*${paramsRef}.${goField}` : `${paramsRef}.${goField}`;
33753384
lines.push(`\t\t\treq["${pName}"] = ${valueExpr}`);
33763385
lines.push(`\t\t}`);
33773386
} else {
3378-
lines.push(`\t\treq["${pName}"] = params.${goField}`);
3387+
lines.push(`\t\treq["${pName}"] = ${paramsRef}.${goField}`);
33793388
}
33803389
}
33813390
lines.push(`\t}`);
33823391
}
33833392
lines.push(`\traw, err := ${clientRef}.Request("${method.rpcMethod}", req)`);
33843393
} else {
3385-
const arg = hasParams ? "params" : "nil";
3394+
const arg = hasParams ? paramsRef : "nil";
33863395
lines.push(`\traw, err := ${clientRef}.Request("${method.rpcMethod}", ${arg})`);
33873396
}
33883397

scripts/codegen/python.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2084,7 +2084,7 @@ function emitRpcWrapper(lines: string[], node: Record<string, unknown>, isSessio
20842084
} else {
20852085
lines.push(`class ${wrapperName}:`);
20862086
lines.push(classPrefix === "_Internal"
2087-
? ` """Internal SDK server-scoped RPC methods (handshake helpers etc.). Not part of the public API."""`
2087+
? ` """Internal SDK server-scoped RPC methods. Not part of the public API."""`
20882088
: ` """Typed server-scoped RPC methods."""`);
20892089
lines.push(` def __init__(self, client: "JsonRpcClient"):`);
20902090
lines.push(` self._client = client`);

0 commit comments

Comments
 (0)