Skip to content

Commit 929b769

Browse files
patnikoCopilot
andcommitted
Add optional header field to ask_user across all SDKs
Companion to the runtime change (github/copilot-agent-runtime#10078), which adds a short, model-populated `header` to the `ask_user` tool / `user_input.requested` event / `userInput.request` RPC — mirroring Anthropic's `AskUserQuestion.header`. Hosts can render it as a dialog title instead of synthesizing one from the question. This surfaces `header` to SDK integrators in every language, on both the generated `UserInputRequestedData` event type and the hand-written `userInput.request` handler request type: - Node: generated/session-events.ts, types.ts (UserInputRequest), client.ts handler, README - Python: generated/session_events.py (from/to_dict), session.py (TypedDict + handler), README - Go: rpc/zsession_events.go, types.go (public + wire structs), client.go mapping, README - .NET: Generated/SessionEvents.cs, Types.cs, Client.cs RPC param - Rust: generated/session_events.rs, handler.rs trait, session.rs dispatch, example/tests, README - Java: generated UserInputRequestedEvent record, rpc/UserInputRequest (+getHeader/setHeader), RpcHandlerDispatcher param mapping The field is optional everywhere; existing callers are unaffected. BREAKING (Rust only): `UserInputHandler::handle` gains a `header: Option<String>` parameter. All in-repo implementors are updated. Notes for finalization (do not merge before these): - The generated-type edits are a PREVIEW. Codegen could not run here: node_modules `@github/copilot` is stale (1.0.40) and the schema carrying `header` isn't published yet. Once the runtime change ships, bump `@github/copilot`, run `npm run generate` (ts/csharp/python/go/rust) and `mvn generate-sources -Pcodegen` (java), and confirm the regenerated files match these edits. - E2E snapshots under test/snapshots/ask_user/ are unchanged; re-record once the CLI emits `header`. Verified: Node typecheck, Go build, .NET build, Rust build + test-compile, Python py_compile. Java not compiled (no JDK in env); edits follow existing patterns. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 53ffb24 commit 929b769

24 files changed

Lines changed: 95 additions & 7 deletions

File tree

dotnet/src/Client.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2138,12 +2138,13 @@ public void OnSessionLifecycle(string type, string sessionId, JsonElement? metad
21382138
client.DispatchLifecycleEvent(evt);
21392139
}
21402140

2141-
public async ValueTask<UserInputRequestResponse> OnUserInputRequest(string sessionId, string question, IList<string>? choices = null, bool? allowFreeform = null)
2141+
public async ValueTask<UserInputRequestResponse> OnUserInputRequest(string sessionId, string question, IList<string>? choices = null, bool? allowFreeform = null, string? header = null)
21422142
{
21432143
var session = client.GetSession(sessionId) ?? throw new ArgumentException($"Unknown session {sessionId}");
21442144
var request = new UserInputRequest
21452145
{
21462146
Question = question,
2147+
Header = header,
21472148
Choices = choices,
21482149
AllowFreeform = allowFreeform
21492150
};

dotnet/src/Generated/SessionEvents.cs

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

dotnet/src/Types.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,12 @@ public sealed class UserInputRequest
759759
[JsonPropertyName("question")]
760760
public string Question { get; set; } = string.Empty;
761761

762+
/// <summary>
763+
/// Optional short title summarizing the question, shown as the dialog header/title in some UIs.
764+
/// </summary>
765+
[JsonPropertyName("header")]
766+
public string? Header { get; set; }
767+
762768
/// <summary>
763769
/// Optional choices for multiple choice questions.
764770
/// </summary>

go/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,7 @@ session, err := client.CreateSession(context.Background(), &copilot.SessionConfi
649649
Model: "gpt-5",
650650
OnUserInputRequest: func(request copilot.UserInputRequest, invocation copilot.UserInputInvocation) (copilot.UserInputResponse, error) {
651651
// request.Question - The question to ask
652+
// request.Header - Optional short title summarizing the question (suitable as a dialog title)
652653
// request.Choices - Optional slice of choices for multiple choice
653654
// request.AllowFreeform - Whether freeform input is allowed (default: true)
654655

go/client.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1955,6 +1955,7 @@ func (c *Client) handleUserInputRequest(req userInputRequest) (*userInputRespons
19551955

19561956
response, err := session.handleUserInputRequest(UserInputRequest{
19571957
Question: req.Question,
1958+
Header: req.Header,
19581959
Choices: req.Choices,
19591960
AllowFreeform: req.AllowFreeform,
19601961
})

go/rpc/zsession_events.go

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

go/types.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ type PermissionInvocation struct {
312312
// UserInputRequest represents a request for user input from the agent
313313
type UserInputRequest struct {
314314
Question string
315+
Header *string
315316
Choices []string
316317
AllowFreeform *bool
317318
}
@@ -1980,6 +1981,7 @@ type sessionEventRequest struct {
19801981
type userInputRequest struct {
19811982
SessionID string `json:"sessionId"`
19821983
Question string `json:"question"`
1984+
Header *string `json:"header,omitempty"`
19831985
Choices []string `json:"choices,omitempty"`
19841986
AllowFreeform *bool `json:"allowFreeform,omitempty"`
19851987
}

java/src/generated/java/com/github/copilot/generated/UserInputRequestedEvent.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ public record UserInputRequestedEventData(
3939
@JsonProperty("requestId") String requestId,
4040
/** The question or prompt to present to the user */
4141
@JsonProperty("question") String question,
42+
/** Optional short title summarizing the question (a few words), suitable for display as the dialog header/title */
43+
@JsonProperty("header") String header,
4244
/** Predefined choices for the user to select from, if applicable */
4345
@JsonProperty("choices") List<String> choices,
4446
/** Whether the user can provide a free-form text response in addition to predefined choices */

java/src/main/java/com/github/copilot/RpcHandlerDispatcher.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ private void handleUserInputRequest(JsonRpcClient rpc, String requestId, JsonNod
251251
String sessionId = params.get("sessionId").asText();
252252
String question = params.get("question").asText();
253253
LOG.fine("Processing userInput for session " + sessionId + ", question: " + question);
254+
JsonNode headerNode = params.get("header");
254255
JsonNode choicesNode = params.get("choices");
255256
JsonNode allowFreeformNode = params.get("allowFreeform");
256257

@@ -263,6 +264,9 @@ private void handleUserInputRequest(JsonRpcClient rpc, String requestId, JsonNod
263264
}
264265

265266
var request = new UserInputRequest().setQuestion(question);
267+
if (headerNode != null && !headerNode.isNull()) {
268+
request.setHeader(headerNode.asText());
269+
}
266270
if (choicesNode != null && choicesNode.isArray()) {
267271
var choices = new ArrayList<String>();
268272
for (JsonNode choice : choicesNode) {

java/src/main/java/com/github/copilot/rpc/UserInputRequest.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ public class UserInputRequest {
2828
@JsonProperty("question")
2929
private String question;
3030

31+
@JsonProperty("header")
32+
private String header;
33+
3134
@JsonProperty("choices")
3235
private List<String> choices;
3336

@@ -55,6 +58,28 @@ public UserInputRequest setQuestion(String question) {
5558
return this;
5659
}
5760

61+
/**
62+
* Gets the optional short title summarizing the question, suitable for display
63+
* as the dialog header/title.
64+
*
65+
* @return the header text, or {@code null} if not specified
66+
*/
67+
public String getHeader() {
68+
return header;
69+
}
70+
71+
/**
72+
* Sets the optional short title summarizing the question.
73+
*
74+
* @param header
75+
* the header text
76+
* @return this instance for method chaining
77+
*/
78+
public UserInputRequest setHeader(String header) {
79+
this.header = header;
80+
return this;
81+
}
82+
5883
/**
5984
* Gets the optional choices for multiple choice questions.
6085
*

0 commit comments

Comments
 (0)