Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,19 @@ All notable changes to this project will be documented in this file. This change

## [Unreleased]

### Added (documentation)
### Added (v0.1.27 sync)
- `list-agents` — list available custom agents for a session (`session/list-agents`) (upstream PR #544).
- `current-agent` — get the currently selected custom agent (`session/current-agent`) (upstream PR #544).
- `select-agent!` — select a custom agent by name (`session/select-agent!`) (upstream PR #544).
- `deselect-agent!` — deselect the current agent, reverting to default Copilot agent (`session/deselect-agent!`) (upstream PR #544).
- `compact!` — manually compact session history to free up context window space (`session/compact!`) (upstream PR #544).
- `:copilot/session.task_complete` event type — emitted when a task is complete (upstream PR #544).
- `:custom-tool` permission kind — permission requests now include SDK-registered custom tools (upstream PR #555).

### Changed (v0.1.27 sync)
- **BREAKING**: `:on-permission-request` is now required in `create-session` and `resume-session` configs. Omitting the handler now throws an explicit error: `"An :on-permission-request handler is required when creating a session"` (upstream PR #554).
- Removed 0-arity overloads of `create-session`, `<create-session`, `resume-session`, and `<resume-session` — the config map argument is now required (upstream PR #554).

- Microsoft Foundry Local BYOK provider guide in `doc/auth/byok.md`: quick start example, installation instructions, and connection troubleshooting (upstream PR #461).

### Added (upstream PR #329 sync)
Expand Down
48 changes: 47 additions & 1 deletion doc/reference/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ Create a client and session together, ensuring both are cleaned up on exit.
| `:provider` | map | Provider config for BYOK (see [BYOK docs](../auth/byok.md)). Required key: `:base-url`. Optional: `:provider-type` (`:openai`/`:azure`/`:anthropic`), `:wire-api` (`:completions`/`:responses`), `:api-key`, `:bearer-token`, `:azure-options` |
| `:mcp-servers` | map | MCP server configs keyed by server ID (see [MCP docs](../mcp/overview.md)). Local servers: `:mcp-command`, `:mcp-args`, `:mcp-tools`. Remote servers: `:mcp-server-type` (`:http`/`:sse`), `:mcp-url`, `:mcp-tools` |
| `:custom-agents` | vector | Custom agent configs |
| `:on-permission-request` | fn | Permission handler function. Without a handler, all permissions are denied (deny-by-default). Use `copilot/approve-all` to approve everything. |
| `:on-permission-request` | fn | **Required.** Permission handler function. Use `copilot/approve-all` to approve everything, or provide a custom function. |
| `:streaming?` | boolean | Enable streaming deltas |
| `:config-dir` | string | Override config directory for CLI |
| `:skill-directories` | vector | Additional skill directories to load |
Expand Down Expand Up @@ -766,6 +766,51 @@ Switch the model for this session mid-conversation. Returns the new model ID str
;; After: claude-sonnet-4.5
```

#### `list-agents`

```clojure
(session/list-agents session)
;; => {:agents [{:name "my-agent" :display-name "My Agent" :description "..."}]}
```

List available custom agents for this session. Returns a map with `:agents` — a vector of agent maps.

#### `current-agent`

```clojure
(session/current-agent session)
;; => {:agent {:name "my-agent" :display-name "My Agent"}}
```

Get the currently selected custom agent. Returns a map with `:agent` (or nil if no agent selected).

#### `select-agent!`

```clojure
(session/select-agent! session "my-agent")
;; => {:agent {:name "my-agent" :display-name "My Agent"}}
```

Select a custom agent by name. Returns a map with `:agent`.

#### `deselect-agent!`

```clojure
(session/deselect-agent! session)
;; => {}
```

Deselect the current custom agent, reverting to the default Copilot agent.

#### `compact!`

```clojure
(session/compact! session)
;; => {:success? true :tokens-removed 1200 :messages-removed 5}
```

Manually compact session history to free up context window space. Returns a map with `:success?`, `:tokens-removed`, and `:messages-removed`.

#### `destroy!`

```clojure
Expand Down Expand Up @@ -853,6 +898,7 @@ copilot/tool-events
| `:copilot/session.snapshot_rewind` | Session state rolled back |
| `:copilot/session.compaction_start` | Context compaction started (infinite sessions) |
| `:copilot/session.compaction_complete` | Context compaction completed (infinite sessions) |
| `:copilot/session.task_complete` | Task complete signal emitted by the session |
| `:copilot/skill.invoked` | Skill invocation triggered |
| `:copilot/user.message` | User message added |
| `:copilot/pending_messages.modified` | Pending message queue updated |
Expand Down
5 changes: 4 additions & 1 deletion src/github/copilot_sdk.clj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
(copilot/start! client)

;; Create a session
(def session (copilot/create-session client {:model \"gpt-5.2\"}))
(def session (copilot/create-session client {:on-permission-request copilot/approve-all
:model \"gpt-5.2\"}))

;; Send a message and wait for response
(def response (copilot/send-and-wait! session {:prompt \"What is 2+2?\"}))
Expand Down Expand Up @@ -42,6 +43,7 @@
:copilot/session.usage_info
:copilot/session.compaction_start
:copilot/session.compaction_complete
:copilot/session.task_complete
:copilot/session.shutdown
:copilot/session.context_changed
:copilot/session.title_changed
Expand Down Expand Up @@ -85,6 +87,7 @@
:copilot/session.usage_info
:copilot/session.compaction_start
:copilot/session.compaction_complete
:copilot/session.task_complete
:copilot/session.shutdown
:copilot/session.context_changed
:copilot/session.title_changed
Expand Down
21 changes: 11 additions & 10 deletions src/github/copilot_sdk/client.clj
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,9 @@
(defn- validate-session-config!
"Validate session config, throwing on invalid input."
[config]
(when-not (:on-permission-request config)
(throw (ex-info "An :on-permission-request handler is required when creating a session. For example, to allow all permissions, use {:on-permission-request copilot/approve-all}."
{:config config})))
(when-not (s/valid? ::specs/session-config config)
(let [unknown (specs/unknown-keys config specs/session-config-keys)
explain (s/explain-data ::specs/session-config config)
Expand Down Expand Up @@ -1038,6 +1041,7 @@
"Create a new conversation session.

Config options:
- :on-permission-request - (Required) Permission handler function. Use `approve-all` to approve everything.
- :session-id - Custom session ID
- :client-name - Client name to identify the application (included in User-Agent header)
- :model - Model to use (e.g., \"gpt-5.2\")
Expand All @@ -1046,7 +1050,6 @@
- :available-tools - List of allowed tool names
- :excluded-tools - List of excluded tool names
- :provider - Custom provider config (BYOK)
- :on-permission-request - Permission handler function
- :streaming? - Enable streaming
- :mcp-servers - MCP server configs map
- :custom-agents - Custom agent configs
Expand All @@ -1067,8 +1070,6 @@
:on-session-start, :on-session-end, :on-error-occurred}

Returns a CopilotSession."
([client]
(create-session client {}))
([client config]
(log/debug "Creating session with config: " (select-keys config [:model :session-id]))
(validate-session-config! config)
Expand All @@ -1084,6 +1085,7 @@
"Resume an existing session by ID.

Config options (parity with create-session, upstream PR #376):
- :on-permission-request - (Required) Permission handler. Use `approve-all` to approve everything.
- :client-name - Client name to identify the application (included in User-Agent header)
- :model - Change the model for the resumed session
- :tools - Tools exposed to the CLI server
Expand All @@ -1092,7 +1094,6 @@
- :excluded-tools - List of tool names to disable
- :provider - Custom provider configuration (BYOK)
- :streaming? - Enable streaming responses
- :on-permission-request - Permission handler
- :mcp-servers - MCP server configurations
- :custom-agents - Custom agent configurations
- :config-dir - Override configuration directory
Expand All @@ -1104,9 +1105,10 @@
- :hooks - Lifecycle hooks map

Returns a CopilotSession."
([client session-id]
(resume-session client session-id {}))
([client session-id config]
(when-not (:on-permission-request config)
(throw (ex-info "An :on-permission-request handler is required when resuming a session. For example, to allow all permissions, use {:on-permission-request copilot/approve-all}."
{:config config})))
(when-not (s/valid? ::specs/resume-session-config config)
(throw (ex-info "Invalid resume session config"
{:config config
Expand Down Expand Up @@ -1138,8 +1140,6 @@
(println \"Error:\" (ex-message result))
;; use result as session
)))"
([client]
(<create-session client {}))
([client config]
(log/debug "Creating session (async) with config: " (select-keys config [:model :session-id]))
(validate-session-config! config)
Expand Down Expand Up @@ -1175,9 +1175,10 @@
(println \"Error:\" (ex-message result))
;; use result as session
)))"
([client session-id]
(<resume-session client session-id {}))
([client session-id config]
(when-not (:on-permission-request config)
(throw (ex-info "An :on-permission-request handler is required when resuming a session. For example, to allow all permissions, use {:on-permission-request copilot/approve-all}."
{:config config})))
(when-not (s/valid? ::specs/resume-session-config config)
(throw (ex-info "Invalid resume session config"
{:config config
Expand Down
39 changes: 35 additions & 4 deletions src/github/copilot_sdk/instrument.clj
Original file line number Diff line number Diff line change
Expand Up @@ -48,24 +48,24 @@

(s/fdef github.copilot-sdk.client/create-session
:args (s/cat :client ::specs/client
:config (s/? ::specs/session-config))
:config ::specs/session-config)
:ret ::specs/session)

(s/fdef github.copilot-sdk.client/resume-session
:args (s/cat :client ::specs/client
:session-id ::specs/session-id
:config (s/? ::specs/resume-session-config))
:config ::specs/resume-session-config)
:ret ::specs/session)

(s/fdef github.copilot-sdk.client/<create-session
:args (s/cat :client ::specs/client
:config (s/? ::specs/session-config))
:config ::specs/session-config)
:ret ::specs/events-ch)

(s/fdef github.copilot-sdk.client/<resume-session
:args (s/cat :client ::specs/client
:session-id ::specs/session-id
:config (s/? ::specs/resume-session-config))
:config ::specs/resume-session-config)
:ret ::specs/events-ch)

(s/fdef github.copilot-sdk.client/list-sessions
Expand Down Expand Up @@ -210,6 +210,27 @@
:model-id string?)
:ret ::specs/model-id)

(s/fdef github.copilot-sdk.session/list-agents
:args (s/cat :session ::specs/session)
:ret map?)

(s/fdef github.copilot-sdk.session/current-agent
:args (s/cat :session ::specs/session)
:ret map?)

(s/fdef github.copilot-sdk.session/select-agent!
:args (s/cat :session ::specs/session
:agent-name string?)
:ret map?)

(s/fdef github.copilot-sdk.session/deselect-agent!
:args (s/cat :session ::specs/session)
:ret map?)

(s/fdef github.copilot-sdk.session/compact!
:args (s/cat :session ::specs/session)
:ret map?)

;; -----------------------------------------------------------------------------
;; Function specs for helpers namespace
;; -----------------------------------------------------------------------------
Expand Down Expand Up @@ -275,6 +296,11 @@
github.copilot-sdk.session/workspace-path
github.copilot-sdk.session/get-current-model
github.copilot-sdk.session/switch-model!
github.copilot-sdk.session/list-agents
github.copilot-sdk.session/current-agent
github.copilot-sdk.session/select-agent!
github.copilot-sdk.session/deselect-agent!
github.copilot-sdk.session/compact!
github.copilot-sdk.session/events
github.copilot-sdk.session/subscribe-events
github.copilot-sdk.session/unsubscribe-events
Expand Down Expand Up @@ -322,6 +348,11 @@
github.copilot-sdk.session/workspace-path
github.copilot-sdk.session/get-current-model
github.copilot-sdk.session/switch-model!
github.copilot-sdk.session/list-agents
github.copilot-sdk.session/current-agent
github.copilot-sdk.session/select-agent!
github.copilot-sdk.session/deselect-agent!
github.copilot-sdk.session/compact!
github.copilot-sdk.session/events
github.copilot-sdk.session/subscribe-events
github.copilot-sdk.session/unsubscribe-events
Expand Down
55 changes: 55 additions & 0 deletions src/github/copilot_sdk/session.clj
Original file line number Diff line number Diff line change
Expand Up @@ -723,3 +723,58 @@
{:sessionId session-id
:modelId model-id})]
(:model-id result)))

;; -----------------------------------------------------------------------------
;; Agent selection API (upstream PR #544)
;; -----------------------------------------------------------------------------

(defn list-agents
"List available custom agents for this session.
Returns a map with :agents — a vector of agent maps, each with :name, :display-name, :description."
[session]
(let [{:keys [session-id client]} session
conn (connection-io client)
result (proto/send-request! conn "session.agent.list" {:sessionId session-id})]
result))

(defn current-agent
"Get the currently selected custom agent for this session.
Returns a map with :agent — the selected agent map (or nil if no agent is selected)."
[session]
(let [{:keys [session-id client]} session
conn (connection-io client)
result (proto/send-request! conn "session.agent.getCurrent" {:sessionId session-id})]
result))

(defn select-agent!
"Select a custom agent for this session by name.
agent-name — the name of the custom agent to select.
Returns a map with :agent — the selected agent."
[session agent-name]
(let [{:keys [session-id client]} session
conn (connection-io client)
result (proto/send-request! conn "session.agent.select"
{:sessionId session-id :name agent-name})]
result))

(defn deselect-agent!
"Deselect the current custom agent, reverting to the default Copilot agent.
Returns an empty map."
[session]
(let [{:keys [session-id client]} session
conn (connection-io client)
result (proto/send-request! conn "session.agent.deselect" {:sessionId session-id})]
result))

;; -----------------------------------------------------------------------------
;; Session compaction API (upstream PR #544)
;; -----------------------------------------------------------------------------

(defn compact!
"Manually compact session history to free up context window space.
Returns a map with :success?, :tokens-removed, :messages-removed."
[session]
(let [{:keys [session-id client]} session
conn (connection-io client)
result (proto/send-request! conn "session.compaction.compact" {:sessionId session-id})]
result))
13 changes: 8 additions & 5 deletions src/github/copilot_sdk/specs.clj
Original file line number Diff line number Diff line change
Expand Up @@ -208,9 +208,10 @@

(s/def ::session-config
(closed-keys
(s/keys :opt-un [::session-id ::client-name ::model ::tools ::system-message
(s/keys :req-un [::on-permission-request]
:opt-un [::session-id ::client-name ::model ::tools ::system-message
::available-tools ::excluded-tools ::provider
::on-permission-request ::streaming? ::mcp-servers
::streaming? ::mcp-servers
::custom-agents ::config-dir ::skill-directories
::disabled-skills ::large-output ::infinite-sessions
::reasoning-effort ::on-user-input-request ::hooks
Expand All @@ -226,8 +227,9 @@

(s/def ::resume-session-config
(closed-keys
(s/keys :opt-un [::client-name ::model ::tools ::system-message ::available-tools ::excluded-tools
::provider ::streaming? ::on-permission-request
(s/keys :req-un [::on-permission-request]
:opt-un [::client-name ::model ::tools ::system-message ::available-tools ::excluded-tools
::provider ::streaming?
::mcp-servers ::custom-agents ::config-dir ::skill-directories
::disabled-skills ::infinite-sessions ::reasoning-effort
::on-user-input-request ::hooks ::working-directory ::disable-resume?])
Expand Down Expand Up @@ -352,6 +354,7 @@
:copilot/session.info :copilot/session.model_change :copilot/session.handoff
:copilot/session.truncation :copilot/session.snapshot_rewind :copilot/session.usage_info
:copilot/session.compaction_start :copilot/session.compaction_complete
:copilot/session.task_complete
:copilot/session.shutdown
:copilot/session.title_changed :copilot/session.warning :copilot/session.context_changed
:copilot/user.message :copilot/pending_messages.modified
Expand Down Expand Up @@ -470,7 +473,7 @@
;; Permission types
;; -----------------------------------------------------------------------------

(s/def ::permission-kind #{:shell :write :mcp :read :url})
(s/def ::permission-kind #{:shell :write :mcp :read :url :custom-tool})

(s/def ::permission-request
(s/keys :req-un [::permission-kind]
Expand Down
Loading