From f2654bcab172136f6ef454b46837202109451675 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 May 2026 23:57:21 +0000 Subject: [PATCH 1/3] Initial plan From 6e8b1004ff598b7ce27dd272cf5e4d7449f7b401 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 12 May 2026 00:33:46 +0000 Subject: [PATCH 2/3] refactor: use Optional return types instead of nullable boxed primitives in public API Change getter return types from nullable Boolean/Integer/Double to Optional/OptionalInt/OptionalDouble on all mutable config/builder classes. Setters now take primitive parameters. Add clearXxx() methods for resetting to null (server default). Add @JsonIgnore on Optional-returning getters to preserve Jackson serialization. Update all callers and tests. Co-authored-by: edburns <75821+edburns@users.noreply.github.com> --- refactor_optionals.py | 616 ++++++++++++++++++ .../github/copilot/sdk/CliServerManager.java | 14 +- .../com/github/copilot/sdk/CopilotClient.java | 2 +- .../github/copilot/sdk/CopilotSession.java | 13 +- .../copilot/sdk/SessionRequestBuilder.java | 40 +- .../sdk/json/CopilotClientOptions.java | 57 +- .../sdk/json/CreateSessionRequest.java | 73 ++- .../copilot/sdk/json/CustomAgentConfig.java | 19 +- .../sdk/json/InfiniteSessionConfig.java | 70 +- .../github/copilot/sdk/json/InputOptions.java | 34 +- .../copilot/sdk/json/McpHttpServerConfig.java | 2 +- .../copilot/sdk/json/McpServerConfig.java | 25 +- .../sdk/json/McpStdioServerConfig.java | 2 +- .../sdk/json/ModelCapabilitiesOverride.java | 90 ++- .../github/copilot/sdk/json/ModelLimits.java | 19 +- .../copilot/sdk/json/ProviderConfig.java | 37 +- .../copilot/sdk/json/ResumeSessionConfig.java | 54 +- .../sdk/json/ResumeSessionRequest.java | 82 ++- .../copilot/sdk/json/SessionConfig.java | 54 +- .../sdk/json/SessionUiCapabilities.java | 27 +- .../copilot/sdk/json/TelemetryConfig.java | 22 +- .../copilot/sdk/json/UserInputRequest.java | 20 +- .../github/copilot/sdk/ConfigCloneTest.java | 18 +- .../github/copilot/sdk/CopilotClientTest.java | 11 +- .../copilot/sdk/DataObjectCoverageTest.java | 17 +- .../github/copilot/sdk/ElicitationTest.java | 10 +- .../github/copilot/sdk/MetadataApiTest.java | 2 +- .../copilot/sdk/ProviderConfigTest.java | 8 +- .../copilot/sdk/TelemetryConfigTest.java | 8 +- 29 files changed, 1267 insertions(+), 179 deletions(-) create mode 100644 refactor_optionals.py diff --git a/refactor_optionals.py b/refactor_optionals.py new file mode 100644 index 0000000000..8de5f995f6 --- /dev/null +++ b/refactor_optionals.py @@ -0,0 +1,616 @@ +#!/usr/bin/env python3 +"""Refactor Java source files to use Optional return types instead of nullable boxed primitives.""" + +import re +import os + +BASE = "/home/runner/work/copilot-sdk-java/copilot-sdk-java/src/main/java/com/github/copilot/sdk" +JSON_PKG = os.path.join(BASE, "json") + + +def read_file(path): + with open(path, 'r') as f: + return f.read() + + +def write_file(path, content): + with open(path, 'w') as f: + f.write(content) + + +def add_import(content, import_stmt): + """Add an import statement if not already present.""" + if import_stmt in content: + return content + # Find the last import line and add after it + lines = content.split('\n') + last_import_idx = -1 + for i, line in enumerate(lines): + if line.startswith('import '): + last_import_idx = i + if last_import_idx >= 0: + lines.insert(last_import_idx + 1, import_stmt) + return '\n'.join(lines) + + +def refactor_fluent_boolean_getter(content, field_name): + """Refactor a Boolean getter to return Optional (fluent class).""" + # Match the getter method - various javadoc styles + getter_name = f'get{field_name[0].upper()}{field_name[1:]}' + + # Replace return type and body + # Pattern: public Boolean getXxx() {\n return xxx;\n } + pattern = rf'( public )Boolean ({getter_name}\(\)) \{{\n(\s+)return {field_name};\n(\s+)\}}' + replacement = rf'\1Optional \2 {{\n\3return Optional.ofNullable({field_name});\n\4}}' + content = re.sub(pattern, replacement, content) + return content + + +def refactor_fluent_boolean_setter(content, field_name, class_name): + """Refactor a Boolean setter to take primitive boolean (fluent class).""" + setter_name = f'set{field_name[0].upper()}{field_name[1:]}' + + # Pattern: public ClassName setXxx(Boolean xxx) {\n this.xxx = xxx;\n return this;\n } + pattern = rf'( public {class_name} {setter_name}\()Boolean ({field_name})\)( \{{)' + replacement = rf'\1boolean \2)\3' + content = re.sub(pattern, replacement, content) + return content + + +def refactor_void_boolean_getter(content, field_name): + """Refactor a Boolean getter to return Optional (void setter class).""" + getter_name = f'get{field_name[0].upper()}{field_name[1:]}' + + pattern = rf'( public )Boolean ({getter_name}\(\)) \{{\n(\s+)return {field_name};\n(\s+)\}}' + replacement = rf'\1Optional \2 {{\n\3return Optional.ofNullable({field_name});\n\4}}' + content = re.sub(pattern, replacement, content) + return content + + +def refactor_void_boolean_setter(content, field_name): + """Refactor a void Boolean setter to take primitive boolean.""" + setter_name = f'set{field_name[0].upper()}{field_name[1:]}' + + pattern = rf'( public void {setter_name}\()Boolean ({field_name})\)' + replacement = rf'\1boolean \2)' + content = re.sub(pattern, replacement, content) + return content + + +def add_fluent_clear_method(content, field_name, class_name, after_setter=True): + """Add a clearXxx() method after the setter for fluent classes.""" + setter_name = f'set{field_name[0].upper()}{field_name[1:]}' + clear_name = f'clear{field_name[0].upper()}{field_name[1:]}' + + # Check if clear method already exists + if f'{clear_name}()' in content: + return content + + clear_method = f''' + /** + * Clears the {field_name} setting, reverting to the default behavior. + * + * @return this instance for method chaining + */ + public {class_name} {clear_name}() {{ + this.{field_name} = null; + return this; + }} +''' + + # Find the end of the setter method and insert after it + # Look for the setter method's closing brace + setter_pattern = rf'( public {class_name} {setter_name}\([^)]+\) \{{[^}}]*\}})' + match = re.search(setter_pattern, content, re.DOTALL) + if match: + insert_pos = match.end() + content = content[:insert_pos] + '\n' + clear_method + content[insert_pos:] + + return content + + +def add_void_clear_method(content, field_name, after_setter=True): + """Add a void clearXxx() method after the setter for request classes.""" + setter_name = f'set{field_name[0].upper()}{field_name[1:]}' + clear_name = f'clear{field_name[0].upper()}{field_name[1:]}' + + if f'{clear_name}()' in content: + return content + + clear_method = f''' + /** + * Clears the {field_name} setting, reverting to the default behavior. + */ + public void {clear_name}() {{ + this.{field_name} = null; + }} +''' + + # Find the end of the setter method + setter_pattern = rf'( public void {setter_name}\([^)]+\) \{{[^}}]*\}})' + match = re.search(setter_pattern, content, re.DOTALL) + if match: + insert_pos = match.end() + content = content[:insert_pos] + '\n' + clear_method + content[insert_pos:] + + return content + + +def refactor_fluent_int_getter(content, field_name): + """Refactor an Integer getter to return OptionalInt.""" + getter_name = f'get{field_name[0].upper()}{field_name[1:]}' + + pattern = rf'( public )Integer ({getter_name}\(\)) \{{\n(\s+)return {field_name};\n(\s+)\}}' + replacement = rf'\1OptionalInt \2 {{\n\3return {field_name} == null ? OptionalInt.empty() : OptionalInt.of({field_name});\n\4}}' + content = re.sub(pattern, replacement, content) + return content + + +def refactor_fluent_int_setter(content, field_name, class_name): + """Refactor an Integer setter to take primitive int (fluent).""" + setter_name = f'set{field_name[0].upper()}{field_name[1:]}' + + pattern = rf'( public {class_name} {setter_name}\()Integer ({field_name})\)( \{{)' + replacement = rf'\1int \2)\3' + content = re.sub(pattern, replacement, content) + return content + + +def refactor_fluent_double_getter(content, field_name): + """Refactor a Double getter to return OptionalDouble.""" + getter_name = f'get{field_name[0].upper()}{field_name[1:]}' + + pattern = rf'( public )Double ({getter_name}\(\)) \{{\n(\s+)return {field_name};\n(\s+)\}}' + replacement = rf'\1OptionalDouble \2 {{\n\3return {field_name} == null ? OptionalDouble.empty() : OptionalDouble.of({field_name});\n\4}}' + content = re.sub(pattern, replacement, content) + return content + + +def refactor_fluent_double_setter(content, field_name, class_name): + """Refactor a Double setter to take primitive double (fluent).""" + setter_name = f'set{field_name[0].upper()}{field_name[1:]}' + + pattern = rf'( public {class_name} {setter_name}\()Double ({field_name})\)( \{{)' + replacement = rf'\1double \2)\3' + content = re.sub(pattern, replacement, content) + return content + + +# Also handle inner class patterns (indented with 8 spaces) +def refactor_inner_boolean_getter(content, field_name): + """Refactor a Boolean getter in an inner class.""" + getter_name = f'get{field_name[0].upper()}{field_name[1:]}' + + pattern = rf'( public )Boolean ({getter_name}\(\)) \{{\n(\s+)return {field_name};\n(\s+)\}}' + replacement = rf'\1Optional \2 {{\n\3return Optional.ofNullable({field_name});\n\4}}' + content = re.sub(pattern, replacement, content) + return content + + +def refactor_inner_boolean_setter(content, field_name, class_name): + """Refactor a Boolean setter in an inner class.""" + setter_name = f'set{field_name[0].upper()}{field_name[1:]}' + + pattern = rf'( public {class_name} {setter_name}\()Boolean ({field_name})\)( \{{)' + replacement = rf'\1boolean \2)\3' + content = re.sub(pattern, replacement, content) + return content + + +def refactor_inner_int_getter(content, field_name): + """Refactor an Integer getter in an inner class.""" + getter_name = f'get{field_name[0].upper()}{field_name[1:]}' + + pattern = rf'( public )Integer ({getter_name}\(\)) \{{\n(\s+)return {field_name};\n(\s+)\}}' + replacement = rf'\1OptionalInt \2 {{\n\3return {field_name} == null ? OptionalInt.empty() : OptionalInt.of({field_name});\n\4}}' + content = re.sub(pattern, replacement, content) + return content + + +def refactor_inner_int_setter(content, field_name, class_name): + """Refactor an Integer setter in an inner class.""" + setter_name = f'set{field_name[0].upper()}{field_name[1:]}' + + pattern = rf'( public {class_name} {setter_name}\()Integer ({field_name})\)( \{{)' + replacement = rf'\1int \2)\3' + content = re.sub(pattern, replacement, content) + return content + + +def add_inner_fluent_clear(content, field_name, class_name): + """Add clear method for inner class fields.""" + setter_name = f'set{field_name[0].upper()}{field_name[1:]}' + clear_name = f'clear{field_name[0].upper()}{field_name[1:]}' + + if f'{clear_name}()' in content: + return content + + clear_method = f''' + /** + * Clears the {field_name} setting, reverting to the default behavior. + * + * @return this instance for method chaining + */ + public {class_name} {clear_name}() {{ + this.{field_name} = null; + return this; + }} +''' + + # Find the end of the setter in inner class (8 spaces indent) + setter_pattern = rf'( public {class_name} {setter_name}\([^)]+\) \{{[^}}]*\}})' + match = re.search(setter_pattern, content, re.DOTALL) + if match: + insert_pos = match.end() + content = content[:insert_pos] + '\n' + clear_method + content[insert_pos:] + + return content + + +# ==================== MAIN REFACTORING ==================== + +def refactor_copilot_client_options(): + path = os.path.join(JSON_PKG, "CopilotClientOptions.java") + content = read_file(path) + + content = add_import(content, "import java.util.Optional;") + content = add_import(content, "import java.util.OptionalInt;") + + # sessionIdleTimeoutSeconds: Integer -> OptionalInt + content = refactor_fluent_int_getter(content, "sessionIdleTimeoutSeconds") + content = refactor_fluent_int_setter(content, "sessionIdleTimeoutSeconds", "CopilotClientOptions") + content = add_fluent_clear_method(content, "sessionIdleTimeoutSeconds", "CopilotClientOptions") + + # useLoggedInUser: Boolean -> Optional + content = refactor_fluent_boolean_getter(content, "useLoggedInUser") + # Special case - the setter has custom logic, need to replace it differently + # Old: public CopilotClientOptions setUseLoggedInUser(Boolean useLoggedInUser) { + # this.useLoggedInUser = useLoggedInUser != null ? useLoggedInUser : Boolean.FALSE; + # New: public CopilotClientOptions setUseLoggedInUser(boolean useLoggedInUser) { + # this.useLoggedInUser = useLoggedInUser; + old_setter = "public CopilotClientOptions setUseLoggedInUser(Boolean useLoggedInUser) {\n this.useLoggedInUser = useLoggedInUser != null ? useLoggedInUser : Boolean.FALSE;" + new_setter = "public CopilotClientOptions setUseLoggedInUser(boolean useLoggedInUser) {\n this.useLoggedInUser = useLoggedInUser;" + content = content.replace(old_setter, new_setter) + content = add_fluent_clear_method(content, "useLoggedInUser", "CopilotClientOptions") + + # Update javadoc for getSessionIdleTimeoutSeconds + content = content.replace( + "@return the session idle timeout in seconds, or {@code null} to disable\n * (sessions live indefinitely)", + "@return an {@link OptionalInt} containing the session idle timeout in seconds,\n * or empty to disable (sessions live indefinitely)" + ) + # Update setter javadoc + content = content.replace( + "Sessions without activity for this duration are automatically cleaned up. Set\n * to {@code 0} or leave as {@code null} to disable (sessions live\n * indefinitely).", + "Sessions without activity for this duration are automatically cleaned up. Set\n * to {@code 0} to disable (sessions live indefinitely). Use\n * {@link #clearSessionIdleTimeoutSeconds()} to revert to the default." + ) + content = content.replace( + "@param sessionIdleTimeoutSeconds\n * the idle timeout in seconds, or {@code null} to disable", + "@param sessionIdleTimeoutSeconds\n * the idle timeout in seconds" + ) + + # Update useLoggedInUser getter javadoc + content = content.replace( + "@return {@code true} to use logged-in user auth, {@code false} to use only\n * explicit tokens, or {@code null} to use default behavior", + "@return an {@link Optional} containing the boolean value, or empty if not set" + ) + # Update useLoggedInUser setter javadoc + content = content.replace( + "Passing {@code null} is equivalent to passing {@link Boolean#FALSE}.\n *\n * @param useLoggedInUser\n * {@code true} to use logged-in user auth, {@code false} or\n * {@code null} otherwise", + "@param useLoggedInUser\n * {@code true} to use logged-in user auth, {@code false} otherwise" + ) + + write_file(path, content) + print(f" Refactored: {path}") + + +def refactor_session_config(): + path = os.path.join(JSON_PKG, "SessionConfig.java") + content = read_file(path) + + content = add_import(content, "import java.util.Optional;") + + for field in ["enableSessionTelemetry", "enableConfigDiscovery", "includeSubAgentStreamingEvents"]: + content = refactor_fluent_boolean_getter(content, field) + content = refactor_fluent_boolean_setter(content, field, "SessionConfig") + content = add_fluent_clear_method(content, field, "SessionConfig") + + write_file(path, content) + print(f" Refactored: {path}") + + +def refactor_resume_session_config(): + path = os.path.join(JSON_PKG, "ResumeSessionConfig.java") + content = read_file(path) + + content = add_import(content, "import java.util.Optional;") + + for field in ["enableSessionTelemetry", "enableConfigDiscovery", "includeSubAgentStreamingEvents"]: + content = refactor_fluent_boolean_getter(content, field) + content = refactor_fluent_boolean_setter(content, field, "ResumeSessionConfig") + content = add_fluent_clear_method(content, field, "ResumeSessionConfig") + + write_file(path, content) + print(f" Refactored: {path}") + + +def refactor_infinite_session_config(): + path = os.path.join(JSON_PKG, "InfiniteSessionConfig.java") + content = read_file(path) + + content = add_import(content, "import java.util.Optional;") + content = add_import(content, "import java.util.OptionalDouble;") + + # enabled: Boolean -> Optional + content = refactor_fluent_boolean_getter(content, "enabled") + content = refactor_fluent_boolean_setter(content, "enabled", "InfiniteSessionConfig") + content = add_fluent_clear_method(content, "enabled", "InfiniteSessionConfig") + + # backgroundCompactionThreshold: Double -> OptionalDouble + content = refactor_fluent_double_getter(content, "backgroundCompactionThreshold") + content = refactor_fluent_double_setter(content, "backgroundCompactionThreshold", "InfiniteSessionConfig") + content = add_fluent_clear_method(content, "backgroundCompactionThreshold", "InfiniteSessionConfig") + + # bufferExhaustionThreshold: Double -> OptionalDouble + content = refactor_fluent_double_getter(content, "bufferExhaustionThreshold") + content = refactor_fluent_double_setter(content, "bufferExhaustionThreshold", "InfiniteSessionConfig") + content = add_fluent_clear_method(content, "bufferExhaustionThreshold", "InfiniteSessionConfig") + + # Update javadoc + content = content.replace( + "@return {@code true} if enabled, {@code null} to use default (true)", + "@return an {@link Optional} containing the boolean value, or empty to use default (true)" + ) + content = content.replace( + "@return the threshold (0.0-1.0), or {@code null} to use default\n */\n public OptionalDouble getBackgroundCompactionThreshold()", + "@return an {@link OptionalDouble} containing the threshold (0.0-1.0), or empty to use default\n */\n public OptionalDouble getBackgroundCompactionThreshold()" + ) + content = content.replace( + "@return the threshold (0.0-1.0), or {@code null} to use default\n */\n public OptionalDouble getBufferExhaustionThreshold()", + "@return an {@link OptionalDouble} containing the threshold (0.0-1.0), or empty to use default\n */\n public OptionalDouble getBufferExhaustionThreshold()" + ) + + write_file(path, content) + print(f" Refactored: {path}") + + +def refactor_input_options(): + path = os.path.join(JSON_PKG, "InputOptions.java") + content = read_file(path) + + content = add_import(content, "import java.util.OptionalInt;") + + for field in ["minLength", "maxLength"]: + content = refactor_fluent_int_getter(content, field) + content = refactor_fluent_int_setter(content, field, "InputOptions") + content = add_fluent_clear_method(content, field, "InputOptions") + + write_file(path, content) + print(f" Refactored: {path}") + + +def refactor_model_capabilities_override(): + path = os.path.join(JSON_PKG, "ModelCapabilitiesOverride.java") + content = read_file(path) + + content = add_import(content, "import java.util.Optional;") + content = add_import(content, "import java.util.OptionalInt;") + + # Inner class Supports: vision, reasoningEffort (Boolean -> Optional) + for field in ["vision", "reasoningEffort"]: + content = refactor_inner_boolean_getter(content, field) + content = refactor_inner_boolean_setter(content, field, "Supports") + content = add_inner_fluent_clear(content, field, "Supports") + + # Inner class Limits: maxPromptTokens, maxOutputTokens, maxContextWindowTokens (Integer -> OptionalInt) + for field in ["maxPromptTokens", "maxOutputTokens", "maxContextWindowTokens"]: + content = refactor_inner_int_getter(content, field) + content = refactor_inner_int_setter(content, field, "Limits") + content = add_inner_fluent_clear(content, field, "Limits") + + write_file(path, content) + print(f" Refactored: {path}") + + +def refactor_provider_config(): + path = os.path.join(JSON_PKG, "ProviderConfig.java") + content = read_file(path) + + content = add_import(content, "import java.util.OptionalInt;") + + for field in ["maxPromptTokens", "maxOutputTokens"]: + content = refactor_fluent_int_getter(content, field) + content = refactor_fluent_int_setter(content, field, "ProviderConfig") + content = add_fluent_clear_method(content, field, "ProviderConfig") + + write_file(path, content) + print(f" Refactored: {path}") + + +def refactor_telemetry_config(): + path = os.path.join(JSON_PKG, "TelemetryConfig.java") + content = read_file(path) + + content = add_import(content, "import java.util.Optional;") + + content = refactor_fluent_boolean_getter(content, "captureContent") + content = refactor_fluent_boolean_setter(content, "captureContent", "TelemetryConfig") + content = add_fluent_clear_method(content, "captureContent", "TelemetryConfig") + + write_file(path, content) + print(f" Refactored: {path}") + + +def refactor_session_ui_capabilities(): + path = os.path.join(JSON_PKG, "SessionUiCapabilities.java") + content = read_file(path) + + content = add_import(content, "import java.util.Optional;") + + content = refactor_fluent_boolean_getter(content, "elicitation") + content = refactor_fluent_boolean_setter(content, "elicitation", "SessionUiCapabilities") + content = add_fluent_clear_method(content, "elicitation", "SessionUiCapabilities") + + write_file(path, content) + print(f" Refactored: {path}") + + +def refactor_custom_agent_config(): + path = os.path.join(JSON_PKG, "CustomAgentConfig.java") + content = read_file(path) + + content = add_import(content, "import java.util.Optional;") + + content = refactor_fluent_boolean_getter(content, "infer") + content = refactor_fluent_boolean_setter(content, "infer", "CustomAgentConfig") + content = add_fluent_clear_method(content, "infer", "CustomAgentConfig") + + write_file(path, content) + print(f" Refactored: {path}") + + +def refactor_user_input_request(): + path = os.path.join(JSON_PKG, "UserInputRequest.java") + content = read_file(path) + + content = add_import(content, "import java.util.Optional;") + + content = refactor_fluent_boolean_getter(content, "allowFreeform") + content = refactor_fluent_boolean_setter(content, "allowFreeform", "UserInputRequest") + content = add_fluent_clear_method(content, "allowFreeform", "UserInputRequest") + + write_file(path, content) + print(f" Refactored: {path}") + + +def refactor_create_session_request(): + path = os.path.join(JSON_PKG, "CreateSessionRequest.java") + content = read_file(path) + + content = add_import(content, "import java.util.Optional;") + + fields = ["enableSessionTelemetry", "requestPermission", "requestUserInput", + "hooks", "streaming", "enableConfigDiscovery", + "includeSubAgentStreamingEvents", "requestElicitation"] + + for field in fields: + content = refactor_void_boolean_getter(content, field) + content = refactor_void_boolean_setter(content, field) + content = add_void_clear_method(content, field) + + write_file(path, content) + print(f" Refactored: {path}") + + +def refactor_resume_session_request(): + path = os.path.join(JSON_PKG, "ResumeSessionRequest.java") + content = read_file(path) + + content = add_import(content, "import java.util.Optional;") + + fields = ["enableSessionTelemetry", "requestPermission", "requestUserInput", + "hooks", "enableConfigDiscovery", "disableResume", "streaming", + "includeSubAgentStreamingEvents", "requestElicitation"] + + for field in fields: + content = refactor_void_boolean_getter(content, field) + content = refactor_void_boolean_setter(content, field) + content = add_void_clear_method(content, field) + + write_file(path, content) + print(f" Refactored: {path}") + + +def refactor_mcp_server_config(): + path = os.path.join(JSON_PKG, "McpServerConfig.java") + content = read_file(path) + + content = add_import(content, "import java.util.OptionalInt;") + + content = refactor_fluent_int_getter(content, "timeout") + content = refactor_fluent_int_setter(content, "timeout", "McpServerConfig") + content = add_fluent_clear_method(content, "timeout", "McpServerConfig") + + # Update javadoc + content = content.replace( + "@return the timeout in milliseconds, or {@code null} for the default", + "@return an {@link OptionalInt} containing the timeout in milliseconds, or empty for the default" + ) + content = content.replace( + "@param timeout\n * the timeout in milliseconds, or {@code null} for the default", + "@param timeout\n * the timeout in milliseconds" + ) + + write_file(path, content) + print(f" Refactored: {path}") + + +def refactor_model_limits(): + path = os.path.join(JSON_PKG, "ModelLimits.java") + content = read_file(path) + + content = add_import(content, "import java.util.OptionalInt;") + + content = refactor_fluent_int_getter(content, "maxPromptTokens") + content = refactor_fluent_int_setter(content, "maxPromptTokens", "ModelLimits") + content = add_fluent_clear_method(content, "maxPromptTokens", "ModelLimits") + + write_file(path, content) + print(f" Refactored: {path}") + + +def refactor_session_request_builder(): + """Update SessionRequestBuilder to handle Optional returns from config.""" + path = os.path.join(BASE, "SessionRequestBuilder.java") + content = read_file(path) + + # The config getters now return Optional, so we need to use ifPresent + # Old: request.setEnableSessionTelemetry(config.getEnableSessionTelemetry()); + # New: config.getEnableSessionTelemetry().ifPresent(request::setEnableSessionTelemetry); + + # For create request: + content = content.replace( + "request.setEnableSessionTelemetry(config.getEnableSessionTelemetry());\n request.setRequestUserInput(config.getOnUserInputRequest() != null ? true : null);\n request.setHooks(config.getHooks() != null && config.getHooks().hasHooks() ? true : null);", + "config.getEnableSessionTelemetry().ifPresent(request::setEnableSessionTelemetry);\n if (config.getOnUserInputRequest() != null) {\n request.setRequestUserInput(true);\n }\n if (config.getHooks() != null && config.getHooks().hasHooks()) {\n request.setHooks(true);\n }" + ) + + content = content.replace( + "request.setStreaming(config.isStreaming() ? true : null);\n request.setIncludeSubAgentStreamingEvents(config.getIncludeSubAgentStreamingEvents());", + "if (config.isStreaming()) {\n request.setStreaming(true);\n }\n config.getIncludeSubAgentStreamingEvents().ifPresent(request::setIncludeSubAgentStreamingEvents);" + ) + + content = content.replace( + "request.setEnableConfigDiscovery(config.getEnableConfigDiscovery());\n request.setModelCapabilities(config.getModelCapabilities());", + "config.getEnableConfigDiscovery().ifPresent(request::setEnableConfigDiscovery);\n request.setModelCapabilities(config.getModelCapabilities());" + ) + + # For resume request: + content = content.replace( + "request.setEnableSessionTelemetry(config.getEnableSessionTelemetry());\n request.setRequestUserInput(config.getOnUserInputRequest() != null ? true : null);\n request.setHooks(config.getHooks() != null && config.getHooks().hasHooks() ? true : null);\n request.setWorkingDirectory(config.getWorkingDirectory());\n request.setConfigDir(config.getConfigDir());\n request.setEnableConfigDiscovery(config.getEnableConfigDiscovery());\n request.setDisableResume(config.isDisableResume() ? true : null);\n request.setStreaming(config.isStreaming() ? true : null);\n request.setIncludeSubAgentStreamingEvents(config.getIncludeSubAgentStreamingEvents());", + "config.getEnableSessionTelemetry().ifPresent(request::setEnableSessionTelemetry);\n if (config.getOnUserInputRequest() != null) {\n request.setRequestUserInput(true);\n }\n if (config.getHooks() != null && config.getHooks().hasHooks()) {\n request.setHooks(true);\n }\n request.setWorkingDirectory(config.getWorkingDirectory());\n request.setConfigDir(config.getConfigDir());\n config.getEnableConfigDiscovery().ifPresent(request::setEnableConfigDiscovery);\n if (config.isDisableResume()) {\n request.setDisableResume(true);\n }\n if (config.isStreaming()) {\n request.setStreaming(true);\n }\n config.getIncludeSubAgentStreamingEvents().ifPresent(request::setIncludeSubAgentStreamingEvents);" + ) + + write_file(path, content) + print(f" Refactored: {path}") + + +if __name__ == "__main__": + print("Refactoring to Optional return types...") + + refactor_copilot_client_options() + refactor_session_config() + refactor_resume_session_config() + refactor_infinite_session_config() + refactor_input_options() + refactor_model_capabilities_override() + refactor_provider_config() + refactor_telemetry_config() + refactor_session_ui_capabilities() + refactor_custom_agent_config() + refactor_user_input_request() + refactor_create_session_request() + refactor_resume_session_request() + refactor_mcp_server_config() + refactor_model_limits() + refactor_session_request_builder() + + print("\nDone! Run 'mvn spotless:apply' then 'mvn verify' to validate.") diff --git a/src/main/java/com/github/copilot/sdk/CliServerManager.java b/src/main/java/com/github/copilot/sdk/CliServerManager.java index 3087966d39..bd4effe5a8 100644 --- a/src/main/java/com/github/copilot/sdk/CliServerManager.java +++ b/src/main/java/com/github/copilot/sdk/CliServerManager.java @@ -90,16 +90,16 @@ ProcessInfo startCliServer() throws IOException, InterruptedException { } // Default UseLoggedInUser to false when GitHubToken is provided - boolean useLoggedInUser = options.getUseLoggedInUser() != null - ? options.getUseLoggedInUser() - : (options.getGitHubToken() == null || options.getGitHubToken().isEmpty()); + boolean useLoggedInUser = options.getUseLoggedInUser() + .orElse(options.getGitHubToken() == null || options.getGitHubToken().isEmpty()); if (!useLoggedInUser) { args.add("--no-auto-login"); } - if (options.getSessionIdleTimeoutSeconds() != null && options.getSessionIdleTimeoutSeconds() > 0) { + if (options.getSessionIdleTimeoutSeconds().isPresent() + && options.getSessionIdleTimeoutSeconds().getAsInt() > 0) { args.add("--session-idle-timeout"); - args.add(String.valueOf(options.getSessionIdleTimeoutSeconds())); + args.add(String.valueOf(options.getSessionIdleTimeoutSeconds().getAsInt())); } if (options.isRemote()) { @@ -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() != null) { + if (telemetry.getCaptureContent().isPresent()) { pb.environment().put("OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT", - telemetry.getCaptureContent() ? "true" : "false"); + telemetry.getCaptureContent().get() ? "true" : "false"); } } diff --git a/src/main/java/com/github/copilot/sdk/CopilotClient.java b/src/main/java/com/github/copilot/sdk/CopilotClient.java index 5b988d9d2b..4d0770319a 100644 --- a/src/main/java/com/github/copilot/sdk/CopilotClient.java +++ b/src/main/java/com/github/copilot/sdk/CopilotClient.java @@ -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() != null)) { + && (this.options.getGitHubToken() != null || this.options.getUseLoggedInUser().isPresent())) { throw new IllegalArgumentException( "GitHubToken and UseLoggedInUser cannot be used with CliUrl (external server manages its own auth)"); } diff --git a/src/main/java/com/github/copilot/sdk/CopilotSession.java b/src/main/java/com/github/copilot/sdk/CopilotSession.java index ad5561c09e..a35ab75520 100644 --- a/src/main/java/com/github/copilot/sdk/CopilotSession.java +++ b/src/main/java/com/github/copilot/sdk/CopilotSession.java @@ -1118,7 +1118,7 @@ private void handleElicitationRequestAsync(ElicitationContext context, String re */ private void assertElicitation() { SessionCapabilities caps = capabilities; - if (caps == null || caps.getUi() == null || !Boolean.TRUE.equals(caps.getUi().getElicitation())) { + if (caps == null || caps.getUi() == null || !caps.getUi().getElicitation().orElse(false)) { throw new IllegalStateException("Elicitation is not supported by the host. " + "Check session.getCapabilities().getUi()?.getElicitation() before calling UI methods."); } @@ -1201,10 +1201,10 @@ public CompletableFuture input(String message, InputOptions options) { field.put("title", options.getTitle()); if (options.getDescription() != null) field.put("description", options.getDescription()); - if (options.getMinLength() != null) - field.put("minLength", options.getMinLength()); - if (options.getMaxLength() != null) - field.put("maxLength", options.getMaxLength()); + if (options.getMinLength().isPresent()) + field.put("minLength", options.getMinLength().getAsInt()); + if (options.getMaxLength().isPresent()) + field.put("maxLength", options.getMaxLength().getAsInt()); if (options.getFormat() != null) field.put("format", options.getFormat()); if (options.getDefaultValue() != null) @@ -1695,7 +1695,8 @@ public CompletableFuture setModel(String model, String reasoningEffort, ModelCapabilitiesOverrideSupports supports = null; if (modelCapabilities.getSupports() != null) { var s = modelCapabilities.getSupports(); - supports = new ModelCapabilitiesOverrideSupports(s.getVision(), s.getReasoningEffort()); + supports = new ModelCapabilitiesOverrideSupports(s.getVision().orElse(null), + s.getReasoningEffort().orElse(null)); } ModelCapabilitiesOverrideLimits limits = null; if (modelCapabilities.getLimits() != null) { diff --git a/src/main/java/com/github/copilot/sdk/SessionRequestBuilder.java b/src/main/java/com/github/copilot/sdk/SessionRequestBuilder.java index d9752db7ee..1bd3a50cb7 100644 --- a/src/main/java/com/github/copilot/sdk/SessionRequestBuilder.java +++ b/src/main/java/com/github/copilot/sdk/SessionRequestBuilder.java @@ -111,12 +111,18 @@ static CreateSessionRequest buildCreateRequest(SessionConfig config, String sess request.setAvailableTools(config.getAvailableTools()); request.setExcludedTools(config.getExcludedTools()); request.setProvider(config.getProvider()); - request.setEnableSessionTelemetry(config.getEnableSessionTelemetry()); - request.setRequestUserInput(config.getOnUserInputRequest() != null ? true : null); - request.setHooks(config.getHooks() != null && config.getHooks().hasHooks() ? true : null); + config.getEnableSessionTelemetry().ifPresent(request::setEnableSessionTelemetry); + if (config.getOnUserInputRequest() != null) { + request.setRequestUserInput(true); + } + if (config.getHooks() != null && config.getHooks().hasHooks()) { + request.setHooks(true); + } request.setWorkingDirectory(config.getWorkingDirectory()); - request.setStreaming(config.isStreaming() ? true : null); - request.setIncludeSubAgentStreamingEvents(config.getIncludeSubAgentStreamingEvents()); + if (config.isStreaming()) { + request.setStreaming(true); + } + config.getIncludeSubAgentStreamingEvents().ifPresent(request::setIncludeSubAgentStreamingEvents); request.setMcpServers(config.getMcpServers()); request.setCustomAgents(config.getCustomAgents()); request.setDefaultAgent(config.getDefaultAgent()); @@ -126,7 +132,7 @@ static CreateSessionRequest buildCreateRequest(SessionConfig config, String sess request.setInstructionDirectories(config.getInstructionDirectories()); request.setDisabledSkills(config.getDisabledSkills()); request.setConfigDir(config.getConfigDir()); - request.setEnableConfigDiscovery(config.getEnableConfigDiscovery()); + config.getEnableConfigDiscovery().ifPresent(request::setEnableConfigDiscovery); request.setModelCapabilities(config.getModelCapabilities()); if (config.getCommands() != null && !config.getCommands().isEmpty()) { @@ -194,15 +200,23 @@ static ResumeSessionRequest buildResumeRequest(String sessionId, ResumeSessionCo request.setAvailableTools(config.getAvailableTools()); request.setExcludedTools(config.getExcludedTools()); request.setProvider(config.getProvider()); - request.setEnableSessionTelemetry(config.getEnableSessionTelemetry()); - request.setRequestUserInput(config.getOnUserInputRequest() != null ? true : null); - request.setHooks(config.getHooks() != null && config.getHooks().hasHooks() ? true : null); + config.getEnableSessionTelemetry().ifPresent(request::setEnableSessionTelemetry); + if (config.getOnUserInputRequest() != null) { + request.setRequestUserInput(true); + } + if (config.getHooks() != null && config.getHooks().hasHooks()) { + request.setHooks(true); + } request.setWorkingDirectory(config.getWorkingDirectory()); request.setConfigDir(config.getConfigDir()); - request.setEnableConfigDiscovery(config.getEnableConfigDiscovery()); - request.setDisableResume(config.isDisableResume() ? true : null); - request.setStreaming(config.isStreaming() ? true : null); - request.setIncludeSubAgentStreamingEvents(config.getIncludeSubAgentStreamingEvents()); + config.getEnableConfigDiscovery().ifPresent(request::setEnableConfigDiscovery); + if (config.isDisableResume()) { + request.setDisableResume(true); + } + if (config.isStreaming()) { + request.setStreaming(true); + } + config.getIncludeSubAgentStreamingEvents().ifPresent(request::setIncludeSubAgentStreamingEvents); request.setMcpServers(config.getMcpServers()); request.setCustomAgents(config.getCustomAgents()); request.setDefaultAgent(config.getDefaultAgent()); diff --git a/src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java b/src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java index 5517df631e..a61c32fadf 100644 --- a/src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java +++ b/src/main/java/com/github/copilot/sdk/json/CopilotClientOptions.java @@ -14,6 +14,9 @@ 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 @@ -499,34 +502,46 @@ public CopilotClientOptions setTelemetry(TelemetryConfig telemetry) { /** * Gets the server-wide idle timeout for sessions in seconds. * - * @return the session idle timeout in seconds, or {@code null} to disable - * (sessions live indefinitely) + * @return an {@link OptionalInt} containing the session idle timeout in + * seconds, or empty to disable (sessions live indefinitely) * @since 1.3.0 */ - public Integer getSessionIdleTimeoutSeconds() { - return sessionIdleTimeoutSeconds; + @JsonIgnore + public OptionalInt getSessionIdleTimeoutSeconds() { + return sessionIdleTimeoutSeconds == null ? OptionalInt.empty() : OptionalInt.of(sessionIdleTimeoutSeconds); } /** * Sets the server-wide idle timeout for sessions in seconds. *

