Skip to content

Commit f6b5eef

Browse files
Copilotedburns
andauthored
Port model field for CustomAgentConfig from reference implementation
Adds a 'model' field to CustomAgentConfig allowing agents to specify a preferred model (e.g., 'claude-haiku-4.5'). When set, the runtime will attempt to use this model for the agent, falling back to the parent session model if unavailable. Reference: d0eb531 feat: add model field to CustomAgentConfig across all SDKs (#1309) Co-authored-by: edburns <75821+edburns@users.noreply.github.com>
1 parent d4e751d commit f6b5eef

2 files changed

Lines changed: 42 additions & 0 deletions

File tree

src/main/java/com/github/copilot/sdk/json/CustomAgentConfig.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ public class CustomAgentConfig {
6060
@JsonProperty("skills")
6161
private List<String> skills;
6262

63+
@JsonProperty("model")
64+
private String model;
65+
6366
/**
6467
* Gets the unique identifier name for this agent.
6568
*
@@ -255,4 +258,29 @@ public CustomAgentConfig setSkills(List<String> skills) {
255258
this.skills = skills;
256259
return this;
257260
}
261+
262+
/**
263+
* Gets the model identifier for this agent.
264+
*
265+
* @return the model identifier (e.g., "claude-haiku-4.5"), or {@code null} if
266+
* not set
267+
*/
268+
public String getModel() {
269+
return model;
270+
}
271+
272+
/**
273+
* Sets the model identifier for this agent.
274+
* <p>
275+
* When set, the runtime will attempt to use this model for the agent, falling
276+
* back to the parent session model if unavailable.
277+
*
278+
* @param model
279+
* the model identifier (e.g., "claude-haiku-4.5")
280+
* @return this config for method chaining
281+
*/
282+
public CustomAgentConfig setModel(String model) {
283+
this.model = model;
284+
return this;
285+
}
258286
}

src/test/java/com/github/copilot/sdk/PermissionsTest.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,17 @@ void testDenyPermission(TestInfo testInfo) throws Exception {
112112
try (CopilotClient client = ctx.createClient()) {
113113
CopilotSession session = client.createSession(config).get();
114114

115+
// Regression check for https://github.com/github/copilot-sdk/issues/1194:
116+
// the reject decision must round-trip through the CLI with its discriminator
117+
// intact so the agent surfaces the user-rejected error to the model.
118+
final boolean[] userRejectedToolCall = {false};
119+
session.on(ToolExecutionCompleteEvent.class, evt -> {
120+
if (!evt.getData().success() && evt.getData().error() != null && evt.getData().error().message() != null
121+
&& evt.getData().error().message().toLowerCase().contains("user rejected")) {
122+
userRejectedToolCall[0] = true;
123+
}
124+
});
125+
115126
String originalContent = "protected content";
116127
Path testFile = ctx.getWorkDir().resolve("protected.txt");
117128
Files.writeString(testFile, originalContent);
@@ -120,6 +131,9 @@ void testDenyPermission(TestInfo testInfo) throws Exception {
120131
new MessageOptions().setPrompt("Edit protected.txt and replace 'protected' with 'hacked'."))
121132
.get(60, TimeUnit.SECONDS);
122133

134+
assertTrue(userRejectedToolCall[0],
135+
"Expected a tool.execution_complete event whose error indicates the user rejected the call.");
136+
123137
// Verify the file was NOT modified
124138
String content = Files.readString(testFile);
125139
assertEquals(originalContent, content, "File should not have been modified");

0 commit comments

Comments
 (0)