Skip to content
Merged
Prev Previous commit
refactor: revert Optional usage, use plain nullable fields with @Json…
…Include(NON_NULL)

Remove all Optional<T>/OptionalInt/OptionalDouble usage from DTOs.
Revert to plain nullable boxed fields (Boolean, Integer, Double) per
Java DTO conventions and reference implementation parity.

Add @JsonInclude(JsonInclude.Include.NON_NULL) to classes that were
missing it: InputOptions, TelemetryConfig, SessionUiCapabilities,
UserInputRequest.

Add JsonIncludeNonNullTest verifying annotation presence and
serialization behavior (null fields omitted, set fields included).

Co-authored-by: edburns <75821+edburns@users.noreply.github.com>
  • Loading branch information
Copilot and edburns authored May 14, 2026
commit 8e0eeeb9832f2f113b8a4ec5c4accc05ca1f6e6a
14 changes: 7 additions & 7 deletions src/main/java/com/github/copilot/sdk/CliServerManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,16 @@ ProcessInfo startCliServer() throws IOException, InterruptedException {
}

// Default UseLoggedInUser to false when GitHubToken is provided
boolean useLoggedInUser = options.getUseLoggedInUser()
.orElse(options.getGitHubToken() == null || options.getGitHubToken().isEmpty());
boolean useLoggedInUser = options.getUseLoggedInUser() != null
? options.getUseLoggedInUser()
: (options.getGitHubToken() == null || options.getGitHubToken().isEmpty());
if (!useLoggedInUser) {
args.add("--no-auto-login");
}

