Skip to content

Commit 9c32956

Browse files
committed
Merge remote-tracking branch 'origin/main' into mackinnonbuck/add-session-idle-timeout-option
2 parents ede32da + a3e273c commit 9c32956

70 files changed

Lines changed: 23441 additions & 19015 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/features/custom-agents.md

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,154 @@ const session = await client.createSession({
759759

760760
> **Note:** When `tools` is `null` or omitted, the agent inherits access to all tools configured on the session. Use explicit tool lists to enforce the principle of least privilege.
761761
762+
## Agent-Exclusive Tools
763+
764+
Use the `defaultAgent` property on the session configuration to hide specific tools from the default agent (the built-in agent that handles turns when no custom agent is selected). This forces the main agent to delegate to sub-agents when those tools' capabilities are needed, keeping the main agent's context clean.
765+
766+
This is useful when:
767+
- Certain tools generate large amounts of context that would overwhelm the main agent
768+
- You want the main agent to act as an orchestrator, delegating heavy work to specialized sub-agents
769+
- You need strict separation between orchestration and execution
770+
771+
<details open>
772+
<summary><strong>Node.js / TypeScript</strong></summary>
773+
774+
```typescript
775+
import { CopilotClient, defineTool, approveAll } from "@github/copilot-sdk";
776+
import { z } from "zod";
777+
778+
const heavyContextTool = defineTool("analyze-codebase", {
779+
description: "Performs deep analysis of the codebase, generating extensive context",
780+
parameters: z.object({ query: z.string() }),
781+
handler: async ({ query }) => {
782+
// ... expensive analysis that returns lots of data
783+
return { analysis: "..." };
784+
},
785+
});
786+
787+
const session = await client.createSession({
788+
tools: [heavyContextTool],
789+
defaultAgent: {
790+
excludedTools: ["analyze-codebase"],
791+
},
792+
customAgents: [
793+
{
794+
name: "researcher",
795+
description: "Deep codebase analysis agent with access to heavy-context tools",
796+
tools: ["analyze-codebase"],
797+
prompt: "You perform thorough codebase analysis using the analyze-codebase tool.",
798+
},
799+
],
800+
});
801+
```
802+
803+
</details>
804+
805+
<details>
806+
<summary><strong>Python</strong></summary>
807+
808+
```python
809+
from copilot import CopilotClient
810+
from copilot.tools import Tool
811+
812+
heavy_tool = Tool(
813+
name="analyze-codebase",
814+
description="Performs deep analysis of the codebase",
815+
handler=analyze_handler,
816+
parameters={"type": "object", "properties": {"query": {"type": "string"}}},
817+
)
818+
819+
session = await client.create_session(
820+
tools=[heavy_tool],
821+
default_agent={"excluded_tools": ["analyze-codebase"]},
822+
custom_agents=[
823+
{
824+
"name": "researcher",
825+
"description": "Deep codebase analysis agent",
826+
"tools": ["analyze-codebase"],
827+
"prompt": "You perform thorough codebase analysis.",
828+
},
829+
],
830+
on_permission_request=approve_all,
831+
)
832+
```
833+
834+
</details>
835+
836+
<details>
837+
<summary><strong>Go</strong></summary>
838+
839+
<!-- docs-validate: skip -->
840+
```go
841+
session, err := client.CreateSession(ctx, &copilot.SessionConfig{
842+
Tools: []copilot.Tool{heavyTool},
843+
DefaultAgent: &copilot.DefaultAgentConfig{
844+
ExcludedTools: []string{"analyze-codebase"},
845+
},
846+
CustomAgents: []copilot.CustomAgentConfig{
847+
{
848+
Name: "researcher",
849+
Description: "Deep codebase analysis agent",
850+
Tools: []string{"analyze-codebase"},
851+
Prompt: "You perform thorough codebase analysis.",
852+
},
853+
},
854+
})
855+
```
856+
857+
</details>
858+
859+
<details>
860+
<summary><strong>C# / .NET</strong></summary>
861+
862+
<!-- docs-validate: skip -->
863+
```csharp
864+
var session = await client.CreateSessionAsync(new SessionConfig
865+
{
866+
Tools = [analyzeCodebaseTool],
867+
DefaultAgent = new DefaultAgentConfig
868+
{
869+
ExcludedTools = ["analyze-codebase"],
870+
},
871+
CustomAgents =
872+
[
873+
new CustomAgentConfig
874+
{
875+
Name = "researcher",
876+
Description = "Deep codebase analysis agent",
877+
Tools = ["analyze-codebase"],
878+
Prompt = "You perform thorough codebase analysis.",
879+
},
880+
],
881+
});
882+
```
883+
884+
</details>
885+
886+
### How It Works
887+
888+
Tools listed in `defaultAgent.excludedTools`:
889+
890+
1. **Are registered** — their handlers are available for execution
891+
2. **Are hidden** from the main agent's tool list — the LLM won't see or call them directly
892+
3. **Remain available** to any custom sub-agent that includes them in its `tools` array
893+
894+
### Interaction with Other Tool Filters
895+
896+
`defaultAgent.excludedTools` is orthogonal to the session-level `availableTools` and `excludedTools`:
897+
898+
| Filter | Scope | Effect |
899+
|--------|-------|--------|
900+
| `availableTools` | Session-wide | Allowlist — only these tools exist for anyone |
901+
| `excludedTools` | Session-wide | Blocklist — these tools are blocked for everyone |
902+
| `defaultAgent.excludedTools` | Main agent only | These tools are hidden from the main agent but available to sub-agents |
903+
904+
Precedence:
905+
1. Session-level `availableTools`/`excludedTools` are applied first (globally)
906+
2. `defaultAgent.excludedTools` is applied on top, further restricting the main agent only
907+
908+
> **Note:** If a tool is in both `excludedTools` (session-level) and `defaultAgent.excludedTools`, the session-level exclusion takes precedence — the tool is unavailable to everyone.
909+
762910
## Attaching MCP Servers to Agents
763911

764912
Each custom agent can have its own MCP (Model Context Protocol) servers, giving it access to specialized data sources:

dotnet/src/Client.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Microsoft.Extensions.Logging;
77
using Microsoft.Extensions.Logging.Abstractions;
88
using StreamJsonRpc;
9+
using StreamJsonRpc.Protocol;
910
using System.Collections.Concurrent;
1011
using System.Data;
1112
using System.Diagnostics;
@@ -497,9 +498,11 @@ public async Task<CopilotSession> CreateSessionAsync(SessionConfig config, Cance
497498
hasHooks ? true : null,
498499
config.WorkingDirectory,
499500
config.Streaming is true ? true : null,
501+
config.IncludeSubAgentStreamingEvents,
500502
config.McpServers,
501503
"direct",
502504
config.CustomAgents,
505+
config.DefaultAgent,
503506
config.Agent,
504507
config.ConfigDir,
505508
config.EnableConfigDiscovery,
@@ -622,9 +625,11 @@ public async Task<CopilotSession> ResumeSessionAsync(string sessionId, ResumeSes
622625
config.EnableConfigDiscovery,
623626
config.DisableResume is true ? true : null,
624627
config.Streaming is true ? true : null,
628+
config.IncludeSubAgentStreamingEvents,
625629
config.McpServers,
626630
"direct",
627631
config.CustomAgents,
632+
config.DefaultAgent,
628633
config.Agent,
629634
config.SkillDirectories,
630635
config.DisabledSkills,
@@ -1102,7 +1107,7 @@ await Rpc.SessionFs.SetProviderAsync(
11021107
cancellationToken);
11031108
}
11041109

1105-
private void ConfigureSessionFsHandlers(CopilotSession session, Func<CopilotSession, ISessionFsHandler>? createSessionFsHandler)
1110+
private void ConfigureSessionFsHandlers(CopilotSession session, Func<CopilotSession, SessionFsProvider>? createSessionFsHandler)
11061111
{
11071112
if (_options.SessionFs is null)
11081113
{
@@ -1636,9 +1641,11 @@ internal record CreateSessionRequest(
16361641
bool? Hooks,
16371642
string? WorkingDirectory,
16381643
bool? Streaming,
1644+
bool? IncludeSubAgentStreamingEvents,
16391645
IDictionary<string, McpServerConfig>? McpServers,
16401646
string? EnvValueMode,
16411647
IList<CustomAgentConfig>? CustomAgents,
1648+
DefaultAgentConfig? DefaultAgent,
16421649
string? Agent,
16431650
string? ConfigDir,
16441651
bool? EnableConfigDiscovery,
@@ -1691,9 +1698,11 @@ internal record ResumeSessionRequest(
16911698
bool? EnableConfigDiscovery,
16921699
bool? DisableResume,
16931700
bool? Streaming,
1701+
bool? IncludeSubAgentStreamingEvents,
16941702
IDictionary<string, McpServerConfig>? McpServers,
16951703
string? EnvValueMode,
16961704
IList<CustomAgentConfig>? CustomAgents,
1705+
DefaultAgentConfig? DefaultAgent,
16971706
string? Agent,
16981707
IList<string>? SkillDirectories,
16991708
IList<string>? DisabledSkills,
@@ -1832,6 +1841,7 @@ private static LogLevel MapLevel(TraceEventType eventType)
18321841
AllowOutOfOrderMetadataProperties = true,
18331842
NumberHandling = JsonNumberHandling.AllowReadingFromString,
18341843
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)]
1844+
[JsonSerializable(typeof(CommonErrorData))]
18351845
[JsonSerializable(typeof(CreateSessionRequest))]
18361846
[JsonSerializable(typeof(CreateSessionResponse))]
18371847
[JsonSerializable(typeof(CustomAgentConfig))]

0 commit comments

Comments
 (0)