* Sessions without activity for this duration are automatically cleaned up. Set - * to {@code 0} or leave as {@code null} to disable (sessions live - * indefinitely). + * to {@code 0} to disable (sessions live indefinitely). Use + * {@link #clearSessionIdleTimeoutSeconds()} to revert to the default. *

* 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, or {@code null} to disable + * the idle timeout in seconds * @return this options instance for method chaining * @since 1.3.0 */ - public CopilotClientOptions setSessionIdleTimeoutSeconds(Integer sessionIdleTimeoutSeconds) { + public CopilotClientOptions setSessionIdleTimeoutSeconds(int 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). * @@ -555,11 +570,11 @@ public CopilotClientOptions setTcpConnectionToken(String tcpConnectionToken) { /** * Returns whether to use the logged-in user for authentication. * - * @return {@code true} to use logged-in user auth, {@code false} to use only - * explicit tokens, or {@code null} to use default behavior + * @return an {@link Optional} containing the boolean value, or empty if not set */ - public Boolean getUseLoggedInUser() { - return useLoggedInUser; + @JsonIgnore + public Optional getUseLoggedInUser() { + return Optional.ofNullable(useLoggedInUser); } /** @@ -569,15 +584,23 @@ public Boolean getUseLoggedInUser() { * auth. When false, only explicit tokens (gitHubToken or environment variables) * are used. Default: true (but defaults to false when gitHubToken is provided). *

- * Passing {@code null} is equivalent to passing {@link Boolean#FALSE}. * * @param useLoggedInUser - * {@code true} to use logged-in user auth, {@code false} or - * {@code null} otherwise + * {@code true} to use logged-in user auth, {@code false} otherwise * @return this options instance for method chaining */ - public CopilotClientOptions setUseLoggedInUser(Boolean useLoggedInUser) { - this.useLoggedInUser = useLoggedInUser != null ? useLoggedInUser : Boolean.FALSE; + 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; return this; } diff --git a/src/main/java/com/github/copilot/sdk/json/CreateSessionRequest.java b/src/main/java/com/github/copilot/sdk/json/CreateSessionRequest.java index 12bab4154c..0160724bef 100644 --- a/src/main/java/com/github/copilot/sdk/json/CreateSessionRequest.java +++ b/src/main/java/com/github/copilot/sdk/json/CreateSessionRequest.java @@ -224,40 +224,68 @@ public Boolean getEnableSessionTelemetry() { /** * Sets enable session telemetry flag. @param enableSessionTelemetry the flag */ - public void setEnableSessionTelemetry(Boolean enableSessionTelemetry) { + public void setEnableSessionTelemetry(boolean enableSessionTelemetry) { this.enableSessionTelemetry = enableSessionTelemetry; } + /** + * Clears the enableSessionTelemetry setting, reverting to the default behavior. + */ + public void clearEnableSessionTelemetry() { + this.enableSessionTelemetry = null; + } + /** Gets request permission flag. @return the flag */ public Boolean getRequestPermission() { return requestPermission; } /** Sets request permission flag. @param requestPermission the flag */ - public void setRequestPermission(Boolean requestPermission) { + public void setRequestPermission(boolean requestPermission) { this.requestPermission = requestPermission; } + /** + * Clears the requestPermission setting, reverting to the default behavior. + */ + public void clearRequestPermission() { + this.requestPermission = null; + } + /** Gets request user input flag. @return the flag */ public Boolean getRequestUserInput() { return requestUserInput; } /** Sets request user input flag. @param requestUserInput the flag */ - public void setRequestUserInput(Boolean requestUserInput) { + public void setRequestUserInput(boolean requestUserInput) { this.requestUserInput = requestUserInput; } + /** + * Clears the requestUserInput setting, reverting to the default behavior. + */ + public void clearRequestUserInput() { + this.requestUserInput = null; + } + /** Gets hooks flag. @return the flag */ public Boolean getHooks() { return hooks; } /** Sets hooks flag. @param hooks the flag */ - public void setHooks(Boolean hooks) { + public void setHooks(boolean hooks) { this.hooks = hooks; } + /** + * Clears the hooks setting, reverting to the default behavior. + */ + public void clearHooks() { + this.hooks = null; + } + /** Gets working directory. @return the working directory */ public String getWorkingDirectory() { return workingDirectory; @@ -274,10 +302,17 @@ public Boolean getStreaming() { } /** Sets streaming flag. @param streaming the flag */ - public void setStreaming(Boolean streaming) { + public void setStreaming(boolean streaming) { this.streaming = streaming; } + /** + * Clears the streaming setting, reverting to the default behavior. + */ + public void clearStreaming() { + this.streaming = null; + } + /** Gets MCP servers. @return the servers map */ public Map getMcpServers() { return mcpServers == null ? null : Collections.unmodifiableMap(mcpServers); @@ -388,10 +423,17 @@ public Boolean getEnableConfigDiscovery() { } /** Sets enable config discovery flag. @param enableConfigDiscovery the flag */ - public void setEnableConfigDiscovery(Boolean enableConfigDiscovery) { + public void setEnableConfigDiscovery(boolean enableConfigDiscovery) { this.enableConfigDiscovery = enableConfigDiscovery; } + /** + * Clears the enableConfigDiscovery setting, reverting to the default behavior. + */ + public void clearEnableConfigDiscovery() { + this.enableConfigDiscovery = null; + } + /** Gets include sub-agent streaming events flag. @return the flag */ public Boolean getIncludeSubAgentStreamingEvents() { return includeSubAgentStreamingEvents; @@ -401,10 +443,18 @@ public Boolean getIncludeSubAgentStreamingEvents() { * Sets include sub-agent streaming events flag. @param * includeSubAgentStreamingEvents the flag */ - public void setIncludeSubAgentStreamingEvents(Boolean includeSubAgentStreamingEvents) { + public void setIncludeSubAgentStreamingEvents(boolean includeSubAgentStreamingEvents) { this.includeSubAgentStreamingEvents = includeSubAgentStreamingEvents; } + /** + * Clears the includeSubAgentStreamingEvents setting, reverting to the default + * behavior. + */ + public void clearIncludeSubAgentStreamingEvents() { + this.includeSubAgentStreamingEvents = null; + } + /** Gets the commands wire definitions. @return the commands */ public List getCommands() { return commands == null ? null : Collections.unmodifiableList(commands); @@ -421,10 +471,17 @@ public Boolean getRequestElicitation() { } /** Sets the requestElicitation flag. @param requestElicitation the flag */ - public void setRequestElicitation(Boolean requestElicitation) { + public void setRequestElicitation(boolean requestElicitation) { this.requestElicitation = requestElicitation; } + /** + * Clears the requestElicitation setting, reverting to the default behavior. + */ + public void clearRequestElicitation() { + this.requestElicitation = null; + } + /** Gets the requestExitPlanMode flag. @return the flag */ public Boolean getRequestExitPlanMode() { return requestExitPlanMode; diff --git a/src/main/java/com/github/copilot/sdk/json/CustomAgentConfig.java b/src/main/java/com/github/copilot/sdk/json/CustomAgentConfig.java index 1421db603f..c40d1b3c50 100644 --- a/src/main/java/com/github/copilot/sdk/json/CustomAgentConfig.java +++ b/src/main/java/com/github/copilot/sdk/json/CustomAgentConfig.java @@ -10,6 +10,8 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonIgnore; +import java.util.Optional; /** * Configuration for a custom agent in a Copilot session. @@ -199,8 +201,9 @@ public CustomAgentConfig setMcpServers(Map mcpServers) * * @return the infer flag, or {@code null} if not set */ - public Boolean getInfer() { - return infer; + @JsonIgnore + public Optional getInfer() { + return Optional.ofNullable(infer); } /** @@ -210,11 +213,21 @@ public Boolean getInfer() { * {@code true} to enable inference mode * @return this config for method chaining */ - public CustomAgentConfig setInfer(Boolean infer) { + public CustomAgentConfig setInfer(boolean infer) { this.infer = infer; return this; } + /** + * Clears the infer setting, reverting to the default behavior. + * + * @return this instance for method chaining + */ + public CustomAgentConfig clearInfer() { + this.infer = null; + return this; + } + /** * Gets the list of skill names to preload into this agent's context. * diff --git a/src/main/java/com/github/copilot/sdk/json/InfiniteSessionConfig.java b/src/main/java/com/github/copilot/sdk/json/InfiniteSessionConfig.java index d45851f8a1..561796ede7 100644 --- a/src/main/java/com/github/copilot/sdk/json/InfiniteSessionConfig.java +++ b/src/main/java/com/github/copilot/sdk/json/InfiniteSessionConfig.java @@ -6,6 +6,9 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonIgnore; +import java.util.Optional; +import java.util.OptionalDouble; /** * Configuration for infinite sessions with automatic context compaction and @@ -43,10 +46,12 @@ public class InfiniteSessionConfig { /** * Gets whether infinite sessions are enabled. * - * @return {@code true} if enabled, {@code null} to use default (true) + * @return an {@link Optional} containing the boolean value, or empty to use + * default (true) */ - public Boolean getEnabled() { - return enabled; + @JsonIgnore + public Optional getEnabled() { + return Optional.ofNullable(enabled); } /** @@ -58,18 +63,32 @@ public Boolean getEnabled() { * {@code true} to enable infinite sessions * @return this config instance for method chaining */ - public InfiniteSessionConfig setEnabled(Boolean enabled) { + public InfiniteSessionConfig setEnabled(boolean enabled) { this.enabled = enabled; return this; } + /** + * Clears the enabled setting, reverting to the default behavior. + * + * @return this instance for method chaining + */ + public InfiniteSessionConfig clearEnabled() { + this.enabled = null; + return this; + } + /** * Gets the background compaction threshold. * - * @return the threshold (0.0-1.0), or {@code null} to use default + * @return an {@link OptionalDouble} containing the threshold (0.0-1.0), or + * empty to use default */ - public Double getBackgroundCompactionThreshold() { - return backgroundCompactionThreshold; + @JsonIgnore + public OptionalDouble getBackgroundCompactionThreshold() { + return backgroundCompactionThreshold == null + ? OptionalDouble.empty() + : OptionalDouble.of(backgroundCompactionThreshold); } /** @@ -82,18 +101,33 @@ public Double getBackgroundCompactionThreshold() { * the threshold (0.0-1.0) * @return this config instance for method chaining */ - public InfiniteSessionConfig setBackgroundCompactionThreshold(Double backgroundCompactionThreshold) { + public InfiniteSessionConfig setBackgroundCompactionThreshold(double backgroundCompactionThreshold) { this.backgroundCompactionThreshold = backgroundCompactionThreshold; return this; } + /** + * Clears the backgroundCompactionThreshold setting, reverting to the default + * behavior. + * + * @return this instance for method chaining + */ + public InfiniteSessionConfig clearBackgroundCompactionThreshold() { + this.backgroundCompactionThreshold = null; + return this; + } + /** * Gets the buffer exhaustion threshold. * - * @return the threshold (0.0-1.0), or {@code null} to use default + * @return an {@link OptionalDouble} containing the threshold (0.0-1.0), or + * empty to use default */ - public Double getBufferExhaustionThreshold() { - return bufferExhaustionThreshold; + @JsonIgnore + public OptionalDouble getBufferExhaustionThreshold() { + return bufferExhaustionThreshold == null + ? OptionalDouble.empty() + : OptionalDouble.of(bufferExhaustionThreshold); } /** @@ -107,8 +141,20 @@ public Double getBufferExhaustionThreshold() { * the threshold (0.0-1.0) * @return this config instance for method chaining */ - public InfiniteSessionConfig setBufferExhaustionThreshold(Double bufferExhaustionThreshold) { + public InfiniteSessionConfig setBufferExhaustionThreshold(double bufferExhaustionThreshold) { this.bufferExhaustionThreshold = bufferExhaustionThreshold; return this; } + + /** + * Clears the bufferExhaustionThreshold setting, reverting to the default + * behavior. + * + * @return this instance for method chaining + */ + public InfiniteSessionConfig clearBufferExhaustionThreshold() { + this.bufferExhaustionThreshold = null; + return this; + } + } diff --git a/src/main/java/com/github/copilot/sdk/json/InputOptions.java b/src/main/java/com/github/copilot/sdk/json/InputOptions.java index 9b0b6c8dd8..3b66476a18 100644 --- a/src/main/java/com/github/copilot/sdk/json/InputOptions.java +++ b/src/main/java/com/github/copilot/sdk/json/InputOptions.java @@ -4,6 +4,8 @@ package com.github.copilot.sdk.json; +import java.util.OptionalInt; + /** * Options for the {@link SessionUiApi#input(String, InputOptions)} convenience * method. @@ -47,33 +49,53 @@ public InputOptions setDescription(String description) { } /** Gets the minimum character length. @return the min length */ - public Integer getMinLength() { - return minLength; + public OptionalInt getMinLength() { + return minLength == null ? OptionalInt.empty() : OptionalInt.of(minLength); } /** * Sets the minimum character length. @param minLength the min length @return * this */ - public InputOptions setMinLength(Integer minLength) { + public InputOptions setMinLength(int minLength) { this.minLength = minLength; return this; } + /** + * Clears the minLength setting, reverting to the default behavior. + * + * @return this instance for method chaining + */ + public InputOptions clearMinLength() { + this.minLength = null; + return this; + } + /** Gets the maximum character length. @return the max length */ - public Integer getMaxLength() { - return maxLength; + public OptionalInt getMaxLength() { + return maxLength == null ? OptionalInt.empty() : OptionalInt.of(maxLength); } /** * Sets the maximum character length. @param maxLength the max length @return * this */ - public InputOptions setMaxLength(Integer maxLength) { + public InputOptions setMaxLength(int maxLength) { this.maxLength = maxLength; return this; } + /** + * Clears the maxLength setting, reverting to the default behavior. + * + * @return this instance for method chaining + */ + public InputOptions clearMaxLength() { + this.maxLength = null; + return this; + } + /** * Gets the semantic format hint (e.g., {@code "email"}, {@code "uri"}, * {@code "date"}, {@code "date-time"}). diff --git a/src/main/java/com/github/copilot/sdk/json/McpHttpServerConfig.java b/src/main/java/com/github/copilot/sdk/json/McpHttpServerConfig.java index 7017db3d2d..9c5b8dbedc 100644 --- a/src/main/java/com/github/copilot/sdk/json/McpHttpServerConfig.java +++ b/src/main/java/com/github/copilot/sdk/json/McpHttpServerConfig.java @@ -99,7 +99,7 @@ public McpHttpServerConfig setTools(List tools) { } @Override - public McpHttpServerConfig setTimeout(Integer timeout) { + public McpHttpServerConfig setTimeout(int timeout) { super.setTimeout(timeout); return this; } diff --git a/src/main/java/com/github/copilot/sdk/json/McpServerConfig.java b/src/main/java/com/github/copilot/sdk/json/McpServerConfig.java index 7cf39af6b6..b7f56b05a8 100644 --- a/src/main/java/com/github/copilot/sdk/json/McpServerConfig.java +++ b/src/main/java/com/github/copilot/sdk/json/McpServerConfig.java @@ -11,6 +11,8 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.JsonIgnore; +import java.util.OptionalInt; /** * Abstract base class for MCP (Model Context Protocol) server configurations. @@ -68,21 +70,34 @@ public McpServerConfig setTools(List tools) { /** * Gets the optional timeout in milliseconds for tool calls to this server. * - * @return the timeout in milliseconds, or {@code null} for the default + * @return an {@link OptionalInt} containing the timeout in milliseconds, or + * empty for the default */ - public Integer getTimeout() { - return timeout; + @JsonIgnore + public OptionalInt getTimeout() { + return timeout == null ? OptionalInt.empty() : OptionalInt.of(timeout); } /** * Sets an optional timeout in milliseconds for tool calls to this server. * * @param timeout - * the timeout in milliseconds, or {@code null} for the default + * the timeout in milliseconds * @return this config for method chaining */ - public McpServerConfig setTimeout(Integer timeout) { + public McpServerConfig setTimeout(int timeout) { this.timeout = timeout; return this; } + + /** + * Clears the timeout setting, reverting to the default behavior. + * + * @return this instance for method chaining + */ + public McpServerConfig clearTimeout() { + this.timeout = null; + return this; + } + } diff --git a/src/main/java/com/github/copilot/sdk/json/McpStdioServerConfig.java b/src/main/java/com/github/copilot/sdk/json/McpStdioServerConfig.java index 900034be61..eef4d1e7d5 100644 --- a/src/main/java/com/github/copilot/sdk/json/McpStdioServerConfig.java +++ b/src/main/java/com/github/copilot/sdk/json/McpStdioServerConfig.java @@ -148,7 +148,7 @@ public McpStdioServerConfig setTools(List tools) { } @Override - public McpStdioServerConfig setTimeout(Integer timeout) { + public McpStdioServerConfig setTimeout(int timeout) { super.setTimeout(timeout); return this; } diff --git a/src/main/java/com/github/copilot/sdk/json/ModelCapabilitiesOverride.java b/src/main/java/com/github/copilot/sdk/json/ModelCapabilitiesOverride.java index 18701ad671..ab242d83de 100644 --- a/src/main/java/com/github/copilot/sdk/json/ModelCapabilitiesOverride.java +++ b/src/main/java/com/github/copilot/sdk/json/ModelCapabilitiesOverride.java @@ -7,6 +7,9 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonIgnore; +import java.util.Optional; +import java.util.OptionalInt; /** * Per-property overrides for model capabilities, deep-merged over runtime @@ -109,8 +112,9 @@ public static class Supports { * @return {@code true} to enable vision, {@code false} to disable, or * {@code null} to use the runtime default */ - public Boolean getVision() { - return vision; + @JsonIgnore + public Optional getVision() { + return Optional.ofNullable(vision); } /** @@ -121,19 +125,30 @@ public Boolean getVision() { * to use the runtime default * @return this instance for method chaining */ - public Supports setVision(Boolean vision) { + public Supports setVision(boolean vision) { this.vision = vision; return this; } + /** + * Clears the vision setting, reverting to the default behavior. + * + * @return this instance for method chaining + */ + public Supports clearVision() { + this.vision = null; + return this; + } + /** * Gets the reasoning effort override. * * @return {@code true} to enable reasoning effort, {@code false} to disable, or * {@code null} to use the runtime default */ - public Boolean getReasoningEffort() { - return reasoningEffort; + @JsonIgnore + public Optional getReasoningEffort() { + return Optional.ofNullable(reasoningEffort); } /** @@ -144,10 +159,21 @@ public Boolean getReasoningEffort() { * to use the runtime default * @return this instance for method chaining */ - public Supports setReasoningEffort(Boolean reasoningEffort) { + public Supports setReasoningEffort(boolean reasoningEffort) { this.reasoningEffort = reasoningEffort; return this; } + + /** + * Clears the reasoningEffort setting, reverting to the default behavior. + * + * @return this instance for method chaining + */ + public Supports clearReasoningEffort() { + this.reasoningEffort = null; + return this; + } + } /** @@ -174,8 +200,9 @@ public static class Limits { * * @return the override value, or {@code null} to use the runtime default */ - public Integer getMaxPromptTokens() { - return maxPromptTokens; + @JsonIgnore + public OptionalInt getMaxPromptTokens() { + return maxPromptTokens == null ? OptionalInt.empty() : OptionalInt.of(maxPromptTokens); } /** @@ -185,18 +212,29 @@ public Integer getMaxPromptTokens() { * the override value, or {@code null} to use the runtime default * @return this instance for method chaining */ - public Limits setMaxPromptTokens(Integer maxPromptTokens) { + public Limits setMaxPromptTokens(int maxPromptTokens) { this.maxPromptTokens = maxPromptTokens; return this; } + /** + * Clears the maxPromptTokens setting, reverting to the default behavior. + * + * @return this instance for method chaining + */ + public Limits clearMaxPromptTokens() { + this.maxPromptTokens = null; + return this; + } + /** * Gets the maximum output tokens override. * * @return the override value, or {@code null} to use the runtime default */ - public Integer getMaxOutputTokens() { - return maxOutputTokens; + @JsonIgnore + public OptionalInt getMaxOutputTokens() { + return maxOutputTokens == null ? OptionalInt.empty() : OptionalInt.of(maxOutputTokens); } /** @@ -206,18 +244,29 @@ public Integer getMaxOutputTokens() { * the override value, or {@code null} to use the runtime default * @return this instance for method chaining */ - public Limits setMaxOutputTokens(Integer maxOutputTokens) { + public Limits setMaxOutputTokens(int maxOutputTokens) { this.maxOutputTokens = maxOutputTokens; return this; } + /** + * Clears the maxOutputTokens setting, reverting to the default behavior. + * + * @return this instance for method chaining + */ + public Limits clearMaxOutputTokens() { + this.maxOutputTokens = null; + return this; + } + /** * Gets the maximum context window tokens override. * * @return the override value, or {@code null} to use the runtime default */ - public Integer getMaxContextWindowTokens() { - return maxContextWindowTokens; + @JsonIgnore + public OptionalInt getMaxContextWindowTokens() { + return maxContextWindowTokens == null ? OptionalInt.empty() : OptionalInt.of(maxContextWindowTokens); } /** @@ -227,9 +276,20 @@ public Integer getMaxContextWindowTokens() { * the override value, or {@code null} to use the runtime default * @return this instance for method chaining */ - public Limits setMaxContextWindowTokens(Integer maxContextWindowTokens) { + public Limits setMaxContextWindowTokens(int maxContextWindowTokens) { this.maxContextWindowTokens = maxContextWindowTokens; return this; } + + /** + * Clears the maxContextWindowTokens setting, reverting to the default behavior. + * + * @return this instance for method chaining + */ + public Limits clearMaxContextWindowTokens() { + this.maxContextWindowTokens = null; + return this; + } + } } diff --git a/src/main/java/com/github/copilot/sdk/json/ModelLimits.java b/src/main/java/com/github/copilot/sdk/json/ModelLimits.java index 734a50deda..fedecd6d36 100644 --- a/src/main/java/com/github/copilot/sdk/json/ModelLimits.java +++ b/src/main/java/com/github/copilot/sdk/json/ModelLimits.java @@ -6,6 +6,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonIgnore; +import java.util.OptionalInt; /** * Model limits. @@ -24,15 +26,26 @@ public class ModelLimits { @JsonProperty("vision") private ModelVisionLimits vision; - public Integer getMaxPromptTokens() { - return maxPromptTokens; + @JsonIgnore + public OptionalInt getMaxPromptTokens() { + return maxPromptTokens == null ? OptionalInt.empty() : OptionalInt.of(maxPromptTokens); } - public ModelLimits setMaxPromptTokens(Integer maxPromptTokens) { + public ModelLimits setMaxPromptTokens(int maxPromptTokens) { this.maxPromptTokens = maxPromptTokens; return this; } + /** + * Clears the maxPromptTokens setting, reverting to the default behavior. + * + * @return this instance for method chaining + */ + public ModelLimits clearMaxPromptTokens() { + this.maxPromptTokens = null; + return this; + } + public int getMaxContextWindowTokens() { return maxContextWindowTokens; } diff --git a/src/main/java/com/github/copilot/sdk/json/ProviderConfig.java b/src/main/java/com/github/copilot/sdk/json/ProviderConfig.java index 8947696c9a..3826f9dd83 100644 --- a/src/main/java/com/github/copilot/sdk/json/ProviderConfig.java +++ b/src/main/java/com/github/copilot/sdk/json/ProviderConfig.java @@ -9,6 +9,8 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonIgnore; +import java.util.OptionalInt; /** * Configuration for a custom API provider (BYOK - Bring Your Own Key). @@ -298,8 +300,9 @@ public ProviderConfig setWireModel(String wireModel) { * * @return the max prompt tokens, or {@code null} if not set */ - public Integer getMaxPromptTokens() { - return maxPromptTokens; + @JsonIgnore + public OptionalInt getMaxPromptTokens() { + return maxPromptTokens == null ? OptionalInt.empty() : OptionalInt.of(maxPromptTokens); } /** @@ -314,18 +317,29 @@ public Integer getMaxPromptTokens() { * the max prompt tokens * @return this config for method chaining */ - public ProviderConfig setMaxPromptTokens(Integer maxPromptTokens) { + public ProviderConfig setMaxPromptTokens(int maxPromptTokens) { this.maxPromptTokens = maxPromptTokens; return this; } + /** + * Clears the maxPromptTokens setting, reverting to the default behavior. + * + * @return this instance for method chaining + */ + public ProviderConfig clearMaxPromptTokens() { + this.maxPromptTokens = null; + return this; + } + /** * Gets the maximum output token override. * * @return the max output tokens, or {@code null} if not set */ - public Integer getMaxOutputTokens() { - return maxOutputTokens; + @JsonIgnore + public OptionalInt getMaxOutputTokens() { + return maxOutputTokens == null ? OptionalInt.empty() : OptionalInt.of(maxOutputTokens); } /** @@ -338,8 +352,19 @@ public Integer getMaxOutputTokens() { * the max output tokens * @return this config for method chaining */ - public ProviderConfig setMaxOutputTokens(Integer maxOutputTokens) { + public ProviderConfig setMaxOutputTokens(int maxOutputTokens) { this.maxOutputTokens = maxOutputTokens; return this; } + + /** + * Clears the maxOutputTokens setting, reverting to the default behavior. + * + * @return this instance for method chaining + */ + public ProviderConfig clearMaxOutputTokens() { + this.maxOutputTokens = null; + return this; + } + } diff --git a/src/main/java/com/github/copilot/sdk/json/ResumeSessionConfig.java b/src/main/java/com/github/copilot/sdk/json/ResumeSessionConfig.java index f2caad7710..9d76212140 100644 --- a/src/main/java/com/github/copilot/sdk/json/ResumeSessionConfig.java +++ b/src/main/java/com/github/copilot/sdk/json/ResumeSessionConfig.java @@ -11,8 +11,10 @@ import java.util.function.Consumer; import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.github.copilot.sdk.generated.SessionEvent; +import java.util.Optional; /** * Configuration for resuming an existing Copilot session. @@ -244,8 +246,9 @@ public ResumeSessionConfig setProvider(ProviderConfig provider) { * * @return whether session telemetry is enabled */ - public Boolean getEnableSessionTelemetry() { - return enableSessionTelemetry; + @JsonIgnore + public Optional getEnableSessionTelemetry() { + return Optional.ofNullable(enableSessionTelemetry); } /** @@ -259,11 +262,21 @@ public Boolean getEnableSessionTelemetry() { * whether to enable session telemetry * @return this config for method chaining */ - public ResumeSessionConfig setEnableSessionTelemetry(Boolean enableSessionTelemetry) { + public ResumeSessionConfig setEnableSessionTelemetry(boolean enableSessionTelemetry) { this.enableSessionTelemetry = enableSessionTelemetry; return this; } + /** + * Clears the enableSessionTelemetry setting, reverting to the default behavior. + * + * @return this instance for method chaining + */ + public ResumeSessionConfig clearEnableSessionTelemetry() { + this.enableSessionTelemetry = null; + return this; + } + /** * Gets the reasoning effort level. * @@ -403,8 +416,9 @@ public ResumeSessionConfig setConfigDir(String configDir) { * @return {@code true} to enable discovery, {@code false} to disable, or * {@code null} to use the runtime default */ - public Boolean getEnableConfigDiscovery() { - return enableConfigDiscovery; + @JsonIgnore + public Optional getEnableConfigDiscovery() { + return Optional.ofNullable(enableConfigDiscovery); } /** @@ -420,19 +434,30 @@ public Boolean getEnableConfigDiscovery() { * {@code null} to use the runtime default * @return this config for method chaining */ - public ResumeSessionConfig setEnableConfigDiscovery(Boolean enableConfigDiscovery) { + public ResumeSessionConfig setEnableConfigDiscovery(boolean enableConfigDiscovery) { this.enableConfigDiscovery = enableConfigDiscovery; return this; } + /** + * Clears the enableConfigDiscovery setting, reverting to the default behavior. + * + * @return this instance for method chaining + */ + public ResumeSessionConfig clearEnableConfigDiscovery() { + this.enableConfigDiscovery = null; + return this; + } + /** * Gets whether sub-agent streaming events are included. * * @return {@code true} to include sub-agent streaming events, {@code false} to * suppress them, or {@code null} to use the runtime default */ - public Boolean getIncludeSubAgentStreamingEvents() { - return includeSubAgentStreamingEvents; + @JsonIgnore + public Optional getIncludeSubAgentStreamingEvents() { + return Optional.ofNullable(includeSubAgentStreamingEvents); } /** @@ -443,11 +468,22 @@ public Boolean getIncludeSubAgentStreamingEvents() { * suppress * @return this config for method chaining */ - public ResumeSessionConfig setIncludeSubAgentStreamingEvents(Boolean includeSubAgentStreamingEvents) { + public ResumeSessionConfig setIncludeSubAgentStreamingEvents(boolean includeSubAgentStreamingEvents) { this.includeSubAgentStreamingEvents = includeSubAgentStreamingEvents; return this; } + /** + * Clears the includeSubAgentStreamingEvents setting, reverting to the default + * behavior. + * + * @return this instance for method chaining + */ + public ResumeSessionConfig clearIncludeSubAgentStreamingEvents() { + this.includeSubAgentStreamingEvents = null; + return this; + } + /** * Gets the model capabilities override. * diff --git a/src/main/java/com/github/copilot/sdk/json/ResumeSessionRequest.java b/src/main/java/com/github/copilot/sdk/json/ResumeSessionRequest.java index a1af269700..054fc8fba9 100644 --- a/src/main/java/com/github/copilot/sdk/json/ResumeSessionRequest.java +++ b/src/main/java/com/github/copilot/sdk/json/ResumeSessionRequest.java @@ -231,40 +231,68 @@ public Boolean getEnableSessionTelemetry() { /** * Sets enable session telemetry flag. @param enableSessionTelemetry the flag */ - public void setEnableSessionTelemetry(Boolean enableSessionTelemetry) { + public void setEnableSessionTelemetry(boolean enableSessionTelemetry) { this.enableSessionTelemetry = enableSessionTelemetry; } + /** + * Clears the enableSessionTelemetry setting, reverting to the default behavior. + */ + public void clearEnableSessionTelemetry() { + this.enableSessionTelemetry = null; + } + /** Gets request permission flag. @return the flag */ public Boolean getRequestPermission() { return requestPermission; } /** Sets request permission flag. @param requestPermission the flag */ - public void setRequestPermission(Boolean requestPermission) { + public void setRequestPermission(boolean requestPermission) { this.requestPermission = requestPermission; } + /** + * Clears the requestPermission setting, reverting to the default behavior. + */ + public void clearRequestPermission() { + this.requestPermission = null; + } + /** Gets request user input flag. @return the flag */ public Boolean getRequestUserInput() { return requestUserInput; } /** Sets request user input flag. @param requestUserInput the flag */ - public void setRequestUserInput(Boolean requestUserInput) { + public void setRequestUserInput(boolean requestUserInput) { this.requestUserInput = requestUserInput; } + /** + * Clears the requestUserInput setting, reverting to the default behavior. + */ + public void clearRequestUserInput() { + this.requestUserInput = null; + } + /** Gets hooks flag. @return the flag */ public Boolean getHooks() { return hooks; } /** Sets hooks flag. @param hooks the flag */ - public void setHooks(Boolean hooks) { + public void setHooks(boolean hooks) { this.hooks = hooks; } + /** + * Clears the hooks setting, reverting to the default behavior. + */ + public void clearHooks() { + this.hooks = null; + } + /** Gets working directory. @return the working directory */ public String getWorkingDirectory() { return workingDirectory; @@ -291,30 +319,51 @@ public Boolean getEnableConfigDiscovery() { } /** Sets enable config discovery flag. @param enableConfigDiscovery the flag */ - public void setEnableConfigDiscovery(Boolean enableConfigDiscovery) { + public void setEnableConfigDiscovery(boolean enableConfigDiscovery) { this.enableConfigDiscovery = enableConfigDiscovery; } + /** + * Clears the enableConfigDiscovery setting, reverting to the default behavior. + */ + public void clearEnableConfigDiscovery() { + this.enableConfigDiscovery = null; + } + /** Gets disable resume flag. @return the flag */ public Boolean getDisableResume() { return disableResume; } /** Sets disable resume flag. @param disableResume the flag */ - public void setDisableResume(Boolean disableResume) { + public void setDisableResume(boolean disableResume) { this.disableResume = disableResume; } + /** + * Clears the disableResume setting, reverting to the default behavior. + */ + public void clearDisableResume() { + this.disableResume = null; + } + /** Gets streaming flag. @return the flag */ public Boolean getStreaming() { return streaming; } /** Sets streaming flag. @param streaming the flag */ - public void setStreaming(Boolean streaming) { + public void setStreaming(boolean streaming) { this.streaming = streaming; } + /** + * Clears the streaming setting, reverting to the default behavior. + */ + public void clearStreaming() { + this.streaming = null; + } + /** Gets include sub-agent streaming events flag. @return the flag */ public Boolean getIncludeSubAgentStreamingEvents() { return includeSubAgentStreamingEvents; @@ -324,10 +373,18 @@ public Boolean getIncludeSubAgentStreamingEvents() { * Sets include sub-agent streaming events flag. @param * includeSubAgentStreamingEvents the flag */ - public void setIncludeSubAgentStreamingEvents(Boolean includeSubAgentStreamingEvents) { + public void setIncludeSubAgentStreamingEvents(boolean includeSubAgentStreamingEvents) { this.includeSubAgentStreamingEvents = includeSubAgentStreamingEvents; } + /** + * Clears the includeSubAgentStreamingEvents setting, reverting to the default + * behavior. + */ + public void clearIncludeSubAgentStreamingEvents() { + this.includeSubAgentStreamingEvents = null; + } + /** Gets MCP servers. @return the servers map */ public Map getMcpServers() { return mcpServers == null ? null : Collections.unmodifiableMap(mcpServers); @@ -441,10 +498,17 @@ public Boolean getRequestElicitation() { } /** Sets the requestElicitation flag. @param requestElicitation the flag */ - public void setRequestElicitation(Boolean requestElicitation) { + public void setRequestElicitation(boolean requestElicitation) { this.requestElicitation = requestElicitation; } + /** + * Clears the requestElicitation setting, reverting to the default behavior. + */ + public void clearRequestElicitation() { + this.requestElicitation = null; + } + /** Gets the requestExitPlanMode flag. @return the flag */ public Boolean getRequestExitPlanMode() { return requestExitPlanMode; diff --git a/src/main/java/com/github/copilot/sdk/json/SessionConfig.java b/src/main/java/com/github/copilot/sdk/json/SessionConfig.java index 51cad884ed..c83aa00fca 100644 --- a/src/main/java/com/github/copilot/sdk/json/SessionConfig.java +++ b/src/main/java/com/github/copilot/sdk/json/SessionConfig.java @@ -11,8 +11,10 @@ import java.util.function.Consumer; import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.github.copilot.sdk.generated.SessionEvent; +import java.util.Optional; /** * Configuration for creating a new Copilot session. @@ -298,8 +300,9 @@ public SessionConfig setProvider(ProviderConfig provider) { * * @return whether session telemetry is enabled */ - public Boolean getEnableSessionTelemetry() { - return enableSessionTelemetry; + @JsonIgnore + public Optional getEnableSessionTelemetry() { + return Optional.ofNullable(enableSessionTelemetry); } /** @@ -313,11 +316,21 @@ public Boolean getEnableSessionTelemetry() { * whether to enable session telemetry * @return this config instance for method chaining */ - public SessionConfig setEnableSessionTelemetry(Boolean enableSessionTelemetry) { + public SessionConfig setEnableSessionTelemetry(boolean enableSessionTelemetry) { this.enableSessionTelemetry = enableSessionTelemetry; return this; } + /** + * Clears the enableSessionTelemetry setting, reverting to the default behavior. + * + * @return this instance for method chaining + */ + public SessionConfig clearEnableSessionTelemetry() { + this.enableSessionTelemetry = null; + return this; + } + /** * Gets the permission request handler. * @@ -661,8 +674,9 @@ public SessionConfig setConfigDir(String configDir) { * @return {@code true} to enable discovery, {@code false} to disable, or * {@code null} to use the runtime default */ - public Boolean getEnableConfigDiscovery() { - return enableConfigDiscovery; + @JsonIgnore + public Optional getEnableConfigDiscovery() { + return Optional.ofNullable(enableConfigDiscovery); } /** @@ -680,19 +694,30 @@ public Boolean getEnableConfigDiscovery() { * {@code null} to use the runtime default * @return this config instance for method chaining */ - public SessionConfig setEnableConfigDiscovery(Boolean enableConfigDiscovery) { + public SessionConfig setEnableConfigDiscovery(boolean enableConfigDiscovery) { this.enableConfigDiscovery = enableConfigDiscovery; return this; } + /** + * Clears the enableConfigDiscovery setting, reverting to the default behavior. + * + * @return this instance for method chaining + */ + public SessionConfig clearEnableConfigDiscovery() { + this.enableConfigDiscovery = null; + return this; + } + /** * Gets whether sub-agent streaming events are included. * * @return {@code true} to include sub-agent streaming events, {@code false} to * suppress them, or {@code null} to use the runtime default */ - public Boolean getIncludeSubAgentStreamingEvents() { - return includeSubAgentStreamingEvents; + @JsonIgnore + public Optional getIncludeSubAgentStreamingEvents() { + return Optional.ofNullable(includeSubAgentStreamingEvents); } /** @@ -709,11 +734,22 @@ public Boolean getIncludeSubAgentStreamingEvents() { * suppress * @return this config instance for method chaining */ - public SessionConfig setIncludeSubAgentStreamingEvents(Boolean includeSubAgentStreamingEvents) { + public SessionConfig setIncludeSubAgentStreamingEvents(boolean includeSubAgentStreamingEvents) { this.includeSubAgentStreamingEvents = includeSubAgentStreamingEvents; return this; } + /** + * Clears the includeSubAgentStreamingEvents setting, reverting to the default + * behavior. + * + * @return this instance for method chaining + */ + public SessionConfig clearIncludeSubAgentStreamingEvents() { + this.includeSubAgentStreamingEvents = null; + return this; + } + /** * Gets the model capabilities override. * diff --git a/src/main/java/com/github/copilot/sdk/json/SessionUiCapabilities.java b/src/main/java/com/github/copilot/sdk/json/SessionUiCapabilities.java index 9b8e0b5872..06ddfc760d 100644 --- a/src/main/java/com/github/copilot/sdk/json/SessionUiCapabilities.java +++ b/src/main/java/com/github/copilot/sdk/json/SessionUiCapabilities.java @@ -4,6 +4,11 @@ package com.github.copilot.sdk.json; +import java.util.Optional; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; + /** * UI-specific capability flags for a session. * @@ -11,16 +16,17 @@ */ public class SessionUiCapabilities { + @JsonProperty("elicitation") private Boolean elicitation; /** * Returns whether the host supports interactive elicitation dialogs. * - * @return {@code true} if elicitation is supported, {@code false} or - * {@code null} otherwise + * @return an {@link Optional} containing the boolean value, or empty if not set */ - public Boolean getElicitation() { - return elicitation; + @JsonIgnore + public Optional getElicitation() { + return Optional.ofNullable(elicitation); } /** @@ -30,8 +36,19 @@ public Boolean getElicitation() { * {@code true} if elicitation is supported * @return this instance for method chaining */ - public SessionUiCapabilities setElicitation(Boolean elicitation) { + public SessionUiCapabilities setElicitation(boolean elicitation) { this.elicitation = elicitation; return this; } + + /** + * Clears the elicitation setting, reverting to the default behavior. + * + * @return this instance for method chaining + */ + public SessionUiCapabilities clearElicitation() { + this.elicitation = null; + return this; + } + } diff --git a/src/main/java/com/github/copilot/sdk/json/TelemetryConfig.java b/src/main/java/com/github/copilot/sdk/json/TelemetryConfig.java index 8407ab6098..9b28a3150a 100644 --- a/src/main/java/com/github/copilot/sdk/json/TelemetryConfig.java +++ b/src/main/java/com/github/copilot/sdk/json/TelemetryConfig.java @@ -4,6 +4,10 @@ package com.github.copilot.sdk.json; +import java.util.Optional; + +import com.fasterxml.jackson.annotation.JsonIgnore; + /** * OpenTelemetry configuration for the Copilot CLI server. *

@@ -131,8 +135,9 @@ public TelemetryConfig setSourceName(String sourceName) { * @return {@code true} to capture content, {@code false} to suppress it, or * {@code null} to use the default */ - public Boolean getCaptureContent() { - return captureContent; + @JsonIgnore + public Optional getCaptureContent() { + return Optional.ofNullable(captureContent); } /** @@ -142,8 +147,19 @@ public Boolean getCaptureContent() { * {@code true} to capture content, {@code false} to suppress it * @return this config for method chaining */ - public TelemetryConfig setCaptureContent(Boolean captureContent) { + public TelemetryConfig setCaptureContent(boolean captureContent) { this.captureContent = captureContent; return this; } + + /** + * Clears the captureContent setting, reverting to the default behavior. + * + * @return this instance for method chaining + */ + public TelemetryConfig clearCaptureContent() { + this.captureContent = null; + return this; + } + } diff --git a/src/main/java/com/github/copilot/sdk/json/UserInputRequest.java b/src/main/java/com/github/copilot/sdk/json/UserInputRequest.java index 9b466f866c..dfbb1b6da3 100644 --- a/src/main/java/com/github/copilot/sdk/json/UserInputRequest.java +++ b/src/main/java/com/github/copilot/sdk/json/UserInputRequest.java @@ -9,6 +9,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonIgnore; +import java.util.Optional; /** * Request for user input from the agent. @@ -78,8 +80,9 @@ public UserInputRequest setChoices(List choices) { * @return {@code true} if freeform input is allowed, {@code null} if not * specified */ - public Boolean getAllowFreeform() { - return allowFreeform; + @JsonIgnore + public Optional getAllowFreeform() { + return Optional.ofNullable(allowFreeform); } /** @@ -89,8 +92,19 @@ public Boolean getAllowFreeform() { * {@code true} to allow freeform input * @return this instance for method chaining */ - public UserInputRequest setAllowFreeform(Boolean allowFreeform) { + public UserInputRequest setAllowFreeform(boolean allowFreeform) { this.allowFreeform = allowFreeform; return this; } + + /** + * Clears the allowFreeform setting, reverting to the default behavior. + * + * @return this instance for method chaining + */ + public UserInputRequest clearAllowFreeform() { + this.allowFreeform = null; + return this; + } + } diff --git a/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java b/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java index 7abc47e4a4..af92baa7e2 100644 --- a/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java +++ b/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java @@ -203,7 +203,7 @@ void sessionConfigEnableSessionTelemetryCopied() { SessionConfig cloned = original.clone(); - assertFalse(cloned.getEnableSessionTelemetry()); + assertFalse(cloned.getEnableSessionTelemetry().orElse(true)); } @Test @@ -212,7 +212,7 @@ void sessionConfigEnableSessionTelemetryDefaultIsNull() { SessionConfig cloned = original.clone(); - assertNull(cloned.getEnableSessionTelemetry()); + assertTrue(cloned.getEnableSessionTelemetry().isEmpty()); } @Test @@ -222,7 +222,7 @@ void resumeSessionConfigEnableSessionTelemetryCopied() { ResumeSessionConfig cloned = original.clone(); - assertFalse(cloned.getEnableSessionTelemetry()); + assertFalse(cloned.getEnableSessionTelemetry().orElse(true)); } @Test @@ -231,7 +231,7 @@ void resumeSessionConfigEnableSessionTelemetryDefaultIsNull() { ResumeSessionConfig cloned = original.clone(); - assertNull(cloned.getEnableSessionTelemetry()); + assertTrue(cloned.getEnableSessionTelemetry().isEmpty()); } @Test @@ -301,11 +301,11 @@ void copilotClientOptionsSetTelemetry() { } @Test - void copilotClientOptionsSetUseLoggedInUserNull() { + void copilotClientOptionsSetUseLoggedInUserClear() { var opts = new CopilotClientOptions(); - opts.setUseLoggedInUser(null); - // null → Boolean.FALSE - assertEquals(Boolean.FALSE, opts.getUseLoggedInUser()); + opts.setUseLoggedInUser(true); + opts.clearUseLoggedInUser(); + assertTrue(opts.getUseLoggedInUser().isEmpty()); } @Test @@ -375,7 +375,7 @@ void copilotClientOptionsSessionIdleTimeoutCloned() { CopilotClientOptions cloned = original.clone(); - assertEquals(600, cloned.getSessionIdleTimeoutSeconds()); + assertEquals(600, cloned.getSessionIdleTimeoutSeconds().getAsInt()); } @Test diff --git a/src/test/java/com/github/copilot/sdk/CopilotClientTest.java b/src/test/java/com/github/copilot/sdk/CopilotClientTest.java index b0430959b9..14ed8ca89e 100644 --- a/src/test/java/com/github/copilot/sdk/CopilotClientTest.java +++ b/src/test/java/com/github/copilot/sdk/CopilotClientTest.java @@ -20,6 +20,7 @@ import java.util.concurrent.ExecutionException; import static org.junit.jupiter.api.Assertions.*; +import java.util.Optional; /** * Tests for CopilotClient. @@ -153,14 +154,14 @@ void testGitHubTokenOptionAccepted() { void testUseLoggedInUserDefaultsToNull() { var options = new CopilotClientOptions().setCliPath("/path/to/cli"); - assertNull(options.getUseLoggedInUser()); + assertTrue(options.getUseLoggedInUser().isEmpty()); } @Test void testExplicitUseLoggedInUserFalse() { var options = new CopilotClientOptions().setCliPath("/path/to/cli").setUseLoggedInUser(false); - assertEquals(false, options.getUseLoggedInUser()); + assertEquals(Optional.of(false), options.getUseLoggedInUser()); } @Test @@ -168,7 +169,7 @@ void testExplicitUseLoggedInUserTrueWithGitHubToken() { var options = new CopilotClientOptions().setCliPath("/path/to/cli").setGitHubToken("gho_test_token") .setUseLoggedInUser(true); - assertEquals(true, options.getUseLoggedInUser()); + assertEquals(Optional.of(true), options.getUseLoggedInUser()); } @Test @@ -189,14 +190,14 @@ void testUseLoggedInUserWithCliUrlThrows() { void testSessionIdleTimeoutSecondsDefaultsToNull() { var options = new CopilotClientOptions(); - assertNull(options.getSessionIdleTimeoutSeconds()); + assertTrue(options.getSessionIdleTimeoutSeconds().isEmpty()); } @Test void testSessionIdleTimeoutSecondsOptionAccepted() { var options = new CopilotClientOptions().setSessionIdleTimeoutSeconds(600); - assertEquals(600, options.getSessionIdleTimeoutSeconds()); + assertEquals(600, options.getSessionIdleTimeoutSeconds().getAsInt()); } @Test diff --git a/src/test/java/com/github/copilot/sdk/DataObjectCoverageTest.java b/src/test/java/com/github/copilot/sdk/DataObjectCoverageTest.java index b61c93559b..e8e983a4ca 100644 --- a/src/test/java/com/github/copilot/sdk/DataObjectCoverageTest.java +++ b/src/test/java/com/github/copilot/sdk/DataObjectCoverageTest.java @@ -194,7 +194,7 @@ void mcpHttpServerConfigCoversGettersAndFluentSetters() { assertEquals("https://mcp.example.com/sse", cfg.getUrl()); assertEquals("Bearer token", cfg.getHeaders().get("Authorization")); assertEquals(tools, cfg.getTools()); - assertEquals(45, cfg.getTimeout()); + assertEquals(45, cfg.getTimeout().getAsInt()); } @Test @@ -212,22 +212,21 @@ void mcpStdioServerConfigCoversGettersAndFluentSetters() { assertEquals("1", cfg.getEnv().get("DEBUG")); assertEquals("/tmp", cfg.getWorkingDirectory()); assertEquals(tools, cfg.getTools()); - assertEquals(30, cfg.getTimeout()); + assertEquals(30, cfg.getTimeout().getAsInt()); } @Test void modelCapabilitiesOverrideCoversNestedSupportsAndLimits() { - var supports = new ModelCapabilitiesOverride.Supports().setVision(Boolean.TRUE) - .setReasoningEffort(Boolean.FALSE); + var supports = new ModelCapabilitiesOverride.Supports().setVision(true).setReasoningEffort(false); var limits = new ModelCapabilitiesOverride.Limits().setMaxPromptTokens(2048).setMaxOutputTokens(512) .setMaxContextWindowTokens(8192); var override = new ModelCapabilitiesOverride().setSupports(supports).setLimits(limits); - assertTrue(override.getSupports().getVision()); - assertFalse(override.getSupports().getReasoningEffort()); - assertEquals(2048, override.getLimits().getMaxPromptTokens()); - assertEquals(512, override.getLimits().getMaxOutputTokens()); - assertEquals(8192, override.getLimits().getMaxContextWindowTokens()); + assertTrue(override.getSupports().getVision().orElse(false)); + assertFalse(override.getSupports().getReasoningEffort().orElse(true)); + assertEquals(2048, override.getLimits().getMaxPromptTokens().getAsInt()); + assertEquals(512, override.getLimits().getMaxOutputTokens().getAsInt()); + assertEquals(8192, override.getLimits().getMaxContextWindowTokens().getAsInt()); } } diff --git a/src/test/java/com/github/copilot/sdk/ElicitationTest.java b/src/test/java/com/github/copilot/sdk/ElicitationTest.java index 6b748b4cc2..bf3c0bfb29 100644 --- a/src/test/java/com/github/copilot/sdk/ElicitationTest.java +++ b/src/test/java/com/github/copilot/sdk/ElicitationTest.java @@ -40,7 +40,7 @@ void sessionCapabilitiesTypesAreProperlyStructured() { var capabilities = new SessionCapabilities().setUi(new SessionUiCapabilities().setElicitation(true)); assertNotNull(capabilities.getUi()); - assertTrue(capabilities.getUi().getElicitation()); + assertTrue(capabilities.getUi().getElicitation().get()); // Test with null UI var emptyCapabilities = new SessionCapabilities(); @@ -119,8 +119,8 @@ void inputOptionsHasAllFields() { assertEquals("My Title", opts.getTitle()); assertEquals("My Desc", opts.getDescription()); - assertEquals(1, opts.getMinLength()); - assertEquals(100, opts.getMaxLength()); + assertEquals(1, opts.getMinLength().getAsInt()); + assertEquals(100, opts.getMaxLength().getAsInt()); assertEquals("email", opts.getFormat()); assertEquals("default@example.com", opts.getDefaultValue()); } @@ -164,7 +164,7 @@ void buildCreateRequestSetsRequestElicitationWhenHandlerPresent() { var request = SessionRequestBuilder.buildCreateRequest(config); - assertTrue(Boolean.TRUE.equals(request.getRequestElicitation())); + assertTrue(request.getRequestElicitation()); } @Test @@ -186,6 +186,6 @@ void buildResumeRequestSetsRequestElicitationWhenHandlerPresent() { var request = SessionRequestBuilder.buildResumeRequest("session-1", config); - assertTrue(Boolean.TRUE.equals(request.getRequestElicitation())); + assertTrue(request.getRequestElicitation()); } } diff --git a/src/test/java/com/github/copilot/sdk/MetadataApiTest.java b/src/test/java/com/github/copilot/sdk/MetadataApiTest.java index 3a9120a525..91ab628435 100644 --- a/src/test/java/com/github/copilot/sdk/MetadataApiTest.java +++ b/src/test/java/com/github/copilot/sdk/MetadataApiTest.java @@ -156,7 +156,7 @@ void testModelInfoDeserialization() throws Exception { // Capabilities assertNotNull(model.getCapabilities()); assertTrue(model.getCapabilities().getSupports().isVision()); - assertEquals(8192, model.getCapabilities().getLimits().getMaxPromptTokens()); + assertEquals(8192, model.getCapabilities().getLimits().getMaxPromptTokens().getAsInt()); assertEquals(128000, model.getCapabilities().getLimits().getMaxContextWindowTokens()); // Vision limits diff --git a/src/test/java/com/github/copilot/sdk/ProviderConfigTest.java b/src/test/java/com/github/copilot/sdk/ProviderConfigTest.java index e7602619ca..6bbb3ae284 100644 --- a/src/test/java/com/github/copilot/sdk/ProviderConfigTest.java +++ b/src/test/java/com/github/copilot/sdk/ProviderConfigTest.java @@ -410,8 +410,8 @@ void testProviderModelIdAndWireModelSerialization() throws Exception { ProviderConfig deserialized = MAPPER.readValue(MAPPER.writeValueAsString(provider), ProviderConfig.class); assertEquals("gpt-4o", deserialized.getModelId()); assertEquals("my-finetune-v3", deserialized.getWireModel()); - assertEquals(100_000, deserialized.getMaxPromptTokens()); - assertEquals(4096, deserialized.getMaxOutputTokens()); + assertEquals(100_000, deserialized.getMaxPromptTokens().getAsInt()); + assertEquals(4096, deserialized.getMaxOutputTokens().getAsInt()); } @Test @@ -419,8 +419,8 @@ void testProviderModelFieldsDefaultToNull() { var provider = new ProviderConfig(); assertNull(provider.getModelId()); assertNull(provider.getWireModel()); - assertNull(provider.getMaxPromptTokens()); - assertNull(provider.getMaxOutputTokens()); + assertTrue(provider.getMaxPromptTokens().isEmpty()); + assertTrue(provider.getMaxOutputTokens().isEmpty()); } @Test diff --git a/src/test/java/com/github/copilot/sdk/TelemetryConfigTest.java b/src/test/java/com/github/copilot/sdk/TelemetryConfigTest.java index 99b360d2db..278777ce13 100644 --- a/src/test/java/com/github/copilot/sdk/TelemetryConfigTest.java +++ b/src/test/java/com/github/copilot/sdk/TelemetryConfigTest.java @@ -22,7 +22,7 @@ void defaultValuesAreNull() { assertNull(config.getFilePath()); assertNull(config.getExporterType()); assertNull(config.getSourceName()); - assertNull(config.getCaptureContent()); + assertTrue(config.getCaptureContent().isEmpty()); } @Test @@ -57,10 +57,10 @@ void sourceNameGetterSetter() { void captureContentGetterSetter() { var config = new TelemetryConfig(); config.setCaptureContent(true); - assertTrue(config.getCaptureContent()); + assertTrue(config.getCaptureContent().get()); config.setCaptureContent(false); - assertFalse(config.getCaptureContent()); + assertFalse(config.getCaptureContent().get()); } @Test @@ -72,6 +72,6 @@ void fluentChainingReturnsThis() { assertEquals("/tmp/spans.json", config.getFilePath()); assertEquals("file", config.getExporterType()); assertEquals("sdk-test", config.getSourceName()); - assertTrue(config.getCaptureContent()); + assertTrue(config.getCaptureContent().get()); } } From c708aa2305f408a1e23f7f2941c214b70044a043 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 12 May 2026 00:36:41 +0000 Subject: [PATCH 3/3] fix: remove accidentally committed temp file and rename test method Co-authored-by: edburns <75821+edburns@users.noreply.github.com> --- refactor_optionals.py | 616 ------------------ .../github/copilot/sdk/ConfigCloneTest.java | 2 +- 2 files changed, 1 insertion(+), 617 deletions(-) delete mode 100644 refactor_optionals.py diff --git a/refactor_optionals.py b/refactor_optionals.py deleted file mode 100644 index 8de5f995f6..0000000000 --- a/refactor_optionals.py +++ /dev/null @@ -1,616 +0,0 @@ -#!/usr/bin/env python3 -"""Refactor Java source files to use Optional return types instead of nullable boxed primitives.""" - -import re -import os - -BASE = "/home/runner/work/copilot-sdk-java/copilot-sdk-java/src/main/java/com/github/copilot/sdk" -JSON_PKG = os.path.join(BASE, "json") - - -def read_file(path): - with open(path, 'r') as f: - return f.read() - - -def write_file(path, content): - with open(path, 'w') as f: - f.write(content) - - -def add_import(content, import_stmt): - """Add an import statement if not already present.""" - if import_stmt in content: - return content - # Find the last import line and add after it - lines = content.split('\n') - last_import_idx = -1 - for i, line in enumerate(lines): - if line.startswith('import '): - last_import_idx = i - if last_import_idx >= 0: - lines.insert(last_import_idx + 1, import_stmt) - return '\n'.join(lines) - - -def refactor_fluent_boolean_getter(content, field_name): - """Refactor a Boolean getter to return Optional (fluent class).""" - # Match the getter method - various javadoc styles - getter_name = f'get{field_name[0].upper()}{field_name[1:]}' - - # Replace return type and body - # Pattern: public Boolean getXxx() {\n return xxx;\n } - pattern = rf'( public )Boolean ({getter_name}\(\)) \{{\n(\s+)return {field_name};\n(\s+)\}}' - replacement = rf'\1Optional \2 {{\n\3return Optional.ofNullable({field_name});\n\4}}' - content = re.sub(pattern, replacement, content) - return content - - -def refactor_fluent_boolean_setter(content, field_name, class_name): - """Refactor a Boolean setter to take primitive boolean (fluent class).""" - setter_name = f'set{field_name[0].upper()}{field_name[1:]}' - - # Pattern: public ClassName setXxx(Boolean xxx) {\n this.xxx = xxx;\n return this;\n } - pattern = rf'( public {class_name} {setter_name}\()Boolean ({field_name})\)( \{{)' - replacement = rf'\1boolean \2)\3' - content = re.sub(pattern, replacement, content) - return content - - -def refactor_void_boolean_getter(content, field_name): - """Refactor a Boolean getter to return Optional (void setter class).""" - getter_name = f'get{field_name[0].upper()}{field_name[1:]}' - - pattern = rf'( public )Boolean ({getter_name}\(\)) \{{\n(\s+)return {field_name};\n(\s+)\}}' - replacement = rf'\1Optional \2 {{\n\3return Optional.ofNullable({field_name});\n\4}}' - content = re.sub(pattern, replacement, content) - return content - - -def refactor_void_boolean_setter(content, field_name): - """Refactor a void Boolean setter to take primitive boolean.""" - setter_name = f'set{field_name[0].upper()}{field_name[1:]}' - - pattern = rf'( public void {setter_name}\()Boolean ({field_name})\)' - replacement = rf'\1boolean \2)' - content = re.sub(pattern, replacement, content) - return content - - -def add_fluent_clear_method(content, field_name, class_name, after_setter=True): - """Add a clearXxx() method after the setter for fluent classes.""" - setter_name = f'set{field_name[0].upper()}{field_name[1:]}' - clear_name = f'clear{field_name[0].upper()}{field_name[1:]}' - - # Check if clear method already exists - if f'{clear_name}()' in content: - return content - - clear_method = f''' - /** - * Clears the {field_name} setting, reverting to the default behavior. - * - * @return this instance for method chaining - */ - public {class_name} {clear_name}() {{ - this.{field_name} = null; - return this; - }} -''' - - # Find the end of the setter method and insert after it - # Look for the setter method's closing brace - setter_pattern = rf'( public {class_name} {setter_name}\([^)]+\) \{{[^}}]*\}})' - match = re.search(setter_pattern, content, re.DOTALL) - if match: - insert_pos = match.end() - content = content[:insert_pos] + '\n' + clear_method + content[insert_pos:] - - return content - - -def add_void_clear_method(content, field_name, after_setter=True): - """Add a void clearXxx() method after the setter for request classes.""" - setter_name = f'set{field_name[0].upper()}{field_name[1:]}' - clear_name = f'clear{field_name[0].upper()}{field_name[1:]}' - - if f'{clear_name}()' in content: - return content - - clear_method = f''' - /** - * Clears the {field_name} setting, reverting to the default behavior. - */ - public void {clear_name}() {{ - this.{field_name} = null; - }} -''' - - # Find the end of the setter method - setter_pattern = rf'( public void {setter_name}\([^)]+\) \{{[^}}]*\}})' - match = re.search(setter_pattern, content, re.DOTALL) - if match: - insert_pos = match.end() - content = content[:insert_pos] + '\n' + clear_method + content[insert_pos:] - - return content - - -def refactor_fluent_int_getter(content, field_name): - """Refactor an Integer getter to return OptionalInt.""" - getter_name = f'get{field_name[0].upper()}{field_name[1:]}' - - pattern = rf'( public )Integer ({getter_name}\(\)) \{{\n(\s+)return {field_name};\n(\s+)\}}' - replacement = rf'\1OptionalInt \2 {{\n\3return {field_name} == null ? OptionalInt.empty() : OptionalInt.of({field_name});\n\4}}' - content = re.sub(pattern, replacement, content) - return content - - -def refactor_fluent_int_setter(content, field_name, class_name): - """Refactor an Integer setter to take primitive int (fluent).""" - setter_name = f'set{field_name[0].upper()}{field_name[1:]}' - - pattern = rf'( public {class_name} {setter_name}\()Integer ({field_name})\)( \{{)' - replacement = rf'\1int \2)\3' - content = re.sub(pattern, replacement, content) - return content - - -def refactor_fluent_double_getter(content, field_name): - """Refactor a Double getter to return OptionalDouble.""" - getter_name = f'get{field_name[0].upper()}{field_name[1:]}' - - pattern = rf'( public )Double ({getter_name}\(\)) \{{\n(\s+)return {field_name};\n(\s+)\}}' - replacement = rf'\1OptionalDouble \2 {{\n\3return {field_name} == null ? OptionalDouble.empty() : OptionalDouble.of({field_name});\n\4}}' - content = re.sub(pattern, replacement, content) - return content - - -def refactor_fluent_double_setter(content, field_name, class_name): - """Refactor a Double setter to take primitive double (fluent).""" - setter_name = f'set{field_name[0].upper()}{field_name[1:]}' - - pattern = rf'( public {class_name} {setter_name}\()Double ({field_name})\)( \{{)' - replacement = rf'\1double \2)\3' - content = re.sub(pattern, replacement, content) - return content - - -# Also handle inner class patterns (indented with 8 spaces) -def refactor_inner_boolean_getter(content, field_name): - """Refactor a Boolean getter in an inner class.""" - getter_name = f'get{field_name[0].upper()}{field_name[1:]}' - - pattern = rf'( public )Boolean ({getter_name}\(\)) \{{\n(\s+)return {field_name};\n(\s+)\}}' - replacement = rf'\1Optional \2 {{\n\3return Optional.ofNullable({field_name});\n\4}}' - content = re.sub(pattern, replacement, content) - return content - - -def refactor_inner_boolean_setter(content, field_name, class_name): - """Refactor a Boolean setter in an inner class.""" - setter_name = f'set{field_name[0].upper()}{field_name[1:]}' - - pattern = rf'( public {class_name} {setter_name}\()Boolean ({field_name})\)( \{{)' - replacement = rf'\1boolean \2)\3' - content = re.sub(pattern, replacement, content) - return content - - -def refactor_inner_int_getter(content, field_name): - """Refactor an Integer getter in an inner class.""" - getter_name = f'get{field_name[0].upper()}{field_name[1:]}' - - pattern = rf'( public )Integer ({getter_name}\(\)) \{{\n(\s+)return {field_name};\n(\s+)\}}' - replacement = rf'\1OptionalInt \2 {{\n\3return {field_name} == null ? OptionalInt.empty() : OptionalInt.of({field_name});\n\4}}' - content = re.sub(pattern, replacement, content) - return content - - -def refactor_inner_int_setter(content, field_name, class_name): - """Refactor an Integer setter in an inner class.""" - setter_name = f'set{field_name[0].upper()}{field_name[1:]}' - - pattern = rf'( public {class_name} {setter_name}\()Integer ({field_name})\)( \{{)' - replacement = rf'\1int \2)\3' - content = re.sub(pattern, replacement, content) - return content - - -def add_inner_fluent_clear(content, field_name, class_name): - """Add clear method for inner class fields.""" - setter_name = f'set{field_name[0].upper()}{field_name[1:]}' - clear_name = f'clear{field_name[0].upper()}{field_name[1:]}' - - if f'{clear_name}()' in content: - return content - - clear_method = f''' - /** - * Clears the {field_name} setting, reverting to the default behavior. - * - * @return this instance for method chaining - */ - public {class_name} {clear_name}() {{ - this.{field_name} = null; - return this; - }} -''' - - # Find the end of the setter in inner class (8 spaces indent) - setter_pattern = rf'( public {class_name} {setter_name}\([^)]+\) \{{[^}}]*\}})' - match = re.search(setter_pattern, content, re.DOTALL) - if match: - insert_pos = match.end() - content = content[:insert_pos] + '\n' + clear_method + content[insert_pos:] - - return content - - -# ==================== MAIN REFACTORING ==================== - -def refactor_copilot_client_options(): - path = os.path.join(JSON_PKG, "CopilotClientOptions.java") - content = read_file(path) - - content = add_import(content, "import java.util.Optional;") - content = add_import(content, "import java.util.OptionalInt;") - - # sessionIdleTimeoutSeconds: Integer -> OptionalInt - content = refactor_fluent_int_getter(content, "sessionIdleTimeoutSeconds") - content = refactor_fluent_int_setter(content, "sessionIdleTimeoutSeconds", "CopilotClientOptions") - content = add_fluent_clear_method(content, "sessionIdleTimeoutSeconds", "CopilotClientOptions") - - # useLoggedInUser: Boolean -> Optional - content = refactor_fluent_boolean_getter(content, "useLoggedInUser") - # Special case - the setter has custom logic, need to replace it differently - # Old: public CopilotClientOptions setUseLoggedInUser(Boolean useLoggedInUser) { - # this.useLoggedInUser = useLoggedInUser != null ? useLoggedInUser : Boolean.FALSE; - # New: public CopilotClientOptions setUseLoggedInUser(boolean useLoggedInUser) { - # this.useLoggedInUser = useLoggedInUser; - old_setter = "public CopilotClientOptions setUseLoggedInUser(Boolean useLoggedInUser) {\n this.useLoggedInUser = useLoggedInUser != null ? useLoggedInUser : Boolean.FALSE;" - new_setter = "public CopilotClientOptions setUseLoggedInUser(boolean useLoggedInUser) {\n this.useLoggedInUser = useLoggedInUser;" - content = content.replace(old_setter, new_setter) - content = add_fluent_clear_method(content, "useLoggedInUser", "CopilotClientOptions") - - # Update javadoc for getSessionIdleTimeoutSeconds - content = content.replace( - "@return the session idle timeout in seconds, or {@code null} to disable\n * (sessions live indefinitely)", - "@return an {@link OptionalInt} containing the session idle timeout in seconds,\n * or empty to disable (sessions live indefinitely)" - ) - # Update setter javadoc - content = content.replace( - "Sessions without activity for this duration are automatically cleaned up. Set\n * to {@code 0} or leave as {@code null} to disable (sessions live\n * indefinitely).", - "Sessions without activity for this duration are automatically cleaned up. Set\n * to {@code 0} to disable (sessions live indefinitely). Use\n * {@link #clearSessionIdleTimeoutSeconds()} to revert to the default." - ) - content = content.replace( - "@param sessionIdleTimeoutSeconds\n * the idle timeout in seconds, or {@code null} to disable", - "@param sessionIdleTimeoutSeconds\n * the idle timeout in seconds" - ) - - # Update useLoggedInUser getter javadoc - content = content.replace( - "@return {@code true} to use logged-in user auth, {@code false} to use only\n * explicit tokens, or {@code null} to use default behavior", - "@return an {@link Optional} containing the boolean value, or empty if not set" - ) - # Update useLoggedInUser setter javadoc - content = content.replace( - "Passing {@code null} is equivalent to passing {@link Boolean#FALSE}.\n *\n * @param useLoggedInUser\n * {@code true} to use logged-in user auth, {@code false} or\n * {@code null} otherwise", - "@param useLoggedInUser\n * {@code true} to use logged-in user auth, {@code false} otherwise" - ) - - write_file(path, content) - print(f" Refactored: {path}") - - -def refactor_session_config(): - path = os.path.join(JSON_PKG, "SessionConfig.java") - content = read_file(path) - - content = add_import(content, "import java.util.Optional;") - - for field in ["enableSessionTelemetry", "enableConfigDiscovery", "includeSubAgentStreamingEvents"]: - content = refactor_fluent_boolean_getter(content, field) - content = refactor_fluent_boolean_setter(content, field, "SessionConfig") - content = add_fluent_clear_method(content, field, "SessionConfig") - - write_file(path, content) - print(f" Refactored: {path}") - - -def refactor_resume_session_config(): - path = os.path.join(JSON_PKG, "ResumeSessionConfig.java") - content = read_file(path) - - content = add_import(content, "import java.util.Optional;") - - for field in ["enableSessionTelemetry", "enableConfigDiscovery", "includeSubAgentStreamingEvents"]: - content = refactor_fluent_boolean_getter(content, field) - content = refactor_fluent_boolean_setter(content, field, "ResumeSessionConfig") - content = add_fluent_clear_method(content, field, "ResumeSessionConfig") - - write_file(path, content) - print(f" Refactored: {path}") - - -def refactor_infinite_session_config(): - path = os.path.join(JSON_PKG, "InfiniteSessionConfig.java") - content = read_file(path) - - content = add_import(content, "import java.util.Optional;") - content = add_import(content, "import java.util.OptionalDouble;") - - # enabled: Boolean -> Optional - content = refactor_fluent_boolean_getter(content, "enabled") - content = refactor_fluent_boolean_setter(content, "enabled", "InfiniteSessionConfig") - content = add_fluent_clear_method(content, "enabled", "InfiniteSessionConfig") - - # backgroundCompactionThreshold: Double -> OptionalDouble - content = refactor_fluent_double_getter(content, "backgroundCompactionThreshold") - content = refactor_fluent_double_setter(content, "backgroundCompactionThreshold", "InfiniteSessionConfig") - content = add_fluent_clear_method(content, "backgroundCompactionThreshold", "InfiniteSessionConfig") - - # bufferExhaustionThreshold: Double -> OptionalDouble - content = refactor_fluent_double_getter(content, "bufferExhaustionThreshold") - content = refactor_fluent_double_setter(content, "bufferExhaustionThreshold", "InfiniteSessionConfig") - content = add_fluent_clear_method(content, "bufferExhaustionThreshold", "InfiniteSessionConfig") - - # Update javadoc - content = content.replace( - "@return {@code true} if enabled, {@code null} to use default (true)", - "@return an {@link Optional} containing the boolean value, or empty to use default (true)" - ) - content = content.replace( - "@return the threshold (0.0-1.0), or {@code null} to use default\n */\n public OptionalDouble getBackgroundCompactionThreshold()", - "@return an {@link OptionalDouble} containing the threshold (0.0-1.0), or empty to use default\n */\n public OptionalDouble getBackgroundCompactionThreshold()" - ) - content = content.replace( - "@return the threshold (0.0-1.0), or {@code null} to use default\n */\n public OptionalDouble getBufferExhaustionThreshold()", - "@return an {@link OptionalDouble} containing the threshold (0.0-1.0), or empty to use default\n */\n public OptionalDouble getBufferExhaustionThreshold()" - ) - - write_file(path, content) - print(f" Refactored: {path}") - - -def refactor_input_options(): - path = os.path.join(JSON_PKG, "InputOptions.java") - content = read_file(path) - - content = add_import(content, "import java.util.OptionalInt;") - - for field in ["minLength", "maxLength"]: - content = refactor_fluent_int_getter(content, field) - content = refactor_fluent_int_setter(content, field, "InputOptions") - content = add_fluent_clear_method(content, field, "InputOptions") - - write_file(path, content) - print(f" Refactored: {path}") - - -def refactor_model_capabilities_override(): - path = os.path.join(JSON_PKG, "ModelCapabilitiesOverride.java") - content = read_file(path) - - content = add_import(content, "import java.util.Optional;") - content = add_import(content, "import java.util.OptionalInt;") - - # Inner class Supports: vision, reasoningEffort (Boolean -> Optional) - for field in ["vision", "reasoningEffort"]: - content = refactor_inner_boolean_getter(content, field) - content = refactor_inner_boolean_setter(content, field, "Supports") - content = add_inner_fluent_clear(content, field, "Supports") - - # Inner class Limits: maxPromptTokens, maxOutputTokens, maxContextWindowTokens (Integer -> OptionalInt) - for field in ["maxPromptTokens", "maxOutputTokens", "maxContextWindowTokens"]: - content = refactor_inner_int_getter(content, field) - content = refactor_inner_int_setter(content, field, "Limits") - content = add_inner_fluent_clear(content, field, "Limits") - - write_file(path, content) - print(f" Refactored: {path}") - - -def refactor_provider_config(): - path = os.path.join(JSON_PKG, "ProviderConfig.java") - content = read_file(path) - - content = add_import(content, "import java.util.OptionalInt;") - - for field in ["maxPromptTokens", "maxOutputTokens"]: - content = refactor_fluent_int_getter(content, field) - content = refactor_fluent_int_setter(content, field, "ProviderConfig") - content = add_fluent_clear_method(content, field, "ProviderConfig") - - write_file(path, content) - print(f" Refactored: {path}") - - -def refactor_telemetry_config(): - path = os.path.join(JSON_PKG, "TelemetryConfig.java") - content = read_file(path) - - content = add_import(content, "import java.util.Optional;") - - content = refactor_fluent_boolean_getter(content, "captureContent") - content = refactor_fluent_boolean_setter(content, "captureContent", "TelemetryConfig") - content = add_fluent_clear_method(content, "captureContent", "TelemetryConfig") - - write_file(path, content) - print(f" Refactored: {path}") - - -def refactor_session_ui_capabilities(): - path = os.path.join(JSON_PKG, "SessionUiCapabilities.java") - content = read_file(path) - - content = add_import(content, "import java.util.Optional;") - - content = refactor_fluent_boolean_getter(content, "elicitation") - content = refactor_fluent_boolean_setter(content, "elicitation", "SessionUiCapabilities") - content = add_fluent_clear_method(content, "elicitation", "SessionUiCapabilities") - - write_file(path, content) - print(f" Refactored: {path}") - - -def refactor_custom_agent_config(): - path = os.path.join(JSON_PKG, "CustomAgentConfig.java") - content = read_file(path) - - content = add_import(content, "import java.util.Optional;") - - content = refactor_fluent_boolean_getter(content, "infer") - content = refactor_fluent_boolean_setter(content, "infer", "CustomAgentConfig") - content = add_fluent_clear_method(content, "infer", "CustomAgentConfig") - - write_file(path, content) - print(f" Refactored: {path}") - - -def refactor_user_input_request(): - path = os.path.join(JSON_PKG, "UserInputRequest.java") - content = read_file(path) - - content = add_import(content, "import java.util.Optional;") - - content = refactor_fluent_boolean_getter(content, "allowFreeform") - content = refactor_fluent_boolean_setter(content, "allowFreeform", "UserInputRequest") - content = add_fluent_clear_method(content, "allowFreeform", "UserInputRequest") - - write_file(path, content) - print(f" Refactored: {path}") - - -def refactor_create_session_request(): - path = os.path.join(JSON_PKG, "CreateSessionRequest.java") - content = read_file(path) - - content = add_import(content, "import java.util.Optional;") - - fields = ["enableSessionTelemetry", "requestPermission", "requestUserInput", - "hooks", "streaming", "enableConfigDiscovery", - "includeSubAgentStreamingEvents", "requestElicitation"] - - for field in fields: - content = refactor_void_boolean_getter(content, field) - content = refactor_void_boolean_setter(content, field) - content = add_void_clear_method(content, field) - - write_file(path, content) - print(f" Refactored: {path}") - - -def refactor_resume_session_request(): - path = os.path.join(JSON_PKG, "ResumeSessionRequest.java") - content = read_file(path) - - content = add_import(content, "import java.util.Optional;") - - fields = ["enableSessionTelemetry", "requestPermission", "requestUserInput", - "hooks", "enableConfigDiscovery", "disableResume", "streaming", - "includeSubAgentStreamingEvents", "requestElicitation"] - - for field in fields: - content = refactor_void_boolean_getter(content, field) - content = refactor_void_boolean_setter(content, field) - content = add_void_clear_method(content, field) - - write_file(path, content) - print(f" Refactored: {path}") - - -def refactor_mcp_server_config(): - path = os.path.join(JSON_PKG, "McpServerConfig.java") - content = read_file(path) - - content = add_import(content, "import java.util.OptionalInt;") - - content = refactor_fluent_int_getter(content, "timeout") - content = refactor_fluent_int_setter(content, "timeout", "McpServerConfig") - content = add_fluent_clear_method(content, "timeout", "McpServerConfig") - - # Update javadoc - content = content.replace( - "@return the timeout in milliseconds, or {@code null} for the default", - "@return an {@link OptionalInt} containing the timeout in milliseconds, or empty for the default" - ) - content = content.replace( - "@param timeout\n * the timeout in milliseconds, or {@code null} for the default", - "@param timeout\n * the timeout in milliseconds" - ) - - write_file(path, content) - print(f" Refactored: {path}") - - -def refactor_model_limits(): - path = os.path.join(JSON_PKG, "ModelLimits.java") - content = read_file(path) - - content = add_import(content, "import java.util.OptionalInt;") - - content = refactor_fluent_int_getter(content, "maxPromptTokens") - content = refactor_fluent_int_setter(content, "maxPromptTokens", "ModelLimits") - content = add_fluent_clear_method(content, "maxPromptTokens", "ModelLimits") - - write_file(path, content) - print(f" Refactored: {path}") - - -def refactor_session_request_builder(): - """Update SessionRequestBuilder to handle Optional returns from config.""" - path = os.path.join(BASE, "SessionRequestBuilder.java") - content = read_file(path) - - # The config getters now return Optional, so we need to use ifPresent - # Old: request.setEnableSessionTelemetry(config.getEnableSessionTelemetry()); - # New: config.getEnableSessionTelemetry().ifPresent(request::setEnableSessionTelemetry); - - # For create request: - content = content.replace( - "request.setEnableSessionTelemetry(config.getEnableSessionTelemetry());\n request.setRequestUserInput(config.getOnUserInputRequest() != null ? true : null);\n request.setHooks(config.getHooks() != null && config.getHooks().hasHooks() ? true : null);", - "config.getEnableSessionTelemetry().ifPresent(request::setEnableSessionTelemetry);\n if (config.getOnUserInputRequest() != null) {\n request.setRequestUserInput(true);\n }\n if (config.getHooks() != null && config.getHooks().hasHooks()) {\n request.setHooks(true);\n }" - ) - - content = content.replace( - "request.setStreaming(config.isStreaming() ? true : null);\n request.setIncludeSubAgentStreamingEvents(config.getIncludeSubAgentStreamingEvents());", - "if (config.isStreaming()) {\n request.setStreaming(true);\n }\n config.getIncludeSubAgentStreamingEvents().ifPresent(request::setIncludeSubAgentStreamingEvents);" - ) - - content = content.replace( - "request.setEnableConfigDiscovery(config.getEnableConfigDiscovery());\n request.setModelCapabilities(config.getModelCapabilities());", - "config.getEnableConfigDiscovery().ifPresent(request::setEnableConfigDiscovery);\n request.setModelCapabilities(config.getModelCapabilities());" - ) - - # For resume request: - content = content.replace( - "request.setEnableSessionTelemetry(config.getEnableSessionTelemetry());\n request.setRequestUserInput(config.getOnUserInputRequest() != null ? true : null);\n request.setHooks(config.getHooks() != null && config.getHooks().hasHooks() ? true : null);\n request.setWorkingDirectory(config.getWorkingDirectory());\n request.setConfigDir(config.getConfigDir());\n request.setEnableConfigDiscovery(config.getEnableConfigDiscovery());\n request.setDisableResume(config.isDisableResume() ? true : null);\n request.setStreaming(config.isStreaming() ? true : null);\n request.setIncludeSubAgentStreamingEvents(config.getIncludeSubAgentStreamingEvents());", - "config.getEnableSessionTelemetry().ifPresent(request::setEnableSessionTelemetry);\n if (config.getOnUserInputRequest() != null) {\n request.setRequestUserInput(true);\n }\n if (config.getHooks() != null && config.getHooks().hasHooks()) {\n request.setHooks(true);\n }\n request.setWorkingDirectory(config.getWorkingDirectory());\n request.setConfigDir(config.getConfigDir());\n config.getEnableConfigDiscovery().ifPresent(request::setEnableConfigDiscovery);\n if (config.isDisableResume()) {\n request.setDisableResume(true);\n }\n if (config.isStreaming()) {\n request.setStreaming(true);\n }\n config.getIncludeSubAgentStreamingEvents().ifPresent(request::setIncludeSubAgentStreamingEvents);" - ) - - write_file(path, content) - print(f" Refactored: {path}") - - -if __name__ == "__main__": - print("Refactoring to Optional return types...") - - refactor_copilot_client_options() - refactor_session_config() - refactor_resume_session_config() - refactor_infinite_session_config() - refactor_input_options() - refactor_model_capabilities_override() - refactor_provider_config() - refactor_telemetry_config() - refactor_session_ui_capabilities() - refactor_custom_agent_config() - refactor_user_input_request() - refactor_create_session_request() - refactor_resume_session_request() - refactor_mcp_server_config() - refactor_model_limits() - refactor_session_request_builder() - - print("\nDone! Run 'mvn spotless:apply' then 'mvn verify' to validate.") diff --git a/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java b/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java index af92baa7e2..09bd3ee385 100644 --- a/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java +++ b/src/test/java/com/github/copilot/sdk/ConfigCloneTest.java @@ -301,7 +301,7 @@ void copilotClientOptionsSetTelemetry() { } @Test - void copilotClientOptionsSetUseLoggedInUserClear() { + void copilotClientOptionsClearUseLoggedInUser() { var opts = new CopilotClientOptions(); opts.setUseLoggedInUser(true); opts.clearUseLoggedInUser();