if (options.getSessionIdleTimeoutSeconds().isPresent()
&& options.getSessionIdleTimeoutSeconds().getAsInt() > 0) {
if (options.getSessionIdleTimeoutSeconds() != null && options.getSessionIdleTimeoutSeconds() > 0) {
args.add("--session-idle-timeout");
args.add(String.valueOf(options.getSessionIdleTimeoutSeconds().getAsInt()));
args.add(String.valueOf(options.getSessionIdleTimeoutSeconds()));
}

if (options.isRemote()) {
Expand Down Expand Up @@ -159,9 +159,9 @@ ProcessInfo startCliServer() throws IOException, InterruptedException {
if (telemetry.getSourceName() != null) {
pb.environment().put("COPILOT_OTEL_SOURCE_NAME", telemetry.getSourceName());
}
if (telemetry.getCaptureContent().isPresent()) {
if (telemetry.getCaptureContent() != null) {
pb.environment().put("OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT",
telemetry.getCaptureContent().get() ? "true" : "false");
telemetry.getCaptureContent() ? "true" : "false");
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/github/copilot/sdk/CopilotClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ public CopilotClient(CopilotClientOptions options) {

// Validate auth options with external server
if (this.options.getCliUrl() != null && !this.options.getCliUrl().isEmpty()
&& (this.options.getGitHubToken() != null || this.options.getUseLoggedInUser().isPresent())) {
&& (this.options.getGitHubToken() != null || this.options.getUseLoggedInUser() != null)) {
throw new IllegalArgumentException(
"GitHubToken and UseLoggedInUser cannot be used with CliUrl (external server manages its own auth)");
}
Expand Down
15 changes: 7 additions & 8 deletions src/main/java/com/github/copilot/sdk/CopilotSession.java
Original file line number Diff line number Diff line change
Expand Up @@ -1118,9 +1118,9 @@ private void handleElicitationRequestAsync(ElicitationContext context, String re
*/
private void assertElicitation() {
SessionCapabilities caps = capabilities;
if (caps == null || caps.getUi() == null || !caps.getUi().getElicitation().orElse(false)) {
if (caps == null || caps.getUi() == null || !Boolean.TRUE.equals(caps.getUi().getElicitation())) {
throw new IllegalStateException("Elicitation is not supported by the host. "
+ "Check session.getCapabilities().getUi().getElicitation().orElse(false) before calling UI methods.");
+ "Check session.getCapabilities().getUi()?.getElicitation() before calling UI methods.");
Comment thread
edburns marked this conversation as resolved.
}
}

Expand Down Expand Up @@ -1201,10 +1201,10 @@ public CompletableFuture<String> input(String message, InputOptions options) {
field.put("title", options.getTitle());
if (options.getDescription() != null)
field.put("description", options.getDescription());
if (options.getMinLength().isPresent())
field.put("minLength", options.getMinLength().getAsInt());
if (options.getMaxLength().isPresent())
field.put("maxLength", options.getMaxLength().getAsInt());
if (options.getMinLength() != null)
field.put("minLength", options.getMinLength());
if (options.getMaxLength() != null)
field.put("maxLength", options.getMaxLength());
if (options.getFormat() != null)
field.put("format", options.getFormat());
if (options.getDefaultValue() != null)
Expand Down Expand Up @@ -1695,8 +1695,7 @@ public CompletableFuture<Void> setModel(String model, String reasoningEffort,
ModelCapabilitiesOverrideSupports supports = null;
if (modelCapabilities.getSupports() != null) {
var s = modelCapabilities.getSupports();
supports = new ModelCapabilitiesOverrideSupports(s.getVision().orElse(null),
s.getReasoningEffort().orElse(null));
supports = new ModelCapabilitiesOverrideSupports(s.getVision(), s.getReasoningEffort());
}
ModelCapabilitiesOverrideLimits limits = null;
if (modelCapabilities.getLimits() != null) {
Expand Down
40 changes: 13 additions & 27 deletions src/main/java/com/github/copilot/sdk/SessionRequestBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -111,18 +111,12 @@ static CreateSessionRequest buildCreateRequest(SessionConfig config, String sess
request.setAvailableTools(config.getAvailableTools());
request.setExcludedTools(config.getExcludedTools());
request.setProvider(config.getProvider());
config.getEnableSessionTelemetry().ifPresent(request::setEnableSessionTelemetry);
if (config.getOnUserInputRequest() != null) {
request.setRequestUserInput(true);
}
if (config.getHooks() != null && config.getHooks().hasHooks()) {
request.setHooks(true);
}
request.setEnableSessionTelemetry(config.getEnableSessionTelemetry());
request.setRequestUserInput(config.getOnUserInputRequest() != null ? true : null);
request.setHooks(config.getHooks() != null && config.getHooks().hasHooks() ? true : null);
request.setWorkingDirectory(config.getWorkingDirectory());
if (config.isStreaming()) {
request.setStreaming(true);
}
config.getIncludeSubAgentStreamingEvents().ifPresent(request::setIncludeSubAgentStreamingEvents);
request.setStreaming(config.isStreaming() ? true : null);
request.setIncludeSubAgentStreamingEvents(config.getIncludeSubAgentStreamingEvents());
request.setMcpServers(config.getMcpServers());
request.setCustomAgents(config.getCustomAgents());
request.setDefaultAgent(config.getDefaultAgent());
Expand All @@ -132,7 +126,7 @@ static CreateSessionRequest buildCreateRequest(SessionConfig config, String sess
request.setInstructionDirectories(config.getInstructionDirectories());
request.setDisabledSkills(config.getDisabledSkills());
request.setConfigDir(config.getConfigDir());
config.getEnableConfigDiscovery().ifPresent(request::setEnableConfigDiscovery);
request.setEnableConfigDiscovery(config.getEnableConfigDiscovery());
request.setModelCapabilities(config.getModelCapabilities());

if (config.getCommands() != null && !config.getCommands().isEmpty()) {
Expand Down Expand Up @@ -200,23 +194,15 @@ static ResumeSessionRequest buildResumeRequest(String sessionId, ResumeSessionCo
request.setAvailableTools(config.getAvailableTools());
request.setExcludedTools(config.getExcludedTools());
request.setProvider(config.getProvider());
config.getEnableSessionTelemetry().ifPresent(request::setEnableSessionTelemetry);
if (config.getOnUserInputRequest() != null) {
request.setRequestUserInput(true);
}
if (config.getHooks() != null && config.getHooks().hasHooks()) {
request.setHooks(true);
}
request.setEnableSessionTelemetry(config.getEnableSessionTelemetry());
request.setRequestUserInput(config.getOnUserInputRequest() != null ? true : null);
request.setHooks(config.getHooks() != null && config.getHooks().hasHooks() ? true : null);
request.setWorkingDirectory(config.getWorkingDirectory());
request.setConfigDir(config.getConfigDir());
config.getEnableConfigDiscovery().ifPresent(request::setEnableConfigDiscovery);
if (config.isDisableResume()) {
request.setDisableResume(true);
}
if (config.isStreaming()) {
request.setStreaming(true);
}
config.getIncludeSubAgentStreamingEvents().ifPresent(request::setIncludeSubAgentStreamingEvents);
request.setEnableConfigDiscovery(config.getEnableConfigDiscovery());
request.setDisableResume(config.isDisableResume() ? true : null);
request.setStreaming(config.isStreaming() ? true : null);
request.setIncludeSubAgentStreamingEvents(config.getIncludeSubAgentStreamingEvents());
request.setMcpServers(config.getMcpServers());
request.setCustomAgents(config.getCustomAgents());
request.setDefaultAgent(config.getDefaultAgent());
Expand Down
58 changes: 17 additions & 41 deletions src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@
import java.util.function.Supplier;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonIgnore;
import java.util.Optional;
import java.util.OptionalInt;

/**
* Configuration options for creating a
Expand Down Expand Up @@ -502,47 +499,34 @@ public CopilotClientOptions setTelemetry(TelemetryConfig telemetry) {
/**
* Gets the server-wide idle timeout for sessions in seconds.
*
* @return an {@link OptionalInt} containing the session idle timeout in
* seconds, or {@link java.util.OptionalInt#empty()} if not set. Use
* {@link #clearSessionIdleTimeoutSeconds()} to revert to the default.
* @return the session idle timeout in seconds, or {@code null} to disable
* (sessions live indefinitely)
* @since 1.3.0
*/
@JsonIgnore
public OptionalInt getSessionIdleTimeoutSeconds() {
return sessionIdleTimeoutSeconds == null ? OptionalInt.empty() : OptionalInt.of(sessionIdleTimeoutSeconds);
public Integer getSessionIdleTimeoutSeconds() {
return sessionIdleTimeoutSeconds;
}

/**
* Sets the server-wide idle timeout for sessions in seconds.
* <p>
* Sessions without activity for this duration are automatically cleaned up. Set
* to {@code 0} to disable (sessions live indefinitely). Use
* {@link #clearSessionIdleTimeoutSeconds()} to revert to the default.
* to {@code 0} or leave as {@code null} to disable (sessions live
* indefinitely).
* <p>
Comment thread
edburns marked this conversation as resolved.
* This option is only used when the SDK spawns the CLI process; it is ignored
* when connecting to an external server via {@link #setCliUrl(String)}.
*
* @param sessionIdleTimeoutSeconds
* the idle timeout in seconds
* the idle timeout in seconds, or {@code null} to disable
* @return this options instance for method chaining
* @since 1.3.0
*/
public CopilotClientOptions setSessionIdleTimeoutSeconds(int sessionIdleTimeoutSeconds) {
public CopilotClientOptions setSessionIdleTimeoutSeconds(Integer sessionIdleTimeoutSeconds) {
this.sessionIdleTimeoutSeconds = sessionIdleTimeoutSeconds;
return this;
}

/**
* Clears the sessionIdleTimeoutSeconds setting, reverting to the default
* behavior.
*
* @return this instance for method chaining
*/
public CopilotClientOptions clearSessionIdleTimeoutSeconds() {
this.sessionIdleTimeoutSeconds = null;
return this;
}

/**
* Gets the connection token for the headless CLI server (TCP only).
*
Expand Down Expand Up @@ -571,11 +555,11 @@ public CopilotClientOptions setTcpConnectionToken(String tcpConnectionToken) {
/**
* Returns whether to use the logged-in user for authentication.
*
* @return an {@link Optional} containing the boolean value, or empty if not set
* @return {@code true} to use logged-in user auth, {@code false} to use only
* explicit tokens, or {@code null} to use default behavior
*/
@JsonIgnore
public Optional<Boolean> getUseLoggedInUser() {
return Optional.ofNullable(useLoggedInUser);
public Boolean getUseLoggedInUser() {
return useLoggedInUser;
}

/**
Expand All @@ -585,23 +569,15 @@ public Optional<Boolean> getUseLoggedInUser() {
* auth. When false, only explicit tokens (gitHubToken or environment variables)
* are used. Default: true (but defaults to false when gitHubToken is provided).
* <p>
* Passing {@code null} is equivalent to passing {@link Boolean#FALSE}.
*
* @param useLoggedInUser
* {@code true} to use logged-in user auth, {@code false} otherwise
* {@code true} to use logged-in user auth, {@code false} or
* {@code null} otherwise
* @return this options instance for method chaining
*/
public CopilotClientOptions setUseLoggedInUser(boolean useLoggedInUser) {
this.useLoggedInUser = useLoggedInUser;
return this;
}

/**
* Clears the useLoggedInUser setting, reverting to the default behavior.
*
* @return this instance for method chaining
*/
public CopilotClientOptions clearUseLoggedInUser() {
this.useLoggedInUser = null;
public CopilotClientOptions setUseLoggedInUser(Boolean useLoggedInUser) {
this.useLoggedInUser = useLoggedInUser != null ? useLoggedInUser : Boolean.FALSE;
return this;
}

Expand Down
Loading
Loading