From 2bd0f18d7cc290e74e782122e594d28c9998f6dd Mon Sep 17 00:00:00 2001 From: GitHub Copilot Date: Wed, 25 Feb 2026 14:22:08 +0000 Subject: [PATCH] Port upstream PRs #544, #554, #555: agent selection, compaction, required permission handler, custom-tool kind - PR #554: Make :on-permission-request required in create-session and resume-session. Adds explicit validation with helpful error message. Removes 0-arity overloads. event type. - PR #555: Add :custom-tool to permission-kind spec. - Update integration tests: replace test-permission-denied-without-handler with test-permission-required-on-create (tests the new throwing behavior); add :on-permission-request to all remaining test calls; add :custom-tool to test-approve-all-returns-approved doseq. - Update e2e tests: add :on-permission-request sdk/approve-all to all session creation calls. - Update instrument.clj: add fdefs for 5 new session functions; update session creation fdefs to require config (no more optional). - Update docs: mark :on-permission-request as Required; add agent/compaction function docs; add session.task_complete to event type table. - Update CHANGELOG.md: document all 3 ported PRs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- CHANGELOG.md | 14 +- doc/reference/API.md | 48 ++++++- src/github/copilot_sdk.clj | 5 +- src/github/copilot_sdk/client.clj | 21 +-- src/github/copilot_sdk/instrument.clj | 39 +++++- src/github/copilot_sdk/session.clj | 55 ++++++++ src/github/copilot_sdk/specs.clj | 13 +- test/github/copilot_sdk/e2e_test.clj | 32 ++--- test/github/copilot_sdk/integration_test.clj | 129 ++++++++++--------- 9 files changed, 256 insertions(+), 100 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f41aa57..a8c6237 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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`, ` {: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 @@ -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 | diff --git a/src/github/copilot_sdk.clj b/src/github/copilot_sdk.clj index 1f081e3..001d8b0 100644 --- a/src/github/copilot_sdk.clj +++ b/src/github/copilot_sdk.clj @@ -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?\"})) @@ -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 @@ -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 diff --git a/src/github/copilot_sdk/client.clj b/src/github/copilot_sdk/client.clj index 3384041..5d4a0b1 100644 --- a/src/github/copilot_sdk/client.clj +++ b/src/github/copilot_sdk/client.clj @@ -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) @@ -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\") @@ -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 @@ -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) @@ -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 @@ -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 @@ -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 @@ -1138,8 +1140,6 @@ (println \"Error:\" (ex-message result)) ;; use result as session )))" - ([client] - (