Skip to content

Commit 8ca33be

Browse files
committed
feat: add skills configuration and event handling features
1 parent 917f24f commit 8ca33be

12 files changed

Lines changed: 892 additions & 18 deletions

File tree

β€Žsrc/main/java/com/github/copilot/sdk/CopilotClient.javaβ€Ž

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,9 @@ public CompletableFuture<CopilotSession> createSession(SessionConfig config) {
428428
request.setMcpServers(config.getMcpServers());
429429
request.setCustomAgents(config.getCustomAgents());
430430
request.setInfiniteSessions(config.getInfiniteSessions());
431+
request.setSkillDirectories(config.getSkillDirectories());
432+
request.setDisabledSkills(config.getDisabledSkills());
433+
request.setConfigDir(config.getConfigDir());
431434
}
432435

433436
return connection.rpc.invoke("session.create", request, CreateSessionResponse.class).thenApply(response -> {

β€Žsrc/main/java/com/github/copilot/sdk/CopilotSession.javaβ€Ž

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,52 @@ public Closeable on(Consumer<AbstractSessionEvent> handler) {
305305
return () -> eventHandlers.remove(handler);
306306
}
307307

308+
/**
309+
* Registers an event handler for a specific event type.
310+
* <p>
311+
* This provides a type-safe way to handle specific events without needing
312+
* {@code instanceof} checks. The handler will only be called for events
313+
* matching the specified type.
314+
*
315+
* <h2>Example Usage</h2>
316+
*
317+
* <pre>{@code
318+
* // Handle assistant messages
319+
* session.on(AssistantMessageEvent.class, msg -> {
320+
* System.out.println(msg.getData().getContent());
321+
* });
322+
*
323+
* // Handle session idle
324+
* session.on(SessionIdleEvent.class, idle -> {
325+
* done.complete(null);
326+
* });
327+
*
328+
* // Handle streaming deltas
329+
* session.on(AssistantMessageDeltaEvent.class, delta -> {
330+
* System.out.print(delta.getData().getDeltaContent());
331+
* });
332+
* }</pre>
333+
*
334+
* @param <T>
335+
* the event type
336+
* @param eventType
337+
* the class of the event to listen for
338+
* @param handler
339+
* a callback invoked when events of this type occur
340+
* @return a Closeable that unsubscribes the handler when closed
341+
* @see #on(Consumer)
342+
* @see AbstractSessionEvent
343+
*/
344+
public <T extends AbstractSessionEvent> Closeable on(Class<T> eventType, Consumer<T> handler) {
345+
Consumer<AbstractSessionEvent> wrapper = event -> {
346+
if (eventType.isInstance(event)) {
347+
handler.accept(eventType.cast(event));
348+
}
349+
};
350+
eventHandlers.add(wrapper);
351+
return () -> eventHandlers.remove(wrapper);
352+
}
353+
308354
/**
309355
* Dispatches an event to all registered handlers.
310356
* <p>

β€Žsrc/main/java/com/github/copilot/sdk/json/CreateSessionRequest.javaβ€Ž

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,15 @@ public final class CreateSessionRequest {
6060
@JsonProperty("infiniteSessions")
6161
private InfiniteSessionConfig infiniteSessions;
6262

63+
@JsonProperty("skillDirectories")
64+
private List<String> skillDirectories;
65+
66+
@JsonProperty("disabledSkills")
67+
private List<String> disabledSkills;
68+
69+
@JsonProperty("configDir")
70+
private String configDir;
71+
6372
/** Gets the model name. @return the model */
6473
public String getModel() {
6574
return model;
@@ -179,4 +188,34 @@ public InfiniteSessionConfig getInfiniteSessions() {
179188
public void setInfiniteSessions(InfiniteSessionConfig infiniteSessions) {
180189
this.infiniteSessions = infiniteSessions;
181190
}
191+
192+
/** Gets skill directories. @return the skill directories */
193+
public List<String> getSkillDirectories() {
194+
return skillDirectories;
195+
}
196+
197+
/** Sets skill directories. @param skillDirectories the directories */
198+
public void setSkillDirectories(List<String> skillDirectories) {
199+
this.skillDirectories = skillDirectories;
200+
}
201+
202+
/** Gets disabled skills. @return the disabled skill names */
203+
public List<String> getDisabledSkills() {
204+
return disabledSkills;
205+
}
206+
207+
/** Sets disabled skills. @param disabledSkills the skill names to disable */
208+
public void setDisabledSkills(List<String> disabledSkills) {
209+
this.disabledSkills = disabledSkills;
210+
}
211+
212+
/** Gets config directory. @return the config directory path */
213+
public String getConfigDir() {
214+
return configDir;
215+
}
216+
217+
/** Sets config directory. @param configDir the config directory path */
218+
public void setConfigDir(String configDir) {
219+
this.configDir = configDir;
220+
}
182221
}

β€Žsrc/main/java/com/github/copilot/sdk/json/SessionConfig.javaβ€Ž

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ public class SessionConfig {
4343
private Map<String, Object> mcpServers;
4444
private List<CustomAgentConfig> customAgents;
4545
private InfiniteSessionConfig infiniteSessions;
46+
private List<String> skillDirectories;
47+
private List<String> disabledSkills;
48+
private String configDir;
4649

4750
/**
4851
* Gets the custom session ID.
@@ -338,4 +341,77 @@ public SessionConfig setInfiniteSessions(InfiniteSessionConfig infiniteSessions)
338341
this.infiniteSessions = infiniteSessions;
339342
return this;
340343
}
344+
345+
/**
346+
* Gets the skill directories.
347+
*
348+
* @return the list of skill directory paths
349+
*/
350+
public List<String> getSkillDirectories() {
351+
return skillDirectories;
352+
}
353+
354+
/**
355+
* Sets the skill directories for loading custom skills.
356+
* <p>
357+
* Skills are loaded from SKILL.md files in subdirectories of the specified
358+
* directories. Each skill subdirectory should contain a SKILL.md file with YAML
359+
* frontmatter defining the skill metadata.
360+
*
361+
* @param skillDirectories
362+
* the list of skill directory paths
363+
* @return this config instance for method chaining
364+
*/
365+
public SessionConfig setSkillDirectories(List<String> skillDirectories) {
366+
this.skillDirectories = skillDirectories;
367+
return this;
368+
}
369+
370+
/**
371+
* Gets the disabled skill names.
372+
*
373+
* @return the list of disabled skill names
374+
*/
375+
public List<String> getDisabledSkills() {
376+
return disabledSkills;
377+
}
378+
379+
/**
380+
* Sets the list of skill names to disable.
381+
* <p>
382+
* Skills in this list will not be applied to the session, even if they are
383+
* found in the skill directories.
384+
*
385+
* @param disabledSkills
386+
* the list of skill names to disable
387+
* @return this config instance for method chaining
388+
*/
389+
public SessionConfig setDisabledSkills(List<String> disabledSkills) {
390+
this.disabledSkills = disabledSkills;
391+
return this;
392+
}
393+
394+
/**
395+
* Gets the custom configuration directory.
396+
*
397+
* @return the config directory path
398+
*/
399+
public String getConfigDir() {
400+
return configDir;
401+
}
402+
403+
/**
404+
* Sets a custom configuration directory for the session.
405+
* <p>
406+
* This allows using a specific directory for session configuration instead of
407+
* the default location.
408+
*
409+
* @param configDir
410+
* the configuration directory path
411+
* @return this config instance for method chaining
412+
*/
413+
public SessionConfig setConfigDir(String configDir) {
414+
this.configDir = configDir;
415+
return this;
416+
}
341417
}

β€Žsrc/site/markdown/advanced.mdβ€Ž

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,22 @@ var session = client.createSession(
130130
String workspace = session.getWorkspacePath();
131131
```
132132

133+
### Compaction Events
134+
135+
When compaction occurs, the session emits events that you can listen for:
136+
137+
```java
138+
session.on(event -> {
139+
if (event instanceof SessionCompactionStartEvent start) {
140+
System.out.println("Compaction started");
141+
} else if (event instanceof SessionCompactionCompleteEvent complete) {
142+
var data = complete.getData();
143+
System.out.println("Compaction completed - success: " + data.isSuccess()
144+
+ ", tokens removed: " + data.getTokensRemoved());
145+
}
146+
});
147+
```
148+
133149
For short conversations, disable to avoid overhead:
134150

135151
```java
@@ -160,6 +176,63 @@ var session = client.createSession(
160176

161177
---
162178

179+
## Skills Configuration
180+
181+
Load custom skills from directories to extend the AI's capabilities with domain-specific knowledge.
182+
183+
### Loading Skills
184+
185+
Skills are loaded from `SKILL.md` files in subdirectories of the specified skill directories:
186+
187+
```java
188+
var session = client.createSession(
189+
new SessionConfig()
190+
.setSkillDirectories(List.of("/path/to/skills"))
191+
).get();
192+
```
193+
194+
Each skill subdirectory should contain a `SKILL.md` file with YAML frontmatter:
195+
196+
```markdown
197+
---
198+
name: my-skill
199+
description: A skill that provides domain-specific knowledge
200+
---
201+
202+
# Skill Instructions
203+
204+
Your skill instructions go here...
205+
```
206+
207+
### Disabling Skills
208+
209+
Disable specific skills by name:
210+
211+
```java
212+
var session = client.createSession(
213+
new SessionConfig()
214+
.setSkillDirectories(List.of("/path/to/skills"))
215+
.setDisabledSkills(List.of("my-skill"))
216+
).get();
217+
```
218+
219+
---
220+
221+
## Custom Configuration Directory
222+
223+
Use a custom configuration directory for session settings:
224+
225+
```java
226+
var session = client.createSession(
227+
new SessionConfig()
228+
.setConfigDir("/path/to/custom/config")
229+
).get();
230+
```
231+
232+
This is useful when you need to isolate session configuration or use different settings for different environments.
233+
234+
---
235+
163236
## Permission Handling
164237

165238
Approve or deny permission requests from the AI.

β€Žsrc/site/markdown/documentation.mdβ€Ž

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -58,20 +58,39 @@ For more control, subscribe to events and use `send()`:
5858
```java
5959
var done = new CompletableFuture<Void>();
6060

61-
session.on(event -> {
62-
if (event instanceof AssistantMessageEvent msg) {
63-
System.out.println("Response: " + msg.getData().getContent());
64-
} else if (event instanceof SessionErrorEvent err) {
65-
System.err.println("Error: " + err.getData().getMessage());
66-
} else if (event instanceof SessionIdleEvent) {
67-
done.complete(null);
68-
}
61+
// Type-safe event handlers (recommended)
62+
session.on(AssistantMessageEvent.class, msg -> {
63+
System.out.println("Response: " + msg.getData().getContent());
64+
});
65+
66+
session.on(SessionErrorEvent.class, err -> {
67+
System.err.println("Error: " + err.getData().getMessage());
68+
});
69+
70+
session.on(SessionIdleEvent.class, idle -> {
71+
done.complete(null);
6972
});
7073

7174
session.send("Tell me a joke").get();
7275
done.get(); // Wait for completion
7376
```
7477

78+
You can also use a single handler for all events:
79+
80+
```java
81+
session.on(event -> {
82+
switch (event) {
83+
case AssistantMessageEvent msg ->
84+
System.out.println("Response: " + msg.getData().getContent());
85+
case SessionErrorEvent err ->
86+
System.err.println("Error: " + err.getData().getMessage());
87+
case SessionIdleEvent idle ->
88+
done.complete(null);
89+
default -> { }
90+
}
91+
});
92+
```
93+
7594
### Key Event Types
7695

7796
| Event | Description |
@@ -82,6 +101,9 @@ done.get(); // Wait for completion
82101
| `SessionErrorEvent` | An error occurred |
83102
| `ToolExecutionStartEvent` | Tool invocation started |
84103
| `ToolExecutionCompleteEvent` | Tool invocation completed |
104+
| `SessionCompactionStartEvent` | Context compaction started (infinite sessions) |
105+
| `SessionCompactionCompleteEvent` | Context compaction completed |
106+
| `SessionUsageInfoEvent` | Token usage information |
85107

86108
See the [events package Javadoc](apidocs/com/github/copilot/sdk/events/package-summary.html) for all event types.
87109

@@ -185,6 +207,6 @@ client.deleteSession(sessionId).get();
185207

186208
## Next Steps
187209

188-
- πŸ“– **[Advanced Usage](advanced.html)** - Tools, BYOK, MCP Servers, System Messages, Infinite Sessions
210+
- πŸ“– **[Advanced Usage](advanced.html)** - Tools, BYOK, MCP Servers, System Messages, Infinite Sessions, Skills
189211
- πŸ“– **[MCP Servers](mcp.html)** - Integrate external tools via Model Context Protocol
190212
- πŸ“– **[API Javadoc](apidocs/index.html)** - Complete API reference

β€Žsrc/site/markdown/index.mdβ€Ž

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public class Example {
6969
| Document | Description |
7070
|----------|-------------|
7171
| [Documentation](documentation.html) | Basic usage, streaming, handling responses, and session management |
72-
| [Advanced Usage](advanced.html) | Tools, BYOK, MCP servers, infinite sessions, and more |
72+
| [Advanced Usage](advanced.html) | Tools, BYOK, MCP servers, infinite sessions, skills, and more |
7373
| [MCP Servers](mcp.html) | Integrating Model Context Protocol servers |
7474
| [Javadoc](apidocs/index.html) | Generated API documentation |
7575

0 commit comments

Comments
Β (0)